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

Annotation of src/usr.bin/sudo/sudo.c, Revision 1.23

1.1       millert     1: /*
1.23    ! millert     2:  * Copyright (c) 1993-1996,1998-2004 Todd C. Miller <Todd.Miller@courtesan.com>
1.1       millert     3:  *
1.23    ! millert     4:  * Permission to use, copy, modify, and distribute this software for any
        !             5:  * purpose with or without fee is hereby granted, provided that the above
        !             6:  * copyright notice and this permission notice appear in all copies.
1.1       millert     7:  *
1.23    ! millert     8:  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
        !             9:  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
        !            10:  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
        !            11:  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
        !            12:  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
        !            13:  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
        !            14:  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1.1       millert    15:  *
1.20      millert    16:  * Sponsored in part by the Defense Advanced Research Projects
                     17:  * Agency (DARPA) and Air Force Research Laboratory, Air Force
                     18:  * Materiel Command, USAF, under agreement number F39502-99-1-0512.
                     19:  *
1.1       millert    20:  * For a brief history of sudo, please see the HISTORY file included
                     21:  * with this distribution.
                     22:  */
                     23:
1.19      millert    24: #define _SUDO_MAIN
1.1       millert    25:
1.23    ! millert    26: #ifdef __TANDEM
        !            27: # include <floss.h>
        !            28: #endif
        !            29:
1.1       millert    30: #include "config.h"
                     31:
1.11      millert    32: #include <sys/types.h>
                     33: #include <sys/stat.h>
                     34: #include <sys/param.h>
                     35: #include <sys/socket.h>
                     36: #ifdef HAVE_SETRLIMIT
                     37: # include <sys/time.h>
                     38: # include <sys/resource.h>
                     39: #endif
1.1       millert    40: #include <stdio.h>
                     41: #ifdef STDC_HEADERS
1.11      millert    42: # include <stdlib.h>
                     43: # include <stddef.h>
                     44: #else
                     45: # ifdef HAVE_STDLIB_H
                     46: #  include <stdlib.h>
                     47: # endif
1.1       millert    48: #endif /* STDC_HEADERS */
1.11      millert    49: #ifdef HAVE_STRING_H
                     50: # if defined(HAVE_MEMORY_H) && !defined(STDC_HEADERS)
                     51: #  include <memory.h>
                     52: # endif
                     53: # include <string.h>
                     54: #else
                     55: # ifdef HAVE_STRINGS_H
                     56: #  include <strings.h>
                     57: # endif
                     58: #endif /* HAVE_STRING_H */
1.1       millert    59: #ifdef HAVE_UNISTD_H
1.11      millert    60: # include <unistd.h>
1.1       millert    61: #endif /* HAVE_UNISTD_H */
1.19      millert    62: #ifdef HAVE_ERR_H
                     63: # include <err.h>
                     64: #else
                     65: # include "emul/err.h"
                     66: #endif /* HAVE_ERR_H */
1.1       millert    67: #include <pwd.h>
                     68: #include <errno.h>
                     69: #include <fcntl.h>
                     70: #include <signal.h>
                     71: #include <grp.h>
                     72: #include <time.h>
                     73: #include <netinet/in.h>
                     74: #include <netdb.h>
                     75: #if defined(HAVE_GETPRPWNAM) && defined(HAVE_SET_AUTH_PARAMETERS)
                     76: # ifdef __hpux
                     77: #  undef MAXINT
                     78: #  include <hpsecurity.h>
                     79: # else
                     80: #  include <sys/security.h>
                     81: # endif /* __hpux */
                     82: # include <prot.h>
                     83: #endif /* HAVE_GETPRPWNAM && HAVE_SET_AUTH_PARAMETERS */
1.8       millert    84: #ifdef HAVE_LOGIN_CAP_H
1.4       millert    85: # include <login_cap.h>
                     86: # ifndef LOGIN_DEFROOTCLASS
                     87: #  define LOGIN_DEFROOTCLASS   "daemon"
                     88: # endif
                     89: #endif
1.1       millert    90:
                     91: #include "sudo.h"
                     92: #include "interfaces.h"
                     93: #include "version.h"
                     94:
                     95: #ifndef lint
1.23    ! millert    96: static const char rcsid[] = "$Sudo: sudo.c,v 1.370 2004/08/24 18:01:13 millert Exp $";
1.1       millert    97: #endif /* lint */
                     98:
                     99: /*
                    100:  * Prototypes
                    101:  */
1.11      millert   102: static int init_vars                   __P((int));
1.19      millert   103: static int parse_args                  __P((int, char **));
1.11      millert   104: static void check_sudoers              __P((void));
                    105: static void initial_setup              __P((void));
                    106: static void set_loginclass             __P((struct passwd *));
1.1       millert   107: static void usage                      __P((int));
                    108: static void usage_excl                 __P((int));
1.6       millert   109: static struct passwd *get_authpw       __P((void));
1.23    ! millert   110: extern int sudo_edit                   __P((int, char **));
1.11      millert   111: extern void list_matches               __P((void));
1.23    ! millert   112: extern char **rebuild_env              __P((char **, int, int));
1.11      millert   113: extern char **zero_env                 __P((char **));
                    114: extern struct passwd *sudo_getpwnam    __P((const char *));
1.1       millert   115: extern struct passwd *sudo_getpwuid    __P((uid_t));
1.23    ! millert   116: extern struct passwd *sudo_pwdup       __P((const struct passwd *));
1.1       millert   117:
                    118: /*
                    119:  * Globals
                    120:  */
1.19      millert   121: int Argc, NewArgc;
                    122: char **Argv, **NewArgv;
1.23    ! millert   123: char *prev_user;
1.1       millert   124: struct sudo_user sudo_user;
1.6       millert   125: struct passwd *auth_pw;
1.19      millert   126: FILE *sudoers_fp;
1.1       millert   127: struct interface *interfaces;
                    128: int num_interfaces;
1.4       millert   129: int tgetpass_flags;
1.17      millert   130: uid_t timestamp_uid;
1.1       millert   131: extern int errorlineno;
1.4       millert   132: #if defined(RLIMIT_CORE) && !defined(SUDO_DEVEL)
                    133: static struct rlimit corelimit;
1.20      millert   134: #endif /* RLIMIT_CORE && !SUDO_DEVEL */
1.8       millert   135: #ifdef HAVE_LOGIN_CAP_H
                    136: login_cap_t *lc;
                    137: #endif /* HAVE_LOGIN_CAP_H */
                    138: #ifdef HAVE_BSD_AUTH_H
                    139: char *login_style;
                    140: #endif /* HAVE_BSD_AUTH_H */
1.23    ! millert   141: sigaction_t saved_sa_int, saved_sa_quit, saved_sa_tstp, saved_sa_chld;
1.17      millert   142: void (*set_perms) __P((int));
1.1       millert   143:
                    144:
                    145: int
1.11      millert   146: main(argc, argv, envp)
1.1       millert   147:     int argc;
                    148:     char **argv;
1.11      millert   149:     char **envp;
1.1       millert   150: {
                    151:     int validated;
                    152:     int fd;
                    153:     int cmnd_status;
                    154:     int sudo_mode;
1.11      millert   155:     int pwflag;
1.12      millert   156:     char **new_environ;
1.23    ! millert   157:     sigaction_t sa;
1.11      millert   158:     extern int printmatches;
1.1       millert   159:     extern char **environ;
                    160:
1.19      millert   161:     Argv = argv;
1.23    ! millert   162:     if ((Argc = argc) < 1)
        !           163:        usage(1);
1.19      millert   164:
1.1       millert   165:     /* Must be done as the first thing... */
                    166: #if defined(HAVE_GETPRPWNAM) && defined(HAVE_SET_AUTH_PARAMETERS)
1.19      millert   167:     (void) set_auth_parameters(Argc, Argv);
1.1       millert   168: # ifdef HAVE_INITPRIVS
                    169:     initprivs();
                    170: # endif
                    171: #endif /* HAVE_GETPRPWNAM && HAVE_SET_AUTH_PARAMETERS */
                    172:
1.11      millert   173:     /* Zero out the environment. */
                    174:     environ = zero_env(envp);
                    175:
1.19      millert   176:     if (geteuid() != 0)
                    177:        errx(1, "must be setuid root");
1.1       millert   178:
                    179:     /*
1.17      millert   180:      * Signal setup:
                    181:      * Ignore keyboard-generated signals so the user cannot interrupt
                    182:      *  us at some point and avoid the logging.
                    183:      *  Install handler to wait for children when they exit.
1.1       millert   184:      */
1.11      millert   185:     sigemptyset(&sa.sa_mask);
                    186:     sa.sa_flags = SA_RESTART;
                    187:     sa.sa_handler = SIG_IGN;
1.17      millert   188:     (void) sigaction(SIGINT, &sa, &saved_sa_int);
                    189:     (void) sigaction(SIGQUIT, &sa, &saved_sa_quit);
                    190:     (void) sigaction(SIGTSTP, &sa, &saved_sa_tstp);
                    191:     sa.sa_handler = reapchild;
                    192:     (void) sigaction(SIGCHLD, &sa, &saved_sa_chld);
1.1       millert   193:
                    194:     /*
1.17      millert   195:      * Turn off core dumps, close open files and setup set_perms().
1.1       millert   196:      */
                    197:     initial_setup();
1.11      millert   198:     setpwent();
1.1       millert   199:
                    200:     /* Parse our arguments. */
1.19      millert   201:     sudo_mode = parse_args(Argc, Argv);
1.1       millert   202:
                    203:     /* Setup defaults data structures. */
                    204:     init_defaults();
                    205:
1.11      millert   206:     /* Load the list of local ip addresses and netmasks.  */
                    207:     load_interfaces();
                    208:
                    209:     pwflag = 0;
1.23    ! millert   210:     if (ISSET(sudo_mode, MODE_SHELL))
1.1       millert   211:        user_cmnd = "shell";
1.23    ! millert   212:     else if (ISSET(sudo_mode, MODE_EDIT))
        !           213:        user_cmnd = "sudoedit";
1.1       millert   214:     else
                    215:        switch (sudo_mode) {
                    216:            case MODE_VERSION:
                    217:                (void) printf("Sudo version %s\n", version);
                    218:                if (getuid() == 0) {
                    219:                    putchar('\n');
                    220:                    dump_auth_methods();
                    221:                    dump_defaults();
1.11      millert   222:                    dump_interfaces();
1.1       millert   223:                }
                    224:                exit(0);
                    225:                break;
                    226:            case MODE_HELP:
                    227:                usage(0);
                    228:                break;
                    229:            case MODE_VALIDATE:
                    230:                user_cmnd = "validate";
1.23    ! millert   231:                pwflag = I_VERIFYPW;
1.1       millert   232:                break;
                    233:            case MODE_KILL:
                    234:            case MODE_INVALIDATE:
                    235:                user_cmnd = "kill";
1.11      millert   236:                pwflag = -1;
1.1       millert   237:                break;
                    238:            case MODE_LISTDEFS:
                    239:                list_options();
                    240:                exit(0);
                    241:                break;
                    242:            case MODE_LIST:
                    243:                user_cmnd = "list";
1.23    ! millert   244:                pwflag = I_LISTPW;
1.1       millert   245:                printmatches = 1;
                    246:                break;
                    247:        }
                    248:
                    249:     /* Must have a command to run... */
                    250:     if (user_cmnd == NULL && NewArgc == 0)
                    251:        usage(1);
                    252:
                    253:     cmnd_status = init_vars(sudo_mode);
                    254:
1.23    ! millert   255: #ifdef HAVE_LDAP
        !           256:     validated = sudo_ldap_check(pwflag);
        !           257:
        !           258:     /* Skip reading /etc/sudoers if LDAP told us to */
        !           259:     if (def_ignore_local_sudoers); /* skips */
        !           260:     else if (ISSET(validated, VALIDATE_OK) && !printmatches); /* skips */
        !           261:     else if (ISSET(validated, VALIDATE_OK) && printmatches)
        !           262:     {
        !           263:        check_sudoers();        /* check mode/owner on _PATH_SUDOERS */
        !           264:
        !           265:        /* User is found in LDAP and we want a list of all sudo commands the
        !           266:         * user can do, so consult sudoers but throw away result.
        !           267:         */
        !           268:        sudoers_lookup(pwflag);
        !           269:     }
        !           270:     else
        !           271: #endif
        !           272:     {
        !           273:        check_sudoers();        /* check mode/owner on _PATH_SUDOERS */
1.1       millert   274:
1.23    ! millert   275:        /* Validate the user but don't search for pseudo-commands. */
        !           276:        validated = sudoers_lookup(pwflag);
        !           277:     }
1.13      millert   278:
                    279:     /*
1.17      millert   280:      * If we are using set_perms_posix() and the stay_setuid flag was not set,
                    281:      * set the real, effective and saved uids to 0 and use set_perms_nosuid()
1.13      millert   282:      * instead of set_perms_posix().
                    283:      */
1.17      millert   284: #if !defined(HAVE_SETRESUID) && !defined(HAVE_SETREUID) && \
                    285:     !defined(NO_SAVED_IDS) && defined(_SC_SAVED_IDS) && defined(_SC_VERSION)
1.23    ! millert   286:     if (!def_stay_setuid && set_perms == set_perms_posix) {
1.13      millert   287:        if (setuid(0)) {
                    288:            perror("setuid(0)");
                    289:            exit(1);
                    290:        }
1.17      millert   291:        set_perms = set_perms_nosuid;
1.13      millert   292:     }
                    293: #endif
1.1       millert   294:
1.11      millert   295:     /*
1.17      millert   296:      * Look up the timestamp dir owner if one is specified.
                    297:      */
1.23    ! millert   298:     if (def_timestampowner) {
1.17      millert   299:        struct passwd *pw;
                    300:
1.23    ! millert   301:        if (*def_timestampowner == '#')
        !           302:            pw = getpwuid(atoi(def_timestampowner + 1));
1.17      millert   303:        else
1.23    ! millert   304:            pw = getpwnam(def_timestampowner);
1.17      millert   305:        if (!pw)
                    306:            log_error(0, "timestamp owner (%s): No such user",
1.23    ! millert   307:                def_timestampowner);
1.17      millert   308:        timestamp_uid = pw->pw_uid;
                    309:     }
                    310:
1.2       millert   311:     /* This goes after the sudoers parse since we honor sudoers options. */
1.1       millert   312:     if (sudo_mode == MODE_KILL || sudo_mode == MODE_INVALIDATE) {
                    313:        remove_timestamp((sudo_mode == MODE_KILL));
                    314:        exit(0);
                    315:     }
                    316:
1.23    ! millert   317:     if (ISSET(validated, VALIDATE_ERROR))
1.1       millert   318:        log_error(0, "parse error in %s near line %d", _PATH_SUDOERS,
                    319:            errorlineno);
                    320:
                    321:     /* Is root even allowed to run sudo? */
1.23    ! millert   322:     if (user_uid == 0 && !def_root_sudo) {
1.17      millert   323:        (void) fprintf(stderr,
                    324:            "Sorry, %s has been configured to not allow root to run it.\n",
1.19      millert   325:            getprogname());
1.1       millert   326:        exit(1);
                    327:     }
                    328:
1.11      millert   329:     /* If given the -P option, set the "preserve_groups" flag. */
1.23    ! millert   330:     if (ISSET(sudo_mode, MODE_PRESERVE_GROUPS))
        !           331:        def_preserve_groups = TRUE;
1.11      millert   332:
1.3       millert   333:     /* If no command line args and "set_home" is not set, error out. */
1.23    ! millert   334:     if (ISSET(sudo_mode, MODE_IMPLIED_SHELL) && !def_shell_noargs)
1.3       millert   335:        usage(1);
                    336:
1.15      millert   337:     /* May need to set $HOME to target user if we are running a command. */
1.23    ! millert   338:     if (ISSET(sudo_mode, MODE_RUN) && (def_always_set_home ||
        !           339:        (ISSET(sudo_mode, MODE_SHELL) && def_set_home)))
        !           340:        SET(sudo_mode, MODE_RESET_HOME);
1.2       millert   341:
1.1       millert   342:     /* Bail if a tty is required and we don't have one.  */
1.23    ! millert   343:     if (def_requiretty) {
1.1       millert   344:        if ((fd = open(_PATH_TTY, O_RDWR|O_NOCTTY)) == -1)
                    345:            log_error(NO_MAIL, "sorry, you must have a tty to run sudo");
                    346:        else
                    347:            (void) close(fd);
                    348:     }
                    349:
1.6       millert   350:     /* Fill in passwd struct based on user we are authenticating as.  */
                    351:     auth_pw = get_authpw();
1.4       millert   352:
1.23    ! millert   353:     /* Require a password if sudoers says so.  */
        !           354:     if (!ISSET(validated, FLAG_NOPASS))
        !           355:        check_user(ISSET(validated, FLAG_CHECK_USER));
        !           356:
        !           357:     /* If run as root with SUDO_USER set, set sudo_user.pw to that user. */
        !           358:     if (user_uid == 0 && prev_user != NULL && strcmp(prev_user, "root") != 0) {
        !           359:            struct passwd *pw;
        !           360:
        !           361:            if ((pw = sudo_getpwnam(prev_user)) != NULL) {
        !           362:                    free(sudo_user.pw);
        !           363:                    sudo_user.pw = pw;
        !           364:            }
        !           365:     }
1.1       millert   366:
1.23    ! millert   367:     /* Build a new environment that avoids any nasty bits if we have a cmnd. */
        !           368:     if (ISSET(sudo_mode, MODE_RUN))
        !           369:        new_environ = rebuild_env(envp, sudo_mode, ISSET(validated, FLAG_NOEXEC));
        !           370:     else
        !           371:        new_environ = envp;
1.14      millert   372:
1.23    ! millert   373:     if (ISSET(validated, VALIDATE_OK)) {
1.1       millert   374:        /* Finally tell the user if the command did not exist. */
                    375:        if (cmnd_status == NOT_FOUND_DOT) {
1.19      millert   376:            warnx("ignoring `%s' found in '.'\nUse `sudo ./%s' if this is the `%s' you wish to run.", user_cmnd, user_cmnd, user_cmnd);
1.1       millert   377:            exit(1);
                    378:        } else if (cmnd_status == NOT_FOUND) {
1.19      millert   379:            warnx("%s: command not found", user_cmnd);
1.1       millert   380:            exit(1);
                    381:        }
                    382:
                    383:        log_auth(validated, 1);
                    384:        if (sudo_mode == MODE_VALIDATE)
                    385:            exit(0);
                    386:        else if (sudo_mode == MODE_LIST) {
                    387:            list_matches();
1.23    ! millert   388: #ifdef HAVE_LDAP
        !           389:            sudo_ldap_list_matches();
        !           390: #endif
1.1       millert   391:            exit(0);
                    392:        }
                    393:
                    394:        /* This *must* have been set if we got a match but... */
                    395:        if (safe_cmnd == NULL) {
                    396:            log_error(MSG_ONLY,
1.11      millert   397:                "internal error, safe_cmnd never got set for %s; %s",
1.1       millert   398:                user_cmnd,
                    399:                "please report this error at http://courtesan.com/sudo/bugs/");
                    400:        }
                    401:
                    402:        /* Override user's umask if configured to do so. */
1.23    ! millert   403:        if (def_umask != 0777)
        !           404:            (void) umask(def_umask);
1.1       millert   405:
1.4       millert   406:        /* Restore coredumpsize resource limit. */
                    407: #if defined(RLIMIT_CORE) && !defined(SUDO_DEVEL)
                    408:        (void) setrlimit(RLIMIT_CORE, &corelimit);
1.20      millert   409: #endif /* RLIMIT_CORE && !SUDO_DEVEL */
1.4       millert   410:
1.23    ! millert   411:        /* Become specified user or root if executing a command. */
        !           412:        if (ISSET(sudo_mode, MODE_RUN))
        !           413:            set_perms(PERM_FULL_RUNAS);
1.16      millert   414:
                    415:        /* Close the password and group files */
                    416:        endpwent();
                    417:        endgrent();
1.12      millert   418:
1.23    ! millert   419:        /* Install the real environment. */
1.12      millert   420:        environ = new_environ;
1.5       millert   421:
1.23    ! millert   422:        if (ISSET(sudo_mode, MODE_LOGIN_SHELL)) {
        !           423:            char *p;
        !           424:
        !           425:            /* Convert /bin/sh -> -sh so shell knows it is a login shell */
        !           426:            if ((p = strrchr(NewArgv[0], '/')) == NULL)
        !           427:                p = NewArgv[0];
        !           428:            *p = '-';
        !           429:            NewArgv[0] = p;
        !           430:
        !           431:            /* Change to target user's homedir. */
        !           432:            if (chdir(runas_pw->pw_dir) == -1)
        !           433:                warn("unable to change directory to %s", runas_pw->pw_dir);
        !           434:        }
        !           435:
        !           436:        if (ISSET(sudo_mode, MODE_EDIT))
        !           437:            exit(sudo_edit(NewArgc, NewArgv));
        !           438:
1.17      millert   439:        /* Restore signal handlers before we exec. */
                    440:        (void) sigaction(SIGINT, &saved_sa_int, NULL);
                    441:        (void) sigaction(SIGQUIT, &saved_sa_quit, NULL);
                    442:        (void) sigaction(SIGTSTP, &saved_sa_tstp, NULL);
                    443:        (void) sigaction(SIGCHLD, &saved_sa_chld, NULL);
                    444:
1.1       millert   445: #ifndef PROFILING
1.23    ! millert   446:        if (ISSET(sudo_mode, MODE_BACKGROUND) && fork() > 0)
1.1       millert   447:            exit(0);
                    448:        else
1.23    ! millert   449:            EXECV(safe_cmnd, NewArgv);  /* run the command */
1.1       millert   450: #else
                    451:        exit(0);
                    452: #endif /* PROFILING */
                    453:        /*
                    454:         * If we got here then the exec() failed...
                    455:         */
1.19      millert   456:        warn("unable to execute %s", safe_cmnd);
1.11      millert   457:        exit(127);
1.23    ! millert   458:     } else if (ISSET(validated, FLAG_NO_USER) || (validated & FLAG_NO_HOST)) {
1.1       millert   459:        log_auth(validated, 1);
                    460:        exit(1);
1.23    ! millert   461:     } else if (ISSET(validated, VALIDATE_NOT_OK)) {
        !           462:        if (def_path_info) {
1.1       millert   463:            /*
                    464:             * We'd like to not leak path info at all here, but that can
                    465:             * *really* confuse the users.  To really close the leak we'd
                    466:             * have to say "not allowed to run foo" even when the problem
                    467:             * is just "no foo in path" since the user can trivially set
                    468:             * their path to just contain a single dir.
                    469:             */
                    470:            log_auth(validated,
                    471:                !(cmnd_status == NOT_FOUND_DOT || cmnd_status == NOT_FOUND));
                    472:            if (cmnd_status == NOT_FOUND)
1.19      millert   473:                warnx("%s: command not found", user_cmnd);
1.1       millert   474:            else if (cmnd_status == NOT_FOUND_DOT)
1.19      millert   475:                warnx("ignoring `%s' found in '.'\nUse `sudo ./%s' if this is the `%s' you wish to run.", user_cmnd, user_cmnd, user_cmnd);
1.1       millert   476:        } else {
                    477:            /* Just tell the user they are not allowed to run foo. */
                    478:            log_auth(validated, 1);
                    479:        }
                    480:        exit(1);
                    481:     } else {
                    482:        /* should never get here */
                    483:        log_auth(validated, 1);
                    484:        exit(1);
                    485:     }
                    486:     exit(0);   /* not reached */
                    487: }
                    488:
                    489: /*
                    490:  * Initialize timezone, set umask, fill in ``sudo_user'' struct and
                    491:  * load the ``interfaces'' array.
                    492:  */
                    493: static int
                    494: init_vars(sudo_mode)
                    495:     int sudo_mode;
                    496: {
                    497:     char *p, thost[MAXHOSTNAMELEN];
1.11      millert   498:     int nohostname, rval;
1.1       millert   499:
                    500:     /* Sanity check command from user. */
1.23    ! millert   501:     if (user_cmnd == NULL && strlen(NewArgv[0]) >= PATH_MAX)
1.19      millert   502:        errx(1, "%s: File name too long", NewArgv[0]);
1.1       millert   503:
                    504: #ifdef HAVE_TZSET
                    505:     (void) tzset();            /* set the timezone if applicable */
                    506: #endif /* HAVE_TZSET */
                    507:
                    508:     /* Default value for cmnd and cwd, overridden later. */
                    509:     if (user_cmnd == NULL)
                    510:        user_cmnd = NewArgv[0];
1.17      millert   511:     (void) strlcpy(user_cwd, "unknown", sizeof(user_cwd));
1.1       millert   512:
                    513:     /*
                    514:      * We avoid gethostbyname() if possible since we don't want
                    515:      * sudo to block if DNS or NIS is hosed.
                    516:      * "host" is the (possibly fully-qualified) hostname and
                    517:      * "shost" is the unqualified form of the hostname.
                    518:      */
1.11      millert   519:     nohostname = gethostname(thost, sizeof(thost));
                    520:     if (nohostname)
                    521:        user_host = user_shost = "localhost";
                    522:     else {
1.1       millert   523:        user_host = estrdup(thost);
1.23    ! millert   524:        if (def_fqdn) {
1.11      millert   525:            /* Defer call to set_fqdn() until log_error() is safe. */
                    526:            user_shost = user_host;
1.1       millert   527:        } else {
1.11      millert   528:            if ((p = strchr(user_host, '.'))) {
                    529:                *p = '\0';
                    530:                user_shost = estrdup(user_host);
                    531:                *p = '.';
                    532:            } else {
                    533:                user_shost = user_host;
                    534:            }
1.1       millert   535:        }
                    536:     }
                    537:
                    538:     if ((p = ttyname(STDIN_FILENO)) || (p = ttyname(STDOUT_FILENO))) {
                    539:        if (strncmp(p, _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0)
                    540:            p += sizeof(_PATH_DEV) - 1;
                    541:        user_tty = estrdup(p);
                    542:     } else
                    543:        user_tty = "unknown";
                    544:
                    545:     /*
                    546:      * Get a local copy of the user's struct passwd with the shadow password
                    547:      * if necessary.  It is assumed that euid is 0 at this point so we
                    548:      * can read the shadow passwd file if necessary.
                    549:      */
                    550:     if ((sudo_user.pw = sudo_getpwuid(getuid())) == NULL) {
                    551:        /* Need to make a fake struct passwd for logging to work. */
                    552:        struct passwd pw;
                    553:        char pw_name[MAX_UID_T_LEN + 1];
                    554:
                    555:        pw.pw_uid = getuid();
1.17      millert   556:        (void) snprintf(pw_name, sizeof(pw_name), "%lu",
                    557:            (unsigned long) pw.pw_uid);
1.1       millert   558:        pw.pw_name = pw_name;
                    559:        sudo_user.pw = &pw;
                    560:
1.21      millert   561:        /*
                    562:         * If we are in -k/-K mode, just spew to stderr.  It is not unusual for
                    563:         * users to place "sudo -k" in a .logout file which can cause sudo to
                    564:         * be run during reboot after the YP/NIS/NIS+/LDAP/etc daemon has died.
                    565:         */
                    566:        if (sudo_mode & (MODE_INVALIDATE|MODE_KILL))
                    567:            errx(1, "uid %s does not exist in the passwd file!", pw_name);
                    568:        log_error(0, "uid %s does not exist in the passwd file!", pw_name);
1.1       millert   569:     }
1.15      millert   570:     if (user_shell == NULL || *user_shell == '\0')
                    571:        user_shell = sudo_user.pw->pw_shell;
1.1       millert   572:
                    573:     /* It is now safe to use log_error() and set_perms() */
                    574:
1.23    ! millert   575:     if (def_fqdn)
        !           576:        set_fqdn();                     /* may call log_error() */
1.11      millert   577:
                    578:     if (nohostname)
                    579:        log_error(USE_ERRNO|MSG_ONLY, "can't get hostname");
                    580:
1.23    ! millert   581:     set_runaspw(*user_runas);          /* may call log_error() */
        !           582:     if (*user_runas[0] == '#' && runas_pw->pw_name && runas_pw->pw_name[0])
        !           583:        *user_runas = estrdup(runas_pw->pw_name);
        !           584:
1.11      millert   585:     /*
1.1       millert   586:      * Get current working directory.  Try as user, fall back to root.
                    587:      */
1.17      millert   588:     set_perms(PERM_USER);
1.1       millert   589:     if (!getcwd(user_cwd, sizeof(user_cwd))) {
1.17      millert   590:        set_perms(PERM_ROOT);
1.1       millert   591:        if (!getcwd(user_cwd, sizeof(user_cwd))) {
1.19      millert   592:            warnx("cannot get working directory");
1.17      millert   593:            (void) strlcpy(user_cwd, "unknown", sizeof(user_cwd));
1.1       millert   594:        }
                    595:     } else
1.17      millert   596:        set_perms(PERM_ROOT);
1.1       millert   597:
                    598:     /*
1.23    ! millert   599:      * If we were given the '-e', '-i' or '-s' options we need to redo
1.1       millert   600:      * NewArgv and NewArgc.
                    601:      */
1.23    ! millert   602:     if ((sudo_mode & (MODE_SHELL | MODE_EDIT))) {
1.1       millert   603:        char **dst, **src = NewArgv;
                    604:
1.17      millert   605:        NewArgv = (char **) emalloc2((++NewArgc + 1), sizeof(char *));
1.23    ! millert   606:        if (ISSET(sudo_mode, MODE_EDIT))
        !           607:            NewArgv[0] = "sudoedit";
        !           608:        else if (ISSET(sudo_mode, MODE_LOGIN_SHELL))
        !           609:            NewArgv[0] = runas_pw->pw_shell;
        !           610:        else if (user_shell && *user_shell)
1.1       millert   611:            NewArgv[0] = user_shell;
1.23    ! millert   612:        else
1.19      millert   613:            errx(1, "unable to determine shell");
1.1       millert   614:
1.19      millert   615:        /* copy the args from NewArgv */
1.1       millert   616:        for (dst = NewArgv + 1; (*dst = *src) != NULL; ++src, ++dst)
                    617:            ;
                    618:     }
                    619:
1.8       millert   620:     /* Set login class if applicable. */
                    621:     set_loginclass(sudo_user.pw);
                    622:
1.1       millert   623:     /* Resolve the path and return. */
1.23    ! millert   624:     rval = FOUND;
        !           625:     user_stat = emalloc(sizeof(struct stat));
        !           626:     if (sudo_mode & (MODE_RUN | MODE_EDIT)) {
        !           627:        if (ISSET(sudo_mode, MODE_RUN)) {
        !           628:            /* XXX - default_runas may be modified during parsing of sudoers */
        !           629:            set_perms(PERM_RUNAS);
        !           630:            rval = find_path(NewArgv[0], &user_cmnd, user_stat, user_path);
1.17      millert   631:            set_perms(PERM_ROOT);
1.23    ! millert   632:            if (rval != FOUND) {
        !           633:                /* Failed as root, try as invoking user. */
        !           634:                set_perms(PERM_USER);
        !           635:                rval = find_path(NewArgv[0], &user_cmnd, user_stat, user_path);
        !           636:                set_perms(PERM_ROOT);
        !           637:            }
1.11      millert   638:        }
                    639:
                    640:        /* set user_args */
                    641:        if (NewArgc > 1) {
                    642:            char *to, **from;
1.17      millert   643:            size_t size, n;
1.11      millert   644:
1.23    ! millert   645:            /* If we didn't realloc NewArgv it is contiguous so just count. */
        !           646:            if (!(sudo_mode & (MODE_SHELL | MODE_EDIT))) {
1.11      millert   647:                size = (size_t) (NewArgv[NewArgc-1] - NewArgv[1]) +
                    648:                        strlen(NewArgv[NewArgc-1]) + 1;
                    649:            } else {
                    650:                for (size = 0, from = NewArgv + 1; *from; from++)
                    651:                    size += strlen(*from) + 1;
                    652:            }
                    653:
1.23    ! millert   654:            /* Alloc and build up user_args. */
1.17      millert   655:            user_args = (char *) emalloc(size);
                    656:            for (to = user_args, from = NewArgv + 1; *from; from++) {
                    657:                n = strlcpy(to, *from, size - (to - user_args));
1.19      millert   658:                if (n >= size - (to - user_args))
                    659:                    errx(1, "internal error, init_vars() overflow");
1.17      millert   660:                to += n;
1.11      millert   661:                *to++ = ' ';
                    662:            }
                    663:            *--to = '\0';
                    664:        }
1.23    ! millert   665:     }
        !           666:     if ((user_base = strrchr(user_cmnd, '/')) != NULL)
        !           667:        user_base++;
        !           668:     else
        !           669:        user_base = user_cmnd;
1.11      millert   670:
                    671:     return(rval);
1.1       millert   672: }
                    673:
                    674: /*
                    675:  * Command line argument parsing, can't use getopt(3).
                    676:  */
                    677: static int
1.19      millert   678: parse_args(argc, argv)
                    679:     int argc;
                    680:     char **argv;
1.1       millert   681: {
1.17      millert   682:     int rval = MODE_RUN;               /* what mode is sudo to be run in? */
1.1       millert   683:     int excl = 0;                      /* exclusive arg, no others allowed */
                    684:
1.19      millert   685:     NewArgv = argv + 1;
                    686:     NewArgc = argc - 1;
1.1       millert   687:
1.23    ! millert   688:     /* First, check to see if we were invoked as "sudoedit". */
        !           689:     if (strcmp(getprogname(), "sudoedit") == 0) {
        !           690:        rval = MODE_EDIT;
        !           691:        excl = 'e';
        !           692:     } else
        !           693:        rval = MODE_RUN;
        !           694:
        !           695:     if (NewArgc == 0 && rval == MODE_RUN) {    /* no options and no command */
        !           696:        SET(rval, (MODE_IMPLIED_SHELL | MODE_SHELL));
1.1       millert   697:        return(rval);
                    698:     }
                    699:
                    700:     while (NewArgc > 0 && NewArgv[0][0] == '-') {
1.19      millert   701:        if (NewArgv[0][1] != '\0' && NewArgv[0][2] != '\0')
                    702:            warnx("please use single character options");
1.1       millert   703:
                    704:        switch (NewArgv[0][1]) {
                    705:            case 'p':
                    706:                /* Must have an associated prompt. */
                    707:                if (NewArgv[1] == NULL)
                    708:                    usage(1);
                    709:
                    710:                user_prompt = NewArgv[1];
                    711:
                    712:                NewArgc--;
                    713:                NewArgv++;
                    714:                break;
                    715:            case 'u':
                    716:                /* Must have an associated runas user. */
                    717:                if (NewArgv[1] == NULL)
                    718:                    usage(1);
                    719:
                    720:                user_runas = &NewArgv[1];
                    721:
                    722:                NewArgc--;
                    723:                NewArgv++;
                    724:                break;
1.8       millert   725: #ifdef HAVE_BSD_AUTH_H
                    726:            case 'a':
                    727:                /* Must have an associated authentication style. */
                    728:                if (NewArgv[1] == NULL)
                    729:                    usage(1);
                    730:
                    731:                login_style = NewArgv[1];
                    732:
                    733:                NewArgc--;
                    734:                NewArgv++;
                    735:                break;
                    736: #endif
                    737: #ifdef HAVE_LOGIN_CAP_H
1.4       millert   738:            case 'c':
                    739:                /* Must have an associated login class. */
                    740:                if (NewArgv[1] == NULL)
                    741:                    usage(1);
                    742:
                    743:                login_class = NewArgv[1];
1.23    ! millert   744:                def_use_loginclass = TRUE;
1.4       millert   745:
                    746:                NewArgc--;
                    747:                NewArgv++;
                    748:                break;
                    749: #endif
1.1       millert   750:            case 'b':
1.23    ! millert   751:                SET(rval, MODE_BACKGROUND);
        !           752:                break;
        !           753:            case 'e':
        !           754:                rval = MODE_EDIT;
        !           755:                if (excl && excl != 'e')
        !           756:                    usage_excl(1);
        !           757:                excl = 'e';
1.1       millert   758:                break;
                    759:            case 'v':
                    760:                rval = MODE_VALIDATE;
                    761:                if (excl && excl != 'v')
                    762:                    usage_excl(1);
                    763:                excl = 'v';
                    764:                break;
1.23    ! millert   765:            case 'i':
        !           766:                SET(rval, (MODE_LOGIN_SHELL | MODE_SHELL));
        !           767:                def_env_reset = TRUE;
        !           768:                if (excl && excl != 'i')
        !           769:                    usage_excl(1);
        !           770:                excl = 'i';
        !           771:                break;
1.1       millert   772:            case 'k':
                    773:                rval = MODE_INVALIDATE;
                    774:                if (excl && excl != 'k')
                    775:                    usage_excl(1);
                    776:                excl = 'k';
                    777:                break;
                    778:            case 'K':
                    779:                rval = MODE_KILL;
                    780:                if (excl && excl != 'K')
                    781:                    usage_excl(1);
                    782:                excl = 'K';
                    783:                break;
                    784:            case 'L':
                    785:                rval = MODE_LISTDEFS;
                    786:                if (excl && excl != 'L')
                    787:                    usage_excl(1);
                    788:                excl = 'L';
                    789:                break;
                    790:            case 'l':
                    791:                rval = MODE_LIST;
                    792:                if (excl && excl != 'l')
                    793:                    usage_excl(1);
                    794:                excl = 'l';
                    795:                break;
                    796:            case 'V':
                    797:                rval = MODE_VERSION;
                    798:                if (excl && excl != 'V')
                    799:                    usage_excl(1);
                    800:                excl = 'V';
                    801:                break;
                    802:            case 'h':
                    803:                rval = MODE_HELP;
                    804:                if (excl && excl != 'h')
                    805:                    usage_excl(1);
                    806:                excl = 'h';
                    807:                break;
                    808:            case 's':
1.23    ! millert   809:                SET(rval, MODE_SHELL);
1.2       millert   810:                if (excl && excl != 's')
                    811:                    usage_excl(1);
                    812:                excl = 's';
1.1       millert   813:                break;
                    814:            case 'H':
1.23    ! millert   815:                SET(rval, MODE_RESET_HOME);
1.1       millert   816:                break;
1.11      millert   817:            case 'P':
1.23    ! millert   818:                SET(rval, MODE_PRESERVE_GROUPS);
1.11      millert   819:                break;
1.4       millert   820:            case 'S':
1.23    ! millert   821:                SET(tgetpass_flags, TGP_STDIN);
1.4       millert   822:                break;
1.1       millert   823:            case '-':
                    824:                NewArgc--;
                    825:                NewArgv++;
1.2       millert   826:                if (rval == MODE_RUN)
1.23    ! millert   827:                    SET(rval, (MODE_IMPLIED_SHELL | MODE_SHELL));
1.1       millert   828:                return(rval);
                    829:            case '\0':
1.19      millert   830:                warnx("'-' requires an argument");
1.1       millert   831:                usage(1);
                    832:            default:
1.19      millert   833:                warnx("illegal option `%s'", NewArgv[0]);
1.1       millert   834:                usage(1);
                    835:        }
                    836:        NewArgc--;
                    837:        NewArgv++;
                    838:     }
                    839:
1.23    ! millert   840:     if ((NewArgc == 0 && (rval & MODE_EDIT)) ||
        !           841:        (NewArgc > 0 && !(rval & (MODE_RUN | MODE_EDIT))))
1.1       millert   842:        usage(1);
                    843:
                    844:     return(rval);
                    845: }
                    846:
                    847: /*
                    848:  * Sanity check sudoers mode/owner/type.
                    849:  * Leaves a file pointer to the sudoers file open in ``fp''.
                    850:  */
                    851: static void
                    852: check_sudoers()
                    853: {
                    854:     struct stat statbuf;
                    855:     int rootstat, i;
                    856:     char c;
                    857:
                    858:     /*
                    859:      * Fix the mode and group on sudoers file from old default.
1.23    ! millert   860:      * Only works if file system is readable/writable by root.
1.1       millert   861:      */
1.17      millert   862:     if ((rootstat = stat_sudoers(_PATH_SUDOERS, &statbuf)) == 0 &&
1.1       millert   863:        SUDOERS_UID == statbuf.st_uid && SUDOERS_MODE != 0400 &&
                    864:        (statbuf.st_mode & 0007777) == 0400) {
                    865:
                    866:        if (chmod(_PATH_SUDOERS, SUDOERS_MODE) == 0) {
1.19      millert   867:            warnx("fixed mode on %s", _PATH_SUDOERS);
1.23    ! millert   868:            SET(statbuf.st_mode, SUDOERS_MODE);
1.1       millert   869:            if (statbuf.st_gid != SUDOERS_GID) {
                    870:                if (!chown(_PATH_SUDOERS,(uid_t) -1,SUDOERS_GID)) {
1.19      millert   871:                    warnx("set group on %s", _PATH_SUDOERS);
1.1       millert   872:                    statbuf.st_gid = SUDOERS_GID;
1.19      millert   873:                } else
                    874:                    warn("unable to set group on %s", _PATH_SUDOERS);
1.1       millert   875:            }
1.19      millert   876:        } else
                    877:            warn("unable to fix mode on %s", _PATH_SUDOERS);
1.1       millert   878:     }
                    879:
                    880:     /*
                    881:      * Sanity checks on sudoers file.  Must be done as sudoers
                    882:      * file owner.  We already did a stat as root, so use that
                    883:      * data if we can't stat as sudoers file owner.
                    884:      */
1.17      millert   885:     set_perms(PERM_SUDOERS);
1.1       millert   886:
1.17      millert   887:     if (rootstat != 0 && stat_sudoers(_PATH_SUDOERS, &statbuf) != 0)
1.1       millert   888:        log_error(USE_ERRNO, "can't stat %s", _PATH_SUDOERS);
                    889:     else if (!S_ISREG(statbuf.st_mode))
                    890:        log_error(0, "%s is not a regular file", _PATH_SUDOERS);
1.9       millert   891:     else if (statbuf.st_size == 0)
                    892:        log_error(0, "%s is zero length", _PATH_SUDOERS);
1.1       millert   893:     else if ((statbuf.st_mode & 07777) != SUDOERS_MODE)
                    894:        log_error(0, "%s is mode 0%o, should be 0%o", _PATH_SUDOERS,
                    895:            (statbuf.st_mode & 07777), SUDOERS_MODE);
                    896:     else if (statbuf.st_uid != SUDOERS_UID)
1.17      millert   897:        log_error(0, "%s is owned by uid %lu, should be %lu", _PATH_SUDOERS,
                    898:            (unsigned long) statbuf.st_uid, SUDOERS_UID);
1.1       millert   899:     else if (statbuf.st_gid != SUDOERS_GID)
1.17      millert   900:        log_error(0, "%s is owned by gid %lu, should be %lu", _PATH_SUDOERS,
                    901:            (unsigned long) statbuf.st_gid, SUDOERS_GID);
1.1       millert   902:     else {
                    903:        /* Solaris sometimes returns EAGAIN so try 10 times */
                    904:        for (i = 0; i < 10 ; i++) {
                    905:            errno = 0;
                    906:            if ((sudoers_fp = fopen(_PATH_SUDOERS, "r")) == NULL ||
                    907:                fread(&c, sizeof(c), 1, sudoers_fp) != 1) {
                    908:                sudoers_fp = NULL;
                    909:                if (errno != EAGAIN && errno != EWOULDBLOCK)
                    910:                    break;
                    911:            } else
                    912:                break;
                    913:            sleep(1);
                    914:        }
                    915:        if (sudoers_fp == NULL)
                    916:            log_error(USE_ERRNO, "can't open %s", _PATH_SUDOERS);
                    917:     }
                    918:
1.17      millert   919:     set_perms(PERM_ROOT);              /* change back to root */
1.1       millert   920: }
                    921:
                    922: /*
                    923:  * Close all open files (except std*) and turn off core dumps.
1.11      millert   924:  * Also sets the set_perms() pointer to the correct function.
1.1       millert   925:  */
                    926: static void
                    927: initial_setup()
                    928: {
1.22      millert   929: #if defined(RLIMIT_CORE) && !defined(SUDO_DEVEL)
1.1       millert   930:     struct rlimit rl;
                    931:
                    932:     /*
                    933:      * Turn off core dumps.
                    934:      */
1.4       millert   935:     (void) getrlimit(RLIMIT_CORE, &corelimit);
1.20      millert   936:     memcpy(&rl, &corelimit, sizeof(struct rlimit));
                    937:     rl.rlim_cur = 0;
1.1       millert   938:     (void) setrlimit(RLIMIT_CORE, &rl);
1.20      millert   939: #endif /* RLIMIT_CORE && !SUDO_DEVEL */
1.1       millert   940:
1.22      millert   941:     closefrom(STDERR_FILENO + 1);
1.1       millert   942:
1.17      millert   943:     /*
                    944:      * Make set_perms point to the correct function.
                    945:      * If we are using setresuid() or setreuid() we only need to set this
                    946:      * once.  If we are using POSIX saved uids we will switch to
                    947:      * set_perms_nosuid after sudoers has been parsed if the "stay_suid"
                    948:      * option is not set.
                    949:      */
                    950: #if defined(HAVE_SETRESUID) || defined(HAVE_SETREUID)
                    951:     set_perms = set_perms_suid;
                    952: #else
                    953: # if !defined(NO_SAVED_IDS) && defined(_SC_SAVED_IDS) && defined(_SC_VERSION)
1.11      millert   954:     if (sysconf(_SC_SAVED_IDS) == 1 && sysconf(_SC_VERSION) >= 199009)
                    955:        set_perms = set_perms_posix;
                    956:     else
1.17      millert   957: # endif
                    958:        set_perms = set_perms_nosuid;
                    959: #endif /* HAVE_SETRESUID || HAVE_SETREUID */
1.1       millert   960: }
                    961:
1.8       millert   962: #ifdef HAVE_LOGIN_CAP_H
                    963: static void
1.4       millert   964: set_loginclass(pw)
                    965:     struct passwd *pw;
                    966: {
                    967:     int errflags;
                    968:
                    969:     /*
                    970:      * Don't make it a fatal error if the user didn't specify the login
                    971:      * class themselves.  We do this because if login.conf gets
                    972:      * corrupted we want the admin to be able to use sudo to fix it.
                    973:      */
                    974:     if (login_class)
                    975:        errflags = NO_MAIL|MSG_ONLY;
                    976:     else
                    977:        errflags = NO_MAIL|MSG_ONLY|NO_EXIT;
                    978:
                    979:     if (login_class && strcmp(login_class, "-") != 0) {
1.19      millert   980:        if (strcmp(*user_runas, "root") != 0 && user_uid != 0)
                    981:            errx(1, "only root can use -c %s", login_class);
1.4       millert   982:     } else {
                    983:        login_class = pw->pw_class;
                    984:        if (!login_class || !*login_class)
                    985:            login_class =
                    986:                (pw->pw_uid == 0) ? LOGIN_DEFROOTCLASS : LOGIN_DEFCLASS;
                    987:     }
                    988:
                    989:     lc = login_getclass(login_class);
1.10      millert   990:     if (!lc || !lc->lc_class || strcmp(lc->lc_class, login_class) != 0) {
1.4       millert   991:        log_error(errflags, "unknown login class: %s", login_class);
1.11      millert   992:        if (!lc)
                    993:            lc = login_getclass(NULL);  /* needed for login_getstyle() later */
1.10      millert   994:     }
1.4       millert   995: }
                    996: #else
1.8       millert   997: static void
1.4       millert   998: set_loginclass(pw)
                    999:     struct passwd *pw;
                   1000: {
                   1001: }
1.8       millert  1002: #endif /* HAVE_LOGIN_CAP_H */
1.4       millert  1003:
1.1       millert  1004: /*
1.2       millert  1005:  * Look up the fully qualified domain name and set user_host and user_shost.
                   1006:  */
                   1007: void
                   1008: set_fqdn()
                   1009: {
                   1010:     struct hostent *hp;
                   1011:     char *p;
                   1012:
1.14      millert  1013:     if (!(hp = gethostbyname(user_host))) {
                   1014:        log_error(MSG_ONLY|NO_EXIT,
                   1015:            "unable to lookup %s via gethostbyname()", user_host);
                   1016:     } else {
                   1017:        if (user_shost != user_host)
                   1018:            free(user_shost);
                   1019:        free(user_host);
                   1020:        user_host = estrdup(hp->h_name);
1.2       millert  1021:     }
                   1022:     if ((p = strchr(user_host, '.'))) {
                   1023:        *p = '\0';
                   1024:        user_shost = estrdup(user_host);
                   1025:        *p = '.';
                   1026:     } else {
                   1027:        user_shost = user_host;
                   1028:     }
                   1029: }
                   1030:
                   1031: /*
1.23    ! millert  1032:  * Get passwd entry for the user we are going to run commands as.
        !          1033:  * By default, this is "root".  Updates runas_pw as a side effect.
        !          1034:  */
        !          1035: int
        !          1036: set_runaspw(user)
        !          1037:     char *user;
        !          1038: {
        !          1039:     if (runas_pw != NULL) {
        !          1040:        if (user_runas != &def_runas_default)
        !          1041:            return(TRUE);               /* don't override -u option */
        !          1042:        free(runas_pw);
        !          1043:     }
        !          1044:     if (*user == '#') {
        !          1045:        runas_pw = sudo_getpwuid(atoi(user + 1));
        !          1046:        if (runas_pw == NULL) {
        !          1047:            runas_pw = emalloc(sizeof(struct passwd));
        !          1048:            (void) memset((VOID *)runas_pw, 0, sizeof(struct passwd));
        !          1049:            runas_pw->pw_uid = atoi(user + 1);
        !          1050:        }
        !          1051:     } else {
        !          1052:        runas_pw = sudo_getpwnam(user);
        !          1053:        if (runas_pw == NULL)
        !          1054:            log_error(NO_MAIL|MSG_ONLY, "no passwd entry for %s!", user);
        !          1055:     }
        !          1056:     return(TRUE);
        !          1057: }
        !          1058:
        !          1059: /*
1.6       millert  1060:  * Get passwd entry for the user we are going to authenticate as.
1.23    ! millert  1061:  * By default, this is the user invoking sudo.  In the most common
        !          1062:  * case, this matches sudo_user.pw or runas_pw.
1.4       millert  1063:  */
1.6       millert  1064: static struct passwd *
                   1065: get_authpw()
1.4       millert  1066: {
                   1067:     struct passwd *pw;
                   1068:
1.23    ! millert  1069:     if (def_rootpw) {
        !          1070:        if (runas_pw->pw_uid == 0)
        !          1071:            pw = runas_pw;
        !          1072:        else if ((pw = sudo_getpwuid(0)) == NULL)
1.4       millert  1073:            log_error(0, "uid 0 does not exist in the passwd file!");
1.23    ! millert  1074:     } else if (def_runaspw) {
        !          1075:        if (strcmp(def_runas_default, *user_runas) == 0)
        !          1076:            pw = runas_pw;
        !          1077:        else if ((pw = sudo_getpwnam(def_runas_default)) == NULL)
1.4       millert  1078:            log_error(0, "user %s does not exist in the passwd file!",
1.23    ! millert  1079:                def_runas_default);
        !          1080:     } else if (def_targetpw) {
        !          1081:        if (runas_pw->pw_name == NULL)
        !          1082:            log_error(NO_MAIL|MSG_ONLY, "no passwd entry for %lu!",
        !          1083:                runas_pw->pw_uid);
        !          1084:        pw = runas_pw;
1.6       millert  1085:     } else
                   1086:        pw = sudo_user.pw;
                   1087:
                   1088:     return(pw);
1.4       millert  1089: }
                   1090:
                   1091: /*
1.1       millert  1092:  * Tell which options are mutually exclusive and exit.
                   1093:  */
                   1094: static void
                   1095: usage_excl(exit_val)
                   1096:     int exit_val;
                   1097: {
1.23    ! millert  1098:     warnx("Only one of the -e, -h, -k, -K, -l, -s, -v or -V options may be used");
1.1       millert  1099:     usage(exit_val);
                   1100: }
                   1101:
                   1102: /*
                   1103:  * Give usage message and exit.
                   1104:  */
                   1105: static void
                   1106: usage(exit_val)
                   1107:     int exit_val;
                   1108: {
1.23    ! millert  1109:     char **p;
        !          1110:     int linelen, linemax, ulen;
        !          1111:     static char *uvec[] = {
        !          1112:        " [-HPSb]",
        !          1113: #ifdef HAVE_BSD_AUTH_H
        !          1114:        " [-a auth_type]",
        !          1115: #endif
1.8       millert  1116: #ifdef HAVE_LOGIN_CAP_H
1.23    ! millert  1117:        " [-c class|-]",
1.8       millert  1118: #endif
1.23    ! millert  1119:        " [-p prompt]",
        !          1120:        " [-u username|#uid]",
        !          1121:        " { -e file [...] | -i | -s | <command> }",
        !          1122:        NULL
        !          1123:     };
        !          1124:
        !          1125:     /*
        !          1126:      * For sudoedit, replace the last entry in the usage vector.
        !          1127:      * For sudo, print the secondary usage.
        !          1128:      */
        !          1129:     if (strcmp(getprogname(), "sudoedit") == 0) {
        !          1130:        /* Replace the last entry in the usage vector. */
        !          1131:        for (p = uvec; p[1] != NULL; p++)
        !          1132:            continue;
        !          1133:        *p = " file [...]";
        !          1134:     } else {
        !          1135:        fprintf(stderr, "usage: %s -K | -L | -V | -h | -k | -l | -v\n",
        !          1136:            getprogname());
        !          1137:     }
        !          1138:
        !          1139:     /*
        !          1140:      * Print the main usage and wrap lines as needed.
        !          1141:      * Assumes an 80-character wide terminal, which is kind of bogus...
        !          1142:      */
        !          1143:     ulen = (int)strlen(getprogname()) + 7;
        !          1144:     linemax = 80;
        !          1145:     linelen = linemax - ulen;
        !          1146:     printf("usage: %s", getprogname());
        !          1147:     for (p = uvec; *p != NULL; p++) {
        !          1148:        if (linelen == linemax || (linelen -= strlen(*p)) >= 0) {
        !          1149:            fputs(*p, stdout);
        !          1150:        } else {
        !          1151:            p--;
        !          1152:            linelen = linemax;
        !          1153:            printf("\n%*s", ulen, "");
        !          1154:        }
        !          1155:     }
        !          1156:     putchar('\n');
1.1       millert  1157:     exit(exit_val);
                   1158: }