From 99a995a6b8d9ae0ab17938ae63714996ddccbb30 Mon Sep 17 00:00:00 2001 From: Bert Belder Date: Fri, 27 Apr 2012 17:41:56 +0200 Subject: [PATCH] uv_spawn: support setting the child process' user and group id --- include/uv-private/uv-unix.h | 5 +++++ include/uv-private/uv-win.h | 4 ++++ include/uv.h | 39 ++++++++++++++++++++++++++++++++---- src/unix/process.c | 16 +++++++++++++++ src/win/process.c | 11 +++++++--- 5 files changed, 68 insertions(+), 7 deletions(-) diff --git a/include/uv-private/uv-unix.h b/include/uv-private/uv-unix.h index 0137c0c3..e190b853 100644 --- a/include/uv-private/uv-unix.h +++ b/include/uv-private/uv-unix.h @@ -33,6 +33,7 @@ #include #include #include +#include #include #include @@ -51,6 +52,10 @@ typedef pthread_t uv_thread_t; typedef pthread_mutex_t uv_mutex_t; typedef pthread_rwlock_t uv_rwlock_t; +/* Platform-specific definitions for uv_spawn support. */ +typedef gid_t uv_gid_t; +typedef uid_t uv_uid_t; + /* Platform-specific definitions for uv_dlopen support. */ typedef void* uv_lib_t; #define UV_DYNAMIC /* empty */ diff --git a/include/uv-private/uv-win.h b/include/uv-private/uv-win.h index 59eb377a..c55802c6 100644 --- a/include/uv-private/uv-win.h +++ b/include/uv-private/uv-win.h @@ -165,6 +165,10 @@ typedef struct uv_once_s { HANDLE padding; } uv_once_t; +/* Platform-specific definitions for uv_spawn support. */ +typedef unsigned char uv_uid_t; +typedef unsigned char uv_gid_t; + /* Platform-specific definitions for uv_dlopen support. */ typedef HMODULE uv_lib_t; #define UV_DYNAMIC FAR WINAPI diff --git a/include/uv.h b/include/uv.h index c8a81245..97d419d2 100644 --- a/include/uv.h +++ b/include/uv.h @@ -1105,12 +1105,18 @@ typedef struct uv_process_options_s { * in. Stands for current working directory. */ char* cwd; - /* - * TODO describe how this works. + * Various flags that control how uv_spawn() behaves. See the definition of + * `enum uv_process_flags` below. */ - int windows_verbatim_arguments; - + unsigned int flags; + /* + * Libuv can change the child process' user/group id. This happens only when + * the appropriate bits are set in the flags fields. This is not supported on + * windows; uv_spawn() will fail and set the error to UV_ENOTSUP. + */ + uv_uid_t uid; + uv_gid_t gid; /* * The user should supply pointers to initialized uv_pipe_t structs for * stdio. This is used to to send or receive input from the subprocess. @@ -1121,6 +1127,30 @@ typedef struct uv_process_options_s { uv_pipe_t* stderr_stream; } uv_process_options_t; +/* + * These are the flags that can be used for the uv_process_options.flags field. + */ +enum uv_process_flags { + /* + * Set the child process' user id. The user id is supplied in the `uid` field + * of the options struct. This does not work on windows; setting this flag + * will cause uv_spawn() to fail. + */ + UV_PROCESS_SETUID = (1 << 0), + /* + * Set the child process' group id. The user id is supplied in the `gid` + * field of the options struct. This does not work on windows; setting this + * flag will cause uv_spawn() to fail. + */ + UV_PROCESS_SETGID = (1 << 1), + /* + * Do not wrap any arguments in quotes, or perform any other escaping, when + * converting the argument list into a command line string. This option is + * only meaningful on Windows systems. On unix it is silently ignored. + */ + UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS = (1 << 2) +}; + /* * uv_process_t is a subclass of uv_handle_t */ @@ -1135,6 +1165,7 @@ struct uv_process_s { UV_EXTERN int uv_spawn(uv_loop_t*, uv_process_t*, uv_process_options_t options); + /* * Kills the process with the specified signal. The user must still * call uv_close on the process. diff --git a/src/unix/process.c b/src/unix/process.c index 9a5c76c7..10872cce 100644 --- a/src/unix/process.c +++ b/src/unix/process.c @@ -174,6 +174,12 @@ int uv_spawn(uv_loop_t* loop, uv_process_t* process, pid_t pid; int flags; + assert(options.file != NULL); + assert(!(options.flags & ~(UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS | + UV_PROCESS_SETGID | + UV_PROCESS_SETUID))); + + uv__handle_init(loop, (uv_handle_t*)process, UV_PROCESS); loop->counters.process_init++; @@ -263,6 +269,16 @@ int uv_spawn(uv_loop_t* loop, uv_process_t* process, _exit(127); } + if ((options.flags & UV_PROCESS_SETGID) && setgid(options.gid)) { + perror("setgid()"); + _exit(127); + } + + if ((options.flags & UV_PROCESS_SETUID) && setuid(options.uid)) { + perror("setuid()"); + _exit(127); + } + environ = options.env; execvp(options.file, options.args); diff --git a/src/win/process.c b/src/win/process.c index 74744860..aacb0617 100644 --- a/src/win/process.c +++ b/src/win/process.c @@ -872,17 +872,22 @@ int uv_spawn(uv_loop_t* loop, uv_process_t* process, STARTUPINFOW startup; PROCESS_INFORMATION info; - if (!options.file) { - uv__set_artificial_error(loop, UV_EINVAL); + if (options.flags & (UV_PROCESS_SETGID | UV_PROCESS_SETUID)) { + uv__set_artificial_error(loop, UV_ENOTSUP); return -1; } + assert(options.file != NULL); + assert(!(options.flags & ~(UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS | + UV_PROCESS_SETGID | + UV_PROCESS_SETUID))); + uv_process_init(loop, process); process->exit_cb = options.exit_cb; UTF8_TO_UTF16(options.file, application); arguments = options.args ? make_program_args(options.args, - options.windows_verbatim_arguments) : NULL; + options.flags & UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS) : NULL; env = options.env ? make_program_env(options.env) : NULL; if (options.cwd) {