fix from Peter Samuelson for use-after-free bug parsing wildcards in sudoers
[debian/sudo] / sudo.c
diff --git a/sudo.c b/sudo.c
index d98d8c85ff5bc566540ec3e236592ea40ab7eddd..6eb5930b165cd1c03c6ced4d304ba724fdb2917d 100644 (file)
--- a/sudo.c
+++ b/sudo.c
 # include <project.h>
 # include <sys/task.h>
 #endif
+#ifdef HAVE_SELINUX
+# include <selinux/selinux.h>
+#endif
 
 #include "sudo.h"
 #include "interfaces.h"
 #include "version.h"
 
 #ifndef lint
-__unused __unused static const char rcsid[] = "$Sudo: sudo.c,v 1.369.2.33 2007/12/02 17:13:52 millert Exp $";
+__unused __unused static const char rcsid[] = "$Sudo: sudo.c,v 1.369.2.41 2008/06/21 19:04:07 millert Exp $";
 #endif /* lint */
 
 /*
@@ -128,6 +131,7 @@ extern char **insert_env_vars               __P((char **, struct list_member *));
 extern struct passwd *sudo_getpwnam    __P((const char *));
 extern struct passwd *sudo_getpwuid    __P((uid_t));
 extern struct passwd *sudo_pwdup       __P((const struct passwd *));
+extern void runas_resetgroups          __P((void));
 
 /*
  * Globals
@@ -152,7 +156,7 @@ login_cap_t *lc;
 #ifdef HAVE_BSD_AUTH_H
 char *login_style;
 #endif /* HAVE_BSD_AUTH_H */
-sigaction_t saved_sa_int, saved_sa_quit, saved_sa_tstp, saved_sa_chld;
+sigaction_t saved_sa_int, saved_sa_quit, saved_sa_tstp;
 
 
 int
@@ -201,8 +205,6 @@ main(argc, argv, envp)
     (void) sigaction(SIGINT, &sa, &saved_sa_int);
     (void) sigaction(SIGQUIT, &sa, &saved_sa_quit);
     (void) sigaction(SIGTSTP, &sa, &saved_sa_tstp);
-    sa.sa_handler = reapchild;
-    (void) sigaction(SIGCHLD, &sa, &saved_sa_chld);
 
     /*
      * Turn off core dumps and close open files.
@@ -270,25 +272,22 @@ main(argc, argv, envp)
     validated = sudo_ldap_check(pwflag);
 
     /* Skip reading /etc/sudoers if LDAP told us to */
-    if (def_ignore_local_sudoers); /* skips */
-    else if (ISSET(validated, VALIDATE_OK) && !printmatches); /* skips */
-    else if (ISSET(validated, VALIDATE_OK) && printmatches)
-    {
-       check_sudoers();        /* check mode/owner on _PATH_SUDOERS */
+    if (!def_ignore_local_sudoers) {
+       int v;
 
-       /* User is found in LDAP and we want a list of all sudo commands the
-        * user can do, so consult sudoers but throw away result.
-        */
-       sudoers_lookup(pwflag);
-    }
-    else
-#endif
-    {
        check_sudoers();        /* check mode/owner on _PATH_SUDOERS */
 
-       /* Validate the user but don't search for pseudo-commands. */
-       validated = sudoers_lookup(pwflag);
+       /* Local sudoers file overrides LDAP if we have a match. */
+       v = sudoers_lookup(pwflag);
+       if (validated == VALIDATE_ERROR || ISSET(v, VALIDATE_OK))
+           validated = v;
     }
+#else
+    check_sudoers();   /* check mode/owner on _PATH_SUDOERS */
+
+    /* Validate the user but don't search for pseudo-commands. */
+    validated = sudoers_lookup(pwflag);
+#endif
     if (safe_cmnd == NULL)
        safe_cmnd = estrdup(user_cmnd);
 
@@ -437,13 +436,18 @@ main(argc, argv, envp)
        (void) sigaction(SIGINT, &saved_sa_int, NULL);
        (void) sigaction(SIGQUIT, &saved_sa_quit, NULL);
        (void) sigaction(SIGTSTP, &saved_sa_tstp, NULL);
-       (void) sigaction(SIGCHLD, &saved_sa_chld, NULL);
 
 #ifndef PROFILING
        if (ISSET(sudo_mode, MODE_BACKGROUND) && fork() > 0)
            exit(0);
-       else
+       else {
+#ifdef HAVE_SELINUX
+           if (is_selinux_enabled() > 0 && user_role != NULL)
+               selinux_exec(user_role, user_type, NewArgv, environ,
+                   ISSET(sudo_mode, MODE_LOGIN_SHELL));
+#endif
            execve(safe_cmnd, NewArgv, environ);
+       }
 #else
        exit(0);
 #endif /* PROFILING */
@@ -520,6 +524,7 @@ init_vars(sudo_mode, envp)
      * "host" is the (possibly fully-qualified) hostname and
      * "shost" is the unqualified form of the hostname.
      */
+    sudo_user.host_fqdn_queried = FALSE;
     nohostname = gethostname(thost, sizeof(thost));
     if (nohostname)
        user_host = user_shost = "localhost";
@@ -529,13 +534,7 @@ init_vars(sudo_mode, envp)
            /* Defer call to set_fqdn() until log_error() is safe. */
            user_shost = user_host;
        } else {
-           if ((p = strchr(user_host, '.'))) {
-               *p = '\0';
-               user_shost = estrdup(user_host);
-               *p = '.';
-           } else {
-               user_shost = user_host;
-           }
+           user_shost = user_host;
        }
     }
 
@@ -730,8 +729,10 @@ parse_args(argc, argv)
 
     while (NewArgc > 0) {
        if (NewArgv[0][0] == '-') {
-           if (NewArgv[0][1] != '\0' && NewArgv[0][2] != '\0')
+           if (NewArgv[0][1] != '\0' && NewArgv[0][2] != '\0') {
                warnx("please use single character options");
+               usage(1);
+           }
 
            switch (NewArgv[0][1]) {
                case 'p':
@@ -856,6 +857,28 @@ parse_args(argc, argv)
                case 'E':
                    SET(rval, MODE_PRESERVE_ENV);
                    break;
+#ifdef HAVE_SELINUX
+               case 'r':
+                   /* Must have an associated SELinux role. */
+                   if (NewArgv[1] == NULL)
+                       usage(1);
+
+                   user_role = NewArgv[1];
+
+                   NewArgc--;
+                   NewArgv++;
+                   break;
+               case 't':
+                   /* Must have an associated SELinux type. */
+                   if (NewArgv[1] == NULL)
+                       usage(1);
+
+                   user_type = NewArgv[1];
+
+                   NewArgc--;
+                   NewArgv++;
+                   break;
+#endif
                case '-':
                    NewArgc--;
                    NewArgv++;
@@ -891,7 +914,10 @@ args_done:
            warnx("you may not specify environment variables in edit mode");
        usage(1);
     }
-
+    if (ISSET(rval, MODE_PRESERVE_ENV) && ISSET(rval, MODE_LOGIN_SHELL)) {
+       warnx("you may not specify both the `-i' and `-E' options");
+       usage(1);
+    }
     if (user_runas != NULL && !ISSET(rval, (MODE_EDIT|MODE_RUN))) {
        if (excl != '\0')
            warnx("the `-u' and '-%c' options may not be used together", excl);
@@ -990,9 +1016,25 @@ static void
 initial_setup()
 {
     int miss[3], devnull = -1;
-#if defined(RLIMIT_CORE) && !defined(SUDO_DEVEL)
+#if defined(__linux__) || (defined(RLIMIT_CORE) && !defined(SUDO_DEVEL))
     struct rlimit rl;
+#endif
 
+#if defined(__linux__)
+    /*
+     * Unlimit the number of processes since Linux's setuid() will
+     * apply resource limits when changing uid and return EAGAIN if
+     * nproc would be violated by the uid switch.
+     */
+    rl.rlim_cur = rl.rlim_max = RLIM_INFINITY;
+    if (setrlimit(RLIMIT_NPROC, &rl)) {
+       if (getrlimit(RLIMIT_NPROC, &rl) == 0) {
+           rl.rlim_cur = rl.rlim_max;
+           (void)setrlimit(RLIMIT_NPROC, &rl);
+       }
+    }
+#endif /* __linux__ */
+#if defined(RLIMIT_CORE) && !defined(SUDO_DEVEL)
     /*
      * Turn off core dumps.
      */
@@ -1171,6 +1213,7 @@ set_fqdn()
     } else {
        user_shost = user_host;
     }
+    sudo_user.host_fqdn_queried = TRUE;
 }
 
 /*
@@ -1198,6 +1241,7 @@ set_runaspw(user)
        if (runas_pw == NULL)
            log_error(NO_MAIL|MSG_ONLY, "no passwd entry for %s!", user);
     }
+    runas_resetgroups();
     return(TRUE);
 }
 
@@ -1270,8 +1314,14 @@ usage(exit_val)
 #endif
 #ifdef HAVE_LOGIN_CAP_H
        " [-c class|-]",
+#endif
+#ifdef HAVE_SELINUX
+       " [-r role]",
 #endif
        " [-p prompt]",
+#ifdef HAVE_SELINUX
+       " [-t type]",
+#endif
        " [-u username|#uid]",
        " [VAR=value]",
        " {-i | -s | <command>}",