[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.10.2.1

1.1       millert     1: /*
1.10.2.1! millert     2:  * Copyright (c) 1993-1996,1998-2002 Todd C. Miller <Todd.Miller@courtesan.com>
1.1       millert     3:  * All rights reserved.
                      4:  *
                      5:  * Redistribution and use in source and binary forms, with or without
                      6:  * modification, are permitted provided that the following conditions
                      7:  * are met:
                      8:  *
                      9:  * 1. Redistributions of source code must retain the above copyright
                     10:  *    notice, this list of conditions and the following disclaimer.
                     11:  *
                     12:  * 2. Redistributions in binary form must reproduce the above copyright
                     13:  *    notice, this list of conditions and the following disclaimer in the
                     14:  *    documentation and/or other materials provided with the distribution.
                     15:  *
                     16:  * 3. The name of the author may not be used to endorse or promote products
                     17:  *    derived from this software without specific prior written permission.
                     18:  *
                     19:  * 4. Products derived from this software may not be called "Sudo" nor
                     20:  *    may "Sudo" appear in their names without specific prior written
                     21:  *    permission from the author.
                     22:  *
                     23:  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
                     24:  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
                     25:  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
                     26:  * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
                     27:  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
                     28:  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
                     29:  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
                     30:  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
                     31:  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
                     32:  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
                     33:  *
                     34:  * For a brief history of sudo, please see the HISTORY file included
                     35:  * with this distribution.
                     36:  */
                     37:
                     38: #define _SUDO_SUDO_C
                     39:
                     40: #include "config.h"
                     41:
1.10.2.1! millert    42: #include <sys/types.h>
        !            43: #include <sys/stat.h>
        !            44: #include <sys/param.h>
        !            45: #include <sys/socket.h>
        !            46: #ifdef HAVE_SETRLIMIT
        !            47: # include <sys/time.h>
        !            48: # include <sys/resource.h>
        !            49: #endif
1.1       millert    50: #include <stdio.h>
                     51: #ifdef STDC_HEADERS
1.10.2.1! millert    52: # include <stdlib.h>
        !            53: # include <stddef.h>
        !            54: #else
        !            55: # ifdef HAVE_STDLIB_H
        !            56: #  include <stdlib.h>
        !            57: # endif
1.1       millert    58: #endif /* STDC_HEADERS */
                     59: #ifdef HAVE_STRING_H
1.10.2.1! millert    60: # if defined(HAVE_MEMORY_H) && !defined(STDC_HEADERS)
        !            61: #  include <memory.h>
        !            62: # endif
        !            63: # include <string.h>
        !            64: #else
        !            65: # ifdef HAVE_STRINGS_H
        !            66: #  include <strings.h>
        !            67: # endif
1.1       millert    68: #endif /* HAVE_STRING_H */
1.10.2.1! millert    69: #ifdef HAVE_UNISTD_H
        !            70: # include <unistd.h>
        !            71: #endif /* HAVE_UNISTD_H */
1.1       millert    72: #include <pwd.h>
                     73: #include <errno.h>
                     74: #include <fcntl.h>
                     75: #include <signal.h>
                     76: #include <grp.h>
                     77: #include <time.h>
                     78: #include <netinet/in.h>
                     79: #include <netdb.h>
                     80: #if defined(HAVE_GETPRPWNAM) && defined(HAVE_SET_AUTH_PARAMETERS)
                     81: # ifdef __hpux
                     82: #  undef MAXINT
                     83: #  include <hpsecurity.h>
                     84: # else
                     85: #  include <sys/security.h>
                     86: # endif /* __hpux */
                     87: # include <prot.h>
                     88: #endif /* HAVE_GETPRPWNAM && HAVE_SET_AUTH_PARAMETERS */
1.8       millert    89: #ifdef HAVE_LOGIN_CAP_H
1.4       millert    90: # include <login_cap.h>
                     91: # ifndef LOGIN_DEFROOTCLASS
                     92: #  define LOGIN_DEFROOTCLASS   "daemon"
                     93: # endif
                     94: #endif
1.1       millert    95:
                     96: #include "sudo.h"
                     97: #include "interfaces.h"
                     98: #include "version.h"
                     99:
                    100: #ifndef lint
1.10.2.1! millert   101: static const char rcsid[] = "$Sudo: sudo.c,v 1.318 2002/01/15 23:43:59 millert Exp $";
1.1       millert   102: #endif /* lint */
                    103:
                    104: /*
                    105:  * Prototypes
                    106:  */
                    107: static int init_vars                   __P((int));
1.10.2.1! millert   108: static int parse_args                  __P((void));
        !           109: static void check_sudoers              __P((void));
1.1       millert   110: static void initial_setup              __P((void));
1.10.2.1! millert   111: static void set_loginclass             __P((struct passwd *));
        !           112: static void usage                      __P((int));
        !           113: static void usage_excl                 __P((int));
1.6       millert   114: static struct passwd *get_authpw       __P((void));
1.1       millert   115: extern void list_matches               __P((void));
1.10.2.1! millert   116: extern char **rebuild_env              __P((int, char **));
        !           117: extern char **zero_env                 __P((char **));
        !           118: extern struct passwd *sudo_getpwnam    __P((const char *));
        !           119: extern struct passwd *sudo_getpwuid    __P((uid_t));
1.1       millert   120:
                    121: /*
                    122:  * Globals
                    123:  */
                    124: int Argc;
                    125: char **Argv;
                    126: int NewArgc = 0;
                    127: char **NewArgv = NULL;
                    128: struct sudo_user sudo_user;
1.6       millert   129: struct passwd *auth_pw;
1.1       millert   130: FILE *sudoers_fp = NULL;
                    131: struct interface *interfaces;
                    132: int num_interfaces;
1.4       millert   133: int tgetpass_flags;
1.1       millert   134: extern int errorlineno;
1.4       millert   135: #if defined(RLIMIT_CORE) && !defined(SUDO_DEVEL)
                    136: static struct rlimit corelimit;
                    137: #endif /* RLIMIT_CORE */
1.8       millert   138: #ifdef HAVE_LOGIN_CAP_H
                    139: login_cap_t *lc;
                    140: #endif /* HAVE_LOGIN_CAP_H */
                    141: #ifdef HAVE_BSD_AUTH_H
                    142: char *login_style;
                    143: #endif /* HAVE_BSD_AUTH_H */
1.10.2.1! millert   144: void (*set_perms) __P((int, int));
1.1       millert   145:
                    146:
                    147: int
1.10.2.1! millert   148: main(argc, argv, envp)
1.1       millert   149:     int argc;
                    150:     char **argv;
1.10.2.1! millert   151:     char **envp;
1.1       millert   152: {
                    153:     int validated;
                    154:     int fd;
                    155:     int cmnd_status;
                    156:     int sudo_mode;
1.10.2.1! millert   157:     int pwflag;
        !           158:     char **new_environ;
        !           159:     sigaction_t sa;
1.1       millert   160:     extern int printmatches;
1.10.2.1! millert   161:     extern char **environ;
1.1       millert   162:
                    163:     /* Must be done as the first thing... */
                    164: #if defined(HAVE_GETPRPWNAM) && defined(HAVE_SET_AUTH_PARAMETERS)
                    165:     (void) set_auth_parameters(argc, argv);
                    166: # ifdef HAVE_INITPRIVS
                    167:     initprivs();
                    168: # endif
                    169: #endif /* HAVE_GETPRPWNAM && HAVE_SET_AUTH_PARAMETERS */
                    170:
1.10.2.1! millert   171:     /* Zero out the environment. */
        !           172:     environ = zero_env(envp);
        !           173:
1.1       millert   174:     Argv = argv;
                    175:     Argc = argc;
                    176:
                    177:     if (geteuid() != 0) {
                    178:        (void) fprintf(stderr, "Sorry, %s must be setuid root.\n", Argv[0]);
                    179:        exit(1);
                    180:     }
                    181:
                    182:     /*
1.10.2.1! millert   183:      * Ignore keyboard-generated signals so the user cannot interrupt
        !           184:      * us at some point and avoid the logging.
1.1       millert   185:      */
1.10.2.1! millert   186:     sigemptyset(&sa.sa_mask);
        !           187:     sa.sa_flags = SA_RESTART;
        !           188:     sa.sa_handler = SIG_IGN;
        !           189:     (void) sigaction(SIGINT, &sa, NULL);
        !           190:     (void) sigaction(SIGQUIT, &sa, NULL);
        !           191:     (void) sigaction(SIGTSTP, &sa, NULL);
1.1       millert   192:
                    193:     /*
                    194:      * Setup signal handlers, turn off core dumps, and close open files.
                    195:      */
                    196:     initial_setup();
1.10.2.1! millert   197:     setpwent();
1.1       millert   198:
                    199:     /* Parse our arguments. */
                    200:     sudo_mode = parse_args();
                    201:
                    202:     /* Setup defaults data structures. */
                    203:     init_defaults();
                    204:
1.10.2.1! millert   205:     /* Load the list of local ip addresses and netmasks.  */
        !           206:     load_interfaces();
        !           207:
        !           208:     pwflag = 0;
1.1       millert   209:     if (sudo_mode & MODE_SHELL)
                    210:        user_cmnd = "shell";
                    211:     else
                    212:        switch (sudo_mode) {
                    213:            case MODE_VERSION:
                    214:                (void) printf("Sudo version %s\n", version);
                    215:                if (getuid() == 0) {
                    216:                    putchar('\n');
                    217:                    dump_auth_methods();
                    218:                    dump_defaults();
1.10.2.1! millert   219:                    dump_interfaces();
        !           220:                    dump_badenv();
1.1       millert   221:                }
                    222:                exit(0);
                    223:                break;
                    224:            case MODE_HELP:
                    225:                usage(0);
                    226:                break;
                    227:            case MODE_VALIDATE:
                    228:                user_cmnd = "validate";
1.10.2.1! millert   229:                pwflag = I_VERIFYPW_I;
1.1       millert   230:                break;
                    231:            case MODE_KILL:
                    232:            case MODE_INVALIDATE:
                    233:                user_cmnd = "kill";
1.10.2.1! millert   234:                pwflag = -1;
1.1       millert   235:                break;
                    236:            case MODE_LISTDEFS:
                    237:                list_options();
                    238:                exit(0);
                    239:                break;
                    240:            case MODE_LIST:
                    241:                user_cmnd = "list";
1.10.2.1! millert   242:                pwflag = I_LISTPW_I;
1.1       millert   243:                printmatches = 1;
                    244:                break;
                    245:        }
                    246:
                    247:     /* Must have a command to run... */
                    248:     if (user_cmnd == NULL && NewArgc == 0)
                    249:        usage(1);
                    250:
                    251:     cmnd_status = init_vars(sudo_mode);
                    252:
                    253:     check_sudoers();   /* check mode/owner on _PATH_SUDOERS */
                    254:
1.2       millert   255:     /* Validate the user but don't search for pseudo-commands. */
1.10.2.1! millert   256:     validated = sudoers_lookup(pwflag);
        !           257:
        !           258:     /*
        !           259:      * If we have POSIX saved uids and the stay_setuid flag was not set,
        !           260:      * set the real, effective and saved uids to 0 and use set_perms_fallback()
        !           261:      * instead of set_perms_posix().
        !           262:      */
        !           263: #if !defined(NO_SAVED_IDS) && defined(_SC_SAVED_IDS) && defined(_SC_VERSION)
        !           264:     if (!def_flag(I_STAY_SETUID) && set_perms == set_perms_posix) {
        !           265:        if (setuid(0)) {
        !           266:            perror("setuid(0)");
        !           267:            exit(1);
        !           268:        }
        !           269:        set_perms = set_perms_fallback;
        !           270:     }
        !           271: #endif
        !           272:
        !           273:     /*
        !           274:      * Look up runas user passwd struct.  If we are given a uid then
        !           275:      * there may be no corresponding passwd(5) entry (which is OK).
        !           276:      */
        !           277:     if (**user_runas == '#') {
        !           278:        runas_pw = sudo_getpwuid(atoi(*user_runas + 1));
        !           279:        if (runas_pw == NULL) {
        !           280:            runas_pw = emalloc(sizeof(struct passwd));
        !           281:            (void) memset((VOID *)runas_pw, 0, sizeof(struct passwd));
        !           282:            runas_pw->pw_uid = atoi(*user_runas + 1);
        !           283:        }
        !           284:     } else {
        !           285:        runas_pw = sudo_getpwnam(*user_runas);
        !           286:        if (runas_pw == NULL)
        !           287:            log_error(NO_MAIL|MSG_ONLY, "no passwd entry for %s!", *user_runas);
        !           288:     }
1.2       millert   289:
                    290:     /* This goes after the sudoers parse since we honor sudoers options. */
1.1       millert   291:     if (sudo_mode == MODE_KILL || sudo_mode == MODE_INVALIDATE) {
                    292:        remove_timestamp((sudo_mode == MODE_KILL));
                    293:        exit(0);
                    294:     }
                    295:
                    296:     if (validated & VALIDATE_ERROR)
                    297:        log_error(0, "parse error in %s near line %d", _PATH_SUDOERS,
                    298:            errorlineno);
                    299:
                    300:     /* Is root even allowed to run sudo? */
                    301:     if (user_uid == 0 && !def_flag(I_ROOT_SUDO)) {
                    302:        (void) fputs("You are already root, you don't need to use sudo.\n",
                    303:            stderr);
                    304:        exit(1);
                    305:     }
                    306:
1.10.2.1! millert   307:     /* If given the -P option, set the "preserve_groups" flag. */
        !           308:     if (sudo_mode & MODE_PRESERVE_GROUPS)
        !           309:        def_flag(I_PRESERVE_GROUPS) = TRUE;
        !           310:
1.3       millert   311:     /* If no command line args and "set_home" is not set, error out. */
                    312:     if ((sudo_mode & MODE_IMPLIED_SHELL) && !def_flag(I_SHELL_NOARGS))
                    313:        usage(1);
                    314:
1.10.2.1! millert   315:     /* May need to set $HOME to target user if we are running a command. */
        !           316:     if ((sudo_mode & MODE_RUN) && (def_flag(I_ALWAYS_SET_HOME) ||
        !           317:        ((sudo_mode & MODE_SHELL) && def_flag(I_SET_HOME))))
1.2       millert   318:        sudo_mode |= MODE_RESET_HOME;
                    319:
1.1       millert   320:     /* Bail if a tty is required and we don't have one.  */
                    321:     if (def_flag(I_REQUIRETTY)) {
                    322:        if ((fd = open(_PATH_TTY, O_RDWR|O_NOCTTY)) == -1)
                    323:            log_error(NO_MAIL, "sorry, you must have a tty to run sudo");
                    324:        else
                    325:            (void) close(fd);
                    326:     }
                    327:
1.6       millert   328:     /* Fill in passwd struct based on user we are authenticating as.  */
                    329:     auth_pw = get_authpw();
1.4       millert   330:
1.1       millert   331:     /* Require a password unless the NOPASS tag was set.  */
                    332:     if (!(validated & FLAG_NOPASS))
                    333:        check_user();
                    334:
1.10.2.1! millert   335:     /* Build up custom environment that avoids any nasty bits. */
        !           336:     new_environ = rebuild_env(sudo_mode, envp);
        !           337:
1.1       millert   338:     if (validated & VALIDATE_OK) {
                    339:        /* Finally tell the user if the command did not exist. */
                    340:        if (cmnd_status == NOT_FOUND_DOT) {
                    341:            (void) fprintf(stderr, "%s: ignoring `%s' found in '.'\nUse `sudo ./%s' if this is the `%s' you wish to run.\n", Argv[0], user_cmnd, user_cmnd, user_cmnd);
                    342:            exit(1);
                    343:        } else if (cmnd_status == NOT_FOUND) {
                    344:            (void) fprintf(stderr, "%s: %s: command not found\n", Argv[0],
                    345:                user_cmnd);
                    346:            exit(1);
                    347:        }
                    348:
                    349:        log_auth(validated, 1);
                    350:        if (sudo_mode == MODE_VALIDATE)
                    351:            exit(0);
                    352:        else if (sudo_mode == MODE_LIST) {
                    353:            list_matches();
                    354:            exit(0);
                    355:        }
                    356:
                    357:        /* This *must* have been set if we got a match but... */
                    358:        if (safe_cmnd == NULL) {
                    359:            log_error(MSG_ONLY,
1.10.2.1! millert   360:                "internal error, safe_cmnd never got set for %s; %s",
1.1       millert   361:                user_cmnd,
                    362:                "please report this error at http://courtesan.com/sudo/bugs/");
                    363:        }
                    364:
1.10.2.1! millert   365:        /* Reset signal handlers before we exec. */
        !           366:        sigemptyset(&sa.sa_mask);
        !           367:        sa.sa_flags = SA_RESTART;
        !           368:        sa.sa_handler = SIG_DFL;
        !           369:        (void) sigaction(SIGINT, &sa, NULL);
        !           370:        (void) sigaction(SIGQUIT, &sa, NULL);
        !           371:        (void) sigaction(SIGTSTP, &sa, NULL);
1.1       millert   372:
1.10.2.1! millert   373:        /* Close the password file */
        !           374:        endpwent();
1.1       millert   375:
                    376:        /* Override user's umask if configured to do so. */
                    377:        if (def_ival(I_UMASK) != 0777)
                    378:            (void) umask(def_mode(I_UMASK));
                    379:
1.4       millert   380:        /* Restore coredumpsize resource limit. */
                    381: #if defined(RLIMIT_CORE) && !defined(SUDO_DEVEL)
                    382:        (void) setrlimit(RLIMIT_CORE, &corelimit);
                    383: #endif /* RLIMIT_CORE */
                    384:
                    385:        /* Become specified user or root. */
                    386:        set_perms(PERM_RUNAS, sudo_mode);
1.5       millert   387:
1.10.2.1! millert   388:        /* Install the new environment. */
        !           389:        environ = new_environ;
1.4       millert   390:
1.1       millert   391: #ifndef PROFILING
                    392:        if ((sudo_mode & MODE_BACKGROUND) && fork() > 0)
                    393:            exit(0);
                    394:        else
                    395:            EXEC(safe_cmnd, NewArgv);   /* run the command */
                    396: #else
                    397:        exit(0);
                    398: #endif /* PROFILING */
                    399:        /*
                    400:         * If we got here then the exec() failed...
                    401:         */
                    402:        (void) fprintf(stderr, "%s: unable to exec %s: %s\n",
                    403:            Argv[0], safe_cmnd, strerror(errno));
1.10.2.1! millert   404:        exit(127);
1.1       millert   405:     } else if ((validated & FLAG_NO_USER) || (validated & FLAG_NO_HOST)) {
                    406:        log_auth(validated, 1);
                    407:        exit(1);
                    408:     } else if (validated & VALIDATE_NOT_OK) {
                    409:        if (def_flag(I_PATH_INFO)) {
                    410:            /*
                    411:             * We'd like to not leak path info at all here, but that can
                    412:             * *really* confuse the users.  To really close the leak we'd
                    413:             * have to say "not allowed to run foo" even when the problem
                    414:             * is just "no foo in path" since the user can trivially set
                    415:             * their path to just contain a single dir.
                    416:             */
                    417:            log_auth(validated,
                    418:                !(cmnd_status == NOT_FOUND_DOT || cmnd_status == NOT_FOUND));
                    419:            if (cmnd_status == NOT_FOUND)
                    420:                (void) fprintf(stderr, "%s: %s: command not found\n", Argv[0],
                    421:                    user_cmnd);
                    422:            else if (cmnd_status == NOT_FOUND_DOT)
                    423:                (void) fprintf(stderr, "%s: ignoring `%s' found in '.'\nUse `sudo ./%s' if this is the `%s' you wish to run.\n", Argv[0], user_cmnd, user_cmnd, user_cmnd);
                    424:        } else {
                    425:            /* Just tell the user they are not allowed to run foo. */
                    426:            log_auth(validated, 1);
                    427:        }
                    428:        exit(1);
                    429:     } else {
                    430:        /* should never get here */
                    431:        log_auth(validated, 1);
                    432:        exit(1);
                    433:     }
                    434:     exit(0);   /* not reached */
                    435: }
                    436:
                    437: /*
                    438:  * Initialize timezone, set umask, fill in ``sudo_user'' struct and
                    439:  * load the ``interfaces'' array.
                    440:  */
                    441: static int
                    442: init_vars(sudo_mode)
                    443:     int sudo_mode;
                    444: {
                    445:     char *p, thost[MAXHOSTNAMELEN];
1.10.2.1! millert   446:     int nohostname, rval;
1.1       millert   447:
                    448:     /* Sanity check command from user. */
                    449:     if (user_cmnd == NULL && strlen(NewArgv[0]) >= MAXPATHLEN) {
                    450:        (void) fprintf(stderr, "%s: %s: Pathname too long\n", Argv[0],
                    451:            NewArgv[0]);
                    452:        exit(1);
                    453:     }
                    454:
                    455: #ifdef HAVE_TZSET
                    456:     (void) tzset();            /* set the timezone if applicable */
                    457: #endif /* HAVE_TZSET */
                    458:
                    459:     /* Default value for cmnd and cwd, overridden later. */
                    460:     if (user_cmnd == NULL)
                    461:        user_cmnd = NewArgv[0];
                    462:     (void) strcpy(user_cwd, "unknown");
                    463:
                    464:     /*
                    465:      * We avoid gethostbyname() if possible since we don't want
                    466:      * sudo to block if DNS or NIS is hosed.
                    467:      * "host" is the (possibly fully-qualified) hostname and
                    468:      * "shost" is the unqualified form of the hostname.
                    469:      */
1.10.2.1! millert   470:     nohostname = gethostname(thost, sizeof(thost));
        !           471:     if (nohostname)
        !           472:        user_host = user_shost = "localhost";
1.2       millert   473:     else {
1.10.2.1! millert   474:        user_host = estrdup(thost);
        !           475:        if (def_flag(I_FQDN)) {
        !           476:            /* Defer call to set_fqdn() until log_error() is safe. */
1.2       millert   477:            user_shost = user_host;
1.10.2.1! millert   478:        } else {
        !           479:            if ((p = strchr(user_host, '.'))) {
        !           480:                *p = '\0';
        !           481:                user_shost = estrdup(user_host);
        !           482:                *p = '.';
        !           483:            } else {
        !           484:                user_shost = user_host;
        !           485:            }
1.1       millert   486:        }
                    487:     }
                    488:
                    489:     if ((p = ttyname(STDIN_FILENO)) || (p = ttyname(STDOUT_FILENO))) {
                    490:        if (strncmp(p, _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0)
                    491:            p += sizeof(_PATH_DEV) - 1;
                    492:        user_tty = estrdup(p);
                    493:     } else
                    494:        user_tty = "unknown";
                    495:
                    496:     /*
                    497:      * Get a local copy of the user's struct passwd with the shadow password
                    498:      * if necessary.  It is assumed that euid is 0 at this point so we
                    499:      * can read the shadow passwd file if necessary.
                    500:      */
                    501:     if ((sudo_user.pw = sudo_getpwuid(getuid())) == NULL) {
                    502:        /* Need to make a fake struct passwd for logging to work. */
                    503:        struct passwd pw;
                    504:        char pw_name[MAX_UID_T_LEN + 1];
                    505:
                    506:        pw.pw_uid = getuid();
                    507:        (void) sprintf(pw_name, "%ld", (long) pw.pw_uid);
                    508:        pw.pw_name = pw_name;
                    509:        sudo_user.pw = &pw;
                    510:
                    511:        log_error(0, "uid %ld does not exist in the passwd file!",
                    512:            (long) pw.pw_uid);
                    513:     }
1.10.2.1! millert   514:     if (user_shell == NULL || *user_shell == '\0')
        !           515:        user_shell = sudo_user.pw->pw_shell;
1.1       millert   516:
                    517:     /* It is now safe to use log_error() and set_perms() */
                    518:
                    519:     /*
1.10.2.1! millert   520:      * Must defer set_fqdn() until it is safe to call log_error()
        !           521:      */
        !           522:     if (def_flag(I_FQDN))
        !           523:        set_fqdn();
        !           524:
        !           525:     if (nohostname)
        !           526:        log_error(USE_ERRNO|MSG_ONLY, "can't get hostname");
        !           527:
        !           528:     /*
1.1       millert   529:      * Get current working directory.  Try as user, fall back to root.
                    530:      */
                    531:     set_perms(PERM_USER, sudo_mode);
                    532:     if (!getcwd(user_cwd, sizeof(user_cwd))) {
                    533:        set_perms(PERM_ROOT, sudo_mode);
                    534:        if (!getcwd(user_cwd, sizeof(user_cwd))) {
                    535:            (void) fprintf(stderr, "%s: Can't get working directory!\n",
                    536:                           Argv[0]);
                    537:            (void) strcpy(user_cwd, "unknown");
                    538:        }
                    539:     } else
                    540:        set_perms(PERM_ROOT, sudo_mode);
                    541:
                    542:     /*
                    543:      * If we were given the '-s' option (run shell) we need to redo
                    544:      * NewArgv and NewArgc.
                    545:      */
                    546:     if ((sudo_mode & MODE_SHELL)) {
                    547:        char **dst, **src = NewArgv;
                    548:
                    549:        NewArgv = (char **) emalloc (sizeof(char *) * (++NewArgc + 1));
                    550:        if (user_shell && *user_shell) {
                    551:            NewArgv[0] = user_shell;
                    552:        } else {
                    553:            (void) fprintf(stderr, "%s: Unable to determine shell.", Argv[0]);
                    554:            exit(1);
                    555:        }
                    556:
                    557:        /* copy the args from Argv */
                    558:        for (dst = NewArgv + 1; (*dst = *src) != NULL; ++src, ++dst)
                    559:            ;
                    560:     }
                    561:
1.8       millert   562:     /* Set login class if applicable. */
                    563:     set_loginclass(sudo_user.pw);
                    564:
1.1       millert   565:     /* Resolve the path and return. */
1.10.2.1! millert   566:     if ((sudo_mode & MODE_RUN)) {
        !           567:        /* XXX - should call this as runas user, not root. */
        !           568:        rval = find_path(NewArgv[0], &user_cmnd, user_path);
        !           569:        if (rval != FOUND) {
        !           570:            /* Failed as root, try as invoking user. */
        !           571:            set_perms(PERM_USER, sudo_mode);
        !           572:            rval = find_path(NewArgv[0], &user_cmnd, user_path);
        !           573:            set_perms(PERM_ROOT, sudo_mode);
        !           574:        }
        !           575:
        !           576:        /* set user_args */
        !           577:        if (NewArgc > 1) {
        !           578:            char *to, **from;
        !           579:            size_t size;
        !           580:
        !           581:            /* If MODE_SHELL not set then NewArgv is contiguous so just count */
        !           582:            if (!(sudo_mode & MODE_SHELL)) {
        !           583:                size = (size_t) (NewArgv[NewArgc-1] - NewArgv[1]) +
        !           584:                        strlen(NewArgv[NewArgc-1]) + 1;
        !           585:            } else {
        !           586:                for (size = 0, from = NewArgv + 1; *from; from++)
        !           587:                    size += strlen(*from) + 1;
        !           588:            }
        !           589:
        !           590:            /* alloc and copy. */
        !           591:            to = user_args = (char *) emalloc(size);
        !           592:            for (from = NewArgv + 1; *from; from++) {
        !           593:                (void) strcpy(to, *from);
        !           594:                to += strlen(*from);
        !           595:                *to++ = ' ';
        !           596:            }
        !           597:            *--to = '\0';
        !           598:        }
        !           599:     } else
        !           600:        rval = FOUND;
        !           601:
        !           602:     return(rval);
1.1       millert   603: }
                    604:
                    605: /*
                    606:  * Command line argument parsing, can't use getopt(3).
                    607:  */
                    608: static int
                    609: parse_args()
                    610: {
                    611:     int rval = MODE_RUN;               /* what mode is suod to be run in? */
                    612:     int excl = 0;                      /* exclusive arg, no others allowed */
                    613:
                    614:     NewArgv = Argv + 1;
                    615:     NewArgc = Argc - 1;
                    616:
1.2       millert   617:     if (NewArgc == 0) {                        /* no options and no command */
1.3       millert   618:        rval |= (MODE_IMPLIED_SHELL | MODE_SHELL);
1.1       millert   619:        return(rval);
                    620:     }
                    621:
                    622:     while (NewArgc > 0 && NewArgv[0][0] == '-') {
                    623:        if (NewArgv[0][1] != '\0' && NewArgv[0][2] != '\0') {
                    624:            (void) fprintf(stderr, "%s: Please use single character options\n",
                    625:                Argv[0]);
                    626:            usage(1);
                    627:        }
                    628:
                    629:        switch (NewArgv[0][1]) {
                    630:            case 'p':
                    631:                /* Must have an associated prompt. */
                    632:                if (NewArgv[1] == NULL)
                    633:                    usage(1);
                    634:
                    635:                user_prompt = NewArgv[1];
                    636:
                    637:                /* Shift Argv over and adjust Argc. */
                    638:                NewArgc--;
                    639:                NewArgv++;
                    640:                break;
                    641:            case 'u':
                    642:                /* Must have an associated runas user. */
                    643:                if (NewArgv[1] == NULL)
                    644:                    usage(1);
                    645:
                    646:                user_runas = &NewArgv[1];
                    647:
                    648:                /* Shift Argv over and adjust Argc. */
                    649:                NewArgc--;
                    650:                NewArgv++;
                    651:                break;
1.8       millert   652: #ifdef HAVE_BSD_AUTH_H
                    653:            case 'a':
                    654:                /* Must have an associated authentication style. */
                    655:                if (NewArgv[1] == NULL)
                    656:                    usage(1);
                    657:
                    658:                login_style = NewArgv[1];
                    659:
                    660:                /* Shift Argv over and adjust Argc. */
                    661:                NewArgc--;
                    662:                NewArgv++;
                    663:                break;
                    664: #endif
                    665: #ifdef HAVE_LOGIN_CAP_H
1.4       millert   666:            case 'c':
                    667:                /* Must have an associated login class. */
                    668:                if (NewArgv[1] == NULL)
                    669:                    usage(1);
                    670:
                    671:                login_class = NewArgv[1];
1.10.2.1! millert   672:                def_flag(I_USE_LOGINCLASS) = TRUE;
1.4       millert   673:
                    674:                /* Shift Argv over and adjust Argc. */
                    675:                NewArgc--;
                    676:                NewArgv++;
                    677:                break;
                    678: #endif
1.1       millert   679:            case 'b':
                    680:                rval |= MODE_BACKGROUND;
                    681:                break;
                    682:            case 'v':
                    683:                rval = MODE_VALIDATE;
                    684:                if (excl && excl != 'v')
                    685:                    usage_excl(1);
                    686:                excl = 'v';
                    687:                break;
                    688:            case 'k':
                    689:                rval = MODE_INVALIDATE;
                    690:                if (excl && excl != 'k')
                    691:                    usage_excl(1);
                    692:                excl = 'k';
                    693:                break;
                    694:            case 'K':
                    695:                rval = MODE_KILL;
                    696:                if (excl && excl != 'K')
                    697:                    usage_excl(1);
                    698:                excl = 'K';
                    699:                break;
                    700:            case 'L':
                    701:                rval = MODE_LISTDEFS;
                    702:                if (excl && excl != 'L')
                    703:                    usage_excl(1);
                    704:                excl = 'L';
                    705:                break;
                    706:            case 'l':
                    707:                rval = MODE_LIST;
                    708:                if (excl && excl != 'l')
                    709:                    usage_excl(1);
                    710:                excl = 'l';
                    711:                break;
                    712:            case 'V':
                    713:                rval = MODE_VERSION;
                    714:                if (excl && excl != 'V')
                    715:                    usage_excl(1);
                    716:                excl = 'V';
                    717:                break;
                    718:            case 'h':
                    719:                rval = MODE_HELP;
                    720:                if (excl && excl != 'h')
                    721:                    usage_excl(1);
                    722:                excl = 'h';
                    723:                break;
                    724:            case 's':
                    725:                rval |= MODE_SHELL;
1.2       millert   726:                if (excl && excl != 's')
                    727:                    usage_excl(1);
                    728:                excl = 's';
1.1       millert   729:                break;
                    730:            case 'H':
                    731:                rval |= MODE_RESET_HOME;
                    732:                break;
1.10.2.1! millert   733:            case 'P':
        !           734:                rval |= MODE_PRESERVE_GROUPS;
        !           735:                break;
1.4       millert   736:            case 'S':
                    737:                tgetpass_flags |= TGP_STDIN;
                    738:                break;
1.1       millert   739:            case '-':
                    740:                NewArgc--;
                    741:                NewArgv++;
1.2       millert   742:                if (rval == MODE_RUN)
1.3       millert   743:                    rval |= (MODE_IMPLIED_SHELL | MODE_SHELL);
1.1       millert   744:                return(rval);
                    745:            case '\0':
                    746:                (void) fprintf(stderr, "%s: '-' requires an argument\n",
                    747:                    Argv[0]);
                    748:                usage(1);
                    749:            default:
                    750:                (void) fprintf(stderr, "%s: Illegal option %s\n", Argv[0],
                    751:                    NewArgv[0]);
                    752:                usage(1);
                    753:        }
                    754:        NewArgc--;
                    755:        NewArgv++;
                    756:     }
                    757:
                    758:     if (NewArgc > 0 && !(rval & MODE_RUN))
                    759:        usage(1);
                    760:
                    761:     return(rval);
                    762: }
                    763:
                    764: /*
                    765:  * Sanity check sudoers mode/owner/type.
                    766:  * Leaves a file pointer to the sudoers file open in ``fp''.
                    767:  */
                    768: static void
                    769: check_sudoers()
                    770: {
                    771:     struct stat statbuf;
                    772:     int rootstat, i;
                    773:     char c;
                    774:
                    775:     /*
                    776:      * Fix the mode and group on sudoers file from old default.
                    777:      * Only works if filesystem is readable/writable by root.
                    778:      */
                    779:     if ((rootstat = lstat(_PATH_SUDOERS, &statbuf)) == 0 &&
                    780:        SUDOERS_UID == statbuf.st_uid && SUDOERS_MODE != 0400 &&
                    781:        (statbuf.st_mode & 0007777) == 0400) {
                    782:
                    783:        if (chmod(_PATH_SUDOERS, SUDOERS_MODE) == 0) {
                    784:            (void) fprintf(stderr, "%s: fixed mode on %s\n",
                    785:                Argv[0], _PATH_SUDOERS);
1.3       millert   786:            statbuf.st_mode |= SUDOERS_MODE;
1.1       millert   787:            if (statbuf.st_gid != SUDOERS_GID) {
                    788:                if (!chown(_PATH_SUDOERS,(uid_t) -1,SUDOERS_GID)) {
                    789:                    (void) fprintf(stderr, "%s: set group on %s\n",
                    790:                        Argv[0], _PATH_SUDOERS);
                    791:                    statbuf.st_gid = SUDOERS_GID;
                    792:                } else {
                    793:                    (void) fprintf(stderr,"%s: Unable to set group on %s: %s\n",
                    794:                        Argv[0], _PATH_SUDOERS, strerror(errno));
                    795:                }
                    796:            }
                    797:        } else {
                    798:            (void) fprintf(stderr, "%s: Unable to fix mode on %s: %s\n",
                    799:                Argv[0], _PATH_SUDOERS, strerror(errno));
                    800:        }
                    801:     }
                    802:
                    803:     /*
                    804:      * Sanity checks on sudoers file.  Must be done as sudoers
                    805:      * file owner.  We already did a stat as root, so use that
                    806:      * data if we can't stat as sudoers file owner.
                    807:      */
                    808:     set_perms(PERM_SUDOERS, 0);
                    809:
                    810:     if (rootstat != 0 && lstat(_PATH_SUDOERS, &statbuf) != 0)
                    811:        log_error(USE_ERRNO, "can't stat %s", _PATH_SUDOERS);
                    812:     else if (!S_ISREG(statbuf.st_mode))
                    813:        log_error(0, "%s is not a regular file", _PATH_SUDOERS);
1.9       millert   814:     else if (statbuf.st_size == 0)
                    815:        log_error(0, "%s is zero length", _PATH_SUDOERS);
1.1       millert   816:     else if ((statbuf.st_mode & 07777) != SUDOERS_MODE)
                    817:        log_error(0, "%s is mode 0%o, should be 0%o", _PATH_SUDOERS,
                    818:            (statbuf.st_mode & 07777), SUDOERS_MODE);
                    819:     else if (statbuf.st_uid != SUDOERS_UID)
                    820:        log_error(0, "%s is owned by uid %ld, should be %d", _PATH_SUDOERS,
                    821:            (long) statbuf.st_uid, SUDOERS_UID);
                    822:     else if (statbuf.st_gid != SUDOERS_GID)
                    823:        log_error(0, "%s is owned by gid %ld, should be %d", _PATH_SUDOERS,
                    824:            (long) statbuf.st_gid, SUDOERS_GID);
                    825:     else {
                    826:        /* Solaris sometimes returns EAGAIN so try 10 times */
                    827:        for (i = 0; i < 10 ; i++) {
                    828:            errno = 0;
                    829:            if ((sudoers_fp = fopen(_PATH_SUDOERS, "r")) == NULL ||
                    830:                fread(&c, sizeof(c), 1, sudoers_fp) != 1) {
                    831:                sudoers_fp = NULL;
                    832:                if (errno != EAGAIN && errno != EWOULDBLOCK)
                    833:                    break;
                    834:            } else
                    835:                break;
                    836:            sleep(1);
                    837:        }
                    838:        if (sudoers_fp == NULL)
                    839:            log_error(USE_ERRNO, "can't open %s", _PATH_SUDOERS);
                    840:     }
                    841:
                    842:     set_perms(PERM_ROOT, 0);           /* change back to root */
                    843: }
                    844:
                    845: /*
                    846:  * Close all open files (except std*) and turn off core dumps.
1.10.2.1! millert   847:  * Also sets the set_perms() pointer to the correct function.
1.1       millert   848:  */
                    849: static void
                    850: initial_setup()
                    851: {
                    852:     int fd, maxfd;
                    853: #ifdef HAVE_SETRLIMIT
                    854:     struct rlimit rl;
                    855: #endif
1.10.2.1! millert   856:     sigaction_t sa;
1.1       millert   857:
                    858: #if defined(RLIMIT_CORE) && !defined(SUDO_DEVEL)
                    859:     /*
                    860:      * Turn off core dumps.
                    861:      */
1.4       millert   862:     (void) getrlimit(RLIMIT_CORE, &corelimit);
1.1       millert   863:     rl.rlim_cur = rl.rlim_max = 0;
                    864:     (void) setrlimit(RLIMIT_CORE, &rl);
                    865: #endif /* RLIMIT_CORE */
                    866:
                    867:     /*
                    868:      * Close any open fd's other than stdin, stdout and stderr.
                    869:      */
                    870: #ifdef HAVE_SYSCONF
1.3       millert   871:     maxfd = sysconf(_SC_OPEN_MAX) - 1;
1.1       millert   872: #else
1.3       millert   873:     maxfd = getdtablesize() - 1;
1.1       millert   874: #endif /* HAVE_SYSCONF */
1.3       millert   875: #ifdef RLIMIT_NOFILE
                    876:     if (getrlimit(RLIMIT_NOFILE, &rl) == 0) {
                    877:        if (rl.rlim_max != RLIM_INFINITY && rl.rlim_max <= maxfd)
                    878:            maxfd = rl.rlim_max - 1;
                    879:     }
                    880: #endif /* RLIMIT_NOFILE */
1.1       millert   881:
                    882:     for (fd = maxfd; fd > STDERR_FILENO; fd--)
                    883:        (void) close(fd);
                    884:
                    885:     /* Catch children as they die... */
1.10.2.1! millert   886:     sigemptyset(&sa.sa_mask);
        !           887:     sa.sa_flags = SA_RESTART;
1.1       millert   888:     sa.sa_handler = reapchild;
                    889:     (void) sigaction(SIGCHLD, &sa, NULL);
1.10.2.1! millert   890:
        !           891:     /* Set set_perms pointer to the correct function */
        !           892: #if !defined(NO_SAVED_IDS) && defined(_SC_SAVED_IDS) && defined(_SC_VERSION)
        !           893:     if (sysconf(_SC_SAVED_IDS) == 1 && sysconf(_SC_VERSION) >= 199009)
        !           894:        set_perms = set_perms_posix;
        !           895:     else
        !           896: #endif
        !           897:        set_perms = set_perms_fallback;
1.1       millert   898: }
                    899:
1.8       millert   900: #ifdef HAVE_LOGIN_CAP_H
                    901: static void
1.4       millert   902: set_loginclass(pw)
                    903:     struct passwd *pw;
                    904: {
                    905:     int errflags;
                    906:
                    907:     /*
                    908:      * Don't make it a fatal error if the user didn't specify the login
                    909:      * class themselves.  We do this because if login.conf gets
                    910:      * corrupted we want the admin to be able to use sudo to fix it.
                    911:      */
                    912:     if (login_class)
                    913:        errflags = NO_MAIL|MSG_ONLY;
                    914:     else
                    915:        errflags = NO_MAIL|MSG_ONLY|NO_EXIT;
                    916:
                    917:     if (login_class && strcmp(login_class, "-") != 0) {
                    918:        if (strcmp(*user_runas, "root") != 0 && user_uid != 0) {
                    919:            (void) fprintf(stderr, "%s: only root can use -c %s\n",
                    920:                Argv[0], login_class);
                    921:            exit(1);
                    922:        }
                    923:     } else {
                    924:        login_class = pw->pw_class;
                    925:        if (!login_class || !*login_class)
                    926:            login_class =
                    927:                (pw->pw_uid == 0) ? LOGIN_DEFROOTCLASS : LOGIN_DEFCLASS;
                    928:     }
                    929:
                    930:     lc = login_getclass(login_class);
1.10      millert   931:     if (!lc || !lc->lc_class || strcmp(lc->lc_class, login_class) != 0) {
1.4       millert   932:        log_error(errflags, "unknown login class: %s", login_class);
1.10.2.1! millert   933:        if (!lc)
        !           934:            lc = login_getclass(NULL);  /* needed for login_getstyle() later */
1.10      millert   935:     }
1.4       millert   936: }
                    937: #else
1.8       millert   938: static void
1.4       millert   939: set_loginclass(pw)
                    940:     struct passwd *pw;
                    941: {
                    942: }
1.8       millert   943: #endif /* HAVE_LOGIN_CAP_H */
1.4       millert   944:
1.1       millert   945: /*
1.2       millert   946:  * Look up the fully qualified domain name and set user_host and user_shost.
                    947:  */
                    948: void
                    949: set_fqdn()
                    950: {
                    951:     struct hostent *hp;
                    952:     char *p;
                    953:
1.10.2.1! millert   954:     if (!(hp = gethostbyname(user_host))) {
        !           955:        log_error(MSG_ONLY|NO_EXIT,
        !           956:            "unable to lookup %s via gethostbyname()", user_host);
        !           957:     } else {
        !           958:        if (user_shost != user_host)
        !           959:            free(user_shost);
        !           960:        free(user_host);
        !           961:        user_host = estrdup(hp->h_name);
1.2       millert   962:     }
                    963:     if ((p = strchr(user_host, '.'))) {
                    964:        *p = '\0';
                    965:        user_shost = estrdup(user_host);
                    966:        *p = '.';
                    967:     } else {
                    968:        user_shost = user_host;
                    969:     }
                    970: }
                    971:
                    972: /*
1.6       millert   973:  * Get passwd entry for the user we are going to authenticate as.
                    974:  * By default, this is the user invoking sudo...
1.4       millert   975:  */
1.6       millert   976: static struct passwd *
                    977: get_authpw()
1.4       millert   978: {
                    979:     struct passwd *pw;
                    980:
                    981:     if (def_ival(I_ROOTPW)) {
1.6       millert   982:        if ((pw = sudo_getpwuid(0)) == NULL)
1.4       millert   983:            log_error(0, "uid 0 does not exist in the passwd file!");
                    984:     } else if (def_ival(I_RUNASPW)) {
1.10.2.1! millert   985:        if ((pw = sudo_getpwnam(def_str(I_RUNAS_DEFAULT))) == NULL)
1.4       millert   986:            log_error(0, "user %s does not exist in the passwd file!",
1.10.2.1! millert   987:                def_str(I_RUNAS_DEFAULT));
1.4       millert   988:     } else if (def_ival(I_TARGETPW)) {
                    989:        if (**user_runas == '#') {
1.6       millert   990:            if ((pw = sudo_getpwuid(atoi(*user_runas + 1))) == NULL)
1.4       millert   991:                log_error(0, "uid %s does not exist in the passwd file!",
                    992:                    user_runas);
                    993:        } else {
1.6       millert   994:            if ((pw = sudo_getpwnam(*user_runas)) == NULL)
1.4       millert   995:                log_error(0, "user %s does not exist in the passwd file!",
                    996:                    user_runas);
                    997:        }
1.6       millert   998:     } else
                    999:        pw = sudo_user.pw;
                   1000:
                   1001:     return(pw);
1.4       millert  1002: }
                   1003:
                   1004: /*
1.1       millert  1005:  * Tell which options are mutually exclusive and exit.
                   1006:  */
                   1007: static void
                   1008: usage_excl(exit_val)
                   1009:     int exit_val;
                   1010: {
                   1011:     (void) fprintf(stderr,
1.2       millert  1012:        "Only one of the -h, -k, -K, -l, -s, -v or -V options may be used\n");
1.1       millert  1013:     usage(exit_val);
                   1014: }
                   1015:
                   1016: /*
                   1017:  * Give usage message and exit.
                   1018:  */
                   1019: static void
                   1020: usage(exit_val)
                   1021:     int exit_val;
                   1022: {
1.8       millert  1023:
                   1024:     (void) fprintf(stderr, "usage: sudo -V | -h | -L | -l | -v | -k | -K | %s",
1.10.2.1! millert  1025:        "[-H] [-P] [-S] [-b] [-p prompt]\n            [-u username/#uid] ");
1.8       millert  1026: #ifdef HAVE_LOGIN_CAP_H
                   1027:     (void) fprintf(stderr, "[-c class] ");
                   1028: #endif
                   1029: #ifdef HAVE_BSD_AUTH_H
                   1030:     (void) fprintf(stderr, "[-a auth_type] ");
1.4       millert  1031: #endif
1.8       millert  1032:     (void) fprintf(stderr, "-s | <command>\n");
1.1       millert  1033:     exit(exit_val);
                   1034: }