From: Todd C. Miller Date: Sun, 21 Mar 2010 12:54:06 +0000 (-0400) Subject: Fix the -s and -i flags and add support for the "implied_shell" X-Git-Tag: SUDO_1_8_0~781 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=6b180d24daeb25692da44b41903ba558b4adb6b8;p=sudo Fix the -s and -i flags and add support for the "implied_shell" option. If the user does not specify a command, sudo will now pass in the path to the user's shell and set impied_shell=true. The plugin can them either check the command normally or return -2 to cause sudo to print a usage message and exit. --- diff --git a/doc/sudo_plugin.cat b/doc/sudo_plugin.cat index a6dd702e4..2e0a0b595 100644 --- a/doc/sudo_plugin.cat +++ b/doc/sudo_plugin.cat @@ -61,7 +61,7 @@ SSuuddoo PPlluuggiinn AAPPII -1.8.0a1 March 19, 2010 1 +1.8.0a1 March 21, 2010 1 @@ -127,7 +127,7 @@ SUDO_PLUGIN(1m) MAINTENANCE COMMANDS SUDO_PLUGIN(1m) -1.8.0a1 March 19, 2010 2 +1.8.0a1 March 21, 2010 2 @@ -172,6 +172,15 @@ SUDO_PLUGIN(1m) MAINTENANCE COMMANDS SUDO_PLUGIN(1m) Set to true if the user specified the -i flag, indicating that the user wishes to run a login shell. + implied_shell=bool + If the user does not specify a program on the command line, + ssuuddoo will pass the plugin the path to the user's shell and + set _i_m_p_l_i_e_d___s_h_e_l_l to true. This allows ssuuddoo with no + arguments to be used similarly to _s_u(1). If the plugin + does not to support this usage, it may return a value of -2 + from the check_policy function, which will cause ssuuddoo to + print a usage message and exit. + preserve_groups=bool Set to true if the user specified the -P flag, indicating that the user wishes to preserve the group vector instead @@ -182,25 +191,24 @@ SUDO_PLUGIN(1m) MAINTENANCE COMMANDS SUDO_PLUGIN(1m) command, indicating that the user wishes to ignore any cached authentication credentials. - login_class=string - BSD login class to use when setting resource limits and - nice value, if specified by the -c flag. - - selinux_role=string - SELinux role to use when executing the command, if - specified by the -r flag. +1.8.0a1 March 21, 2010 3 -1.8.0a1 March 19, 2010 3 +SUDO_PLUGIN(1m) MAINTENANCE COMMANDS SUDO_PLUGIN(1m) -SUDO_PLUGIN(1m) MAINTENANCE COMMANDS SUDO_PLUGIN(1m) + login_class=string + BSD login class to use when setting resource limits and + nice value, if specified by the -c flag. + selinux_role=string + SELinux role to use when executing the command, if + specified by the -r flag. selinux_type=string SELinux type to use when executing the command, if @@ -247,19 +255,11 @@ SUDO_PLUGIN(1m) MAINTENANCE COMMANDS SUDO_PLUGIN(1m) terminal device associated with the session, the value will be empty, as in tty=. - host=string - The local machine's hostname as returned by the - gethostname() system call. - lines=int - The number of lines the user's terminal supports. If there - is no terminal device available, a default value of 24 is - used. - -1.8.0a1 March 19, 2010 4 +1.8.0a1 March 21, 2010 4 @@ -268,6 +268,15 @@ SUDO_PLUGIN(1m) MAINTENANCE COMMANDS SUDO_PLUGIN(1m) SUDO_PLUGIN(1m) MAINTENANCE COMMANDS SUDO_PLUGIN(1m) + host=string + The local machine's hostname as returned by the + gethostname() system call. + + lines=int + The number of lines the user's terminal supports. If there + is no terminal device available, a default value of 24 is + used. + cols=int The number of columns the user's terminal supports. If there is no terminal device available, a default value of @@ -311,21 +320,12 @@ SUDO_PLUGIN(1m) MAINTENANCE COMMANDS SUDO_PLUGIN(1m) will be set. check_policy - int (*check_policy)(int argc, char * const argv[] - char *env_add[], char **command_info[], - char **argv_out[], char **user_env_out[]); - The _c_h_e_c_k___p_o_l_i_c_y function is called by ssuuddoo to determine whether - the user is allowed to run the specified commands. Returns 1 if - the command is allowed, 0 if not and -1 on error. On error, the - plugin may optionally call the conversation function with - SUDO_CONF_ERROR_MSG to present additional error information to the - user. -1.8.0a1 March 19, 2010 5 +1.8.0a1 March 21, 2010 5 @@ -334,6 +334,17 @@ SUDO_PLUGIN(1m) MAINTENANCE COMMANDS SUDO_PLUGIN(1m) SUDO_PLUGIN(1m) MAINTENANCE COMMANDS SUDO_PLUGIN(1m) + int (*check_policy)(int argc, char * const argv[] + char *env_add[], char **command_info[], + char **argv_out[], char **user_env_out[]); + + The _c_h_e_c_k___p_o_l_i_c_y function is called by ssuuddoo to determine whether + the user is allowed to run the specified commands. Returns 1 if + the command is allowed, 0 if not and -1 on error. On error, the + plugin may optionally call the conversation function with + SUDO_CONF_ERROR_MSG to present additional error information to the + user. + The function arguments are as follows: argc @@ -377,29 +388,29 @@ SUDO_PLUGIN(1m) MAINTENANCE COMMANDS SUDO_PLUGIN(1m) runas_gid=gid Group ID to run the command as. - runas_egid=gid - Effective group ID to run the command as. If not - specified, the value of _r_u_n_a_s___g_i_d is used. - runas_groups=list - The supplementary group vector to use for the command in - the form of a comma-separated list of group IDs. If - _p_r_e_s_e_r_v_e___g_r_o_u_p_s is set, this option is ignored. - login_class=login_class - BSD login class to use when setting resource limits and +1.8.0a1 March 21, 2010 6 -1.8.0a1 March 19, 2010 6 +SUDO_PLUGIN(1m) MAINTENANCE COMMANDS SUDO_PLUGIN(1m) -SUDO_PLUGIN(1m) MAINTENANCE COMMANDS SUDO_PLUGIN(1m) + runas_egid=gid + Effective group ID to run the command as. If not + specified, the value of _r_u_n_a_s___g_i_d is used. + runas_groups=list + The supplementary group vector to use for the command in + the form of a comma-separated list of group IDs. If + _p_r_e_s_e_r_v_e___g_r_o_u_p_s is set, this option is ignored. + login_class=login_class + BSD login class to use when setting resource limits and nice value (optional). This option is only set on systems that support login classes. @@ -442,22 +453,11 @@ SUDO_PLUGIN(1m) MAINTENANCE COMMANDS SUDO_PLUGIN(1m) system call when executing the command. The plugin is responsible for allocating and populating the vector. - user_env_out - The NULL-terminated environment vector to use when executing - 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 function with SUDO_CONF_ERROR_MSG -1.8.0a1 March 19, 2010 7 +1.8.0a1 March 21, 2010 7 @@ -466,6 +466,18 @@ SUDO_PLUGIN(1m) MAINTENANCE COMMANDS SUDO_PLUGIN(1m) SUDO_PLUGIN(1m) MAINTENANCE COMMANDS SUDO_PLUGIN(1m) + user_env_out + The NULL-terminated environment vector to use when executing + 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 function with SUDO_CONF_ERROR_MSG to present additional error information to the user. Privileges should be output via the conversation function using @@ -509,28 +521,27 @@ SUDO_PLUGIN(1m) MAINTENANCE COMMANDS SUDO_PLUGIN(1m) invalidate void (*invalidate)(int remove); - 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 March 21, 2010 8 -1.8.0a1 March 19, 2010 8 +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. -SUDO_PLUGIN(1m) MAINTENANCE COMMANDS SUDO_PLUGIN(1m) + 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 or display informational or error messages, it may do so via the conversation function. A @@ -566,6 +577,27 @@ SUDO_PLUGIN(1m) MAINTENANCE COMMANDS SUDO_PLUGIN(1m) usage. II//OO PPlluuggiinn AAPPII + + + + + + + + + + + + +1.8.0a1 March 21, 2010 9 + + + + + +SUDO_PLUGIN(1m) MAINTENANCE COMMANDS SUDO_PLUGIN(1m) + + struct io_plugin { #define SUDO_IO_PLUGIN 2 unsigned int type; /* always SUDO_IO_PLUGIN */ @@ -586,18 +618,6 @@ SUDO_PLUGIN(1m) MAINTENANCE COMMANDS SUDO_PLUGIN(1m) disabled, such as passwords). The log_output function receives output from the pseudo-tty that is suitable for replaying the user's session at a later time. Either log_input or log_output may be NULL. If the - - - -1.8.0a1 March 19, 2010 9 - - - - - -SUDO_PLUGIN(1m) MAINTENANCE COMMANDS SUDO_PLUGIN(1m) - - open function returns 0, no I/O will be sent to the plugin. The io_plugin struct has the following fields: @@ -632,6 +652,18 @@ SUDO_PLUGIN(1m) MAINTENANCE COMMANDS SUDO_PLUGIN(1m) A pointer to the conversation function that may be used by the _s_h_o_w___v_e_r_s_i_o_n function to display version information (see show_version below). The conversation function may also be + + + +1.8.0a1 March 21, 2010 10 + + + + + +SUDO_PLUGIN(1m) MAINTENANCE COMMANDS SUDO_PLUGIN(1m) + + used to display additional error message to the user. settings @@ -653,17 +685,6 @@ SUDO_PLUGIN(1m) MAINTENANCE COMMANDS SUDO_PLUGIN(1m) the form of "name=value" strings. The vector is terminated by a NULL pointer. - - -1.8.0a1 March 19, 2010 10 - - - - - -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. @@ -697,6 +718,18 @@ SUDO_PLUGIN(1m) MAINTENANCE COMMANDS SUDO_PLUGIN(1m) of errno set by the _e_x_e_c_v_e(2) system call. If the command was successfully executed, the value of error is 0. + + + +1.8.0a1 March 21, 2010 11 + + + + + +SUDO_PLUGIN(1m) MAINTENANCE COMMANDS SUDO_PLUGIN(1m) + + show_version int (*show_version)(int verbose); @@ -718,18 +751,6 @@ SUDO_PLUGIN(1m) MAINTENANCE COMMANDS SUDO_PLUGIN(1m) The function arguments are as follows: - - - -1.8.0a1 March 19, 2010 11 - - - - - -SUDO_PLUGIN(1m) MAINTENANCE COMMANDS SUDO_PLUGIN(1m) - - buf The buffer containing user input. len The length of _b_u_f in bytes. @@ -757,6 +778,24 @@ SUDO_PLUGIN(1m) MAINTENANCE COMMANDS SUDO_PLUGIN(1m) SSuuddoo iimmpplleemmeennttaattiioonn ddeettaaiillss Version macros: + + + + + + + + + +1.8.0a1 March 21, 2010 12 + + + + + +SUDO_PLUGIN(1m) MAINTENANCE COMMANDS SUDO_PLUGIN(1m) + + #define SUDO_API_VERSION_GET_MAJOR(v) ((v) >> 16) #define SUDO_API_VERSION_GET_MINOR(v) ((v) & 0xffff) #define SUDO_API_VERSION_SET_MAJOR(vp, n) do { \ @@ -787,6 +826,33 @@ SUDO_PLUGIN(1m) MAINTENANCE COMMANDS SUDO_PLUGIN(1m) -1.8.0a1 March 19, 2010 12 + + + + + + + + + + + + + + + + + + + + + + + + + + + +1.8.0a1 March 21, 2010 13 diff --git a/doc/sudo_plugin.man.in b/doc/sudo_plugin.man.in index 8dd462c15..46dab62b0 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@ "March 19, 2010" "1.8.0a1" "MAINTENANCE COMMANDS" +.TH SUDO_PLUGIN @mansectsu@ "March 21, 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 @@ -295,6 +295,15 @@ the user wishes to preserve the environment. .IX Item "login_shell=bool" Set to true if the user specified the \f(CW\*(C`\-i\*(C'\fR flag, indicating that the user wishes to run a login shell. +.IP "implied_shell=bool" 4 +.IX Item "implied_shell=bool" +If the user does not specify a program on the command line, \fBsudo\fR +will pass the plugin the path to the user's shell and set +\&\fIimplied_shell\fR to true. This allows \fBsudo\fR with no arguments +to be used similarly to \fIsu\fR\|(1). If the plugin does not to support +this usage, it may return a value of \-2 from the \f(CW\*(C`check_policy\*(C'\fR +function, which will cause \fBsudo\fR to print a usage message and +exit. .IP "preserve_groups=bool" 4 .IX Item "preserve_groups=bool" Set to true if the user specified the \f(CW\*(C`\-P\*(C'\fR flag, indicating that diff --git a/doc/sudo_plugin.pod b/doc/sudo_plugin.pod index 8f3dbb378..d11114910 100644 --- a/doc/sudo_plugin.pod +++ b/doc/sudo_plugin.pod @@ -180,6 +180,16 @@ the user wishes to preserve the environment. Set to true if the user specified the C<-i> flag, indicating that the user wishes to run a login shell. +=item implied_shell=bool + +If the user does not specify a program on the command line, B +will pass the plugin the path to the user's shell and set +I to true. This allows B with no arguments +to be used similarly to L. If the plugin does not to support +this usage, it may return a value of -2 from the C +function, which will cause B to print a usage message and +exit. + =item preserve_groups=bool Set to true if the user specified the C<-P> flag, indicating that diff --git a/plugins/sudoers/sudoers.c b/plugins/sudoers/sudoers.c index 469c5f1ff..6a5645fa9 100644 --- a/plugins/sudoers/sudoers.c +++ b/plugins/sudoers/sudoers.c @@ -262,12 +262,6 @@ sudoers_policy_open(unsigned int version, sudo_conv_t conversation, /* Set login class if applicable. */ set_loginclass(sudo_user.pw); -#if 0 /* XXX - later */ - /* Update initial shell now that runas is set. */ - if (ISSET(sudo_mode, MODE_LOGIN_SHELL)) - NewArgv[0] = runas_pw->pw_shell; -#endif - /* XXX */ user_env = envp; /* stash for later */ @@ -305,11 +299,17 @@ sudoers_policy_main(int argc, char * const argv[], char *env_add[], return -1; } - /* Local copy of argv */ + /* + * Make a local copy of argc/argv, with special handling + * for the '-e', '-i' or '-s' options. + * XXX - handle sudoedit + */ NewArgv = emalloc2(argc + 1, sizeof(char *)); memcpy(NewArgv, argv, argc * sizeof(char *)); NewArgv[argc] = NULL; NewArgc = argc; + if (ISSET(sudo_mode, MODE_LOGIN_SHELL)) + NewArgv[0] = runas_pw->pw_shell; /* Set environ to contents of user_env. */ env_init(user_env); @@ -387,9 +387,9 @@ sudoers_policy_main(int argc, char * const argv[], char *env_add[], if (ISSET(sudo_mode, MODE_PRESERVE_GROUPS)) def_preserve_groups = TRUE; - /* If no command line args and "set_home" is not set, error out. */ + /* If no command line args and "shell_noargs" is not set, error out. */ if (ISSET(sudo_mode, MODE_IMPLIED_SHELL) && !def_shell_noargs) { - /* XXX - error message */ + rval = -2; /* usage error */ goto done; } @@ -447,7 +447,7 @@ sudoers_policy_main(int argc, char * const argv[], char *env_add[], goto done; } else if (cmnd_status == NOT_FOUND) { //audit_failure(NewArgv, "%s: command not found", user_cmnd); - warningx("command not found", user_cmnd); + warningx("%s: command not found", user_cmnd); goto done; } @@ -622,12 +622,6 @@ init_vars(char * const envp[]) (void) tzset(); /* set the timezone if applicable */ #endif /* HAVE_TZSET */ -#if 0 - /* Default value for cmnd and cwd, overridden later. */ - if (user_cmnd == NULL) - user_cmnd = NewArgv[0]; -#endif - for (ep = envp; *ep; ep++) { /* XXX - don't fill in if empty string */ switch (**ep) { @@ -644,9 +638,7 @@ init_vars(char * const envp[]) user_path = *ep + 5; break; case 'S': - if (strncmp("SHELL=", *ep, 6) == 0) - user_shell = *ep + 6; - else if (!user_prompt && strncmp("SUDO_PROMPT=", *ep, 12) == 0) + if (!user_prompt && strncmp("SUDO_PROMPT=", *ep, 12) == 0) user_prompt = *ep + 12; else if (strncmp("SUDO_USER=", *ep, 10) == 0) prev_user = *ep + 10; @@ -683,8 +675,6 @@ init_vars(char * const envp[]) #ifdef HAVE_MBR_CHECK_MEMBERSHIP mbr_uid_to_uuid(user_uid, user_uuid); #endif - if (user_shell == NULL || *user_shell == '\0') - user_shell = estrdup(sudo_user.pw->pw_shell); /* It is now safe to use log_error() and set_perms() */ @@ -692,43 +682,6 @@ init_vars(char * const envp[]) /* may call log_error() */ set_fqdn(); } - -#if 0 /* XXX need to adapt this in sudo.c */ - /* - * If we were given the '-e', '-i' or '-s' options we need to redo - * NewArgv and NewArgc. - */ - if (ISSET(sudo_mode, MODE_EDIT)) { - NewArgv--; - NewArgc++; - NewArgv[0] = "sudoedit"; - } else if (ISSET(sudo_mode, MODE_SHELL)) { - char **av; - - /* Allocate an extra slot for execve() failure (ENOEXEC). */ - av = (char **) emalloc2(5, sizeof(char *)); - av++; - - av[0] = user_shell; /* may be updated later */ - if (NewArgc > 0) { - size_t size; - char *cmnd, *src, *dst, *end; - size = (size_t) (NewArgv[NewArgc - 1] - NewArgv[0]) + - strlen(NewArgv[NewArgc - 1]) + 1; - cmnd = emalloc(size); - src = NewArgv[0]; - dst = cmnd; - for (end = src + size - 1; src < end; src++, dst++) - *dst = *src == 0 ? ' ' : *src; - *dst = '\0'; - av[1] = "-c"; - av[2] = cmnd; - NewArgc = 2; - } - av[++NewArgc] = NULL; - NewArgv = av; - } -#endif } /* @@ -748,6 +701,10 @@ set_cmnd(sudo_mode) rval = FOUND; user_stat = emalloc(sizeof(struct stat)); + /* Default value for cmnd, overridden below. */ + if (user_cmnd == NULL) + user_cmnd = NewArgv[0]; + if (sudo_mode & (MODE_RUN | MODE_EDIT | MODE_CHECK)) { if (ISSET(sudo_mode, MODE_RUN | MODE_CHECK)) { set_perms(PERM_RUNAS); @@ -766,16 +723,9 @@ set_cmnd(sudo_mode) char *to, **from; size_t size, n; - /* If we didn't realloc NewArgv it is contiguous so just count. */ - if (!ISSET(sudo_mode, MODE_SHELL)) { - size = (size_t) (NewArgv[NewArgc-1] - NewArgv[1]) + - strlen(NewArgv[NewArgc-1]) + 1; - } else { - for (size = 0, from = NewArgv + 1; *from; from++) - size += strlen(*from) + 1; - } - /* Alloc and build up user_args. */ + for (size = 0, from = NewArgv + 1; *from; from++) + size += strlen(*from) + 1; user_args = emalloc(size); for (to = user_args, from = NewArgv + 1; *from; from++) { n = strlcpy(to, *from, size - (to - user_args)); @@ -1197,6 +1147,11 @@ deserialize_info(char * const settings[], char * const user_info[]) } continue; } + if (MATCHES(*cur, "implied_shell=")) { + if (atobool(*cur + sizeof("implied_shell=") - 1) == TRUE) + SET(flags, MODE_IMPLIED_SHELL); + continue; + } if (MATCHES(*cur, "preserve_groups=")) { SET(flags, MODE_PRESERVE_GROUPS); continue; diff --git a/plugins/sudoers/sudoers.h b/plugins/sudoers/sudoers.h index 19ac90131..8a829a19b 100644 --- a/plugins/sudoers/sudoers.h +++ b/plugins/sudoers/sudoers.h @@ -48,7 +48,6 @@ struct sudo_user { struct stat *cmnd_stat; char *name; char *path; - char *shell; char *tty; char *ttypath; char *host; @@ -156,7 +155,6 @@ struct sudo_user { #define user_passwd (sudo_user.pw->pw_passwd) #define user_uuid (sudo_user.uuid) #define user_dir (sudo_user.pw->pw_dir) -#define user_shell (sudo_user.shell) #define user_ngroups (sudo_user.ngroups) #define user_groups (sudo_user.groups) #define user_tty (sudo_user.tty) diff --git a/src/parse_args.c b/src/parse_args.c index 222a19057..d8837a86a 100644 --- a/src/parse_args.c +++ b/src/parse_args.c @@ -66,7 +66,6 @@ const char *list_user, *runas_user, *runas_group; /* * Local functions. */ -static void usage(int) __attribute__((__noreturn__)); static void usage_excl(int) __attribute__((__noreturn__)); /* @@ -102,7 +101,9 @@ static struct sudo_settings { { "runas_user" }, #define ARG_PROGNAME 12 { "progname" }, -#define NUM_SETTINGS 13 +#define ARG_IMPLIED_SHELL 13 + { "implied_shell" }, +#define NUM_SETTINGS 14 { NULL } }; @@ -295,13 +296,13 @@ parse_args(int argc, char **argv, int *nargc, char ***nargv, char ***settingsp, } } - *nargc = argc - optind; - *nargv = argv + optind; + argc -= optind; + argv += optind; if (!mode) { /* Defer -k mode setting until we know whether it is a flag or not */ if (sudo_settings[ARG_IGNORE_TICKET].value != NULL) { - if (*nargc == 0) { + if (argc == 0) { mode = MODE_INVALIDATE; /* -k by itself */ sudo_settings[ARG_IGNORE_TICKET].value = NULL; valid_flags = 0; @@ -311,7 +312,7 @@ parse_args(int argc, char **argv, int *nargc, char ***nargv, char ***settingsp, mode = MODE_RUN; /* running a command */ } - if (*nargc > 0 && mode == MODE_LIST) + if (argc > 0 && mode == MODE_LIST) mode = MODE_CHECK; if (ISSET(flags, MODE_LOGIN_SHELL)) { @@ -347,15 +348,55 @@ parse_args(int argc, char **argv, int *nargc, char ***nargv, char ***settingsp, warningx("the `-A' and `-S' options may not be used together"); usage(1); } - if ((*nargc == 0 && mode == MODE_EDIT) || - (*nargc > 0 && !ISSET(mode, MODE_RUN | MODE_EDIT | MODE_CHECK))) + if ((argc == 0 && mode == MODE_EDIT) || + (argc > 0 && !ISSET(mode, MODE_RUN | MODE_EDIT | MODE_CHECK))) usage(1); - if (*nargc == 0 && mode == MODE_RUN && !ISSET(flags, MODE_SHELL)) + if (argc == 0 && mode == MODE_RUN && !ISSET(flags, MODE_SHELL)) { SET(flags, (MODE_IMPLIED_SHELL | MODE_SHELL)); + sudo_settings[ARG_IMPLIED_SHELL].value = "true"; + } if (mode == MODE_HELP) usage(0); + /* + * For shell mode we need to rewrite argv + */ + if (ISSET(mode, MODE_RUN) && ISSET(flags, MODE_SHELL)) { + char **av; + int ac; + + if (argc == 0) { + /* just the shell */ + ac = argc + 1; + av = emalloc2(ac + 1, sizeof(char *)); + memcpy(av + 1, argv, argc * sizeof(char *)); + } else { + /* shell -c "command" */ + size_t size; + char *src, *dst, *end; + + /* length of the command + NUL terminator */ + size = (size_t)(argv[argc - 1] - argv[0]) + + strlen(argv[argc - 1]) + 1; + + ac = 3; + av = emalloc2(ac + 1, sizeof(char *)); + av[1] = "-c"; + av[2] = dst = emalloc(size); + + src = argv[0]; + for (end = src + size - 1; src < end; src++, dst++) + *dst = *src == 0 ? ' ' : *src; + *dst = '\0'; + } + av[0] = (char *)user_details.shell; /* plugin may override shell */ + av[ac] = NULL; + + argv = av; + argc = ac; + } + /* * Format setting_pairs into settings array. */ @@ -375,6 +416,8 @@ parse_args(int argc, char **argv, int *nargc, char ***nargv, char ***settingsp, *settingsp = settings; *env_addp = env_add; + *nargc = argc; + *nargv = argv; return(mode | flags); } @@ -388,7 +431,7 @@ usage_out(const char *buf) * Give usage message and exit. * The actual usage strings are in sudo_usage.h for configure substitution. */ -static void +void usage(int exit_val) { struct lbuf lbuf; diff --git a/src/sudo.c b/src/sudo.c index a595b0aaa..7b9554955 100644 --- a/src/sudo.c +++ b/src/sudo.c @@ -224,8 +224,11 @@ main(int argc, char *argv[], char *envp[]) ok = policy_plugin.u.policy->check_policy(nargc, nargv, env_add, &command_info, &argv_out, &user_env_out); sudo_debug(8, "policy plugin returns %d", ok); - if (ok != TRUE) - exit(ok); /* plugin printed error message */ + if (ok != TRUE) { + if (ok == -2) + usage(1); + exit(1); /* plugin printed error message */ + } command_info_to_details(command_info, &command_details); /* Restore coredumpsize resource limit before running. */ #if defined(RLIMIT_CORE) && !defined(SUDO_DEVEL) @@ -330,6 +333,12 @@ get_user_info(struct user_details *ud) errorx(1, "unable to allocate memory"); ud->username = user_info[i] + sizeof("user=") - 1; + /* Stash user's shell for use with the -s flag; don't pass to plugin. */ + if ((ud->shell = getenv("SHELL")) == NULL || ud->shell[0] == '\0') { + ud->shell = pw->pw_shell[0] ? pw->pw_shell : _PATH_BSHELL; + } + ud->shell = estrdup(ud->shell); + easprintf(&user_info[++i], "uid=%lu", (unsigned long)ud->uid); easprintf(&user_info[++i], "euid=%lu", (unsigned long)ud->euid); easprintf(&user_info[++i], "gid=%lu", (unsigned long)ud->gid); diff --git a/src/sudo.h b/src/sudo.h index 5dcc4871d..2408e9112 100644 --- a/src/sudo.h +++ b/src/sudo.h @@ -117,6 +117,7 @@ struct user_details { const char *cwd; const char *tty; const char *host; + const char *shell; GETGROUPS_T *groups; int ngroups; int ts_cols; @@ -210,6 +211,9 @@ int exec_setup(struct command_details *details); extern int debug_level; extern struct plugin_container_list io_plugins; +/* parse_args.c */ +void usage(int) __attribute__((__noreturn__)); + #ifndef errno extern int errno; #endif