--- a/src/parse_args.c 2021-02-01 15:25:32.237001319 +0500 +++ b/src/parse_args.c 2021-02-01 16:48:41.694003900 +0500 @@ -113,6 +113,16 @@ }; /* + * Default flags allowed when running a command. + */ +#define DEFAULT_VALID_FLAGS (MODE_BACKGROUND|MODE_PRESERVE_ENV|MODE_RESET_HOME|MODE_LOGIN_SHELL|MODE_NONINTERACTIVE|MODE_PRESERVE_GROUPS|MODE_SHELL) +#define EDIT_VALID_FLAGS MODE_NONINTERACTIVE +#define LIST_VALID_FLAGS (MODE_NONINTERACTIVE|MODE_LONG_LIST) +#define VALIDATE_VALID_FLAGS MODE_NONINTERACTIVE + + + +/* * Command line argument parsing. * Sets nargc and nargv which corresponds to the argc/argv we'll use * for the command to be run (if we are running one). @@ -123,7 +133,8 @@ { int mode = 0; /* what mode is sudo to be run in? */ int flags = 0; /* mode flags */ - int valid_flags, ch; + int valid_flags = DEFAULT_VALID_FLAGS; + int ch; int i, j; char *cp, **env_add, **settings; const char *debug_flags; @@ -140,6 +151,7 @@ if (strcmp(getprogname(), "sudoedit") == 0) { mode = MODE_EDIT; sudo_settings[ARG_SUDOEDIT].value = "true"; + valid_flags = EDIT_VALID_FLAGS; } /* Load local IP addresses and masks. */ @@ -159,9 +171,6 @@ #define is_envar (optind < argc && argv[optind][0] != '/' && \ strchr(argv[optind], '=') != NULL) - /* Flags allowed when running a command */ - valid_flags = MODE_BACKGROUND|MODE_PRESERVE_ENV|MODE_RESET_HOME| - MODE_LOGIN_SHELL|MODE_NONINTERACTIVE|MODE_SHELL; /* XXX - should fill in settings at the end to avoid dupes */ for (;;) { /* @@ -205,7 +214,7 @@ usage_excl(1); mode = MODE_EDIT; sudo_settings[ARG_SUDOEDIT].value = "true"; - valid_flags = MODE_NONINTERACTIVE; + valid_flags = EDIT_VALID_FLAGS; break; case 'g': runas_group = optarg; @@ -213,6 +222,7 @@ break; case 'H': sudo_settings[ARG_SET_HOME].value = "true"; + SET(flags, MODE_RESET_HOME); break; case 'h': if (mode && mode != MODE_HELP) { @@ -244,7 +254,7 @@ usage_excl(1); } mode = MODE_LIST; - valid_flags = MODE_NONINTERACTIVE|MODE_LONG_LIST; + valid_flags = LIST_VALID_FLAGS; break; case 'n': SET(flags, MODE_NONINTERACTIVE); @@ -252,6 +262,7 @@ break; case 'P': sudo_settings[ARG_PRESERVE_GROUPS].value = "true"; + SET(flags, MODE_PRESERVE_GROUPS); break; case 'p': sudo_settings[ARG_PROMPT].value = optarg; @@ -284,7 +295,7 @@ if (mode && mode != MODE_VALIDATE) usage_excl(1); mode = MODE_VALIDATE; - valid_flags = MODE_NONINTERACTIVE; + valid_flags = VALIDATE_VALID_FLAGS; break; case 'V': if (mode && mode != MODE_VERSION) @@ -317,7 +328,7 @@ 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 (argc == 0 && !(flags & (MODE_SHELL|MODE_LOGIN_SHELL))) { + if (argc == 0 && !ISSET(flags, MODE_SHELL|MODE_LOGIN_SHELL)) { mode = MODE_INVALIDATE; /* -k by itself */ sudo_settings[ARG_IGNORE_TICKET].value = NULL; valid_flags = 0; @@ -377,18 +388,22 @@ /* * For shell mode we need to rewrite argv */ - if (ISSET(mode, MODE_RUN) && ISSET(flags, MODE_SHELL)) { + if (ISSET(flags, MODE_SHELL|MODE_LOGIN_SHELL) && ISSET(mode, MODE_RUN)) { char **av, *cmnd = NULL; int ac = 1; if (argc != 0) { /* shell -c "command" */ char *src, *dst; - size_t cmnd_size = (size_t) (argv[argc - 1] - argv[0]) + - strlen(argv[argc - 1]) + 1; + size_t size = 0; + + for (av = argv; *av != NULL; av++) + size += strlen(*av) + 1; + if (size == 0) + errorx(1, _("zero length arg")); + cmnd = emalloc2(size, 2); - cmnd = dst = emalloc2(cmnd_size, 2); - for (av = argv; *av != NULL; av++) { + for (dst = cmnd, av = argv; *av != NULL; av++) { for (src = *av; *src != '\0'; src++) { /* quote potential meta characters */ if (!isalnum((unsigned char)*src) && *src != '_' && *src != '-') --- a/plugins/sudoers/sudoers.c 2021-02-01 13:07:26.965997870 +0500 +++ b/plugins/sudoers/sudoers.c 2021-02-01 15:07:30.767999365 +0500 @@ -495,7 +495,7 @@ /* If run as root with SUDO_USER set, set sudo_user.pw to that user. */ /* XXX - causes confusion when root is not listed in sudoers */ - if (sudo_mode & (MODE_RUN | MODE_EDIT) && prev_user != NULL) { + if (ISSET(sudo_mode, MODE_RUN|MODE_EDIT) && prev_user != NULL) { if (user_uid == 0 && strcmp(prev_user, "root") != 0) { struct passwd *pw; @@ -930,8 +930,8 @@ 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)) { + if (ISSET(sudo_mode, MODE_RUN|MODE_EDIT|MODE_CHECK)) { + if (!ISSET(sudo_mode, MODE_EDIT)) { if (def_secure_path && !user_is_exempt()) path = def_secure_path; set_perms(PERM_RUNAS); @@ -956,7 +956,7 @@ for (size = 0, av = NewArgv + 1; *av; av++) size += strlen(*av) + 1; user_args = emalloc(size); - if (ISSET(sudo_mode, MODE_SHELL|MODE_LOGIN_SHELL)) { + if (ISSET(sudo_mode, MODE_SHELL|MODE_LOGIN_SHELL) && ISSET(sudo_mode, MODE_RUN)) { /* * When running a command via a shell, the sudo front-end * escapes potential meta chars. We unescape non-spaces @@ -964,10 +964,14 @@ */ for (to = user_args, av = NewArgv + 1; (from = *av); av++) { while (*from) { - if (from[0] == '\\' && !isspace((unsigned char)from[1])) + if (from[0] == '\\' && from[1] != '\0' && !isspace((unsigned char)from[1])) from++; + if (size - (to - user_args) < 1) + errorx(1, _("internal error, %s overflow"), "set_cmnd()"); *to++ = *from++; } + if (size - (to - user_args) < 1) + errorx(1, _("internal error, %s overflow"), "set_cmnd()"); *to++ = ' '; } *--to = '\0'; @@ -1366,6 +1370,7 @@ static int deserialize_info(char * const args[], char * const settings[], char * const user_info[]) { + const int edit_mask = MODE_EDIT|MODE_IGNORE_TICKET|MODE_NONINTERACTIVE; char * const *cur; const char *p, *groups = NULL; const char *debug_flags = NULL; @@ -1514,6 +1519,11 @@ } } + /* Sudo front-end should restrict mode flags for sudoedit. */ + if (ISSET(flags, MODE_EDIT) && (flags & edit_mask) != flags) { + errorx(1, _("invalid mode flags from sudo front end: 0x%x"), flags); + } + for (cur = user_info; *cur != NULL; cur++) { if (MATCHES(*cur, "user=")) { user_name = estrdup(*cur + sizeof("user=") - 1);