]> granicus.if.org Git - sudo/commitdiff
Perform command escaping for "sudo -s" and "sudo -i" after validating
authorTodd C. Miller <Todd.Miller@courtesan.com>
Tue, 25 Jan 2011 14:53:16 +0000 (09:53 -0500)
committerTodd C. Miller <Todd.Miller@courtesan.com>
Tue, 25 Jan 2011 14:53:16 +0000 (09:53 -0500)
sudoers so the sudoers entries don't need to have all the backslashes.

--HG--
branch : 1.7

NEWS
sudo.c

diff --git a/NEWS b/NEWS
index 15e9338e36f5442f15a616c83d9fcf82e8124aa6..2356f35d44d63f04067a53fe73f7040552cf6879 100644 (file)
--- 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 b9b814854b42e3b6b4d8ec3f20204b4919a20f2b..2277f8403a48e16db69b394274b5eeb16a8dac97 100644 (file)
--- 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));