Diff for /embedaddon/sudo/src/sudo.c between versions 1.1.1.4 and 1.1.1.5

version 1.1.1.4, 2013/07/22 10:46:13 version 1.1.1.5, 2013/10/14 07:56:35
Line 83 Line 83
 # include <prot.h>  # include <prot.h>
 #endif /* HAVE_GETPRPWNAM && HAVE_SET_AUTH_PARAMETERS */  #endif /* HAVE_GETPRPWNAM && HAVE_SET_AUTH_PARAMETERS */
   
   #include <sudo_usage.h>
 #include "sudo.h"  #include "sudo.h"
 #include "sudo_plugin.h"  #include "sudo_plugin.h"
 #include "sudo_plugin_int.h"  #include "sudo_plugin_int.h"
 #include "sudo_usage.h"  
   
 /*  /*
  * Local variables   * Local variables
Line 94 Line 94
 struct plugin_container policy_plugin;  struct plugin_container policy_plugin;
 struct plugin_container_list io_plugins;  struct plugin_container_list io_plugins;
 struct user_details user_details;  struct user_details user_details;
const char *list_user, *runas_user, *runas_group; /* extern for parse_args.c */const char *list_user; /* extern for parse_args.c */
 static struct command_details command_details;  static struct command_details command_details;
 static int sudo_mode;  static int sudo_mode;
   
Line 133  static void iolog_unlink(struct plugin_container *plug Line 133  static void iolog_unlink(struct plugin_container *plug
   
 #ifdef RLIMIT_CORE  #ifdef RLIMIT_CORE
 static struct rlimit corelimit;  static struct rlimit corelimit;
#endif /* RLIMIT_CORE */#endif
#if defined(__linux__)#ifdef __linux__
 static struct rlimit nproclimit;  static struct rlimit nproclimit;
 #endif  #endif
   
Line 354  fill_group_list(struct user_details *ud, int system_ma Line 354  fill_group_list(struct user_details *ud, int system_ma
      * trying getgrouplist() until we have enough room in the array.       * trying getgrouplist() until we have enough room in the array.
      */       */
     ud->ngroups = sudo_conf_max_groups();      ud->ngroups = sudo_conf_max_groups();
    if (ud->ngroups != -1) {    if (ud->ngroups > 0) {
         ud->groups = emalloc2(ud->ngroups, sizeof(GETGROUPS_T));          ud->groups = emalloc2(ud->ngroups, sizeof(GETGROUPS_T));
         /* No error on insufficient space if user specified max_groups. */          /* No error on insufficient space if user specified max_groups. */
         (void)getgrouplist(ud->username, ud->gid, ud->groups, &ud->ngroups);          (void)getgrouplist(ud->username, ud->gid, ud->groups, &ud->ngroups);
Line 467  get_user_info(struct user_details *ud) Line 467  get_user_info(struct user_details *ud)
   
     user_info[i] = fmt_string("user", pw->pw_name);      user_info[i] = fmt_string("user", pw->pw_name);
     if (user_info[i] == NULL)      if (user_info[i] == NULL)
        fatalx(NULL);        fatal(NULL);
     ud->username = user_info[i] + sizeof("user=") - 1;      ud->username = user_info[i] + sizeof("user=") - 1;
   
     /* Stash user's shell for use with the -s flag; don't pass to plugin. */      /* Stash user's shell for use with the -s flag; don't pass to plugin. */
Line 493  get_user_info(struct user_details *ud) Line 493  get_user_info(struct user_details *ud)
     if (getcwd(cwd, sizeof(cwd)) != NULL) {      if (getcwd(cwd, sizeof(cwd)) != NULL) {
         user_info[++i] = fmt_string("cwd", cwd);          user_info[++i] = fmt_string("cwd", cwd);
         if (user_info[i] == NULL)          if (user_info[i] == NULL)
            fatalx(NULL);            fatal(NULL);
         ud->cwd = user_info[i] + sizeof("cwd=") - 1;          ud->cwd = user_info[i] + sizeof("cwd=") - 1;
     }      }
   
     if ((cp = get_process_ttyname()) != NULL) {      if ((cp = get_process_ttyname()) != NULL) {
         user_info[++i] = fmt_string("tty", cp);          user_info[++i] = fmt_string("tty", cp);
         if (user_info[i] == NULL)          if (user_info[i] == NULL)
            fatalx(NULL);            fatal(NULL);
         ud->tty = user_info[i] + sizeof("tty=") - 1;          ud->tty = user_info[i] + sizeof("tty=") - 1;
         efree(cp);          efree(cp);
     }      }
Line 511  get_user_info(struct user_details *ud) Line 511  get_user_info(struct user_details *ud)
         strlcpy(host, "localhost", sizeof(host));          strlcpy(host, "localhost", sizeof(host));
     user_info[++i] = fmt_string("host", host);      user_info[++i] = fmt_string("host", host);
     if (user_info[i] == NULL)      if (user_info[i] == NULL)
        fatalx(NULL);        fatal(NULL);
     ud->host = user_info[i] + sizeof("host=") - 1;      ud->host = user_info[i] + sizeof("host=") - 1;
   
     get_ttysize(&ud->ts_lines, &ud->ts_cols);      get_ttysize(&ud->ts_lines, &ud->ts_cols);
Line 530  static void Line 530  static void
 command_info_to_details(char * const info[], struct command_details *details)  command_info_to_details(char * const info[], struct command_details *details)
 {  {
     int i;      int i;
       id_t id;
     long lval;      long lval;
     unsigned long ulval;  
     char *cp, *ep;      char *cp, *ep;
       const char *errstr;
     debug_decl(command_info_to_details, SUDO_DEBUG_PCOMM)      debug_decl(command_info_to_details, SUDO_DEBUG_PCOMM)
   
     memset(details, 0, sizeof(*details));      memset(details, 0, sizeof(*details));
Line 553  command_info_to_details(char * const info[], struct co Line 554  command_info_to_details(char * const info[], struct co
                 SET_STRING("command=", command)                  SET_STRING("command=", command)
                 SET_STRING("cwd=", cwd)                  SET_STRING("cwd=", cwd)
                 if (strncmp("closefrom=", info[i], sizeof("closefrom=") - 1) == 0) {                  if (strncmp("closefrom=", info[i], sizeof("closefrom=") - 1) == 0) {
                     cp = info[i] + sizeof("closefrom=") - 1;  
                     if (*cp == '\0')  
                         break;  
                     errno = 0;                      errno = 0;
                    lval = strtol(cp, &ep, 0);                    cp = info[i] + sizeof("closefrom=") - 1;
                    if (*cp != '\0' && *ep == '\0' &&                    lval = strtol(cp, &ep, 10);
                        !(errno == ERANGE &&                    if (*cp == '\0' || *ep != '\0')
                        (lval == LONG_MAX || lval == LONG_MIN)) &&                        fatalx(_("%s: %s"), info[i], _("invalid value"));
                        lval < INT_MAX && lval > INT_MIN) {                    if ((errno == ERANGE &&
                        details->closefrom = (int)lval;                        (lval == LONG_MAX || lval == LONG_MIN)) ||
                    }                        (lval > INT_MAX || lval < 0))
                         fatalx(_("%s: %s"), info[i], _("value out of range"));
                     details->closefrom = (int)lval;
                     break;                      break;
                 }                  }
                 break;                  break;
Line 578  command_info_to_details(char * const info[], struct co Line 578  command_info_to_details(char * const info[], struct co
                 SET_STRING("login_class=", login_class)                  SET_STRING("login_class=", login_class)
                 break;                  break;
             case 'n':              case 'n':
                 /* XXX - bounds check  -NZERO to NZERO (inclusive). */  
                 if (strncmp("nice=", info[i], sizeof("nice=") - 1) == 0) {                  if (strncmp("nice=", info[i], sizeof("nice=") - 1) == 0) {
                     cp = info[i] + sizeof("nice=") - 1;  
                     if (*cp == '\0')  
                         break;  
                     errno = 0;                      errno = 0;
                    lval = strtol(cp, &ep, 0);                    cp = info[i] + sizeof("nice=") - 1;
                    if (*cp != '\0' && *ep == '\0' &&                    lval = strtol(cp, &ep, 10);
                        !(errno == ERANGE &&                    if (*cp == '\0' || *ep != '\0')
                        (lval == LONG_MAX || lval == LONG_MIN)) &&                        fatalx(_("%s: %s"), info[i], _("invalid value"));
                        lval < INT_MAX && lval > INT_MIN) {                    if ((errno == ERANGE &&
                        details->priority = (int)lval;                        (lval == LONG_MAX || lval == LONG_MIN)) ||
                        SET(details->flags, CD_SET_PRIORITY);                        (lval > INT_MAX || lval < INT_MIN))
                    }                        fatalx(_("%s: %s"), info[i], _("value out of range"));
                     details->priority = (int)lval;
                     SET(details->flags, CD_SET_PRIORITY);
                     break;                      break;
                 }                  }
                 if (strncmp("noexec=", info[i], sizeof("noexec=") - 1) == 0) {                  if (strncmp("noexec=", info[i], sizeof("noexec=") - 1) == 0) {
Line 610  command_info_to_details(char * const info[], struct co Line 608  command_info_to_details(char * const info[], struct co
             case 'r':              case 'r':
                 if (strncmp("runas_egid=", info[i], sizeof("runas_egid=") - 1) == 0) {                  if (strncmp("runas_egid=", info[i], sizeof("runas_egid=") - 1) == 0) {
                     cp = info[i] + sizeof("runas_egid=") - 1;                      cp = info[i] + sizeof("runas_egid=") - 1;
                    if (*cp == '\0')                    id = atoid(cp, NULL, NULL, &errstr);
                        break;                    if (errstr != NULL)
                    errno = 0;                        fatalx(_("%s: %s"), info[i], _(errstr));
                    ulval = strtoul(cp, &ep, 0);                    details->egid = (gid_t)id;
                    if (*cp != '\0' && *ep == '\0' &&                    SET(details->flags, CD_SET_EGID);
                        (errno != ERANGE || ulval != ULONG_MAX)) { 
                        details->egid = (gid_t)ulval; 
                        SET(details->flags, CD_SET_EGID); 
                    } 
                     break;                      break;
                 }                  }
                 if (strncmp("runas_euid=", info[i], sizeof("runas_euid=") - 1) == 0) {                  if (strncmp("runas_euid=", info[i], sizeof("runas_euid=") - 1) == 0) {
                     cp = info[i] + sizeof("runas_euid=") - 1;                      cp = info[i] + sizeof("runas_euid=") - 1;
                    if (*cp == '\0')                    id = atoid(cp, NULL, NULL, &errstr);
                        break;                    if (errstr != NULL)
                    errno = 0;                        fatalx(_("%s: %s"), info[i], _(errstr));
                    ulval = strtoul(cp, &ep, 0);                    details->euid = (uid_t)id;
                    if (*cp != '\0' && *ep == '\0' &&                    SET(details->flags, CD_SET_EUID);
                        (errno != ERANGE || ulval != ULONG_MAX)) { 
                        details->euid = (uid_t)ulval; 
                        SET(details->flags, CD_SET_EUID); 
                    } 
                     break;                      break;
                 }                  }
                 if (strncmp("runas_gid=", info[i], sizeof("runas_gid=") - 1) == 0) {                  if (strncmp("runas_gid=", info[i], sizeof("runas_gid=") - 1) == 0) {
                     cp = info[i] + sizeof("runas_gid=") - 1;                      cp = info[i] + sizeof("runas_gid=") - 1;
                    if (*cp == '\0')                    id = atoid(cp, NULL, NULL, &errstr);
                        break;                    if (errstr != NULL)
                    errno = 0;                        fatalx(_("%s: %s"), info[i], _(errstr));
                    ulval = strtoul(cp, &ep, 0);                    details->gid = (gid_t)id;
                    if (*cp != '\0' && *ep == '\0' &&                    SET(details->flags, CD_SET_GID);
                        (errno != ERANGE || ulval != ULONG_MAX)) { 
                        details->gid = (gid_t)ulval; 
                        SET(details->flags, CD_SET_GID); 
                    } 
                     break;                      break;
                 }                  }
                 if (strncmp("runas_groups=", info[i], sizeof("runas_groups=") - 1) == 0) {                  if (strncmp("runas_groups=", info[i], sizeof("runas_groups=") - 1) == 0) {
                    int j;                    /* parse_gid_list() will call fatalx() on error. */
 
                    /* count groups, alloc and fill in */ 
                     cp = info[i] + sizeof("runas_groups=") - 1;                      cp = info[i] + sizeof("runas_groups=") - 1;
                    if (*cp == '\0')                    details->ngroups = parse_gid_list(cp, NULL, &details->groups);
                        break; 
                    for (;;) { 
                        details->ngroups++; 
                        if ((cp = strchr(cp, ',')) == NULL) 
                            break; 
                        cp++; 
                    } 
                    if (details->ngroups != 0) { 
                        details->groups = 
                            emalloc2(details->ngroups, sizeof(GETGROUPS_T)); 
                        cp = info[i] + sizeof("runas_groups=") - 1; 
                        for (j = 0; j < details->ngroups;) { 
                            errno = 0; 
                            ulval = strtoul(cp, &ep, 0); 
                            if (*cp == '\0' || (*ep != ',' && *ep != '\0') || 
                                (ulval == ULONG_MAX && errno == ERANGE)) { 
                                break; 
                            } 
                            details->groups[j++] = (gid_t)ulval; 
                            cp = ep + 1; 
                        } 
                        details->ngroups = j; 
                    } 
                     break;                      break;
                 }                  }
                 if (strncmp("runas_uid=", info[i], sizeof("runas_uid=") - 1) == 0) {                  if (strncmp("runas_uid=", info[i], sizeof("runas_uid=") - 1) == 0) {
                     cp = info[i] + sizeof("runas_uid=") - 1;                      cp = info[i] + sizeof("runas_uid=") - 1;
                    if (*cp == '\0')                    id = atoid(cp, NULL, NULL, &errstr);
                        break;                    if (errstr != NULL)
                    errno = 0;                        fatalx(_("%s: %s"), info[i], _(errstr));
                    ulval = strtoul(cp, &ep, 0);                    details->uid = (uid_t)id;
                    if (*cp != '\0' && *ep == '\0' &&                    SET(details->flags, CD_SET_UID);
                        (errno != ERANGE || ulval != ULONG_MAX)) { 
                        details->uid = (uid_t)ulval; 
                        SET(details->flags, CD_SET_UID); 
                    } 
                     break;                      break;
                 }                  }
 #ifdef HAVE_PRIV_SET  #ifdef HAVE_PRIV_SET
                 if (strncmp("runas_privs=", info[i], sizeof("runas_privs=") - 1) == 0) {                  if (strncmp("runas_privs=", info[i], sizeof("runas_privs=") - 1) == 0) {
                     const char *endp;                      const char *endp;
                     cp = info[i] + sizeof("runas_privs=") - 1;                      cp = info[i] + sizeof("runas_privs=") - 1;
                    if (*cp == '\0')                    if (*cp != '\0') {
                        break;                        details->privs = priv_str_to_set(cp, ",", &endp);
                    errno = 0;                        if (details->privs == NULL)
                    details->privs = priv_str_to_set(cp, ",", &endp); 
                    if (details->privs == NULL) 
                             warning("invalid runas_privs %s", endp);                              warning("invalid runas_privs %s", endp);
                       }
                       break;
                 }                  }
                 if (strncmp("runas_limitprivs=", info[i], sizeof("runas_limitprivs=") - 1) == 0) {                  if (strncmp("runas_limitprivs=", info[i], sizeof("runas_limitprivs=") - 1) == 0) {
                     const char *endp;                      const char *endp;
                     cp = info[i] + sizeof("runas_limitprivs=") - 1;                      cp = info[i] + sizeof("runas_limitprivs=") - 1;
                    if (*cp == '\0')                    if (*cp != '\0') {
                        break;                        details->limitprivs = priv_str_to_set(cp, ",", &endp);
                    errno = 0;                        if (details->limitprivs == NULL)
                    details->limitprivs = priv_str_to_set(cp, ",", &endp); 
                    if (details->limitprivs == NULL) 
                             warning("invalid runas_limitprivs %s", endp);                              warning("invalid runas_limitprivs %s", endp);
                       }
                       break;
                 }                  }
 #endif /* HAVE_PRIV_SET */  #endif /* HAVE_PRIV_SET */
                 break;                  break;
Line 730  command_info_to_details(char * const info[], struct co Line 687  command_info_to_details(char * const info[], struct co
                 break;                  break;
             case 't':              case 't':
                 if (strncmp("timeout=", info[i], sizeof("timeout=") - 1) == 0) {                  if (strncmp("timeout=", info[i], sizeof("timeout=") - 1) == 0) {
                     cp = info[i] + sizeof("timeout=") - 1;  
                     if (*cp == '\0')  
                         break;  
                     errno = 0;                      errno = 0;
                    lval = strtol(cp, &ep, 0);                    cp = info[i] + sizeof("timeout=") - 1;
                    if (*cp != '\0' && *ep == '\0' &&                    lval = strtol(cp, &ep, 10);
                        !(errno == ERANGE &&                    if (*cp == '\0' || *ep != '\0')
                        (lval == LONG_MAX || lval == LONG_MIN)) &&                        fatalx(_("%s: %s"), info[i], _("invalid value"));
                        lval <= INT_MAX && lval >= 0) {                    if ((errno == ERANGE &&
                        details->timeout = (int)lval;                        (lval == LONG_MAX || lval == LONG_MIN)) ||
                        SET(details->flags, CD_SET_TIMEOUT);                        (lval > INT_MAX || lval < 0))
                    }                        fatalx(_("%s: %s"), info[i], _("value out of range"));
                     details->timeout = (int)lval;
                     SET(details->flags, CD_SET_TIMEOUT);
                     break;                      break;
                 }                  }
                 break;                  break;
             case 'u':              case 'u':
                 if (strncmp("umask=", info[i], sizeof("umask=") - 1) == 0) {                  if (strncmp("umask=", info[i], sizeof("umask=") - 1) == 0) {
                     cp = info[i] + sizeof("umask=") - 1;  
                     if (*cp == '\0')  
                         break;  
                     errno = 0;                      errno = 0;
                    ulval = strtoul(cp, &ep, 8);                    cp = info[i] + sizeof("umask=") - 1;
                    if (*cp != '\0' && *ep == '\0' &&                    lval = strtol(cp, &ep, 8);
                        (errno != ERANGE || ulval != ULONG_MAX)) {                    if (*cp == '\0' || *ep != '\0')
                        details->umask = (uid_t)ulval;                        fatalx(_("%s: %s"), info[i], _("invalid value"));
                        SET(details->flags, CD_SET_UMASK);                    if ((errno == ERANGE &&
                    }                        (lval == LONG_MAX || lval == LONG_MIN)) ||
                         (lval > 0777 || lval < 0))
                         fatalx(_("%s: %s"), info[i], _("value out of range"));
                     details->umask = (mode_t)lval;
                     SET(details->flags, CD_SET_UMASK);
                     break;                      break;
                 }                  }
                 if (strncmp("use_pty=", info[i], sizeof("use_pty=") - 1) == 0) {                  if (strncmp("use_pty=", info[i], sizeof("use_pty=") - 1) == 0) {
Line 777  command_info_to_details(char * const info[], struct co Line 734  command_info_to_details(char * const info[], struct co
 #endif  #endif
     details->pw = getpwuid(details->euid);      details->pw = getpwuid(details->euid);
     if (details->pw != NULL && (details->pw = pw_dup(details->pw)) == NULL)      if (details->pw != NULL && (details->pw = pw_dup(details->pw)) == NULL)
        fatalx(NULL);        fatal(NULL);
 #ifdef HAVE_SETAUTHDB  #ifdef HAVE_SETAUTHDB
     aix_restoreauthdb();      aix_restoreauthdb();
 #endif  #endif
Line 790  command_info_to_details(char * const info[], struct co Line 747  command_info_to_details(char * const info[], struct co
 }  }
   
 static void  static void
sudo_check_suid(const char *path)sudo_check_suid(const char *sudo)
 {  {
       char pathbuf[PATH_MAX];
     struct stat sb;      struct stat sb;
       bool qualified;
     debug_decl(sudo_check_suid, SUDO_DEBUG_PCOMM)      debug_decl(sudo_check_suid, SUDO_DEBUG_PCOMM)
   
     if (geteuid() != 0) {      if (geteuid() != 0) {
        if (strchr(path, '/') != NULL && stat(path, &sb) == 0) {        /* Search for sudo binary in PATH if not fully qualified. */
         qualified = strchr(sudo, '/') != NULL;
         if (!qualified) {
             char *path = getenv_unhooked("PATH");
             if (path != NULL) {
                 int len;
                 char *cp, *colon;
 
                 cp = path = estrdup(path);
                 do {
                     if ((colon = strchr(cp, ':')))
                         *colon = '\0';
                     len = snprintf(pathbuf, sizeof(pathbuf), "%s/%s", cp, sudo);
                     if (len <= 0 || len >= sizeof(pathbuf))
                         continue;
                     if (access(pathbuf, X_OK) == 0) {
                         sudo = pathbuf;
                         qualified = true;
                         break;
                     }
                     cp = colon + 1;
                 } while (colon);
                 efree(path);
             }
         }
 
         if (qualified && stat(sudo, &sb) == 0) {
             /* Try to determine why sudo was not running as root. */              /* Try to determine why sudo was not running as root. */
             if (sb.st_uid != ROOT_UID || !ISSET(sb.st_mode, S_ISUID)) {              if (sb.st_uid != ROOT_UID || !ISSET(sb.st_mode, S_ISUID)) {
                 fatalx(                  fatalx(
                     _("%s must be owned by uid %d and have the setuid bit set"),                      _("%s must be owned by uid %d and have the setuid bit set"),
                    path, ROOT_UID);                    sudo, ROOT_UID);
             } else {              } else {
                 fatalx(_("effective uid is not %d, is %s on a file system "                  fatalx(_("effective uid is not %d, is %s on a file system "
                     "with the 'nosuid' option set or an NFS file system without"                      "with the 'nosuid' option set or an NFS file system without"
                    " root privileges?"), ROOT_UID, path);                    " root privileges?"), ROOT_UID, sudo);
             }              }
         } else {          } else {
             fatalx(              fatalx(
Line 824  sudo_check_suid(const char *path) Line 809  sudo_check_suid(const char *path)
 static void  static void
 disable_coredumps(void)  disable_coredumps(void)
 {  {
#if defined(__linux__) || defined(RLIMIT_CORE)#if defined(RLIMIT_CORE)
     struct rlimit rl;      struct rlimit rl;
 #endif  
     debug_decl(disable_coredumps, SUDO_DEBUG_UTIL)      debug_decl(disable_coredumps, SUDO_DEBUG_UTIL)
   
 #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.  
      */  
     (void) getrlimit(RLIMIT_NPROC, &nproclimit);  
     rl.rlim_cur = rl.rlim_max = RLIM_INFINITY;  
     if (setrlimit(RLIMIT_NPROC, &rl)) {  
         memcpy(&rl, &nproclimit, sizeof(struct rlimit));  
         rl.rlim_cur = rl.rlim_max;  
         (void)setrlimit(RLIMIT_NPROC, &rl);  
     }  
 #endif /* __linux__ */  
 #ifdef RLIMIT_CORE  
     /*  
      * Turn off core dumps?       * Turn off core dumps?
      */       */
     if (sudo_conf_disable_coredump()) {      if (sudo_conf_disable_coredump()) {
Line 853  disable_coredumps(void) Line 822  disable_coredumps(void)
         rl.rlim_cur = 0;          rl.rlim_cur = 0;
         (void) setrlimit(RLIMIT_CORE, &rl);          (void) setrlimit(RLIMIT_CORE, &rl);
     }      }
       debug_return;
 #endif /* RLIMIT_CORE */  #endif /* RLIMIT_CORE */
   }
   
   /*
    * Unlimit the number of processes since Linux's setuid() will
    * apply resource limits when changing uid and return EAGAIN if
    * nproc would be exceeded by the uid switch.
    */
   static void
   unlimit_nproc(void)
   {
   #ifdef __linux__
       struct rlimit rl;
       debug_decl(unlimit_nproc, SUDO_DEBUG_UTIL)
   
       (void) getrlimit(RLIMIT_NPROC, &nproclimit);
       rl.rlim_cur = rl.rlim_max = RLIM_INFINITY;
       if (setrlimit(RLIMIT_NPROC, &rl) != 0) {
           memcpy(&rl, &nproclimit, sizeof(struct rlimit));
           rl.rlim_cur = rl.rlim_max;
           (void)setrlimit(RLIMIT_NPROC, &rl);
       }
     debug_return;      debug_return;
   #endif /* __linux__ */
 }  }
   
 /*  /*
    * Restore saved value of RLIMIT_NPROC.
    */
   static void
   restore_nproc(void)
   {
   #ifdef __linux__
       debug_decl(restore_nproc, SUDO_DEBUG_UTIL)
   
       (void) setrlimit(RLIMIT_NPROC, &nproclimit);
   
       debug_return;
   #endif /* __linux__ */
   }
   
   /*
  * Setup the execution environment immediately prior to the call to execve()   * Setup the execution environment immediately prior to the call to execve()
  * Returns true on success and false on failure.   * Returns true on success and false on failure.
  */   */
Line 926  exec_setup(struct command_details *details, const char Line 933  exec_setup(struct command_details *details, const char
                 flags = LOGIN_SETRESOURCES|LOGIN_SETPRIORITY;                  flags = LOGIN_SETRESOURCES|LOGIN_SETPRIORITY;
             }              }
             if (setusercontext(lc, details->pw, details->pw->pw_uid, flags)) {              if (setusercontext(lc, details->pw, details->pw->pw_uid, flags)) {
                if (details->pw->pw_uid != ROOT_UID) {                warning(_("unable to set user context"));
                    warning(_("unable to set user context"));                if (details->pw->pw_uid != ROOT_UID)
                     goto done;                      goto done;
                 } else  
                     warning(_("unable to set user context"));  
             }              }
         }          }
 #endif /* HAVE_LOGIN_CAP_H */  #endif /* HAVE_LOGIN_CAP_H */
Line 975  exec_setup(struct command_details *details, const char Line 980  exec_setup(struct command_details *details, const char
         }          }
     }      }
   
       /* 
        * Unlimit the number of processes since Linux's setuid() will
        * return EAGAIN if RLIMIT_NPROC would be exceeded by the uid switch.
        */
       unlimit_nproc();
   
 #ifdef HAVE_SETRESUID  #ifdef HAVE_SETRESUID
     if (setresuid(details->uid, details->euid, details->euid) != 0) {      if (setresuid(details->uid, details->euid, details->euid) != 0) {
         warning(_("unable to change to runas uid (%u, %u)"), details->uid,          warning(_("unable to change to runas uid (%u, %u)"), details->uid,
Line 995  exec_setup(struct command_details *details, const char Line 1006  exec_setup(struct command_details *details, const char
     }      }
 #endif /* !HAVE_SETRESUID && !HAVE_SETREUID */  #endif /* !HAVE_SETRESUID && !HAVE_SETREUID */
   
       /* Restore previous value of RLIMIT_NPROC. */
       restore_nproc();
   
     /*      /*
      * Only change cwd if we have chroot()ed or the policy modules       * Only change cwd if we have chroot()ed or the policy modules
      * specifies a different cwd.  Must be done after uid change.       * specifies a different cwd.  Must be done after uid change.
Line 1008  exec_setup(struct command_details *details, const char Line 1022  exec_setup(struct command_details *details, const char
             }              }
         }          }
     }      }
   
     /*  
      * SuSE Enterprise Linux uses RLIMIT_NPROC and _SC_CHILD_MAX  
      * interchangably.  This causes problems when setting RLIMIT_NPROC  
      * to RLIM_INFINITY due to a bug in bash where bash tries to honor  
      * the value of _SC_CHILD_MAX but treats a value of -1 as an error,  
      * and uses a default value of 32 instead.  
      *  
      * To work around this problem, we restore the nproc resource limit  
      * if sysconf(_SC_CHILD_MAX) is negative.  In most cases, pam_limits  
      * will set RLIMIT_NPROC for us.  
      *  
      * We must do this *after* the uid change to avoid potential EAGAIN  
      * from setuid().  
      */  
 #if defined(__linux__) && defined(_SC_CHILD_MAX)  
     {  
         struct rlimit rl;  
         long l;  
         errno = 0;  
         l = sysconf(_SC_CHILD_MAX);  
         if (l == -1 && errno == 0 && getrlimit(RLIMIT_NPROC, &rl) == 0) {  
             if (rl.rlim_cur == RLIM_INFINITY && rl.rlim_max == RLIM_INFINITY)  
                 (void) setrlimit(RLIMIT_NPROC, &nproclimit);  
         }  
     }  
 #endif  
   
     rval = true;      rval = true;
   

Removed from v.1.1.1.4  
changed lines
  Added in v.1.1.1.5


FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>