From: Todd C. Miller Date: Tue, 25 Jan 2011 14:53:16 +0000 (-0500) Subject: Perform command escaping for "sudo -s" and "sudo -i" after validating X-Git-Tag: SUDO_1_7_5~50 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=0dc23beddd2ec66963faf86cf38cadf87cd1a1f3;p=sudo Perform command escaping for "sudo -s" and "sudo -i" after validating sudoers so the sudoers entries don't need to have all the backslashes. --HG-- branch : 1.7 --- diff --git a/NEWS b/NEWS index 15e9338e3..2356f35d4 100644 --- a/NEWS +++ b/NEWS @@ -59,6 +59,10 @@ What's new in Sudo 1.7.5? * Sudo will no longer refuse to run if the sudoers file is writable by root. + * Sudo now performs command line escaping for "sudo -s" and "sudo -i" + after validating the command so the sudoers entries do not need + to include the backslashes. + What's new in Sudo 1.7.4p6? * A bug has been fixed in the I/O logging support that could cause diff --git a/sudo.c b/sudo.c index b9b814854..2277f8403 100644 --- a/sudo.c +++ b/sudo.c @@ -559,6 +559,30 @@ main(argc, argv, envp) exit(0); /* not reached */ } +/* + * Escape any non-alpha numeric or blank characters to make sure + * they are not interpreted specially by the shell. + */ +static char * +escape_cmnd(const char *src) +{ + char *cmnd, *dst; + + /* Worst case scenario, we have to escape everything. */ + cmnd = dst = emalloc((2 * strlen(src)) + 1); + while (*src != '\0') { + if (!isalnum((unsigned char)*src) && !isspace((unsigned char)*src) && + *src != '_' && *src != '-') { + /* quote potential meta character */ + *dst++ = '\\'; + } + *dst++ = *src++; + } + *dst++ = '\0'; + + return cmnd; +} + /* * Initialize timezone, set umask, fill in ``sudo_user'' struct and * load the ``interfaces'' array. @@ -708,32 +732,14 @@ init_vars(envp) av[0] = user_shell; /* may be updated later */ if (NewArgc > 0) { - size_t cmnd_size = 1024; - char *cmnd, *src, *dst, **ap; - + size_t cmnd_size; + char *cmnd, *src, *dst, *end; + cmnd_size = (size_t) (NewArgv[NewArgc - 1] - NewArgv[0]) + + strlen(NewArgv[NewArgc - 1]) + 1; cmnd = dst = emalloc(cmnd_size); - for (ap = NewArgv; *ap != NULL; ap++) { - for (src = *ap; *src != '\0'; src++) { - /* reserve room for an escaped char + space */ - if (cmnd_size < (dst - cmnd) + 3) { - char *new_cmnd; - cmnd_size <<= 1; - new_cmnd = erealloc(cmnd, cmnd_size); - dst = new_cmnd + (dst - cmnd); - cmnd = new_cmnd; - } - if (isalnum((unsigned char)*src) || *src == '_' || *src == '-') { - *dst++ = *src; - } else { - /* quote potential meta character */ - *dst++ = '\\'; - *dst++ = *src; - } - } - *dst++ = ' '; - } - if (cmnd != dst) - dst--; /* replace last space with a NUL */ + src = NewArgv[0]; + for (end = src + cmnd_size - 1; src < end; src++, dst++) + *dst = *src == '\0' ? ' ' : *src; *dst = '\0'; av[1] = "-c"; av[2] = cmnd; @@ -929,6 +935,13 @@ run_command(path, argv, envp, uid, dowait) cstat.type = CMD_INVALID; cstat.val = 0; + /* Escape meta chars if running a shell with args. */ + if (ISSET(sudo_mode, MODE_SHELL) && argv[1] != NULL) { + char *cmnd = argv[2]; + argv[2] = escape_cmnd(cmnd); + efree(cmnd); + } + sudo_execve(path, argv, envp, uid, &cstat, dowait, ISSET(sudo_mode, MODE_BACKGROUND));