[BACK]Return to sudo.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / sudo

Diff for /src/usr.bin/sudo/Attic/sudo.c between version 1.22 and 1.23

version 1.22, 2004/01/12 19:13:21 version 1.23, 2004/09/28 15:10:51
Line 1 
Line 1 
 /*  /*
  * Copyright (c) 1993-1996,1998-2003 Todd C. Miller <Todd.Miller@courtesan.com>   * Copyright (c) 1993-1996,1998-2004 Todd C. Miller <Todd.Miller@courtesan.com>
  * All rights reserved.  
  *   *
  * Redistribution and use in source and binary forms, with or without   * Permission to use, copy, modify, and distribute this software for any
  * modification, are permitted provided that the following conditions   * purpose with or without fee is hereby granted, provided that the above
  * are met:   * copyright notice and this permission notice appear in all copies.
  *   *
  * 1. Redistributions of source code must retain the above copyright   * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  *    notice, this list of conditions and the following disclaimer.   * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
    * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
    * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
    * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
    * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
    * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  *   *
  * 2. Redistributions in binary form must reproduce the above copyright  
  *    notice, this list of conditions and the following disclaimer in the  
  *    documentation and/or other materials provided with the distribution.  
  *  
  * 3. The name of the author may not be used to endorse or promote products  
  *    derived from this software without specific prior written permission.  
  *  
  * 4. Products derived from this software may not be called "Sudo" nor  
  *    may "Sudo" appear in their names without specific prior written  
  *    permission from the author.  
  *  
  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,  
  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY  
  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL  
  * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,  
  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,  
  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;  
  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,  
  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR  
  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF  
  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.  
  *  
  * Sponsored in part by the Defense Advanced Research Projects   * Sponsored in part by the Defense Advanced Research Projects
  * Agency (DARPA) and Air Force Research Laboratory, Air Force   * Agency (DARPA) and Air Force Research Laboratory, Air Force
  * Materiel Command, USAF, under agreement number F39502-99-1-0512.   * Materiel Command, USAF, under agreement number F39502-99-1-0512.
Line 41 
Line 23 
   
 #define _SUDO_MAIN  #define _SUDO_MAIN
   
   #ifdef __TANDEM
   # include <floss.h>
   #endif
   
 #include "config.h"  #include "config.h"
   
 #include <sys/types.h>  #include <sys/types.h>
Line 107 
Line 93 
 #include "version.h"  #include "version.h"
   
 #ifndef lint  #ifndef lint
 static const char rcsid[] = "$Sudo: sudo.c,v 1.337 2003/04/16 00:42:10 millert Exp $";  static const char rcsid[] = "$Sudo: sudo.c,v 1.370 2004/08/24 18:01:13 millert Exp $";
 #endif /* lint */  #endif /* lint */
   
 /*  /*
Line 121 
Line 107 
 static void usage                       __P((int));  static void usage                       __P((int));
 static void usage_excl                  __P((int));  static void usage_excl                  __P((int));
 static struct passwd *get_authpw        __P((void));  static struct passwd *get_authpw        __P((void));
   extern int sudo_edit                    __P((int, char **));
 extern void list_matches                __P((void));  extern void list_matches                __P((void));
 extern char **rebuild_env               __P((int, char **));  extern char **rebuild_env               __P((char **, int, int));
 extern char **zero_env                  __P((char **));  extern char **zero_env                  __P((char **));
 extern struct passwd *sudo_getpwnam     __P((const char *));  extern struct passwd *sudo_getpwnam     __P((const char *));
 extern struct passwd *sudo_getpwuid     __P((uid_t));  extern struct passwd *sudo_getpwuid     __P((uid_t));
   extern struct passwd *sudo_pwdup        __P((const struct passwd *));
   
 /*  /*
  * Globals   * Globals
  */   */
 int Argc, NewArgc;  int Argc, NewArgc;
 char **Argv, **NewArgv;  char **Argv, **NewArgv;
   char *prev_user;
 struct sudo_user sudo_user;  struct sudo_user sudo_user;
 struct passwd *auth_pw;  struct passwd *auth_pw;
 FILE *sudoers_fp;  FILE *sudoers_fp;
Line 149 
Line 138 
 #ifdef HAVE_BSD_AUTH_H  #ifdef HAVE_BSD_AUTH_H
 char *login_style;  char *login_style;
 #endif /* HAVE_BSD_AUTH_H */  #endif /* HAVE_BSD_AUTH_H */
   sigaction_t saved_sa_int, saved_sa_quit, saved_sa_tstp, saved_sa_chld;
 void (*set_perms) __P((int));  void (*set_perms) __P((int));
   
   
Line 164 
Line 154 
     int sudo_mode;      int sudo_mode;
     int pwflag;      int pwflag;
     char **new_environ;      char **new_environ;
     sigaction_t sa, saved_sa_int, saved_sa_quit, saved_sa_tstp, saved_sa_chld;      sigaction_t sa;
     extern int printmatches;      extern int printmatches;
     extern char **environ;      extern char **environ;
   
     Argc = argc;  
     Argv = argv;      Argv = argv;
       if ((Argc = argc) < 1)
           usage(1);
   
     /* Must be done as the first thing... */      /* Must be done as the first thing... */
 #if defined(HAVE_GETPRPWNAM) && defined(HAVE_SET_AUTH_PARAMETERS)  #if defined(HAVE_GETPRPWNAM) && defined(HAVE_SET_AUTH_PARAMETERS)
Line 216 
Line 207 
     load_interfaces();      load_interfaces();
   
     pwflag = 0;      pwflag = 0;
     if (sudo_mode & MODE_SHELL)      if (ISSET(sudo_mode, MODE_SHELL))
         user_cmnd = "shell";          user_cmnd = "shell";
       else if (ISSET(sudo_mode, MODE_EDIT))
           user_cmnd = "sudoedit";
     else      else
         switch (sudo_mode) {          switch (sudo_mode) {
             case MODE_VERSION:              case MODE_VERSION:
Line 235 
Line 228 
                 break;                  break;
             case MODE_VALIDATE:              case MODE_VALIDATE:
                 user_cmnd = "validate";                  user_cmnd = "validate";
                 pwflag = I_VERIFYPW_I;                  pwflag = I_VERIFYPW;
                 break;                  break;
             case MODE_KILL:              case MODE_KILL:
             case MODE_INVALIDATE:              case MODE_INVALIDATE:
Line 248 
Line 241 
                 break;                  break;
             case MODE_LIST:              case MODE_LIST:
                 user_cmnd = "list";                  user_cmnd = "list";
                 pwflag = I_LISTPW_I;                  pwflag = I_LISTPW;
                 printmatches = 1;                  printmatches = 1;
                 break;                  break;
         }          }
Line 259 
Line 252 
   
     cmnd_status = init_vars(sudo_mode);      cmnd_status = init_vars(sudo_mode);
   
     check_sudoers();    /* check mode/owner on _PATH_SUDOERS */  #ifdef HAVE_LDAP
       validated = sudo_ldap_check(pwflag);
   
     /* Validate the user but don't search for pseudo-commands. */      /* Skip reading /etc/sudoers if LDAP told us to */
     validated = sudoers_lookup(pwflag);      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 */
   
           /* 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);
       }
   
     /*      /*
      * If we are using set_perms_posix() and the stay_setuid flag was not set,       * If we are using set_perms_posix() and the stay_setuid flag was not set,
      * set the real, effective and saved uids to 0 and use set_perms_nosuid()       * set the real, effective and saved uids to 0 and use set_perms_nosuid()
Line 271 
Line 283 
      */       */
 #if !defined(HAVE_SETRESUID) && !defined(HAVE_SETREUID) && \  #if !defined(HAVE_SETRESUID) && !defined(HAVE_SETREUID) && \
     !defined(NO_SAVED_IDS) && defined(_SC_SAVED_IDS) && defined(_SC_VERSION)      !defined(NO_SAVED_IDS) && defined(_SC_SAVED_IDS) && defined(_SC_VERSION)
     if (!def_flag(I_STAY_SETUID) && set_perms == set_perms_posix) {      if (!def_stay_setuid && set_perms == set_perms_posix) {
         if (setuid(0)) {          if (setuid(0)) {
             perror("setuid(0)");              perror("setuid(0)");
             exit(1);              exit(1);
Line 281 
Line 293 
 #endif  #endif
   
     /*      /*
      * Look up runas user passwd struct.  If we are given a uid then  
      * there may be no corresponding passwd(5) entry (which is OK).  
      */  
     if (**user_runas == '#') {  
         runas_pw = sudo_getpwuid(atoi(*user_runas + 1));  
         if (runas_pw == NULL) {  
             runas_pw = emalloc(sizeof(struct passwd));  
             (void) memset((VOID *)runas_pw, 0, sizeof(struct passwd));  
             runas_pw->pw_uid = atoi(*user_runas + 1);  
         }  
     } else {  
         runas_pw = sudo_getpwnam(*user_runas);  
         if (runas_pw == NULL)  
             log_error(NO_MAIL|MSG_ONLY, "no passwd entry for %s!", *user_runas);  
     }  
   
     /*  
      * Look up the timestamp dir owner if one is specified.       * Look up the timestamp dir owner if one is specified.
      */       */
     if (def_str(I_TIMESTAMPOWNER)) {      if (def_timestampowner) {
         struct passwd *pw;          struct passwd *pw;
   
         if (*def_str(I_TIMESTAMPOWNER) == '#')          if (*def_timestampowner == '#')
             pw = getpwuid(atoi(def_str(I_TIMESTAMPOWNER) + 1));              pw = getpwuid(atoi(def_timestampowner + 1));
         else          else
             pw = getpwnam(def_str(I_TIMESTAMPOWNER));              pw = getpwnam(def_timestampowner);
         if (!pw)          if (!pw)
             log_error(0, "timestamp owner (%s): No such user",              log_error(0, "timestamp owner (%s): No such user",
                 def_str(I_TIMESTAMPOWNER));                  def_timestampowner);
         timestamp_uid = pw->pw_uid;          timestamp_uid = pw->pw_uid;
     }      }
   
Line 319 
Line 314 
         exit(0);          exit(0);
     }      }
   
     if (validated & VALIDATE_ERROR)      if (ISSET(validated, VALIDATE_ERROR))
         log_error(0, "parse error in %s near line %d", _PATH_SUDOERS,          log_error(0, "parse error in %s near line %d", _PATH_SUDOERS,
             errorlineno);              errorlineno);
   
     /* Is root even allowed to run sudo? */      /* Is root even allowed to run sudo? */
     if (user_uid == 0 && !def_flag(I_ROOT_SUDO)) {      if (user_uid == 0 && !def_root_sudo) {
         (void) fprintf(stderr,          (void) fprintf(stderr,
             "Sorry, %s has been configured to not allow root to run it.\n",              "Sorry, %s has been configured to not allow root to run it.\n",
             getprogname());              getprogname());
Line 332 
Line 327 
     }      }
   
     /* If given the -P option, set the "preserve_groups" flag. */      /* If given the -P option, set the "preserve_groups" flag. */
     if (sudo_mode & MODE_PRESERVE_GROUPS)      if (ISSET(sudo_mode, MODE_PRESERVE_GROUPS))
         def_flag(I_PRESERVE_GROUPS) = TRUE;          def_preserve_groups = TRUE;
   
     /* If no command line args and "set_home" is not set, error out. */      /* If no command line args and "set_home" is not set, error out. */
     if ((sudo_mode & MODE_IMPLIED_SHELL) && !def_flag(I_SHELL_NOARGS))      if (ISSET(sudo_mode, MODE_IMPLIED_SHELL) && !def_shell_noargs)
         usage(1);          usage(1);
   
     /* May need to set $HOME to target user if we are running a command. */      /* May need to set $HOME to target user if we are running a command. */
     if ((sudo_mode & MODE_RUN) && (def_flag(I_ALWAYS_SET_HOME) ||      if (ISSET(sudo_mode, MODE_RUN) && (def_always_set_home ||
         ((sudo_mode & MODE_SHELL) && def_flag(I_SET_HOME))))          (ISSET(sudo_mode, MODE_SHELL) && def_set_home)))
         sudo_mode |= MODE_RESET_HOME;          SET(sudo_mode, MODE_RESET_HOME);
   
     /* Bail if a tty is required and we don't have one.  */      /* Bail if a tty is required and we don't have one.  */
     if (def_flag(I_REQUIRETTY)) {      if (def_requiretty) {
         if ((fd = open(_PATH_TTY, O_RDWR|O_NOCTTY)) == -1)          if ((fd = open(_PATH_TTY, O_RDWR|O_NOCTTY)) == -1)
             log_error(NO_MAIL, "sorry, you must have a tty to run sudo");              log_error(NO_MAIL, "sorry, you must have a tty to run sudo");
         else          else
Line 355 
Line 350 
     /* Fill in passwd struct based on user we are authenticating as.  */      /* Fill in passwd struct based on user we are authenticating as.  */
     auth_pw = get_authpw();      auth_pw = get_authpw();
   
     /* Require a password unless the NOPASS tag was set.  */      /* Require a password if sudoers says so.  */
     if (!(validated & FLAG_NOPASS))      if (!ISSET(validated, FLAG_NOPASS))
         check_user();          check_user(ISSET(validated, FLAG_CHECK_USER));
   
     /* Build up custom environment that avoids any nasty bits. */      /* If run as root with SUDO_USER set, set sudo_user.pw to that user. */
     new_environ = rebuild_env(sudo_mode, envp);      if (user_uid == 0 && prev_user != NULL && strcmp(prev_user, "root") != 0) {
               struct passwd *pw;
   
     if (validated & VALIDATE_OK) {              if ((pw = sudo_getpwnam(prev_user)) != NULL) {
                       free(sudo_user.pw);
                       sudo_user.pw = pw;
               }
       }
   
       /* Build a new environment that avoids any nasty bits if we have a cmnd. */
       if (ISSET(sudo_mode, MODE_RUN))
           new_environ = rebuild_env(envp, sudo_mode, ISSET(validated, FLAG_NOEXEC));
       else
           new_environ = envp;
   
       if (ISSET(validated, VALIDATE_OK)) {
         /* Finally tell the user if the command did not exist. */          /* Finally tell the user if the command did not exist. */
         if (cmnd_status == NOT_FOUND_DOT) {          if (cmnd_status == NOT_FOUND_DOT) {
             warnx("ignoring `%s' found in '.'\nUse `sudo ./%s' if this is the `%s' you wish to run.", user_cmnd, user_cmnd, user_cmnd);              warnx("ignoring `%s' found in '.'\nUse `sudo ./%s' if this is the `%s' you wish to run.", user_cmnd, user_cmnd, user_cmnd);
Line 377 
Line 385 
             exit(0);              exit(0);
         else if (sudo_mode == MODE_LIST) {          else if (sudo_mode == MODE_LIST) {
             list_matches();              list_matches();
   #ifdef HAVE_LDAP
               sudo_ldap_list_matches();
   #endif
             exit(0);              exit(0);
         }          }
   
Line 389 
Line 400 
         }          }
   
         /* Override user's umask if configured to do so. */          /* Override user's umask if configured to do so. */
         if (def_ival(I_UMASK) != 0777)          if (def_umask != 0777)
             (void) umask(def_mode(I_UMASK));              (void) umask(def_umask);
   
         /* Restore coredumpsize resource limit. */          /* Restore coredumpsize resource limit. */
 #if defined(RLIMIT_CORE) && !defined(SUDO_DEVEL)  #if defined(RLIMIT_CORE) && !defined(SUDO_DEVEL)
         (void) setrlimit(RLIMIT_CORE, &corelimit);          (void) setrlimit(RLIMIT_CORE, &corelimit);
 #endif /* RLIMIT_CORE && !SUDO_DEVEL */  #endif /* RLIMIT_CORE && !SUDO_DEVEL */
   
         /* Become specified user or root. */          /* Become specified user or root if executing a command. */
         set_perms(PERM_RUNAS);          if (ISSET(sudo_mode, MODE_RUN))
               set_perms(PERM_FULL_RUNAS);
   
         /* Close the password and group files */          /* Close the password and group files */
         endpwent();          endpwent();
         endgrent();          endgrent();
   
         /* Install the new environment. */          /* Install the real environment. */
         environ = new_environ;          environ = new_environ;
   
           if (ISSET(sudo_mode, MODE_LOGIN_SHELL)) {
               char *p;
   
               /* Convert /bin/sh -> -sh so shell knows it is a login shell */
               if ((p = strrchr(NewArgv[0], '/')) == NULL)
                   p = NewArgv[0];
               *p = '-';
               NewArgv[0] = p;
   
               /* Change to target user's homedir. */
               if (chdir(runas_pw->pw_dir) == -1)
                   warn("unable to change directory to %s", runas_pw->pw_dir);
           }
   
           if (ISSET(sudo_mode, MODE_EDIT))
               exit(sudo_edit(NewArgc, NewArgv));
   
         /* Restore signal handlers before we exec. */          /* Restore signal handlers before we exec. */
         (void) sigaction(SIGINT, &saved_sa_int, NULL);          (void) sigaction(SIGINT, &saved_sa_int, NULL);
         (void) sigaction(SIGQUIT, &saved_sa_quit, NULL);          (void) sigaction(SIGQUIT, &saved_sa_quit, NULL);
Line 414 
Line 443 
         (void) sigaction(SIGCHLD, &saved_sa_chld, NULL);          (void) sigaction(SIGCHLD, &saved_sa_chld, NULL);
   
 #ifndef PROFILING  #ifndef PROFILING
         if ((sudo_mode & MODE_BACKGROUND) && fork() > 0)          if (ISSET(sudo_mode, MODE_BACKGROUND) && fork() > 0)
             exit(0);              exit(0);
         else          else
             EXEC(safe_cmnd, NewArgv);   /* run the command */              EXECV(safe_cmnd, NewArgv);  /* run the command */
 #else  #else
         exit(0);          exit(0);
 #endif /* PROFILING */  #endif /* PROFILING */
Line 426 
Line 455 
          */           */
         warn("unable to execute %s", safe_cmnd);          warn("unable to execute %s", safe_cmnd);
         exit(127);          exit(127);
     } else if ((validated & FLAG_NO_USER) || (validated & FLAG_NO_HOST)) {      } else if (ISSET(validated, FLAG_NO_USER) || (validated & FLAG_NO_HOST)) {
         log_auth(validated, 1);          log_auth(validated, 1);
         exit(1);          exit(1);
     } else if (validated & VALIDATE_NOT_OK) {      } else if (ISSET(validated, VALIDATE_NOT_OK)) {
         if (def_flag(I_PATH_INFO)) {          if (def_path_info) {
             /*              /*
              * We'd like to not leak path info at all here, but that can               * We'd like to not leak path info at all here, but that can
              * *really* confuse the users.  To really close the leak we'd               * *really* confuse the users.  To really close the leak we'd
Line 469 
Line 498 
     int nohostname, rval;      int nohostname, rval;
   
     /* Sanity check command from user. */      /* Sanity check command from user. */
     if (user_cmnd == NULL && strlen(NewArgv[0]) >= MAXPATHLEN)      if (user_cmnd == NULL && strlen(NewArgv[0]) >= PATH_MAX)
         errx(1, "%s: File name too long", NewArgv[0]);          errx(1, "%s: File name too long", NewArgv[0]);
   
 #ifdef HAVE_TZSET  #ifdef HAVE_TZSET
Line 492 
Line 521 
         user_host = user_shost = "localhost";          user_host = user_shost = "localhost";
     else {      else {
         user_host = estrdup(thost);          user_host = estrdup(thost);
         if (def_flag(I_FQDN)) {          if (def_fqdn) {
             /* Defer call to set_fqdn() until log_error() is safe. */              /* Defer call to set_fqdn() until log_error() is safe. */
             user_shost = user_host;              user_shost = user_host;
         } else {          } else {
Line 543 
Line 572 
   
     /* It is now safe to use log_error() and set_perms() */      /* It is now safe to use log_error() and set_perms() */
   
     /*      if (def_fqdn)
      * Must defer set_fqdn() until it is safe to call log_error()          set_fqdn();                     /* may call log_error() */
      */  
     if (def_flag(I_FQDN))  
         set_fqdn();  
   
     if (nohostname)      if (nohostname)
         log_error(USE_ERRNO|MSG_ONLY, "can't get hostname");          log_error(USE_ERRNO|MSG_ONLY, "can't get hostname");
   
       set_runaspw(*user_runas);           /* may call log_error() */
       if (*user_runas[0] == '#' && runas_pw->pw_name && runas_pw->pw_name[0])
           *user_runas = estrdup(runas_pw->pw_name);
   
     /*      /*
      * Get current working directory.  Try as user, fall back to root.       * Get current working directory.  Try as user, fall back to root.
      */       */
Line 566 
Line 596 
         set_perms(PERM_ROOT);          set_perms(PERM_ROOT);
   
     /*      /*
      * If we were given the '-s' option (run shell) we need to redo       * If we were given the '-e', '-i' or '-s' options we need to redo
      * NewArgv and NewArgc.       * NewArgv and NewArgc.
      */       */
     if ((sudo_mode & MODE_SHELL)) {      if ((sudo_mode & (MODE_SHELL | MODE_EDIT))) {
         char **dst, **src = NewArgv;          char **dst, **src = NewArgv;
   
         NewArgv = (char **) emalloc2((++NewArgc + 1), sizeof(char *));          NewArgv = (char **) emalloc2((++NewArgc + 1), sizeof(char *));
         if (user_shell && *user_shell) {          if (ISSET(sudo_mode, MODE_EDIT))
               NewArgv[0] = "sudoedit";
           else if (ISSET(sudo_mode, MODE_LOGIN_SHELL))
               NewArgv[0] = runas_pw->pw_shell;
           else if (user_shell && *user_shell)
             NewArgv[0] = user_shell;              NewArgv[0] = user_shell;
         } else          else
             errx(1, "unable to determine shell");              errx(1, "unable to determine shell");
   
         /* copy the args from NewArgv */          /* copy the args from NewArgv */
Line 587 
Line 621 
     set_loginclass(sudo_user.pw);      set_loginclass(sudo_user.pw);
   
     /* Resolve the path and return. */      /* Resolve the path and return. */
     if ((sudo_mode & MODE_RUN)) {      rval = FOUND;
         /* XXX - should call this as runas user, not root. */      user_stat = emalloc(sizeof(struct stat));
         rval = find_path(NewArgv[0], &user_cmnd, user_path);      if (sudo_mode & (MODE_RUN | MODE_EDIT)) {
         if (rval != FOUND) {          if (ISSET(sudo_mode, MODE_RUN)) {
             /* Failed as root, try as invoking user. */              /* XXX - default_runas may be modified during parsing of sudoers */
             set_perms(PERM_USER);              set_perms(PERM_RUNAS);
             rval = find_path(NewArgv[0], &user_cmnd, user_path);              rval = find_path(NewArgv[0], &user_cmnd, user_stat, user_path);
             set_perms(PERM_ROOT);              set_perms(PERM_ROOT);
               if (rval != FOUND) {
                   /* Failed as root, try as invoking user. */
                   set_perms(PERM_USER);
                   rval = find_path(NewArgv[0], &user_cmnd, user_stat, user_path);
                   set_perms(PERM_ROOT);
               }
         }          }
   
         /* set user_args */          /* set user_args */
Line 602 
Line 642 
             char *to, **from;              char *to, **from;
             size_t size, n;              size_t size, n;
   
             /* If MODE_SHELL not set then NewArgv is contiguous so just count */              /* If we didn't realloc NewArgv it is contiguous so just count. */
             if (!(sudo_mode & MODE_SHELL)) {              if (!(sudo_mode & (MODE_SHELL | MODE_EDIT))) {
                 size = (size_t) (NewArgv[NewArgc-1] - NewArgv[1]) +                  size = (size_t) (NewArgv[NewArgc-1] - NewArgv[1]) +
                         strlen(NewArgv[NewArgc-1]) + 1;                          strlen(NewArgv[NewArgc-1]) + 1;
             } else {              } else {
Line 611 
Line 651 
                     size += strlen(*from) + 1;                      size += strlen(*from) + 1;
             }              }
   
             /* alloc and copy. */              /* Alloc and build up user_args. */
             user_args = (char *) emalloc(size);              user_args = (char *) emalloc(size);
             for (to = user_args, from = NewArgv + 1; *from; from++) {              for (to = user_args, from = NewArgv + 1; *from; from++) {
                 n = strlcpy(to, *from, size - (to - user_args));                  n = strlcpy(to, *from, size - (to - user_args));
Line 622 
Line 662 
             }              }
             *--to = '\0';              *--to = '\0';
         }          }
     } else      }
         rval = FOUND;      if ((user_base = strrchr(user_cmnd, '/')) != NULL)
           user_base++;
       else
           user_base = user_cmnd;
   
     return(rval);      return(rval);
 }  }
Line 642 
Line 685 
     NewArgv = argv + 1;      NewArgv = argv + 1;
     NewArgc = argc - 1;      NewArgc = argc - 1;
   
     if (NewArgc == 0) {                 /* no options and no command */      /* First, check to see if we were invoked as "sudoedit". */
         rval |= (MODE_IMPLIED_SHELL | MODE_SHELL);      if (strcmp(getprogname(), "sudoedit") == 0) {
           rval = MODE_EDIT;
           excl = 'e';
       } else
           rval = MODE_RUN;
   
       if (NewArgc == 0 && rval == MODE_RUN) {     /* no options and no command */
           SET(rval, (MODE_IMPLIED_SHELL | MODE_SHELL));
         return(rval);          return(rval);
     }      }
   
Line 691 
Line 741 
                     usage(1);                      usage(1);
   
                 login_class = NewArgv[1];                  login_class = NewArgv[1];
                 def_flag(I_USE_LOGINCLASS) = TRUE;                  def_use_loginclass = TRUE;
   
                 NewArgc--;                  NewArgc--;
                 NewArgv++;                  NewArgv++;
                 break;                  break;
 #endif  #endif
             case 'b':              case 'b':
                 rval |= MODE_BACKGROUND;                  SET(rval, MODE_BACKGROUND);
                 break;                  break;
               case 'e':
                   rval = MODE_EDIT;
                   if (excl && excl != 'e')
                       usage_excl(1);
                   excl = 'e';
                   break;
             case 'v':              case 'v':
                 rval = MODE_VALIDATE;                  rval = MODE_VALIDATE;
                 if (excl && excl != 'v')                  if (excl && excl != 'v')
                     usage_excl(1);                      usage_excl(1);
                 excl = 'v';                  excl = 'v';
                 break;                  break;
               case 'i':
                   SET(rval, (MODE_LOGIN_SHELL | MODE_SHELL));
                   def_env_reset = TRUE;
                   if (excl && excl != 'i')
                       usage_excl(1);
                   excl = 'i';
                   break;
             case 'k':              case 'k':
                 rval = MODE_INVALIDATE;                  rval = MODE_INVALIDATE;
                 if (excl && excl != 'k')                  if (excl && excl != 'k')
Line 743 
Line 806 
                 excl = 'h';                  excl = 'h';
                 break;                  break;
             case 's':              case 's':
                 rval |= MODE_SHELL;                  SET(rval, MODE_SHELL);
                 if (excl && excl != 's')                  if (excl && excl != 's')
                     usage_excl(1);                      usage_excl(1);
                 excl = 's';                  excl = 's';
                 break;                  break;
             case 'H':              case 'H':
                 rval |= MODE_RESET_HOME;                  SET(rval, MODE_RESET_HOME);
                 break;                  break;
             case 'P':              case 'P':
                 rval |= MODE_PRESERVE_GROUPS;                  SET(rval, MODE_PRESERVE_GROUPS);
                 break;                  break;
             case 'S':              case 'S':
                 tgetpass_flags |= TGP_STDIN;                  SET(tgetpass_flags, TGP_STDIN);
                 break;                  break;
             case '-':              case '-':
                 NewArgc--;                  NewArgc--;
                 NewArgv++;                  NewArgv++;
                 if (rval == MODE_RUN)                  if (rval == MODE_RUN)
                     rval |= (MODE_IMPLIED_SHELL | MODE_SHELL);                      SET(rval, (MODE_IMPLIED_SHELL | MODE_SHELL));
                 return(rval);                  return(rval);
             case '\0':              case '\0':
                 warnx("'-' requires an argument");                  warnx("'-' requires an argument");
Line 774 
Line 837 
         NewArgv++;          NewArgv++;
     }      }
   
     if (NewArgc > 0 && !(rval & MODE_RUN))      if ((NewArgc == 0 && (rval & MODE_EDIT)) ||
           (NewArgc > 0 && !(rval & (MODE_RUN | MODE_EDIT))))
         usage(1);          usage(1);
   
     return(rval);      return(rval);
Line 793 
Line 857 
   
     /*      /*
      * Fix the mode and group on sudoers file from old default.       * Fix the mode and group on sudoers file from old default.
      * Only works if filesystem is readable/writable by root.       * Only works if file system is readable/writable by root.
      */       */
     if ((rootstat = stat_sudoers(_PATH_SUDOERS, &statbuf)) == 0 &&      if ((rootstat = stat_sudoers(_PATH_SUDOERS, &statbuf)) == 0 &&
         SUDOERS_UID == statbuf.st_uid && SUDOERS_MODE != 0400 &&          SUDOERS_UID == statbuf.st_uid && SUDOERS_MODE != 0400 &&
Line 801 
Line 865 
   
         if (chmod(_PATH_SUDOERS, SUDOERS_MODE) == 0) {          if (chmod(_PATH_SUDOERS, SUDOERS_MODE) == 0) {
             warnx("fixed mode on %s", _PATH_SUDOERS);              warnx("fixed mode on %s", _PATH_SUDOERS);
             statbuf.st_mode |= SUDOERS_MODE;              SET(statbuf.st_mode, SUDOERS_MODE);
             if (statbuf.st_gid != SUDOERS_GID) {              if (statbuf.st_gid != SUDOERS_GID) {
                 if (!chown(_PATH_SUDOERS,(uid_t) -1,SUDOERS_GID)) {                  if (!chown(_PATH_SUDOERS,(uid_t) -1,SUDOERS_GID)) {
                     warnx("set group on %s", _PATH_SUDOERS);                      warnx("set group on %s", _PATH_SUDOERS);
Line 965 
Line 1029 
 }  }
   
 /*  /*
    * Get passwd entry for the user we are going to run commands as.
    * By default, this is "root".  Updates runas_pw as a side effect.
    */
   int
   set_runaspw(user)
       char *user;
   {
       if (runas_pw != NULL) {
           if (user_runas != &def_runas_default)
               return(TRUE);               /* don't override -u option */
           free(runas_pw);
       }
       if (*user == '#') {
           runas_pw = sudo_getpwuid(atoi(user + 1));
           if (runas_pw == NULL) {
               runas_pw = emalloc(sizeof(struct passwd));
               (void) memset((VOID *)runas_pw, 0, sizeof(struct passwd));
               runas_pw->pw_uid = atoi(user + 1);
           }
       } else {
           runas_pw = sudo_getpwnam(user);
           if (runas_pw == NULL)
               log_error(NO_MAIL|MSG_ONLY, "no passwd entry for %s!", user);
       }
       return(TRUE);
   }
   
   /*
  * Get passwd entry for the user we are going to authenticate as.   * Get passwd entry for the user we are going to authenticate as.
  * By default, this is the user invoking sudo...   * By default, this is the user invoking sudo.  In the most common
    * case, this matches sudo_user.pw or runas_pw.
  */   */
 static struct passwd *  static struct passwd *
 get_authpw()  get_authpw()
 {  {
     struct passwd *pw;      struct passwd *pw;
   
     if (def_ival(I_ROOTPW)) {      if (def_rootpw) {
         if ((pw = sudo_getpwuid(0)) == NULL)          if (runas_pw->pw_uid == 0)
               pw = runas_pw;
           else if ((pw = sudo_getpwuid(0)) == NULL)
             log_error(0, "uid 0 does not exist in the passwd file!");              log_error(0, "uid 0 does not exist in the passwd file!");
     } else if (def_ival(I_RUNASPW)) {      } else if (def_runaspw) {
         if ((pw = sudo_getpwnam(def_str(I_RUNAS_DEFAULT))) == NULL)          if (strcmp(def_runas_default, *user_runas) == 0)
               pw = runas_pw;
           else if ((pw = sudo_getpwnam(def_runas_default)) == NULL)
             log_error(0, "user %s does not exist in the passwd file!",              log_error(0, "user %s does not exist in the passwd file!",
                 def_str(I_RUNAS_DEFAULT));                  def_runas_default);
     } else if (def_ival(I_TARGETPW)) {      } else if (def_targetpw) {
         if (**user_runas == '#') {          if (runas_pw->pw_name == NULL)
             if ((pw = sudo_getpwuid(atoi(*user_runas + 1))) == NULL)              log_error(NO_MAIL|MSG_ONLY, "no passwd entry for %lu!",
                 log_error(0, "uid %s does not exist in the passwd file!",                  runas_pw->pw_uid);
                     user_runas);          pw = runas_pw;
         } else {  
             if ((pw = sudo_getpwnam(*user_runas)) == NULL)  
                 log_error(0, "user %s does not exist in the passwd file!",  
                     user_runas);  
         }  
     } else      } else
         pw = sudo_user.pw;          pw = sudo_user.pw;
   
Line 1003 
Line 1095 
 usage_excl(exit_val)  usage_excl(exit_val)
     int exit_val;      int exit_val;
 {  {
     (void) fprintf(stderr,      warnx("Only one of the -e, -h, -k, -K, -l, -s, -v or -V options may be used");
         "Only one of the -h, -k, -K, -l, -s, -v or -V options may be used\n");  
     usage(exit_val);      usage(exit_val);
 }  }
   
Line 1015 
Line 1106 
 usage(exit_val)  usage(exit_val)
     int exit_val;      int exit_val;
 {  {
       char **p;
     (void) fprintf(stderr, "usage: sudo -V | -h | -L | -l | -v | -k | -K | %s",      int linelen, linemax, ulen;
         "[-H] [-P] [-S] [-b] [-p prompt]\n            [-u username/#uid] ");      static char *uvec[] = {
 #ifdef HAVE_LOGIN_CAP_H          " [-HPSb]",
     (void) fprintf(stderr, "[-c class] ");  
 #endif  
 #ifdef HAVE_BSD_AUTH_H  #ifdef HAVE_BSD_AUTH_H
     (void) fprintf(stderr, "[-a auth_type] ");          " [-a auth_type]",
 #endif  #endif
     (void) fprintf(stderr, "-s | <command>\n");  #ifdef HAVE_LOGIN_CAP_H
           " [-c class|-]",
   #endif
           " [-p prompt]",
           " [-u username|#uid]",
           " { -e file [...] | -i | -s | <command> }",
           NULL
       };
   
       /*
        * For sudoedit, replace the last entry in the usage vector.
        * For sudo, print the secondary usage.
        */
       if (strcmp(getprogname(), "sudoedit") == 0) {
           /* Replace the last entry in the usage vector. */
           for (p = uvec; p[1] != NULL; p++)
               continue;
           *p = " file [...]";
       } else {
           fprintf(stderr, "usage: %s -K | -L | -V | -h | -k | -l | -v\n",
               getprogname());
       }
   
       /*
        * Print the main usage and wrap lines as needed.
        * Assumes an 80-character wide terminal, which is kind of bogus...
        */
       ulen = (int)strlen(getprogname()) + 7;
       linemax = 80;
       linelen = linemax - ulen;
       printf("usage: %s", getprogname());
       for (p = uvec; *p != NULL; p++) {
           if (linelen == linemax || (linelen -= strlen(*p)) >= 0) {
               fputs(*p, stdout);
           } else {
               p--;
               linelen = linemax;
               printf("\n%*s", ulen, "");
           }
       }
       putchar('\n');
     exit(exit_val);      exit(exit_val);
 }  }

Legend:
Removed from v.1.22  
changed lines
  Added in v.1.23