Commit 4ebda86c authored by Dylan Hicks's avatar Dylan Hicks
Browse files

Created a wrapper around child_process.execFile() that runs a command as a...

Created a wrapper around child_process.execFile() that runs a command as a different user via (hopefully safe) sudo, while also sanity checking the parameters (eg. username) it feeds the sudo command. Further testing is needed, however.
parent 7bc0be5e
"use strict";
var cproc = require("child_process");
// TODO: JSDoc
module.exports = function sudo(command, args, options, callback){
const REGEX_USER = /^[a-zA-Z0-9_]+$/;
const REGEX_GROUP = REGEX_USER;
const REGEX_PASS = /^[^\x00-\x1f\x7f]+$/;
var argv = [];
try {
// Process and validate arguments, building an array of args for
// the underlying exec call
if(!command || typeof command != "string")
throw new Error("command must be a non-empty string");
// Validate any additional options
if(options && typeof options == "object"){
if(options.username){
if(
typeof options.username != "string"
|| !options.username.match(REGEX_USER)
)
throw new Error(
"username must be a string with only letters, "
+ "numbers, and underscores"
);
else argv.push("-u", options.username);
}
// TODO: Add test cases for this
if(options.password){
if(
typeof options.password != "string"
|| !options.password.match(REGEX_PASS)
)
throw new Error(
"password must only contain printable characters"
);
}
if(options.group){
if(
typeof options.group != "string"
|| !options.group.match(REGEX_GROUP)
)
throw new Error(
"group must be a string with only letters, "
+ "numbers, and underscores"
);
else argv.push("-g", options.group);
}
if(options.timeout); // here for readability
}
// Add -k to avoid credential caching, -S to accept password from
// stdin, and -- to prevent args from injecting arguments that affect
// the behaviour of sudo. Finally, add command to the list of arguments
// for sudo
argv.push("-kS", "--");
argv.push(command);
// If args was specified, append these one by one to argv for sudo,
// casting each to a string, and checking for null character abuse
if(args && args.length > 0){
for(var i = 0; i < args.length; i++){
var arg = ""+args[i];
if(arg.indexOf("\0") >= 0)
throw new Error("args must not contain null characters");
argv.push(arg);
}
}
console.dir(argv);
// Call sudo, and write password (if any) to its stdin, then return
// the resulting ChildProcess
var execOpts = {
timeout: (options.timeout>0 ? options.timeout : 0),
killSignal: (options.timeout>0 ? "SIGKILL" : "SIGTERM")
};
var childProc = cproc.execFile("sudo", argv, execOpts, callback);
childProc.stdin.end((options.password ? options.password : "") + "\n");
return childProc;
}
catch(e){
if(typeof callback == "function") callback(e);
}
}
......@@ -7,9 +7,14 @@ var qstring = require("querystring");
var express = require("express");
var hsocks = require("common/http-sockets");
var sudo = require("common/sudo");
var config = require("common/config");
function testCredentials(username, password, callback){
// TODO: replace with sudo implementation
// This is a stub that will likely just be replaced with
// a call to the sudo function
function testCredentials(username, password, callback){
// Validate input
if(
typeof username != "string" || !username
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment