]> granicus.if.org Git - sudo/commitdiff
Stash the "safe" path (ie: the one listed in sudoers) to the command instead
authorTodd C. Miller <Todd.Miller@courtesan.com>
Sat, 10 Apr 1999 04:10:01 +0000 (04:10 +0000)
committerTodd C. Miller <Todd.Miller@courtesan.com>
Sat, 10 Apr 1999 04:10:01 +0000 (04:10 +0000)
of stashing the struct stat.  Should be safer.

CHANGES
logging.c
parse.c
parse.yacc
sudo.c
sudo.h
sudo.tab.c
testsudoers.c
visudo.c

diff --git a/CHANGES b/CHANGES
index f578401b805a98c6d26abcb3eb2144bc866d1ae9..1f28f4c5cf4fe79760393055a5b0b09ddb8d524b 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1060,3 +1060,6 @@ Sudo 1.5.9 released.
 
 332) You can now specifiy a host list instead of just a host or alias
      in a privilege list.  Ie: user=host1,host2,ALIAS,!host3 /bin/ls
+
+333)  Stash the "safe" path to the command instead of stashing the struct
+     stat.  Should be safer.
index 45f9250e39f457044f69286144dcd0e5820651a6..c3f665fed65cecb6591dc30c29e302257ab39abe 100644 (file)
--- a/logging.c
+++ b/logging.c
@@ -251,12 +251,6 @@ void log_error(code)
                SUDOERS_MODE);
            break;
 
-       case SPOOF_ATTEMPT:
-           (void) sprintf(p,
-               "probable spoofing attempt; TTY=%s ; PWD=%s ; USER=%s ; COMMAND=",
-               tty, cwd, runas_user);
-           break;
-
        case BAD_STAMPDIR:
            (void) sprintf(p,
            "%s owned by non-root or not mode 0700; TTY=%s ; PWD=%s ; USER=%s ; COMMAND=",
@@ -653,12 +647,6 @@ void inform_user(code)
                SUDOERS_MODE);
            break;
 
-       case SPOOF_ATTEMPT:
-           (void) fprintf(stderr,
-               "%s is not the same command that was validated, disallowing.\n",
-               cmnd);
-           break;
-
        case BAD_STAMPDIR:
            (void) fprintf(stderr,
                "Timestamp directory has wrong permissions, ignoring.\n");
@@ -729,7 +717,6 @@ static int appropriate(code)
      */
     case VALIDATE_ERROR:
     case NO_SUDOERS_FILE:
-    case SPOOF_ATTEMPT:
     case BAD_STAMPDIR:
     case BAD_STAMPFILE:
     case BAD_ALLOCATION:
diff --git a/parse.c b/parse.c
index 25d868f8a5f8c3144c8560c5f2a39d412d1c2d7d..97e4d033bc97ee0ca75feddcbd01a8f8ac6cccb9 100644 (file)
--- a/parse.c
+++ b/parse.c
@@ -209,26 +209,27 @@ int command_matches(cmnd, user_args, path, sudoers_args)
     char *sudoers_args;
 {
     int plen;
+    static struct stat cst;
     struct stat pst;
     DIR *dirp;
     struct dirent *dent;
     char buf[MAXPATHLEN];
-    static char *c;
+    static char *cmnd_base;
 
-    /* don't bother with pseudo commands like "validate" */
+    /* Don't bother with pseudo commands like "validate" */
     if (strchr(cmnd, '/') == NULL)
        return(FALSE);
 
     plen = strlen(path);
 
-    /* only need to stat cmnd once since it never changes */
-    if (cmnd_st.st_dev == 0) {
-       if (stat(cmnd, &cmnd_st) < 0)
+    /* Only need to stat cmnd once since it never changes */
+    if (cst.st_dev == 0) {
+       if (stat(cmnd, &cst) == -1)
            return(FALSE);
-       if ((c = strrchr(cmnd, '/')) == NULL)
-           c = cmnd;
+       if ((cmnd_base = strrchr(cmnd, '/')) == NULL)
+           cmnd_base = cmnd;
        else
-           c++;
+           cmnd_base++;
     }
 
     /*
@@ -237,21 +238,29 @@ int command_matches(cmnd, user_args, path, sudoers_args)
      */
     if (has_meta(path)) {
        /*
-        * Return true if fnmatch(3) succeeds and there are no args
-        * (in sudoers or command) or if the args match;
+        * Return true if fnmatch(3) succeeds AND
+        *  a) there are no args in sudoers OR
+        *  b) there are no args on command line and none required by sudoers OR
+        *  c) there are args in sudoers and on command line and they match
         * else return false.
         */
-       if (fnmatch(path, cmnd, FNM_PATHNAME))
+       if (fnmatch(path, cmnd, FNM_PATHNAME) != 0)
            return(FALSE);
-       if (!sudoers_args)
+       if (!sudoers_args ||
+           (!user_args && sudoers_args && !strcmp("\"\"", sudoers_args)) ||
+           (sudoers_args && fnmatch(sudoers_args, user_args ? user_args : "",
+           0) == 0)) {
+           if (cmnd_safe)
+               free(cmnd_safe);
+           cmnd_safe = estrdup(cmnd);
            return(TRUE);
-       else if (!user_args && sudoers_args && !strcmp("\"\"", sudoers_args))
-           return(TRUE);
-       else if (sudoers_args)
-           return((fnmatch(sudoers_args, user_args ? user_args : "", 0) == 0));
-       else
+       } else
            return(FALSE);
     } else {
+       /*
+        * No meta characters
+        * Check to make sure this is not a directory spec (doesn't end in '/')
+        */
        if (path[plen - 1] != '/') {
            char *p;
 
@@ -260,26 +269,26 @@ int command_matches(cmnd, user_args, path, sudoers_args)
                p = path;
            else
                p++;
-           if (strcmp(c, p))
-               return(FALSE);
-
-           if (stat(path, &pst) < 0)
+           if (strcmp(cmnd_base, p) != 0 || stat(path, &pst) == -1)
                return(FALSE);
 
            /*
-            * Return true if inode/device matches and there are no args
-            * (in sudoers or command) or if the args match;
-            * else return false.
+            * Return true if inode/device matches AND
+            *  a) there are no args in sudoers OR
+            *  b) there are no args on command line and none req by sudoers OR
+            *  c) there are args in sudoers and on command line and they match
             */
-           if (cmnd_st.st_dev != pst.st_dev || cmnd_st.st_ino != pst.st_ino)
+           if (cst.st_dev != pst.st_dev || cst.st_ino != pst.st_ino)
                return(FALSE);
-           if (!sudoers_args)
-               return(TRUE);
-           else if (!user_args && sudoers_args && !strcmp("\"\"", sudoers_args))
+           if (!sudoers_args ||
+               (!user_args && sudoers_args && !strcmp("\"\"", sudoers_args)) ||
+               (sudoers_args &&
+                fnmatch(sudoers_args, user_args ? user_args : "", 0) == 0)) {
+               if (cmnd_safe)
+                   free(cmnd_safe);
+               cmnd_safe = estrdup(path);
                return(TRUE);
-           else if (sudoers_args)
-               return((fnmatch(sudoers_args, user_args ? user_args : "", 0) == 0));
-           else
+           } else
                return(FALSE);
        }
 
@@ -298,12 +307,16 @@ int command_matches(cmnd, user_args, path, sudoers_args)
            strcat(buf, dent->d_name);
 
            /* only stat if basenames are not the same */
-           if (strcmp(c, dent->d_name))
+           if (strcmp(cmnd_base, dent->d_name))
                continue;
-           if (stat(buf, &pst) < 0)
+           if (stat(buf, &pst) == -1)
                continue;
-           if (cmnd_st.st_dev == pst.st_dev && cmnd_st.st_ino == pst.st_ino)
+           if (cst.st_dev == pst.st_dev && cst.st_ino == pst.st_ino) {
+               if (cmnd_safe)
+                   free(cmnd_safe);
+               cmnd_safe = estrdup(buf);
                break;
+           }
        }
 
        closedir(dirp);
@@ -411,7 +424,7 @@ int netgr_matches(netgr, host, user)
     /* get the domain name (if any) */
     if (domain == (char *) -1) {
        domain = (char *) emalloc(MAXHOSTNAMELEN);
-       if (getdomainname(domain, MAXHOSTNAMELEN) != 0 || *domain == '\0') {
+       if (getdomainname(domain, MAXHOSTNAMELEN) == -1 || *domain == '\0') {
            (void) free(domain);
            domain = NULL;
        }
index b537b81ecac846cd1e27be4e6407ae4e1c71983d..760abc4a909420ae6d3b4ca29ab2ea928c87994b 100644 (file)
@@ -475,8 +475,10 @@ cmnd               :       ALL {
                                expand_match_list();
                            }
 
-                           cmnd_matches = TRUE;
-                           $$ = TRUE;
+                           $$ = cmnd_matches = TRUE;
+                           if (cmnd_safe)
+                               free(cmnd_safe);
+                           cmnd_safe = estrdup(cmnd);
                        }
                |       ALIAS {
                            if (printmatches == TRUE && in_alias == TRUE) {
diff --git a/sudo.c b/sudo.c
index bde0d84d61d90ef417740d60f893b3dadbf9cd73..cbb7cd3b23993d1d0a3204ef7e9cafb5c913bab4 100644 (file)
--- a/sudo.c
+++ b/sudo.c
@@ -122,6 +122,7 @@ char **NewArgv = NULL;
 struct passwd *user_pw_ent;
 char *runas_user = RUNAS_DEFAULT;
 char *cmnd = NULL;
+char *cmnd_safe = NULL;
 char *cmnd_args = NULL;
 char *tty = "unknown";
 char *prompt;
@@ -129,7 +130,6 @@ char host[MAXHOSTNAMELEN];
 char *shost;
 char cwd[MAXPATHLEN];
 FILE *sudoers_fp = NULL;
-struct stat cmnd_st;
 static char *runas_homedir = NULL;
 extern struct interface *interfaces;
 extern int num_interfaces;
@@ -334,33 +334,10 @@ int main(argc, argv)
                (void) sudo_setenv("HOME", runas_homedir);
 
 #ifndef PROFILING
-           if ((sudo_mode & MODE_BACKGROUND) && fork() > 0) {
+           if ((sudo_mode & MODE_BACKGROUND) && fork() > 0)
                exit(0);
-           } else {
-               /*
-                * Make sure we are not being spoofed.  The stat should
-                * be cheap enough to make this almost bulletproof.
-                */
-               if (cmnd_st.st_dev) {
-                   struct stat st;
-
-                   if (stat(cmnd, &st) < 0) {
-                       (void) fprintf(stderr, "%s: unable to stat %s: ",
-                                       Argv[0], cmnd);
-                       perror("");
-                       exit(1);
-                   }
-
-                   if (st.st_dev != cmnd_st.st_dev ||
-                       st.st_ino != cmnd_st.st_ino) {
-                       /* log and send mail, then bitch */
-                       log_error(SPOOF_ATTEMPT);
-                       inform_user(SPOOF_ATTEMPT);
-                       exit(1);
-                   }
-               }
-               EXEC(cmnd, NewArgv);    /* run the command */
-           }
+           else
+               EXEC(cmnd_safe, NewArgv);       /* run the command */
 #else
            exit(0);
 #endif /* PROFILING */
diff --git a/sudo.h b/sudo.h
index 1d3d210b3c98def3401956df57f7190782b1ecc4..9d0a93931b4dfe7fa121a2047b337694c5a5f2ee 100644 (file)
--- a/sudo.h
+++ b/sudo.h
@@ -158,12 +158,11 @@ struct generic_alias {
 #define SUDOERS_WRONG_OWNER      ( 0x09 | GLOBAL_PROBLEM )
 #define SUDOERS_WRONG_MODE       ( 0x0A | GLOBAL_PROBLEM )
 #define SUDOERS_NOT_FILE         ( 0x0B | GLOBAL_PROBLEM )
-#define SPOOF_ATTEMPT            0x0C
-#define BAD_STAMPDIR             0x0D
-#define BAD_STAMPFILE            0x0E
-#define BAD_ALLOCATION           0x0F
+#define BAD_STAMPDIR             0x0C
+#define BAD_STAMPFILE            0x0D
+#define BAD_ALLOCATION           0x0E
 #ifdef HAVE_KERB5
-#define GLOBAL_KRB5_INIT_ERR     ( 0x10 | GLOBAL_PROBLEM )
+#define GLOBAL_KRB5_INIT_ERR     ( 0x0F | GLOBAL_PROBLEM )
 #endif /* HAVE_KERB5 */
 
 /*
@@ -268,9 +267,9 @@ extern struct passwd *user_pw_ent;
 extern char *runas_user;
 extern char *tty;
 extern char *cmnd;
+extern char *cmnd_safe;
 extern char *cmnd_args;
 extern char *prompt;
-extern struct stat cmnd_st;
 extern int Argc;
 extern char **Argv;
 extern int NewArgc;
index e040635b6bedc5c90fce06ce18cb9ad0591df138..d8941ad475ef99521038dbb12d7ffa28f9ac3e3a 100644 (file)
@@ -497,7 +497,7 @@ short *yyss;
 short *yysslim;
 YYSTYPE *yyvs;
 int yystacksize;
-#line 659 "parse.yacc"
+#line 661 "parse.yacc"
 
 
 typedef struct {
@@ -1393,12 +1393,14 @@ case 44:
                                expand_match_list();
                            }
 
-                           cmnd_matches = TRUE;
-                           yyval.BOOLEAN = TRUE;
+                           yyval.BOOLEAN = cmnd_matches = TRUE;
+                           if (cmnd_safe)
+                               free(cmnd_safe);
+                           cmnd_safe = estrdup(cmnd);
                        }
 break;
 case 45:
-#line 481 "parse.yacc"
+#line 483 "parse.yacc"
 {
                            if (printmatches == TRUE && in_alias == TRUE) {
                                append(yyvsp[0].string, &ga_list[ga_list_len-1].entries,
@@ -1420,7 +1422,7 @@ case 45:
                        }
 break;
 case 46:
-#line 500 "parse.yacc"
+#line 502 "parse.yacc"
 {
                            if (printmatches == TRUE && in_alias == TRUE) {
                                append(yyvsp[0].command.cmnd, &ga_list[ga_list_len-1].entries,
@@ -1456,11 +1458,11 @@ case 46:
                        }
 break;
 case 49:
-#line 539 "parse.yacc"
+#line 541 "parse.yacc"
 { push; }
 break;
 case 50:
-#line 539 "parse.yacc"
+#line 541 "parse.yacc"
 {
                            if (host_matches == TRUE &&
                                add_alias(yyvsp[-3].string, HOST_ALIAS) == FALSE)
@@ -1469,7 +1471,7 @@ case 50:
                        }
 break;
 case 55:
-#line 555 "parse.yacc"
+#line 557 "parse.yacc"
 {
                            push;
                            if (printmatches == TRUE) {
@@ -1481,7 +1483,7 @@ case 55:
                        }
 break;
 case 56:
-#line 563 "parse.yacc"
+#line 565 "parse.yacc"
 {
                            if (cmnd_matches == TRUE &&
                                add_alias(yyvsp[-3].string, CMND_ALIAS) == FALSE)
@@ -1494,11 +1496,11 @@ case 56:
                        }
 break;
 case 57:
-#line 575 "parse.yacc"
+#line 577 "parse.yacc"
 { ; }
 break;
 case 61:
-#line 583 "parse.yacc"
+#line 585 "parse.yacc"
 {
                            push;
                            if (printmatches == TRUE) {
@@ -1510,7 +1512,7 @@ case 61:
                        }
 break;
 case 62:
-#line 591 "parse.yacc"
+#line 593 "parse.yacc"
 {
                            if (runas_matches > 0 &&
                                add_alias(yyvsp[-3].string, RUNAS_ALIAS) == FALSE)
@@ -1523,11 +1525,11 @@ case 62:
                        }
 break;
 case 65:
-#line 607 "parse.yacc"
+#line 609 "parse.yacc"
 { push; }
 break;
 case 66:
-#line 607 "parse.yacc"
+#line 609 "parse.yacc"
 {
                            if (user_matches == TRUE &&
                                add_alias(yyvsp[-3].string, USER_ALIAS) == FALSE)
@@ -1537,17 +1539,17 @@ case 66:
                        }
 break;
 case 67:
-#line 616 "parse.yacc"
+#line 618 "parse.yacc"
 { ; }
 break;
 case 70:
-#line 621 "parse.yacc"
+#line 623 "parse.yacc"
 {
                            push;
                        }
 break;
 case 71:
-#line 623 "parse.yacc"
+#line 625 "parse.yacc"
 {
                            pop;
                            if (user_matched == TRUE)
@@ -1557,7 +1559,7 @@ case 71:
                        }
 break;
 case 72:
-#line 631 "parse.yacc"
+#line 633 "parse.yacc"
 {
                            if (strcmp(yyvsp[0].string, user_name) == 0)
                                user_matches = TRUE;
@@ -1565,7 +1567,7 @@ case 72:
                        }
 break;
 case 73:
-#line 636 "parse.yacc"
+#line 638 "parse.yacc"
 {
                            if (usergr_matches(yyvsp[0].string, user_name))
                                user_matches = TRUE;
@@ -1573,7 +1575,7 @@ case 73:
                        }
 break;
 case 74:
-#line 641 "parse.yacc"
+#line 643 "parse.yacc"
 {
                            if (netgr_matches(yyvsp[0].string, NULL, user_name))
                                user_matches = TRUE;
@@ -1581,7 +1583,7 @@ case 74:
                        }
 break;
 case 75:
-#line 646 "parse.yacc"
+#line 648 "parse.yacc"
 {
                            /* could be an all-caps username */
                            if (find_alias(yyvsp[0].string, USER_ALIAS) == TRUE ||
@@ -1591,12 +1593,12 @@ case 75:
                        }
 break;
 case 76:
-#line 653 "parse.yacc"
+#line 655 "parse.yacc"
 {
                            user_matches = TRUE;
                        }
 break;
-#line 1600 "sudo.tab.c"
+#line 1602 "sudo.tab.c"
     }
     yyssp -= yym;
     yystate = *yyssp;
index 8a712225e2d2bf31519997911d7972451564597b..ee2b20283e9881025c8e01ea5e6af1181007d785 100644 (file)
@@ -78,6 +78,7 @@ extern int num_interfaces;
 
 char *cmnd = NULL;
 char *cmnd_args = NULL;
+char *cmnd_safe = NULL;
 char *runas_user = RUNAS_DEFAULT;
 char host[MAXHOSTNAMELEN];
 char *shost;
index 79b5dc33d393b191dfcb300928928905c1a81295..7b6cbd0080dcaa5d3f128d6932152cad6a6ca1a1 100644 (file)
--- a/visudo.c
+++ b/visudo.c
@@ -113,6 +113,7 @@ char *runas_user = RUNAS_DEFAULT;
 char host[] = "";
 char *shost = "";
 char *cmnd = "";
+char *cmnd_safe = NULL;
 char *cmnd_args = NULL;
 struct passwd *user_pw_ent;