From 0487aee6b44890ab28830c79103fca8d3a5f0015 Mon Sep 17 00:00:00 2001 From: "Todd C. Miller" Date: Mon, 24 May 2010 15:40:36 -0400 Subject: [PATCH] Bring back closefrom settings. --- doc/sudo_plugin.cat | 130 +++++++++++++++++++------------------- doc/sudo_plugin.man.in | 16 ++++- doc/sudo_plugin.pod | 12 ++++ plugins/sudoers/sudoers.c | 18 +++++- plugins/sudoers/sudoers.h | 2 + src/parse_args.c | 8 ++- src/script.c | 29 ++++++--- src/selinux.c | 7 +- src/sudo.c | 15 +++++ src/sudo.h | 1 + 10 files changed, 153 insertions(+), 85 deletions(-) diff --git a/doc/sudo_plugin.cat b/doc/sudo_plugin.cat index 63841c527..81dc3de09 100644 --- a/doc/sudo_plugin.cat +++ b/doc/sudo_plugin.cat @@ -61,7 +61,7 @@ SSuuddoo PPlluuggiinn AAPPII -1.8.0a1 May 17, 2010 1 +1.8.0a1 May 24, 2010 1 @@ -127,7 +127,7 @@ SUDO_PLUGIN(1m) MAINTENANCE COMMANDS SUDO_PLUGIN(1m) -1.8.0a1 May 17, 2010 2 +1.8.0a1 May 24, 2010 2 @@ -193,7 +193,7 @@ SUDO_PLUGIN(1m) MAINTENANCE COMMANDS SUDO_PLUGIN(1m) -1.8.0a1 May 17, 2010 3 +1.8.0a1 May 24, 2010 3 @@ -242,6 +242,12 @@ SUDO_PLUGIN(1m) MAINTENANCE COMMANDS SUDO_PLUGIN(1m) error if the plugin does not support _s_u_d_o_e_d_i_t. For more information, see the _c_h_e_c_k___p_o_l_i_c_y section. + closefrom=number + If specified, the user has requested via the -C flag that + ssuuddoo close all files descriptors with a value of _n_u_m_b_e_r or + higher. The plugin may optionally pass this, or another + value, back in the _c_o_m_m_a_n_d___i_n_f_o list. + Additional settings may be added in the future so the plugin should silently ignore settings that it does not recognize. @@ -250,16 +256,10 @@ SUDO_PLUGIN(1m) MAINTENANCE COMMANDS SUDO_PLUGIN(1m) the form of "name=value" strings. The vector is terminated by a NULL pointer. - When parsing _u_s_e_r___i_n_f_o, the plugin should split on the ffiirrsstt - equal sign ('=') since the _n_a_m_e field will never include one - itself but the _v_a_l_u_e might. - - user=string - The name of the user invoking ssuuddoo. -1.8.0a1 May 17, 2010 4 +1.8.0a1 May 24, 2010 4 @@ -268,6 +268,13 @@ SUDO_PLUGIN(1m) MAINTENANCE COMMANDS SUDO_PLUGIN(1m) SUDO_PLUGIN(1m) MAINTENANCE COMMANDS SUDO_PLUGIN(1m) + When parsing _u_s_e_r___i_n_f_o, the plugin should split on the ffiirrsstt + equal sign ('=') since the _n_a_m_e field will never include one + itself but the _v_a_l_u_e might. + + user=string + The name of the user invoking ssuuddoo. + uid=uid_t The real user ID of the user invoking ssuuddoo. @@ -316,16 +323,9 @@ SUDO_PLUGIN(1m) MAINTENANCE COMMANDS SUDO_PLUGIN(1m) The function arguments are as follows: - exit_status - The command's exit status, as returned by the _w_a_i_t(2) system - call. The value of exit_status is undefined if error is non- - zero. - - - -1.8.0a1 May 17, 2010 5 +1.8.0a1 May 24, 2010 5 @@ -334,6 +334,11 @@ SUDO_PLUGIN(1m) MAINTENANCE COMMANDS SUDO_PLUGIN(1m) SUDO_PLUGIN(1m) MAINTENANCE COMMANDS SUDO_PLUGIN(1m) + exit_status + The command's exit status, as returned by the _w_a_i_t(2) system + call. The value of exit_status is undefined if error is non- + zero. + error If the command could not be executed, this is set to the value of errno set by the _e_x_e_c_v_e(2) system call. The plugin is @@ -384,14 +389,9 @@ SUDO_PLUGIN(1m) MAINTENANCE COMMANDS SUDO_PLUGIN(1m) The function arguments are as follows: - argc - The number of elements in _a_r_g_v, not counting the final NULL - pointer. - - -1.8.0a1 May 17, 2010 6 +1.8.0a1 May 24, 2010 6 @@ -400,6 +400,10 @@ SUDO_PLUGIN(1m) MAINTENANCE COMMANDS SUDO_PLUGIN(1m) SUDO_PLUGIN(1m) MAINTENANCE COMMANDS SUDO_PLUGIN(1m) + argc + The number of elements in _a_r_g_v, not counting the final NULL + pointer. + argv The argument vector describing the command the user wishes to run, in the same form as what would be passed to the _e_x_e_c_v_e_(_) @@ -451,13 +455,9 @@ SUDO_PLUGIN(1m) MAINTENANCE COMMANDS SUDO_PLUGIN(1m) nice value (optional). This option is only set on systems that support login classes. - preserve_groups=bool - If set, ssuuddoo will preserve the user's group vector instead - of initializing the group vector based on runas_user. - -1.8.0a1 May 17, 2010 7 +1.8.0a1 May 24, 2010 7 @@ -466,6 +466,10 @@ SUDO_PLUGIN(1m) MAINTENANCE COMMANDS SUDO_PLUGIN(1m) SUDO_PLUGIN(1m) MAINTENANCE COMMANDS SUDO_PLUGIN(1m) + preserve_groups=bool + If set, ssuuddoo will preserve the user's group vector instead + of initializing the group vector based on runas_user. + cwd=string The current working directory to change to when executing the command. @@ -501,6 +505,10 @@ SUDO_PLUGIN(1m) MAINTENANCE COMMANDS SUDO_PLUGIN(1m) transparently enable _s_u_d_o_e_d_i_t when the user attempts to run an editor. + closefrom=number + If specified, ssuuddoo will close all files descriptors with a + value of _n_u_m_b_e_r or higher. + Unsupported values will be ignored. argv_out @@ -513,17 +521,9 @@ SUDO_PLUGIN(1m) MAINTENANCE COMMANDS SUDO_PLUGIN(1m) the command. The plugin is responsible for allocating and populating the vector. - list - int (*list)(int verbose, const char *list_user, - int argc, char * const argv[]); - - List available privileges for the invoking user. Returns 1 on - success, 0 on failure and -1 on error. On error, the plugin may - optionally call the conversation or plugin_printf function with - -1.8.0a1 May 17, 2010 8 +1.8.0a1 May 24, 2010 8 @@ -532,6 +532,13 @@ SUDO_PLUGIN(1m) MAINTENANCE COMMANDS SUDO_PLUGIN(1m) SUDO_PLUGIN(1m) MAINTENANCE COMMANDS SUDO_PLUGIN(1m) + list + int (*list)(int verbose, const char *list_user, + int argc, char * const argv[]); + + List available privileges for the invoking user. Returns 1 on + success, 0 on failure and -1 on error. On error, the plugin may + optionally call the conversation or plugin_printf function with SUDO_CONF_ERROR_MSG to present additional error information to the user. @@ -579,24 +586,25 @@ SUDO_PLUGIN(1m) MAINTENANCE COMMANDS SUDO_PLUGIN(1m) The invalidate function is called when ssuuddoo is called with the -k or -K flag. For policy plugins such as _s_u_d_o_e_r_s that cache authentication credentials, this function will invalidate the - credentials. If the _r_e_m_o_v_e flag is set, the plugin may remove the - credentials instead of simply invalidating them. - The invalidate function should be NULL if the plugin does not - support credential caching. - _C_o_n_v_e_r_s_a_t_i_o_n _A_P_I +1.8.0a1 May 24, 2010 9 -1.8.0a1 May 17, 2010 9 +SUDO_PLUGIN(1m) MAINTENANCE COMMANDS SUDO_PLUGIN(1m) -SUDO_PLUGIN(1m) MAINTENANCE COMMANDS SUDO_PLUGIN(1m) + credentials. If the _r_e_m_o_v_e flag is set, the plugin may remove the + credentials instead of simply invalidating them. + The invalidate function should be NULL if the plugin does not + support credential caching. + + _C_o_n_v_e_r_s_a_t_i_o_n _A_P_I If the plugin needs to interact with the user, it may do so via the conversation function. A plugin should not attempt to read directly @@ -644,18 +652,10 @@ SUDO_PLUGIN(1m) MAINTENANCE COMMANDS SUDO_PLUGIN(1m) needed and supports standard _p_r_i_n_t_f_(_) escape sequences. See the sample plugin for an example of the conversation function - usage. - - II//OO PPlluuggiinn AAPPII - - - - - -1.8.0a1 May 17, 2010 10 +1.8.0a1 May 24, 2010 10 @@ -664,6 +664,9 @@ SUDO_PLUGIN(1m) MAINTENANCE COMMANDS SUDO_PLUGIN(1m) SUDO_PLUGIN(1m) MAINTENANCE COMMANDS SUDO_PLUGIN(1m) + usage. + + II//OO PPlluuggiinn AAPPII struct io_plugin { #define SUDO_IO_PLUGIN 2 unsigned int type; /* always SUDO_IO_PLUGIN */ @@ -716,12 +719,9 @@ SUDO_PLUGIN(1m) MAINTENANCE COMMANDS SUDO_PLUGIN(1m) char * const user_info[], int argc, char * const argv[], char * const user_env[]); - The _o_p_e_n function is run before the _l_o_g___i_n_p_u_t, _l_o_g___o_u_t_p_u_t or - _s_h_o_w___v_e_r_s_i_o_n functions are called. It is only called if the - -1.8.0a1 May 17, 2010 11 +1.8.0a1 May 24, 2010 11 @@ -730,6 +730,8 @@ SUDO_PLUGIN(1m) MAINTENANCE COMMANDS SUDO_PLUGIN(1m) SUDO_PLUGIN(1m) MAINTENANCE COMMANDS SUDO_PLUGIN(1m) + The _o_p_e_n function is run before the _l_o_g___i_n_p_u_t, _l_o_g___o_u_t_p_u_t or + _s_h_o_w___v_e_r_s_i_o_n functions are called. It is only called if the version is being requested or the _c_h_e_c_k___p_o_l_i_c_y function has returned successfully. It returns 1 on success, 0 on failure, -1 if a general error occurred, or -2 if there was a usage error. In @@ -785,9 +787,7 @@ SUDO_PLUGIN(1m) MAINTENANCE COMMANDS SUDO_PLUGIN(1m) - - -1.8.0a1 May 17, 2010 12 +1.8.0a1 May 24, 2010 12 @@ -853,7 +853,7 @@ SUDO_PLUGIN(1m) MAINTENANCE COMMANDS SUDO_PLUGIN(1m) -1.8.0a1 May 17, 2010 13 +1.8.0a1 May 24, 2010 13 @@ -919,7 +919,7 @@ SUDO_PLUGIN(1m) MAINTENANCE COMMANDS SUDO_PLUGIN(1m) -1.8.0a1 May 17, 2010 14 +1.8.0a1 May 24, 2010 14 @@ -979,12 +979,12 @@ PPOODD EERRRROORRSS Hey! TThhee aabboovvee ddooccuummeenntt hhaadd ssoommee ccooddiinngg eerrrroorrss,, wwhhiicchh aarree eexxppllaaiinneedd bbeellooww:: - Around line 597: + Around line 609: You forgot a '=back' before '=head3' -1.8.0a1 May 17, 2010 15 +1.8.0a1 May 24, 2010 15 diff --git a/doc/sudo_plugin.man.in b/doc/sudo_plugin.man.in index b3e76cc13..52f49d839 100644 --- a/doc/sudo_plugin.man.in +++ b/doc/sudo_plugin.man.in @@ -139,7 +139,7 @@ .\" ======================================================================== .\" .IX Title "SUDO_PLUGIN @mansectsu@" -.TH SUDO_PLUGIN @mansectsu@ "May 17, 2010" "1.8.0a1" "MAINTENANCE COMMANDS" +.TH SUDO_PLUGIN @mansectsu@ "May 24, 2010" "1.8.0a1" "MAINTENANCE COMMANDS" .\" For nroff, turn off justification. Always turn off hyphenation; it makes .\" way too many mistakes in technical documents. .if n .ad l @@ -352,6 +352,12 @@ Set to true when the \f(CW\*(C`\-e\*(C'\fR flag is is specified or if invoked as in the \fIcheck_policy\fR function or return \f(CW\*(C`\-2\*(C'\fR with a usage error if the plugin does not support \fIsudoedit\fR. For more information, see the \fIcheck_policy\fR section. +.IP "closefrom=number" 4 +.IX Item "closefrom=number" +If specified, the user has requested via the \f(CW\*(C`\-C\*(C'\fR flag that \fBsudo\fR +close all files descriptors with a value of \fInumber\fR or higher. +The plugin may optionally pass this, or another value, back in the +\&\fIcommand_info\fR list. .RE .RS 4 .Sp @@ -578,6 +584,10 @@ Set to true when in \fIsudoedit\fR mode. The plugin may enable \&\fIsudoedit\fR mode even if \fBsudo\fR was not invoked as \fBsudoedit\fR. This allows the plugin to perform command substitution and transparently enable \fIsudoedit\fR when the user attempts to run an editor. +.IP "closefrom=number" 4 +.IX Item "closefrom=number" +If specified, \fBsudo\fR will close all files descriptors with a value +of \fInumber\fR or higher. .RE .RS 4 .Sp @@ -1045,6 +1055,6 @@ the plugin type. .SH "POD ERRORS" .IX Header "POD ERRORS" Hey! \fBThe above document had some coding errors, which are explained below:\fR -.IP "Around line 597:" 4 -.IX Item "Around line 597:" +.IP "Around line 609:" 4 +.IX Item "Around line 609:" You forgot a '=back' before '=head3' diff --git a/doc/sudo_plugin.pod b/doc/sudo_plugin.pod index 07b9034a6..e866f2309 100644 --- a/doc/sudo_plugin.pod +++ b/doc/sudo_plugin.pod @@ -248,6 +248,13 @@ in the I function or return C<-2> with a usage error if the plugin does not support I. For more information, see the I section. +=item closefrom=number + +If specified, the user has requested via the C<-C> flag that B +close all files descriptors with a value of I or higher. +The plugin may optionally pass this, or another value, back in the +I list. + =back Additional settings may be added in the future so the plugin should @@ -505,6 +512,11 @@ I mode even if B was not invoked as B. This allows the plugin to perform command substitution and transparently enable I when the user attempts to run an editor. +=item closefrom=number + +If specified, B will close all files descriptors with a value +of I or higher. + =back Unsupported values will be ignored. diff --git a/plugins/sudoers/sudoers.c b/plugins/sudoers/sudoers.c index 7902f73bf..46a0cd6a4 100644 --- a/plugins/sudoers/sudoers.c +++ b/plugins/sudoers/sudoers.c @@ -289,14 +289,21 @@ sudoers_policy_main(int argc, char * const argv[], int pwflag, char *env_add[], int info_len = 0; int rval = FALSE; - /* refactor so list can use it too */ - /* Is root even allowed to run sudo? */ if (user_uid == 0 && !def_root_sudo) { warningx("sudoers specifies that root is not allowed to sudo"); goto done; } + /* Check for -C overriding def_closefrom. */ + if (user_closefrom >= 0 && user_closefrom != def_closefrom) { + if (!def_closefrom_override) { + warningx("you are not permitted to use the -C option"); + goto done; + } + def_closefrom = user_closefrom; + } + if (sigsetjmp(error_jmp, 1)) { /* error recovery via error(), errorx() or log_error() */ rewind_perms(); @@ -599,6 +606,8 @@ sudoers_policy_main(int argc, char * const argv[], int pwflag, char *env_add[], } command_info[info_len++] = gid_list; } + if (def_closefrom >= 0) + easprintf(&command_info[info_len++], "closefrom=%d", def_closefrom); /* Must audit before uid change. */ audit_success(NewArgv); @@ -1169,7 +1178,12 @@ deserialize_info(char * const settings[], char * const user_info[]) #define MATCHES(s, v) (strncmp(s, v, sizeof(v) - 1) == 0) /* Parse command line settings. */ + user_closefrom = -1; for (cur = settings; *cur != NULL; cur++) { + if (MATCHES(*cur, "closefrom=")) { + user_closefrom = atoi(*cur + sizeof("closefrom=") - 1); + continue; + } if (MATCHES(*cur, "debug_level=")) { debug_level = atoi(*cur + sizeof("debug_level=") - 1); continue; diff --git a/plugins/sudoers/sudoers.h b/plugins/sudoers/sudoers.h index bf95ac783..0b7661702 100644 --- a/plugins/sudoers/sudoers.h +++ b/plugins/sudoers/sudoers.h @@ -62,6 +62,7 @@ struct sudo_user { char *krb5_ccname; char *display; char *askpass; + int closefrom; int ngroups; uid_t uid; uid_t gid; @@ -178,6 +179,7 @@ struct sudo_user { #define runas_gr (sudo_user._runas_gr) #define user_role (sudo_user.role) #define user_type (sudo_user.type) +#define user_closefrom (sudo_user.closefrom) /* * We used to use the system definition of PASS_MAX or _PASSWD_LEN, diff --git a/src/parse_args.c b/src/parse_args.c index 59e1595e2..f6e490cd9 100644 --- a/src/parse_args.c +++ b/src/parse_args.c @@ -60,7 +60,6 @@ extern struct user_details user_details; /* XXX - better home for these and extern in header file */ int tgetpass_flags; -int user_closefrom = -1; const char *list_user, *runas_user, *runas_group; /* @@ -109,7 +108,9 @@ static struct sudo_settings { { "noninteractive" }, #define ARG_SUDOEDIT 16 { "sudoedit" }, -#define NUM_SETTINGS 17 +#define ARG_CLOSEFROM 17 + { "closefrom" }, +#define NUM_SETTINGS 18 { NULL } }; @@ -174,10 +175,11 @@ parse_args(int argc, char **argv, int *nargc, char ***nargv, char ***settingsp, SET(flags, MODE_BACKGROUND); break; case 'C': - if ((user_closefrom = atoi(optarg)) < 3) { + if (atoi(optarg) < 3) { warningx("the argument to -C must be at least 3"); usage(1); } + sudo_settings[ARG_CLOSEFROM].value = optarg; break; #ifdef HAVE_LOGIN_CAP_H case 'c': diff --git a/src/script.c b/src/script.c index caef0dc9b..42e57ee7e 100644 --- a/src/script.c +++ b/src/script.c @@ -125,8 +125,12 @@ static int suspend_parent(int signo, struct io_buffer *iobufs); static void flush_output(struct io_buffer *iobufs); static int perform_io(struct io_buffer *iobufs, fd_set *fdsr, fd_set *fdsw); static void handler(int s); -static int script_child(const char *path, char *argv[], char *envp[], int, int); -static void script_run(const char *path, char *argv[], char *envp[], int); +static int my_execve(const char *path, char *const argv[], + char *const envp[]); +static int script_child(struct command_details *details, char *argv[], + char *envp[], int, int); +static void script_run(struct command_details *detail, char *argv[], + char *envp[], int); static void sigwinch(int s); static void sync_ttysize(int src, int dst); static void deliver_signal(pid_t pid, int signo); @@ -353,7 +357,7 @@ suspend_parent(int signo, struct io_buffer *iobufs) /* * Like execve(2) but falls back to running through /bin/sh - * like execvp(3) if we get ENOEXEC. + * ala execvp(3) if we get ENOEXEC. */ static int my_execve(const char *path, char *const argv[], char *const envp[]) @@ -637,6 +641,7 @@ script_execve(struct command_details *details, char *argv[], char *envp[], /* child */ close(sv[0]); fcntl(sv[1], F_SETFD, FD_CLOEXEC); + /* XXX - defer call to exec_setup() until my_execve()? */ if (exec_setup(details) == 0) { /* headed for execve() */ if (log_io) { @@ -647,8 +652,10 @@ script_execve(struct command_details *details, char *argv[], char *envp[], close(io_pipe[STDOUT_FILENO][0]); if (io_pipe[STDERR_FILENO][0]) close(io_pipe[STDERR_FILENO][0]); - script_child(details->command, argv, envp, sv[1], rbac_enabled); + script_child(details, argv, envp, sv[1], rbac_enabled); } else { + if (details->closefrom >= 0) + closefrom(details->closefrom); #ifdef HAVE_SELINUX if (rbac_enabled) selinux_execve(details->command, argv, envp); @@ -979,7 +986,8 @@ handle_sigchld(int backchannel, struct command_status *cstat) * Returns an error if fork(2) fails, else calls _exit(2). */ int -script_child(const char *path, char *argv[], char *envp[], int backchannel, int rbac) +script_child(struct command_details *details, char *argv[], char *envp[], + int backchannel, int rbac) { struct command_status cstat; struct timeval tv; @@ -1083,7 +1091,7 @@ script_child(const char *path, char *argv[], char *envp[], int backchannel, int fcntl(errpipe[1], F_SETFD, FD_CLOEXEC); /* setup tty and exec command */ - script_run(path, argv, envp, rbac); + script_run(details, argv, envp, rbac); cstat.type = CMD_ERRNO; cstat.val = errno; write(errpipe[1], &cstat, sizeof(cstat)); @@ -1265,7 +1273,8 @@ flush_output(struct io_buffer *iobufs) * Returns only if execve() fails. */ static void -script_run(const char *path, char *argv[], char *envp[], int rbac_enabled) +script_run(struct command_details *details, char *argv[], char *envp[], + int rbac_enabled) { pid_t self = getpid(); @@ -1293,12 +1302,14 @@ script_run(const char *path, char *argv[], char *envp[], int rbac_enabled) if (script_fds[SFD_STDERR] != script_fds[SFD_SLAVE]) close(script_fds[SFD_STDERR]); + if (details->closefrom >= 0) + closefrom(details->closefrom); #ifdef HAVE_SELINUX if (rbac_enabled) - selinux_execve(path, argv, envp); + selinux_execve(details->command, argv, envp); else #endif - my_execve(path, argv, envp); + my_execve(details->command, argv, envp); } /* diff --git a/src/selinux.c b/src/selinux.c index 1e71acefc..c1c97658f 100644 --- a/src/selinux.c +++ b/src/selinux.c @@ -240,7 +240,7 @@ selinux_prefork(char *role, char *type, int ttyfd) } void -selinux_execv(char *path, char **argv) +selinux_execve(const char *path, char *argv[], char *envp[]) { if (setexeccon(new_context)) { warning("unable to set exec context to %s", new_context); @@ -260,11 +260,12 @@ selinux_execv(char *path, char **argv) #endif /* We use the "spare" slot in argv to store sesh. */ + /* XXX - no longer can do this XXX */ --argv; argv[0] = *argv[1] == '-' ? "-sesh" : "sesh"; - argv[1] = path; + argv[1] = (char *)path; - execv(_PATH_SUDO_SESH, argv); + execve(_PATH_SUDO_SESH, argv, envp); warning("%s", path); } diff --git a/src/sudo.c b/src/sudo.c index d9a0d0730..004617381 100644 --- a/src/sudo.c +++ b/src/sudo.c @@ -393,6 +393,7 @@ command_info_to_details(char * const info[], struct command_details *details) char *cp, *ep; memset(details, 0, sizeof(*details)); + details->closefrom = -1; #define SET_STRING(s, n) \ if (strncmp(s, info[i], sizeof(s) - 1) == 0 && info[i][sizeof(s) - 1]) { \ @@ -407,6 +408,20 @@ command_info_to_details(char * const info[], struct command_details *details) SET_STRING("chroot=", chroot) SET_STRING("command=", command) SET_STRING("cwd=", cwd) + if (strncmp("closefrom=", info[i], sizeof("closefrom=") - 1) == 0) { + cp = info[i] + sizeof("closefrom=") - 1; + if (*cp == '\0') + break; + errno = 0; + lval = strtol(cp, &ep, 0); + if (*cp != '\0' && *ep == '\0' && + !(errno == ERANGE && + (lval == LONG_MAX || lval == LONG_MIN)) && + lval < INT_MAX && lval > INT_MIN) { + details->closefrom = (int)lval; + } + break; + } break; case 'l': SET_STRING("login_class=", login_class) diff --git a/src/sudo.h b/src/sudo.h index 76bb5c81e..27e0c2417 100644 --- a/src/sudo.h +++ b/src/sudo.h @@ -127,6 +127,7 @@ struct command_details { int priority; int timeout; int ngroups; + int closefrom; GETGROUPS_T *groups; const char *command; const char *cwd; -- 2.40.0