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

1.1       millert     1: /*
1.34    ! millert     2:  * Copyright (c) 1993-1996, 1998-2008 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.27      millert    30: #include <config.h>
1.1       millert    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 */
                     62: #include <pwd.h>
                     63: #include <errno.h>
                     64: #include <fcntl.h>
                     65: #include <signal.h>
                     66: #include <grp.h>
1.27      millert    67: #if TIME_WITH_SYS_TIME
                     68: # include <time.h>
                     69: #endif
                     70: #ifdef HAVE_SETLOCALE
                     71: # include <locale.h>
                     72: #endif
1.1       millert    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.27      millert    90: #ifdef HAVE_PROJECT_H
                     91: # include <project.h>
                     92: # include <sys/task.h>
                     93: #endif
1.33      millert    94: #ifdef HAVE_SELINUX
                     95: # include <selinux/selinux.h>
                     96: #endif
1.1       millert    97:
                     98: #include "sudo.h"
1.34    ! millert    99: #include "sudo_usage.h"
        !           100: #include "lbuf.h"
1.1       millert   101: #include "interfaces.h"
                    102: #include "version.h"
                    103:
                    104: #ifndef lint
1.34    ! millert   105: __unused static const char rcsid[] = "$Sudo: sudo.c,v 1.499 2008/11/11 18:28:08 millert Exp $";
1.1       millert   106: #endif /* lint */
                    107:
                    108: /*
                    109:  * Prototypes
                    110:  */
1.34    ! millert   111: static void init_vars                  __P((int, char **));
        !           112: static int set_cmnd                    __P((int));
1.19      millert   113: static int parse_args                  __P((int, char **));
1.11      millert   114: static void initial_setup              __P((void));
                    115: static void set_loginclass             __P((struct passwd *));
1.27      millert   116: static void set_project                        __P((struct passwd *));
1.34    ! millert   117: static void set_runasgr                        __P((char *));
        !           118: static void set_runaspw                        __P((char *));
        !           119: static void show_version               __P((void));
1.27      millert   120: static void usage                      __P((int))
                    121:                                            __attribute__((__noreturn__));
                    122: static void usage_excl                 __P((int))
                    123:                                            __attribute__((__noreturn__));
1.6       millert   124: static struct passwd *get_authpw       __P((void));
1.27      millert   125: extern int sudo_edit                   __P((int, char **, char **));
1.34    ! millert   126: extern void rebuild_env                        __P((int, int));
        !           127: void validate_env_vars                 __P((struct list_member *));
        !           128: void insert_env_vars                   __P((struct list_member *));
1.1       millert   129:
                    130: /*
                    131:  * Globals
                    132:  */
1.19      millert   133: int Argc, NewArgc;
                    134: char **Argv, **NewArgv;
1.23      millert   135: char *prev_user;
1.34    ! millert   136: static int user_closefrom = -1;
1.1       millert   137: struct sudo_user sudo_user;
1.34    ! millert   138: struct passwd *auth_pw, *list_pw;
1.1       millert   139: struct interface *interfaces;
                    140: int num_interfaces;
1.4       millert   141: int tgetpass_flags;
1.34    ! millert   142: int long_list;
1.17      millert   143: uid_t timestamp_uid;
1.1       millert   144: extern int errorlineno;
1.34    ! millert   145: extern int parse_error;
        !           146: extern char *errorfile;
1.4       millert   147: #if defined(RLIMIT_CORE) && !defined(SUDO_DEVEL)
                    148: static struct rlimit corelimit;
1.20      millert   149: #endif /* RLIMIT_CORE && !SUDO_DEVEL */
1.8       millert   150: #ifdef HAVE_LOGIN_CAP_H
                    151: login_cap_t *lc;
                    152: #endif /* HAVE_LOGIN_CAP_H */
                    153: #ifdef HAVE_BSD_AUTH_H
                    154: char *login_style;
                    155: #endif /* HAVE_BSD_AUTH_H */
1.33      millert   156: sigaction_t saved_sa_int, saved_sa_quit, saved_sa_tstp;
1.34    ! millert   157: static char *runas_user;
        !           158: static char *runas_group;
        !           159: static struct sudo_nss_list *snl;
        !           160:
        !           161: /* For getopt(3) */
        !           162: extern char *optarg;
        !           163: extern int optind;
1.1       millert   164:
                    165: int
1.11      millert   166: main(argc, argv, envp)
1.1       millert   167:     int argc;
                    168:     char **argv;
1.11      millert   169:     char **envp;
1.1       millert   170: {
1.34    ! millert   171:     int sources = 0, validated;
        !           172:     int fd, cmnd_status, sudo_mode, pwflag, rc = 0;
1.23      millert   173:     sigaction_t sa;
1.34    ! millert   174: #if defined(SUDO_DEVEL) && defined(__OpenBSD__)
        !           175:     extern char *malloc_options;
        !           176:     malloc_options = "AFGJPR";
        !           177: #endif
        !           178:     struct sudo_nss *nss;
1.1       millert   179:
1.27      millert   180: #ifdef HAVE_SETLOCALE
                    181:     setlocale(LC_ALL, "");
                    182: #endif
                    183:
1.19      millert   184:     Argv = argv;
1.23      millert   185:     if ((Argc = argc) < 1)
                    186:        usage(1);
1.19      millert   187:
1.1       millert   188:     /* Must be done as the first thing... */
                    189: #if defined(HAVE_GETPRPWNAM) && defined(HAVE_SET_AUTH_PARAMETERS)
1.19      millert   190:     (void) set_auth_parameters(Argc, Argv);
1.1       millert   191: # ifdef HAVE_INITPRIVS
                    192:     initprivs();
                    193: # endif
                    194: #endif /* HAVE_GETPRPWNAM && HAVE_SET_AUTH_PARAMETERS */
                    195:
1.19      millert   196:     if (geteuid() != 0)
1.34    ! millert   197:        errorx(1, "must be setuid root");
1.1       millert   198:
                    199:     /*
1.17      millert   200:      * Signal setup:
                    201:      * Ignore keyboard-generated signals so the user cannot interrupt
                    202:      *  us at some point and avoid the logging.
                    203:      *  Install handler to wait for children when they exit.
1.1       millert   204:      */
1.34    ! millert   205:     zero_bytes(&sa, sizeof(sa));
1.11      millert   206:     sigemptyset(&sa.sa_mask);
                    207:     sa.sa_flags = SA_RESTART;
                    208:     sa.sa_handler = SIG_IGN;
1.17      millert   209:     (void) sigaction(SIGINT, &sa, &saved_sa_int);
                    210:     (void) sigaction(SIGQUIT, &sa, &saved_sa_quit);
                    211:     (void) sigaction(SIGTSTP, &sa, &saved_sa_tstp);
1.1       millert   212:
                    213:     /*
1.34    ! millert   214:      * Turn off core dumps and make sure fds 0-2 are open.
1.1       millert   215:      */
                    216:     initial_setup();
1.34    ! millert   217:     sudo_setpwent();
        !           218:     sudo_setgrent();
1.1       millert   219:
                    220:     /* Parse our arguments. */
1.19      millert   221:     sudo_mode = parse_args(Argc, Argv);
1.1       millert   222:
                    223:     /* Setup defaults data structures. */
                    224:     init_defaults();
                    225:
1.11      millert   226:     /* Load the list of local ip addresses and netmasks.  */
                    227:     load_interfaces();
                    228:
                    229:     pwflag = 0;
1.23      millert   230:     if (ISSET(sudo_mode, MODE_SHELL))
1.1       millert   231:        user_cmnd = "shell";
1.23      millert   232:     else if (ISSET(sudo_mode, MODE_EDIT))
                    233:        user_cmnd = "sudoedit";
1.1       millert   234:     else
                    235:        switch (sudo_mode) {
                    236:            case MODE_VERSION:
1.34    ! millert   237:                show_version();
1.1       millert   238:                break;
                    239:            case MODE_HELP:
                    240:                usage(0);
                    241:                break;
                    242:            case MODE_VALIDATE:
                    243:                user_cmnd = "validate";
1.23      millert   244:                pwflag = I_VERIFYPW;
1.1       millert   245:                break;
                    246:            case MODE_KILL:
                    247:            case MODE_INVALIDATE:
                    248:                user_cmnd = "kill";
1.11      millert   249:                pwflag = -1;
1.1       millert   250:                break;
                    251:            case MODE_LISTDEFS:
                    252:                list_options();
                    253:                exit(0);
                    254:                break;
                    255:            case MODE_LIST:
                    256:                user_cmnd = "list";
1.23      millert   257:                pwflag = I_LISTPW;
1.34    ! millert   258:                break;
        !           259:            case MODE_CHECK:
        !           260:                pwflag = I_LISTPW;
1.1       millert   261:                break;
                    262:        }
                    263:
                    264:     /* Must have a command to run... */
                    265:     if (user_cmnd == NULL && NewArgc == 0)
                    266:        usage(1);
                    267:
1.34    ! millert   268:     init_vars(sudo_mode, envp);                /* XXX - move this later? */
        !           269:
        !           270:     /* Parse nsswitch.conf for sudoers order. */
        !           271:     snl = sudo_read_nss();
        !           272:
        !           273:     /* Open and parse sudoers, set global defaults */
        !           274:     tq_foreach_fwd(snl, nss) {
        !           275:        if (nss->open(nss) == 0 && nss->parse(nss) == 0) {
        !           276:            sources++;
        !           277:            nss->setdefs(nss);
        !           278:        }
        !           279:     }
        !           280:     if (sources == 0)
        !           281:        log_error(0, "no valid sudoers sources found, quitting");
        !           282:
        !           283:     /* XXX - collect post-sudoers parse settings into a function */
        !           284:
        !           285:     /*
        !           286:      * Set runas passwd/group entries based on command line or sudoers.
        !           287:      * Note that if runas_group was specified without runas_user we
        !           288:      * defer setting runas_pw so the match routines know to ignore it.
        !           289:      */
        !           290:     if (runas_group != NULL) {
        !           291:        set_runasgr(runas_group);
        !           292:        if (runas_user != NULL)
        !           293:            set_runaspw(runas_user);
        !           294:     } else
        !           295:        set_runaspw(runas_user ? runas_user : def_runas_default);
        !           296:
        !           297:     if (!update_defaults(SETDEF_RUNAS))
        !           298:        log_error(NO_STDERR|NO_EXIT, "problem with defaults entries");
        !           299:
        !           300:     /* Set login class if applicable. */
        !           301:     set_loginclass(sudo_user.pw);
1.1       millert   302:
1.34    ! millert   303:     /* Update initial shell now that runas is set. */
        !           304:     if (ISSET(sudo_mode, MODE_LOGIN_SHELL))
        !           305:        NewArgv[0] = runas_pw->pw_shell;
        !           306:
        !           307:     /* This goes after sudoers is parsed since it may have timestamp options. */
        !           308:     if (sudo_mode == MODE_KILL || sudo_mode == MODE_INVALIDATE) {
        !           309:        remove_timestamp((sudo_mode == MODE_KILL));
        !           310:        cleanup(0);
        !           311:        exit(0);
        !           312:     }
        !           313:
        !           314:     /* Is root even allowed to run sudo? */
        !           315:     if (user_uid == 0 && !def_root_sudo) {
        !           316:        (void) fprintf(stderr,
        !           317:            "Sorry, %s has been configured to not allow root to run it.\n",
        !           318:            getprogname());
        !           319:        exit(1);
        !           320:     }
1.23      millert   321:
1.34    ! millert   322:     /* Check for -C overriding def_closefrom. */
        !           323:     if (user_closefrom >= 0 && user_closefrom != def_closefrom) {
        !           324:        if (!def_closefrom_override)
        !           325:            errorx(1, "you are not permitted to use the -C option");
        !           326:        else
        !           327:            def_closefrom = user_closefrom;
1.23      millert   328:     }
1.33      millert   329:
1.34    ! millert   330:     cmnd_status = set_cmnd(sudo_mode);
        !           331:
        !           332: #ifdef HAVE_SETLOCALE
        !           333:     if (!setlocale(LC_ALL, def_sudoers_locale)) {
        !           334:        warningx("unable to set locale to \"%s\", using \"C\"",
        !           335:            def_sudoers_locale);
        !           336:        setlocale(LC_ALL, "C");
        !           337:     }
1.23      millert   338: #endif
1.34    ! millert   339:
        !           340:     validated = FLAG_NO_USER | FLAG_NO_HOST;
        !           341:     tq_foreach_fwd(snl, nss) {
        !           342:        validated = nss->lookup(nss, validated, pwflag);
        !           343:
        !           344:        /* Handle [NOTFOUND=return] */
        !           345:        if (!ISSET(validated, VALIDATE_OK) && nss->ret_notfound)
        !           346:            break;
        !           347:     }
1.26      millert   348:     if (safe_cmnd == NULL)
1.27      millert   349:        safe_cmnd = estrdup(user_cmnd);
1.1       millert   350:
1.34    ! millert   351: #ifdef HAVE_SETLOCALE
        !           352:     setlocale(LC_ALL, "");
        !           353: #endif
        !           354:
        !           355:     /* If only a group was specified, set runas_pw based on invoking user. */
        !           356:     if (runas_pw == NULL)
        !           357:        set_runaspw(user_name);
        !           358:
1.11      millert   359:     /*
1.17      millert   360:      * Look up the timestamp dir owner if one is specified.
                    361:      */
1.23      millert   362:     if (def_timestampowner) {
1.17      millert   363:        struct passwd *pw;
                    364:
1.23      millert   365:        if (*def_timestampowner == '#')
1.34    ! millert   366:            pw = sudo_getpwuid(atoi(def_timestampowner + 1));
1.17      millert   367:        else
1.34    ! millert   368:            pw = sudo_getpwnam(def_timestampowner);
1.17      millert   369:        if (!pw)
                    370:            log_error(0, "timestamp owner (%s): No such user",
1.23      millert   371:                def_timestampowner);
1.17      millert   372:        timestamp_uid = pw->pw_uid;
                    373:     }
                    374:
1.11      millert   375:     /* If given the -P option, set the "preserve_groups" flag. */
1.23      millert   376:     if (ISSET(sudo_mode, MODE_PRESERVE_GROUPS))
                    377:        def_preserve_groups = TRUE;
1.11      millert   378:
1.3       millert   379:     /* If no command line args and "set_home" is not set, error out. */
1.23      millert   380:     if (ISSET(sudo_mode, MODE_IMPLIED_SHELL) && !def_shell_noargs)
1.3       millert   381:        usage(1);
                    382:
1.1       millert   383:     /* Bail if a tty is required and we don't have one.  */
1.23      millert   384:     if (def_requiretty) {
1.1       millert   385:        if ((fd = open(_PATH_TTY, O_RDWR|O_NOCTTY)) == -1)
                    386:            log_error(NO_MAIL, "sorry, you must have a tty to run sudo");
                    387:        else
                    388:            (void) close(fd);
                    389:     }
                    390:
1.34    ! millert   391:     /* Use askpass value from sudoers unless user specified their own. */
        !           392:     if (def_askpass && !user_askpass)
        !           393:        user_askpass = def_askpass;
        !           394:
        !           395:     /* User may have overridden environment resetting via the -E flag. */
        !           396:     if (ISSET(sudo_mode, MODE_PRESERVE_ENV) && def_setenv)
1.27      millert   397:        def_env_reset = FALSE;
                    398:
                    399:     /* Build a new environment that avoids any nasty bits. */
1.34    ! millert   400:     rebuild_env(sudo_mode, def_noexec);
1.27      millert   401:
1.6       millert   402:     /* Fill in passwd struct based on user we are authenticating as.  */
                    403:     auth_pw = get_authpw();
1.4       millert   404:
1.23      millert   405:     /* Require a password if sudoers says so.  */
1.34    ! millert   406:     if (def_authenticate)
        !           407:        check_user(validated, !ISSET(sudo_mode, MODE_NONINTERACTIVE));
1.23      millert   408:
                    409:     /* If run as root with SUDO_USER set, set sudo_user.pw to that user. */
1.34    ! millert   410:     /* XXX - causes confusion when root is not listed in sudoers */
        !           411:     if (sudo_mode & (MODE_RUN | MODE_EDIT) && prev_user != NULL) {
        !           412:        if (user_uid == 0 && strcmp(prev_user, "root") != 0) {
1.23      millert   413:            struct passwd *pw;
                    414:
1.34    ! millert   415:            if ((pw = sudo_getpwnam(prev_user)) != NULL)
1.23      millert   416:                    sudo_user.pw = pw;
1.34    ! millert   417:        }
1.23      millert   418:     }
1.1       millert   419:
1.23      millert   420:     if (ISSET(validated, VALIDATE_OK)) {
1.1       millert   421:        /* Finally tell the user if the command did not exist. */
1.34    ! millert   422:        if (cmnd_status == NOT_FOUND_DOT)
        !           423:            errorx(1, "ignoring `%s' found in '.'\nUse `sudo ./%s' if this is the `%s' you wish to run.", user_cmnd, user_cmnd, user_cmnd);
        !           424:        else if (cmnd_status == NOT_FOUND)
        !           425:            errorx(1, "%s: command not found", user_cmnd);
1.1       millert   426:
1.27      millert   427:        /* If user specified env vars make sure sudoers allows it. */
1.34    ! millert   428:        if (ISSET(sudo_mode, MODE_RUN) && !def_setenv) {
1.27      millert   429:            if (ISSET(sudo_mode, MODE_PRESERVE_ENV))
                    430:                log_error(NO_MAIL,
                    431:                    "sorry, you are not allowed to preserve the environment");
                    432:            else
                    433:                validate_env_vars(sudo_user.env_vars);
                    434:        }
                    435:
1.34    ! millert   436:        log_allowed(validated);
        !           437:        if (sudo_mode == MODE_CHECK)
        !           438:            rc = display_cmnd(snl, list_pw ? list_pw : sudo_user.pw);
        !           439:        else if (sudo_mode == MODE_LIST)
        !           440:            display_privs(snl, list_pw ? list_pw : sudo_user.pw);
        !           441:
        !           442:        /* Cleanup sudoers sources */
        !           443:        tq_foreach_fwd(snl, nss)
        !           444:            nss->close(nss);
        !           445:
        !           446:        /* Deferred exit due to sudo_ldap_close() */
        !           447:        if (sudo_mode == MODE_VALIDATE || sudo_mode == MODE_CHECK ||
        !           448:            sudo_mode == MODE_LIST)
        !           449:            exit(rc);
        !           450:
        !           451:        /*
        !           452:         * Override user's umask if configured to do so.
        !           453:         * If user's umask is more restrictive, OR in those bits too.
        !           454:         */
        !           455:        if (def_umask != 0777) {
        !           456:            mode_t mask = umask(def_umask);
        !           457:            mask |= def_umask;
        !           458:            if (mask != def_umask)
        !           459:                umask(mask);
1.1       millert   460:        }
                    461:
1.4       millert   462:        /* Restore coredumpsize resource limit. */
                    463: #if defined(RLIMIT_CORE) && !defined(SUDO_DEVEL)
                    464:        (void) setrlimit(RLIMIT_CORE, &corelimit);
1.20      millert   465: #endif /* RLIMIT_CORE && !SUDO_DEVEL */
1.4       millert   466:
1.23      millert   467:        /* Become specified user or root if executing a command. */
                    468:        if (ISSET(sudo_mode, MODE_RUN))
                    469:            set_perms(PERM_FULL_RUNAS);
1.16      millert   470:
1.23      millert   471:        if (ISSET(sudo_mode, MODE_LOGIN_SHELL)) {
                    472:            char *p;
                    473:
                    474:            /* Convert /bin/sh -> -sh so shell knows it is a login shell */
                    475:            if ((p = strrchr(NewArgv[0], '/')) == NULL)
                    476:                p = NewArgv[0];
                    477:            *p = '-';
                    478:            NewArgv[0] = p;
                    479:
                    480:            /* Change to target user's homedir. */
                    481:            if (chdir(runas_pw->pw_dir) == -1)
1.34    ! millert   482:                warning("unable to change directory to %s", runas_pw->pw_dir);
        !           483:
        !           484: #if defined(__linux__) || defined(_AIX)
        !           485:            /* Insert system-wide environment variables. */
        !           486:            read_env_file(_PATH_ENVIRONMENT, TRUE);
        !           487: #endif
1.23      millert   488:        }
                    489:
                    490:        if (ISSET(sudo_mode, MODE_EDIT))
1.27      millert   491:            exit(sudo_edit(NewArgc, NewArgv, envp));
                    492:
1.34    ! millert   493:        /* Insert system-wide environment variables. */
        !           494:        if (def_env_file)
        !           495:            read_env_file(def_env_file, FALSE);
        !           496:
1.27      millert   497:        /* Insert user-specified environment variables. */
1.34    ! millert   498:        insert_env_vars(sudo_user.env_vars);
1.23      millert   499:
1.17      millert   500:        /* Restore signal handlers before we exec. */
                    501:        (void) sigaction(SIGINT, &saved_sa_int, NULL);
                    502:        (void) sigaction(SIGQUIT, &saved_sa_quit, NULL);
                    503:        (void) sigaction(SIGTSTP, &saved_sa_tstp, NULL);
                    504:
1.34    ! millert   505:        /* Close the password and group files and free up memory. */
        !           506:        sudo_endpwent();
        !           507:        sudo_endgrent();
        !           508:
        !           509:        closefrom(def_closefrom + 1);
        !           510:
1.1       millert   511: #ifndef PROFILING
1.23      millert   512:        if (ISSET(sudo_mode, MODE_BACKGROUND) && fork() > 0)
1.1       millert   513:            exit(0);
1.33      millert   514:        else {
                    515: #ifdef HAVE_SELINUX
                    516:            if (is_selinux_enabled() > 0 && user_role != NULL)
1.34    ! millert   517:                selinux_exec(user_role, user_type, NewArgv,
1.33      millert   518:                    ISSET(sudo_mode, MODE_LOGIN_SHELL));
                    519: #endif
1.34    ! millert   520:            execv(safe_cmnd, NewArgv);
1.33      millert   521:        }
1.1       millert   522: #else
                    523:        exit(0);
                    524: #endif /* PROFILING */
                    525:        /*
1.34    ! millert   526:         * If we got here then execve() failed...
1.1       millert   527:         */
1.27      millert   528:        if (errno == ENOEXEC) {
                    529:            NewArgv--;                  /* at least one extra slot... */
                    530:            NewArgv[0] = "sh";
                    531:            NewArgv[1] = safe_cmnd;
1.34    ! millert   532:            execv(_PATH_BSHELL, NewArgv);
        !           533:        } warning("unable to execute %s", safe_cmnd);
1.11      millert   534:        exit(127);
1.34    ! millert   535:     } else if (ISSET(validated, FLAG_NO_USER | FLAG_NO_HOST)) {
        !           536:        log_denial(validated, 1);
1.1       millert   537:        exit(1);
1.34    ! millert   538:     } else {
1.23      millert   539:        if (def_path_info) {
1.1       millert   540:            /*
                    541:             * We'd like to not leak path info at all here, but that can
                    542:             * *really* confuse the users.  To really close the leak we'd
                    543:             * have to say "not allowed to run foo" even when the problem
                    544:             * is just "no foo in path" since the user can trivially set
                    545:             * their path to just contain a single dir.
                    546:             */
1.34    ! millert   547:            log_denial(validated,
1.1       millert   548:                !(cmnd_status == NOT_FOUND_DOT || cmnd_status == NOT_FOUND));
                    549:            if (cmnd_status == NOT_FOUND)
1.34    ! millert   550:                warningx("%s: command not found", user_cmnd);
1.1       millert   551:            else if (cmnd_status == NOT_FOUND_DOT)
1.34    ! millert   552:                warningx("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   553:        } else {
                    554:            /* Just tell the user they are not allowed to run foo. */
1.34    ! millert   555:            log_denial(validated, 1);
1.1       millert   556:        }
                    557:        exit(1);
                    558:     }
                    559:     exit(0);   /* not reached */
                    560: }
                    561:
                    562: /*
                    563:  * Initialize timezone, set umask, fill in ``sudo_user'' struct and
                    564:  * load the ``interfaces'' array.
                    565:  */
1.34    ! millert   566: static void
1.27      millert   567: init_vars(sudo_mode, envp)
1.1       millert   568:     int sudo_mode;
1.27      millert   569:     char **envp;
1.1       millert   570: {
1.34    ! millert   571:     char *p, **ep, thost[MAXHOSTNAMELEN + 1];
        !           572:     int nohostname;
1.1       millert   573:
                    574:     /* Sanity check command from user. */
1.23      millert   575:     if (user_cmnd == NULL && strlen(NewArgv[0]) >= PATH_MAX)
1.34    ! millert   576:        errorx(1, "%s: File name too long", NewArgv[0]);
1.1       millert   577:
                    578: #ifdef HAVE_TZSET
                    579:     (void) tzset();            /* set the timezone if applicable */
                    580: #endif /* HAVE_TZSET */
                    581:
                    582:     /* Default value for cmnd and cwd, overridden later. */
                    583:     if (user_cmnd == NULL)
                    584:        user_cmnd = NewArgv[0];
1.17      millert   585:     (void) strlcpy(user_cwd, "unknown", sizeof(user_cwd));
1.1       millert   586:
                    587:     /*
                    588:      * We avoid gethostbyname() if possible since we don't want
                    589:      * sudo to block if DNS or NIS is hosed.
                    590:      * "host" is the (possibly fully-qualified) hostname and
                    591:      * "shost" is the unqualified form of the hostname.
                    592:      */
1.11      millert   593:     nohostname = gethostname(thost, sizeof(thost));
                    594:     if (nohostname)
                    595:        user_host = user_shost = "localhost";
                    596:     else {
1.34    ! millert   597:        thost[sizeof(thost) - 1] = '\0';
1.1       millert   598:        user_host = estrdup(thost);
1.23      millert   599:        if (def_fqdn) {
1.11      millert   600:            /* Defer call to set_fqdn() until log_error() is safe. */
                    601:            user_shost = user_host;
1.1       millert   602:        } else {
1.11      millert   603:            if ((p = strchr(user_host, '.'))) {
                    604:                *p = '\0';
                    605:                user_shost = estrdup(user_host);
                    606:                *p = '.';
                    607:            } else {
                    608:                user_shost = user_host;
                    609:            }
1.1       millert   610:        }
                    611:     }
                    612:
                    613:     if ((p = ttyname(STDIN_FILENO)) || (p = ttyname(STDOUT_FILENO))) {
1.30      millert   614:        user_tty = user_ttypath = estrdup(p);
                    615:        if (strncmp(user_tty, _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0)
                    616:            user_tty += sizeof(_PATH_DEV) - 1;
1.1       millert   617:     } else
                    618:        user_tty = "unknown";
                    619:
1.27      millert   620:     for (ep = envp; *ep; ep++) {
1.34    ! millert   621:        /* XXX - don't fill in if empty string */
1.27      millert   622:        switch (**ep) {
1.34    ! millert   623:            case 'D':
        !           624:                if (strncmp("DISPLAY=", *ep, 8) == 0)
        !           625:                    user_display = *ep + 8;
        !           626:                break;
        !           627:            case 'K':
        !           628:                if (strncmp("KRB5CCNAME=", *ep, 11) == 0)
        !           629:                    user_ccname = *ep + 11;
        !           630:                break;
1.27      millert   631:            case 'P':
                    632:                if (strncmp("PATH=", *ep, 5) == 0)
                    633:                    user_path = *ep + 5;
                    634:                break;
                    635:            case 'S':
                    636:                if (strncmp("SHELL=", *ep, 6) == 0)
                    637:                    user_shell = *ep + 6;
                    638:                else if (!user_prompt && strncmp("SUDO_PROMPT=", *ep, 12) == 0)
                    639:                    user_prompt = *ep + 12;
                    640:                else if (strncmp("SUDO_USER=", *ep, 10) == 0)
                    641:                    prev_user = *ep + 10;
1.34    ! millert   642:                else if (strncmp("SUDO_ASKPASS=", *ep, 13) == 0)
        !           643:                    user_askpass = *ep + 13;
1.27      millert   644:                break;
                    645:            }
                    646:     }
                    647:
1.1       millert   648:     /*
                    649:      * Get a local copy of the user's struct passwd with the shadow password
                    650:      * if necessary.  It is assumed that euid is 0 at this point so we
                    651:      * can read the shadow passwd file if necessary.
                    652:      */
                    653:     if ((sudo_user.pw = sudo_getpwuid(getuid())) == NULL) {
                    654:        /* Need to make a fake struct passwd for logging to work. */
                    655:        struct passwd pw;
                    656:        char pw_name[MAX_UID_T_LEN + 1];
                    657:
                    658:        pw.pw_uid = getuid();
1.17      millert   659:        (void) snprintf(pw_name, sizeof(pw_name), "%lu",
                    660:            (unsigned long) pw.pw_uid);
1.1       millert   661:        pw.pw_name = pw_name;
                    662:        sudo_user.pw = &pw;
                    663:
1.21      millert   664:        /*
                    665:         * If we are in -k/-K mode, just spew to stderr.  It is not unusual for
                    666:         * users to place "sudo -k" in a .logout file which can cause sudo to
                    667:         * be run during reboot after the YP/NIS/NIS+/LDAP/etc daemon has died.
                    668:         */
                    669:        if (sudo_mode & (MODE_INVALIDATE|MODE_KILL))
1.34    ! millert   670:            errorx(1, "unknown uid: %s", pw_name);
        !           671:        log_error(0, "unknown uid: %s", pw_name);
1.1       millert   672:     }
1.15      millert   673:     if (user_shell == NULL || *user_shell == '\0')
1.34    ! millert   674:        user_shell = estrdup(sudo_user.pw->pw_shell);
1.1       millert   675:
                    676:     /* It is now safe to use log_error() and set_perms() */
                    677:
1.27      millert   678: #ifdef HAVE_GETGROUPS
                    679:     if ((user_ngroups = getgroups(0, NULL)) > 0) {
1.31      millert   680:        user_groups = emalloc2(user_ngroups, sizeof(GETGROUPS_T));
1.27      millert   681:        if (getgroups(user_ngroups, user_groups) < 0)
                    682:            log_error(USE_ERRNO|MSG_ONLY, "can't get group vector");
                    683:     } else
                    684:        user_ngroups = 0;
                    685: #endif
                    686:
1.23      millert   687:     if (def_fqdn)
                    688:        set_fqdn();                     /* may call log_error() */
1.11      millert   689:
                    690:     if (nohostname)
                    691:        log_error(USE_ERRNO|MSG_ONLY, "can't get hostname");
                    692:
                    693:     /*
1.1       millert   694:      * Get current working directory.  Try as user, fall back to root.
                    695:      */
1.17      millert   696:     set_perms(PERM_USER);
1.1       millert   697:     if (!getcwd(user_cwd, sizeof(user_cwd))) {
1.17      millert   698:        set_perms(PERM_ROOT);
1.1       millert   699:        if (!getcwd(user_cwd, sizeof(user_cwd))) {
1.34    ! millert   700:            warningx("cannot get working directory");
1.17      millert   701:            (void) strlcpy(user_cwd, "unknown", sizeof(user_cwd));
1.1       millert   702:        }
                    703:     } else
1.17      millert   704:        set_perms(PERM_ROOT);
1.1       millert   705:
                    706:     /*
1.23      millert   707:      * If we were given the '-e', '-i' or '-s' options we need to redo
1.1       millert   708:      * NewArgv and NewArgc.
                    709:      */
1.34    ! millert   710:     if (ISSET(sudo_mode, MODE_EDIT)) {
        !           711:        NewArgv--;
        !           712:        NewArgc++;
        !           713:        NewArgv[0] = "sudoedit";
        !           714:     } else if (ISSET(sudo_mode, MODE_SHELL)) {
        !           715:        char **av;
1.1       millert   716:
1.27      millert   717:        /* Allocate an extra slot for execve() failure (ENOEXEC). */
1.34    ! millert   718:        av = (char **) emalloc2(5, sizeof(char *));
        !           719:        av++;
1.1       millert   720:
1.34    ! millert   721:        av[0] = user_shell;     /* may be updated later */
        !           722:        if (NewArgc > 0) {
        !           723:            size_t size;
        !           724:            char *cmnd, *src, *dst, *end;
        !           725:            size = (size_t) (NewArgv[NewArgc - 1] - NewArgv[0]) +
        !           726:                    strlen(NewArgv[NewArgc - 1]) + 1;
        !           727:            cmnd = emalloc(size);
        !           728:            src = NewArgv[0];
        !           729:            dst = cmnd;
        !           730:            for (end = src + size - 1; src < end; src++, dst++)
        !           731:                *dst = *src == 0 ? ' ' : *src;
        !           732:            *dst = '\0';
        !           733:            av[1] = "-c";
        !           734:            av[2] = cmnd;
        !           735:            NewArgc = 2;
        !           736:        }
        !           737:        av[++NewArgc] = NULL;
        !           738:        NewArgv = av;
1.1       millert   739:     }
1.34    ! millert   740: }
1.1       millert   741:
1.34    ! millert   742: /*
        !           743:  * Fill in user_cmnd, user_args, user_base and user_stat variables
        !           744:  * and apply any command-specific defaults entries.
        !           745:  */
        !           746: static int
        !           747: set_cmnd(sudo_mode)
        !           748:     int sudo_mode;
        !           749: {
        !           750:     int rval;
1.8       millert   751:
1.27      millert   752:     /* Set project if applicable. */
                    753:     set_project(runas_pw);
                    754:
1.1       millert   755:     /* Resolve the path and return. */
1.23      millert   756:     rval = FOUND;
                    757:     user_stat = emalloc(sizeof(struct stat));
1.34    ! millert   758:     if (sudo_mode & (MODE_RUN | MODE_EDIT | MODE_CHECK)) {
        !           759:        if (ISSET(sudo_mode, MODE_RUN | MODE_CHECK)) {
1.23      millert   760:            set_perms(PERM_RUNAS);
                    761:            rval = find_path(NewArgv[0], &user_cmnd, user_stat, user_path);
1.17      millert   762:            set_perms(PERM_ROOT);
1.23      millert   763:            if (rval != FOUND) {
                    764:                /* Failed as root, try as invoking user. */
                    765:                set_perms(PERM_USER);
                    766:                rval = find_path(NewArgv[0], &user_cmnd, user_stat, user_path);
                    767:                set_perms(PERM_ROOT);
                    768:            }
1.11      millert   769:        }
                    770:
                    771:        /* set user_args */
                    772:        if (NewArgc > 1) {
                    773:            char *to, **from;
1.17      millert   774:            size_t size, n;
1.11      millert   775:
1.23      millert   776:            /* If we didn't realloc NewArgv it is contiguous so just count. */
1.34    ! millert   777:            if (!ISSET(sudo_mode, MODE_SHELL)) {
1.11      millert   778:                size = (size_t) (NewArgv[NewArgc-1] - NewArgv[1]) +
                    779:                        strlen(NewArgv[NewArgc-1]) + 1;
                    780:            } else {
                    781:                for (size = 0, from = NewArgv + 1; *from; from++)
                    782:                    size += strlen(*from) + 1;
                    783:            }
                    784:
1.23      millert   785:            /* Alloc and build up user_args. */
1.17      millert   786:            user_args = (char *) emalloc(size);
                    787:            for (to = user_args, from = NewArgv + 1; *from; from++) {
                    788:                n = strlcpy(to, *from, size - (to - user_args));
1.19      millert   789:                if (n >= size - (to - user_args))
1.34    ! millert   790:                    errorx(1, "internal error, init_vars() overflow");
1.17      millert   791:                to += n;
1.11      millert   792:                *to++ = ' ';
                    793:            }
                    794:            *--to = '\0';
                    795:        }
1.23      millert   796:     }
                    797:     if ((user_base = strrchr(user_cmnd, '/')) != NULL)
                    798:        user_base++;
                    799:     else
                    800:        user_base = user_cmnd;
1.11      millert   801:
1.34    ! millert   802:     if (!update_defaults(SETDEF_CMND))
        !           803:        log_error(NO_STDERR|NO_EXIT, "problem with defaults entries");
        !           804:
1.11      millert   805:     return(rval);
1.1       millert   806: }
                    807:
                    808: /*
1.34    ! millert   809:  * Command line argument parsing.
        !           810:  * Sets NewArgc and NewArgv which corresponds to the argc/argv we'll use
        !           811:  * for the command to be run (if we are running one).
1.1       millert   812:  */
                    813: static int
1.19      millert   814: parse_args(argc, argv)
                    815:     int argc;
                    816:     char **argv;
1.1       millert   817: {
1.34    ! millert   818:     int mode = 0;              /* what mode is sudo to be run in? */
        !           819:     int flags = 0;             /* mode flags */
        !           820:     int ch;
1.1       millert   821:
1.23      millert   822:     /* First, check to see if we were invoked as "sudoedit". */
1.34    ! millert   823:     if (strcmp(getprogname(), "sudoedit") == 0)
        !           824:        mode = MODE_EDIT;
1.23      millert   825:
1.34    ! millert   826:     /* Returns true if the last option string was "--" */
        !           827: #define got_end_of_args        (optind > 1 && argv[optind - 1][0] == '-' && \
        !           828:            argv[optind - 1][1] == '-' && argv[optind - 1][2] == '\0')
        !           829:
        !           830:     /* Returns true if next option is an environment variable */
        !           831: #define is_envar (optind < argc && argv[optind][0] != '/' && \
        !           832:            strchr(argv[optind], '=') != NULL)
1.27      millert   833:
1.34    ! millert   834:     for (;;) {
        !           835:        /*
        !           836:         * We disable arg permutation for GNU getopt().
        !           837:         * Some trickiness is required to allow environment variables
        !           838:         * to be interspersed with command line options.
        !           839:         */
        !           840:        if ((ch = getopt(argc, argv, "+Aa:bC:c:Eeg:HhiKkLlnPp:r:Sst:U:u:Vv")) != -1) {
        !           841:            switch (ch) {
        !           842:                case 'A':
        !           843:                    SET(tgetpass_flags, TGP_ASKPASS);
1.27      millert   844:                    break;
1.8       millert   845: #ifdef HAVE_BSD_AUTH_H
1.27      millert   846:                case 'a':
1.34    ! millert   847:                    login_style = optarg;
        !           848:                    break;
        !           849: #endif
        !           850:                case 'b':
        !           851:                    SET(flags, MODE_BACKGROUND);
        !           852:                    break;
        !           853:                case 'C':
        !           854:                    if ((user_closefrom = atoi(optarg)) < 3) {
        !           855:                        warningx("the argument to -C must be at least 3");
1.27      millert   856:                        usage(1);
1.34    ! millert   857:                    }
1.27      millert   858:                    break;
1.8       millert   859: #ifdef HAVE_LOGIN_CAP_H
1.27      millert   860:                case 'c':
1.34    ! millert   861:                    login_class = optarg;
1.27      millert   862:                    def_use_loginclass = TRUE;
                    863:                    break;
1.4       millert   864: #endif
1.34    ! millert   865:                case 'E':
        !           866:                    SET(flags, MODE_PRESERVE_ENV);
1.27      millert   867:                    break;
                    868:                case 'e':
1.34    ! millert   869:                    if (mode && mode != MODE_EDIT)
1.27      millert   870:                        usage_excl(1);
1.34    ! millert   871:                    mode = MODE_EDIT;
        !           872:                    break;
        !           873:                case 'g':
        !           874:                    runas_group = optarg;
        !           875:                    break;
        !           876:                case 'H':
        !           877:                    SET(flags, MODE_RESET_HOME);
1.27      millert   878:                    break;
1.34    ! millert   879:                case 'h':
        !           880:                    if (mode && mode != MODE_HELP)
1.27      millert   881:                        usage_excl(1);
1.34    ! millert   882:                    mode = MODE_HELP;
1.27      millert   883:                    break;
                    884:                case 'i':
1.34    ! millert   885:                    SET(flags, MODE_LOGIN_SHELL);
1.27      millert   886:                    def_env_reset = TRUE;
                    887:                    break;
                    888:                case 'k':
1.34    ! millert   889:                    if (mode && mode != MODE_INVALIDATE)
1.27      millert   890:                        usage_excl(1);
1.34    ! millert   891:                    mode = MODE_INVALIDATE;
1.27      millert   892:                    break;
                    893:                case 'K':
1.34    ! millert   894:                    if (mode && mode != MODE_KILL)
1.27      millert   895:                        usage_excl(1);
1.34    ! millert   896:                    mode = MODE_KILL;
1.27      millert   897:                    break;
                    898:                case 'L':
1.34    ! millert   899:                    if (mode && mode != MODE_LISTDEFS)
1.27      millert   900:                        usage_excl(1);
1.34    ! millert   901:                    mode = MODE_LISTDEFS;
1.27      millert   902:                    break;
                    903:                case 'l':
1.34    ! millert   904:                    if (mode) {
        !           905:                        if (mode == MODE_LIST)
        !           906:                            long_list = 1;
        !           907:                        else
        !           908:                            usage_excl(1);
        !           909:                    }
        !           910:                    mode = MODE_LIST;
1.27      millert   911:                    break;
1.34    ! millert   912:                case 'n':
        !           913:                    SET(flags, MODE_NONINTERACTIVE);
1.27      millert   914:                    break;
1.34    ! millert   915:                case 'P':
        !           916:                    SET(flags, MODE_PRESERVE_GROUPS);
1.27      millert   917:                    break;
1.34    ! millert   918:                case 'p':
        !           919:                    user_prompt = optarg;
        !           920:                    def_passprompt_override = TRUE;
1.27      millert   921:                    break;
1.34    ! millert   922: #ifdef HAVE_SELINUX
        !           923:                case 'r':
        !           924:                    user_role = optarg;
1.27      millert   925:                    break;
1.34    ! millert   926:                case 't':
        !           927:                    user_type = optarg;
1.27      millert   928:                    break;
1.34    ! millert   929: #endif
1.27      millert   930:                case 'S':
                    931:                    SET(tgetpass_flags, TGP_STDIN);
                    932:                    break;
1.34    ! millert   933:                case 's':
        !           934:                    SET(flags, MODE_SHELL);
        !           935:                    break;
        !           936:                case 'U':
        !           937:                    if ((list_pw = sudo_getpwnam(optarg)) == NULL)
        !           938:                        errorx(1, "unknown user: %s", optarg);
        !           939:                    break;
        !           940:                case 'u':
        !           941:                    runas_user = optarg;
1.27      millert   942:                    break;
1.34    ! millert   943:                case 'v':
        !           944:                    if (mode && mode != MODE_VALIDATE)
        !           945:                        usage_excl(1);
        !           946:                    mode = MODE_VALIDATE;
1.33      millert   947:                    break;
1.34    ! millert   948:                case 'V':
        !           949:                    if (mode && mode != MODE_VERSION)
        !           950:                        usage_excl(1);
        !           951:                    mode = MODE_VERSION;
1.33      millert   952:                    break;
1.27      millert   953:                default:
                    954:                    usage(1);
                    955:            }
1.34    ! millert   956:        } else if (!got_end_of_args && is_envar) {
1.27      millert   957:            struct list_member *ev;
1.34    ! millert   958:
        !           959:            /* Store environment variable. */
1.27      millert   960:            ev = emalloc(sizeof(*ev));
1.34    ! millert   961:            ev->value = argv[optind];
1.27      millert   962:            ev->next = sudo_user.env_vars;
                    963:            sudo_user.env_vars = ev;
1.34    ! millert   964:
        !           965:            /* Crank optind and resume getopt. */
        !           966:            optind++;
1.27      millert   967:        } else {
1.34    ! millert   968:            /* Not an option or an environment variable -- we're done. */
1.27      millert   969:            break;
1.1       millert   970:        }
                    971:     }
1.27      millert   972:
1.34    ! millert   973:     NewArgc = argc - optind;
        !           974:     NewArgv = argv + optind;
        !           975:
        !           976:     if (!mode)
        !           977:        mode = MODE_RUN;
        !           978:
        !           979:     if (NewArgc > 0 && mode == MODE_LIST)
        !           980:        mode = MODE_CHECK;
        !           981:
        !           982:     if (ISSET(flags, MODE_LOGIN_SHELL)) {
        !           983:        if (ISSET(flags, MODE_SHELL)) {
        !           984:            warningx("you may not specify both the `-i' and `-s' options");
        !           985:            usage(1);
        !           986:        }
        !           987:        if (ISSET(flags, MODE_PRESERVE_ENV)) {
        !           988:            warningx("you may not specify both the `-i' and `-E' options");
        !           989:            usage(1);
        !           990:        }
        !           991:        SET(flags, MODE_SHELL);
        !           992:     }
        !           993:     if (mode == MODE_EDIT &&
        !           994:        (ISSET(flags, MODE_PRESERVE_ENV) || sudo_user.env_vars != NULL)) {
        !           995:        if (ISSET(mode, MODE_PRESERVE_ENV))
        !           996:            warningx("the `-E' option is not valid in edit mode");
1.27      millert   997:        if (sudo_user.env_vars != NULL)
1.34    ! millert   998:            warningx("you may not specify environment variables in edit mode");
        !           999:        usage(1);
        !          1000:     }
        !          1001:     if ((runas_user != NULL || runas_group != NULL) &&
        !          1002:        !ISSET(mode, MODE_EDIT | MODE_RUN | MODE_CHECK)) {
1.27      millert  1003:        usage(1);
                   1004:     }
1.34    ! millert  1005:     if (list_pw != NULL && mode != MODE_LIST && mode != MODE_CHECK) {
        !          1006:        warningx("the `-U' option may only be used with the `-l' option");
1.33      millert  1007:        usage(1);
                   1008:     }
1.34    ! millert  1009:     if (ISSET(tgetpass_flags, TGP_STDIN) && ISSET(tgetpass_flags, TGP_ASKPASS)) {
        !          1010:        warningx("the `-A' and `-S' options may not be used together");
1.24      millert  1011:        usage(1);
                   1012:     }
1.34    ! millert  1013:     if ((NewArgc == 0 && mode == MODE_EDIT) ||
        !          1014:        (NewArgc > 0 && !ISSET(mode, MODE_RUN | MODE_EDIT | MODE_CHECK)))
1.1       millert  1015:        usage(1);
1.34    ! millert  1016:     if (NewArgc == 0 && mode == MODE_RUN && !ISSET(flags, MODE_SHELL))
        !          1017:        SET(flags, (MODE_IMPLIED_SHELL | MODE_SHELL));
1.1       millert  1018:
1.34    ! millert  1019:     return(mode | flags);
1.1       millert  1020: }
                   1021:
                   1022: /*
1.34    ! millert  1023:  * Open sudoers and sanity check mode/owner/type.
        !          1024:  * Returns a handle to the sudoers file or NULL on error.
1.1       millert  1025:  */
1.34    ! millert  1026: FILE *
        !          1027: open_sudoers(sudoers, keepopen)
        !          1028:     const char *sudoers;
        !          1029:     int *keepopen;
1.1       millert  1030: {
                   1031:     struct stat statbuf;
1.34    ! millert  1032:     FILE *fp = NULL;
        !          1033:     int rootstat;
1.1       millert  1034:
                   1035:     /*
                   1036:      * Fix the mode and group on sudoers file from old default.
1.23      millert  1037:      * Only works if file system is readable/writable by root.
1.1       millert  1038:      */
1.34    ! millert  1039:     if ((rootstat = stat_sudoers(sudoers, &statbuf)) == 0 &&
1.1       millert  1040:        SUDOERS_UID == statbuf.st_uid && SUDOERS_MODE != 0400 &&
                   1041:        (statbuf.st_mode & 0007777) == 0400) {
                   1042:
1.34    ! millert  1043:        if (chmod(sudoers, SUDOERS_MODE) == 0) {
        !          1044:            warningx("fixed mode on %s", sudoers);
1.23      millert  1045:            SET(statbuf.st_mode, SUDOERS_MODE);
1.1       millert  1046:            if (statbuf.st_gid != SUDOERS_GID) {
1.34    ! millert  1047:                if (chown(sudoers, (uid_t) -1, SUDOERS_GID) == 0) {
        !          1048:                    warningx("set group on %s", sudoers);
1.1       millert  1049:                    statbuf.st_gid = SUDOERS_GID;
1.19      millert  1050:                } else
1.34    ! millert  1051:                    warning("unable to set group on %s", sudoers);
1.1       millert  1052:            }
1.19      millert  1053:        } else
1.34    ! millert  1054:            warning("unable to fix mode on %s", sudoers);
1.1       millert  1055:     }
                   1056:
                   1057:     /*
                   1058:      * Sanity checks on sudoers file.  Must be done as sudoers
                   1059:      * file owner.  We already did a stat as root, so use that
                   1060:      * data if we can't stat as sudoers file owner.
                   1061:      */
1.17      millert  1062:     set_perms(PERM_SUDOERS);
1.1       millert  1063:
1.34    ! millert  1064:     if (rootstat != 0 && stat_sudoers(sudoers, &statbuf) != 0)
        !          1065:        log_error(USE_ERRNO|NO_EXIT, "can't stat %s", sudoers);
1.1       millert  1066:     else if (!S_ISREG(statbuf.st_mode))
1.34    ! millert  1067:        log_error(NO_EXIT, "%s is not a regular file", sudoers);
1.1       millert  1068:     else if ((statbuf.st_mode & 07777) != SUDOERS_MODE)
1.34    ! millert  1069:        log_error(NO_EXIT, "%s is mode 0%o, should be 0%o", sudoers,
1.27      millert  1070:            (unsigned int) (statbuf.st_mode & 07777),
                   1071:            (unsigned int) SUDOERS_MODE);
1.1       millert  1072:     else if (statbuf.st_uid != SUDOERS_UID)
1.34    ! millert  1073:        log_error(NO_EXIT, "%s is owned by uid %lu, should be %lu", sudoers,
1.25      millert  1074:            (unsigned long) statbuf.st_uid, (unsigned long) SUDOERS_UID);
1.1       millert  1075:     else if (statbuf.st_gid != SUDOERS_GID)
1.34    ! millert  1076:        log_error(NO_EXIT, "%s is owned by gid %lu, should be %lu", sudoers,
1.25      millert  1077:            (unsigned long) statbuf.st_gid, (unsigned long) SUDOERS_GID);
1.34    ! millert  1078:     else if ((fp = fopen(sudoers, "r")) == NULL)
        !          1079:        log_error(USE_ERRNO, "can't open %s", sudoers);
        !          1080:     else if (statbuf.st_size != 0) {
        !          1081:        /*
        !          1082:         * Make sure we can actually read sudoers so we can present the
        !          1083:         * user with a reasonable error message.
        !          1084:         */
        !          1085:        if (fgetc(fp) == EOF)
        !          1086:            log_error(USE_ERRNO, "can't read %s", sudoers);
        !          1087:        rewind(fp);
1.1       millert  1088:     }
1.34    ! millert  1089:     (void) fcntl(fileno(fp), F_SETFD, 1);
1.1       millert  1090:
1.17      millert  1091:     set_perms(PERM_ROOT);              /* change back to root */
1.34    ! millert  1092:     return(fp);
1.1       millert  1093: }
                   1094:
                   1095: /*
                   1096:  * Close all open files (except std*) and turn off core dumps.
1.34    ! millert  1097:  * Also sets the set_perms() pointer to the correct function.
1.1       millert  1098:  */
                   1099: static void
                   1100: initial_setup()
                   1101: {
1.27      millert  1102:     int miss[3], devnull = -1;
1.33      millert  1103: #if defined(__linux__) || (defined(RLIMIT_CORE) && !defined(SUDO_DEVEL))
1.1       millert  1104:     struct rlimit rl;
1.33      millert  1105: #endif
1.1       millert  1106:
1.33      millert  1107: #if defined(__linux__)
                   1108:     /*
                   1109:      * Unlimit the number of processes since Linux's setuid() will
                   1110:      * apply resource limits when changing uid and return EAGAIN if
                   1111:      * nproc would be violated by the uid switch.
                   1112:      */
                   1113:     rl.rlim_cur = rl.rlim_max = RLIM_INFINITY;
                   1114:     if (setrlimit(RLIMIT_NPROC, &rl)) {
                   1115:        if (getrlimit(RLIMIT_NPROC, &rl) == 0) {
                   1116:            rl.rlim_cur = rl.rlim_max;
                   1117:            (void)setrlimit(RLIMIT_NPROC, &rl);
                   1118:        }
                   1119:     }
                   1120: #endif /* __linux__ */
                   1121: #if defined(RLIMIT_CORE) && !defined(SUDO_DEVEL)
1.1       millert  1122:     /*
                   1123:      * Turn off core dumps.
                   1124:      */
1.4       millert  1125:     (void) getrlimit(RLIMIT_CORE, &corelimit);
1.20      millert  1126:     memcpy(&rl, &corelimit, sizeof(struct rlimit));
                   1127:     rl.rlim_cur = 0;
1.1       millert  1128:     (void) setrlimit(RLIMIT_CORE, &rl);
1.20      millert  1129: #endif /* RLIMIT_CORE && !SUDO_DEVEL */
1.1       millert  1130:
1.17      millert  1131:     /*
1.27      millert  1132:      * stdin, stdout and stderr must be open; set them to /dev/null
                   1133:      * if they are closed and close all other fds.
1.17      millert  1134:      */
1.27      millert  1135:     miss[STDIN_FILENO] = fcntl(STDIN_FILENO, F_GETFL, 0) == -1;
                   1136:     miss[STDOUT_FILENO] = fcntl(STDOUT_FILENO, F_GETFL, 0) == -1;
                   1137:     miss[STDERR_FILENO] = fcntl(STDERR_FILENO, F_GETFL, 0) == -1;
                   1138:     if (miss[STDIN_FILENO] || miss[STDOUT_FILENO] || miss[STDERR_FILENO]) {
                   1139:        if ((devnull = open(_PATH_DEVNULL, O_RDWR, 0644)) != -1) {
                   1140:            if (miss[STDIN_FILENO])
                   1141:                (void) dup2(devnull, STDIN_FILENO);
                   1142:            if (miss[STDOUT_FILENO])
                   1143:                (void) dup2(devnull, STDOUT_FILENO);
                   1144:            if (miss[STDERR_FILENO])
                   1145:                (void) dup2(devnull, STDERR_FILENO);
1.34    ! millert  1146:            if (devnull > STDERR_FILENO)
        !          1147:                close(devnull);
1.27      millert  1148:        }
                   1149:     }
1.1       millert  1150: }
                   1151:
1.8       millert  1152: #ifdef HAVE_LOGIN_CAP_H
                   1153: static void
1.4       millert  1154: set_loginclass(pw)
                   1155:     struct passwd *pw;
                   1156: {
                   1157:     int errflags;
                   1158:
                   1159:     /*
                   1160:      * Don't make it a fatal error if the user didn't specify the login
                   1161:      * class themselves.  We do this because if login.conf gets
                   1162:      * corrupted we want the admin to be able to use sudo to fix it.
                   1163:      */
                   1164:     if (login_class)
                   1165:        errflags = NO_MAIL|MSG_ONLY;
                   1166:     else
                   1167:        errflags = NO_MAIL|MSG_ONLY|NO_EXIT;
                   1168:
                   1169:     if (login_class && strcmp(login_class, "-") != 0) {
1.34    ! millert  1170:        if (user_uid != 0 &&
        !          1171:            strcmp(runas_user ? runas_user : def_runas_default, "root") != 0)
        !          1172:            errorx(1, "only root can use -c %s", login_class);
1.4       millert  1173:     } else {
                   1174:        login_class = pw->pw_class;
                   1175:        if (!login_class || !*login_class)
                   1176:            login_class =
                   1177:                (pw->pw_uid == 0) ? LOGIN_DEFROOTCLASS : LOGIN_DEFCLASS;
                   1178:     }
                   1179:
                   1180:     lc = login_getclass(login_class);
1.10      millert  1181:     if (!lc || !lc->lc_class || strcmp(lc->lc_class, login_class) != 0) {
1.4       millert  1182:        log_error(errflags, "unknown login class: %s", login_class);
1.11      millert  1183:        if (!lc)
                   1184:            lc = login_getclass(NULL);  /* needed for login_getstyle() later */
1.10      millert  1185:     }
1.4       millert  1186: }
                   1187: #else
1.8       millert  1188: static void
1.4       millert  1189: set_loginclass(pw)
                   1190:     struct passwd *pw;
                   1191: {
                   1192: }
1.8       millert  1193: #endif /* HAVE_LOGIN_CAP_H */
1.4       millert  1194:
1.27      millert  1195: #ifdef HAVE_PROJECT_H
                   1196: static void
                   1197: set_project(pw)
                   1198:     struct passwd *pw;
                   1199: {
                   1200:     int errflags = NO_MAIL|MSG_ONLY|NO_EXIT;
                   1201:     int errval;
                   1202:     struct project proj;
                   1203:     struct project *resultp = '\0';
                   1204:     char buf[1024];
                   1205:
                   1206:     /*
                   1207:      * Collect the default project for the user and settaskid
                   1208:      */
                   1209:     setprojent();
                   1210:     if (resultp = getdefaultproj(pw->pw_name, &proj, buf, sizeof(buf))) {
                   1211:        errval = setproject(resultp->pj_name, pw->pw_name, TASK_NORMAL);
                   1212:        if (errval != 0) {
                   1213:            switch(errval) {
                   1214:            case SETPROJ_ERR_TASK:
                   1215:                if (errno == EAGAIN)
                   1216:                    log_error(errflags, "resource control limit has been reached");
                   1217:                else if (errno == ESRCH)
                   1218:                    log_error(errflags, "user \"%s\" is not a member of "
                   1219:                        "project \"%s\"", pw->pw_name, resultp->pj_name);
                   1220:                else if (errno == EACCES)
                   1221:                    log_error(errflags, "the invoking task is final");
                   1222:                else
                   1223:                    log_error(errflags, "could not join project \"%s\"",
                   1224:                        resultp->pj_name);
                   1225:                break;
                   1226:            case SETPROJ_ERR_POOL:
                   1227:                if (errno == EACCES)
                   1228:                    log_error(errflags, "no resource pool accepting "
                   1229:                            "default bindings exists for project \"%s\"",
                   1230:                            resultp->pj_name);
                   1231:                else if (errno == ESRCH)
                   1232:                    log_error(errflags, "specified resource pool does "
                   1233:                            "not exist for project \"%s\"", resultp->pj_name);
                   1234:                else
                   1235:                    log_error(errflags, "could not bind to default "
                   1236:                            "resource pool for project \"%s\"", resultp->pj_name);
                   1237:                break;
                   1238:            default:
                   1239:                if (errval <= 0) {
                   1240:                    log_error(errflags, "setproject failed for project \"%s\"",
                   1241:                        resultp->pj_name);
                   1242:                } else {
                   1243:                    log_error(errflags, "warning, resource control assignment "
                   1244:                        "failed for project \"%s\"", resultp->pj_name);
                   1245:                }
                   1246:            }
                   1247:        }
                   1248:     } else {
                   1249:        log_error(errflags, "getdefaultproj() error: %s", strerror(errno));
                   1250:     }
                   1251:     endprojent();
                   1252: }
                   1253: #else
                   1254: static void
                   1255: set_project(pw)
                   1256:     struct passwd *pw;
                   1257: {
                   1258: }
                   1259: #endif /* HAVE_PROJECT_H */
                   1260:
1.1       millert  1261: /*
1.2       millert  1262:  * Look up the fully qualified domain name and set user_host and user_shost.
                   1263:  */
                   1264: void
                   1265: set_fqdn()
                   1266: {
1.28      millert  1267: #ifdef HAVE_GETADDRINFO
                   1268:     struct addrinfo *res0, hint;
                   1269: #else
1.2       millert  1270:     struct hostent *hp;
1.28      millert  1271: #endif
1.2       millert  1272:     char *p;
                   1273:
1.28      millert  1274: #ifdef HAVE_GETADDRINFO
1.34    ! millert  1275:     zero_bytes(&hint, sizeof(hint));
1.28      millert  1276:     hint.ai_family = PF_UNSPEC;
                   1277:     hint.ai_flags = AI_CANONNAME;
                   1278:     if (getaddrinfo(user_host, NULL, &hint, &res0) != 0) {
                   1279: #else
1.14      millert  1280:     if (!(hp = gethostbyname(user_host))) {
1.28      millert  1281: #endif
1.14      millert  1282:        log_error(MSG_ONLY|NO_EXIT,
1.28      millert  1283:            "unable to resolve host %s", user_host);
1.14      millert  1284:     } else {
                   1285:        if (user_shost != user_host)
1.27      millert  1286:            efree(user_shost);
                   1287:        efree(user_host);
1.28      millert  1288: #ifdef HAVE_GETADDRINFO
                   1289:        user_host = estrdup(res0->ai_canonname);
                   1290:        freeaddrinfo(res0);
                   1291: #else
1.14      millert  1292:        user_host = estrdup(hp->h_name);
1.28      millert  1293: #endif
1.2       millert  1294:     }
                   1295:     if ((p = strchr(user_host, '.'))) {
                   1296:        *p = '\0';
                   1297:        user_shost = estrdup(user_host);
                   1298:        *p = '.';
                   1299:     } else {
                   1300:        user_shost = user_host;
                   1301:     }
                   1302: }
                   1303:
                   1304: /*
1.23      millert  1305:  * Get passwd entry for the user we are going to run commands as.
                   1306:  * By default, this is "root".  Updates runas_pw as a side effect.
                   1307:  */
1.34    ! millert  1308: static void
1.23      millert  1309: set_runaspw(user)
                   1310:     char *user;
                   1311: {
1.34    ! millert  1312:     if (*user == '#') {
        !          1313:        if ((runas_pw = sudo_getpwuid(atoi(user + 1))) == NULL)
        !          1314:            runas_pw = sudo_fakepwnam(user, runas_gr ? runas_gr->gr_gid : 0);
        !          1315:     } else {
        !          1316:        if ((runas_pw = sudo_getpwnam(user)) == NULL)
        !          1317:            log_error(NO_MAIL|MSG_ONLY, "unknown user: %s", user);
1.23      millert  1318:     }
1.34    ! millert  1319: }
        !          1320:
        !          1321: /*
        !          1322:  * Get group entry for the group we are going to run commands as.
        !          1323:  * Updates runas_pw as a side effect.
        !          1324:  */
        !          1325: static void
        !          1326: set_runasgr(group)
        !          1327:     char *group;
        !          1328: {
        !          1329:     if (*group == '#') {
        !          1330:        if ((runas_gr = sudo_getgrgid(atoi(group + 1))) == NULL)
        !          1331:            runas_gr = sudo_fakegrnam(group);
1.23      millert  1332:     } else {
1.34    ! millert  1333:        if ((runas_gr = sudo_getgrnam(group)) == NULL)
        !          1334:            log_error(NO_MAIL|MSG_ONLY, "unknown group: %s", group);
1.23      millert  1335:     }
                   1336: }
                   1337:
                   1338: /*
1.6       millert  1339:  * Get passwd entry for the user we are going to authenticate as.
1.23      millert  1340:  * By default, this is the user invoking sudo.  In the most common
                   1341:  * case, this matches sudo_user.pw or runas_pw.
1.4       millert  1342:  */
1.6       millert  1343: static struct passwd *
                   1344: get_authpw()
1.4       millert  1345: {
                   1346:     struct passwd *pw;
                   1347:
1.23      millert  1348:     if (def_rootpw) {
1.34    ! millert  1349:        if ((pw = sudo_getpwuid(0)) == NULL)
        !          1350:            log_error(0, "unknown uid: 0");
1.23      millert  1351:     } else if (def_runaspw) {
1.34    ! millert  1352:        if ((pw = sudo_getpwnam(def_runas_default)) == NULL)
        !          1353:            log_error(0, "unknown user: %s", def_runas_default);
1.23      millert  1354:     } else if (def_targetpw) {
                   1355:        if (runas_pw->pw_name == NULL)
1.34    ! millert  1356:            log_error(NO_MAIL|MSG_ONLY, "unknown uid: %lu",
1.25      millert  1357:                (unsigned long) runas_pw->pw_uid);
1.23      millert  1358:        pw = runas_pw;
1.6       millert  1359:     } else
                   1360:        pw = sudo_user.pw;
                   1361:
                   1362:     return(pw);
1.4       millert  1363: }
                   1364:
                   1365: /*
1.34    ! millert  1366:  * Cleanup hook for error()/errorx()
        !          1367:  */
        !          1368: void
        !          1369: cleanup(gotsignal)
        !          1370:     int gotsignal;
        !          1371: {
        !          1372:     struct sudo_nss *nss;
        !          1373:
        !          1374:     if (!gotsignal) {
        !          1375:        if (snl != NULL) {
        !          1376:            tq_foreach_fwd(snl, nss)
        !          1377:                nss->close(nss);
        !          1378:        }
        !          1379:        sudo_endpwent();
        !          1380:        sudo_endgrent();
        !          1381:     }
        !          1382: }
        !          1383:
        !          1384: static void
        !          1385: show_version()
        !          1386: {
        !          1387:     (void) printf("Sudo version %s\n", version);
        !          1388:     if (getuid() == 0) {
        !          1389:        putchar('\n');
        !          1390:        (void) printf("Sudoers path: %s\n", _PATH_SUDOERS);
        !          1391: #ifdef HAVE_LDAP
        !          1392: # ifdef _PATH_NSSWITCH_CONF
        !          1393:        (void) printf("nsswitch path: %s\n", _PATH_NSSWITCH_CONF);
        !          1394: # endif
        !          1395:        (void) printf("ldap.conf path: %s\n", _PATH_LDAP_CONF);
        !          1396:        (void) printf("ldap.secret path: %s\n", _PATH_LDAP_SECRET);
        !          1397: #endif
        !          1398:        dump_auth_methods();
        !          1399:        dump_defaults();
        !          1400:        dump_interfaces();
        !          1401:     }
        !          1402:     exit(0);
        !          1403: }
        !          1404:
        !          1405: /*
1.1       millert  1406:  * Tell which options are mutually exclusive and exit.
                   1407:  */
                   1408: static void
                   1409: usage_excl(exit_val)
                   1410:     int exit_val;
                   1411: {
1.34    ! millert  1412:     warningx("Only one of the -e, -h, -i, -k, -K, -l, -s, -v or -V options may be specified");
1.1       millert  1413:     usage(exit_val);
                   1414: }
                   1415:
                   1416: /*
                   1417:  * Give usage message and exit.
1.34    ! millert  1418:  * The actual usage strings are in sudo_usage.h for configure substitution.
1.1       millert  1419:  */
                   1420: static void
                   1421: usage(exit_val)
                   1422:     int exit_val;
                   1423: {
1.34    ! millert  1424:     struct lbuf lbuf;
        !          1425:     char *uvec[5];
        !          1426:     int i, ulen;
1.23      millert  1427:
                   1428:     /*
1.27      millert  1429:      * Use usage vectors appropriate to the progname.
1.23      millert  1430:      */
                   1431:     if (strcmp(getprogname(), "sudoedit") == 0) {
1.34    ! millert  1432:        uvec[0] = SUDO_USAGE4 + 3;
1.27      millert  1433:        uvec[1] = NULL;
1.23      millert  1434:     } else {
1.34    ! millert  1435:        uvec[0] = SUDO_USAGE1;
        !          1436:        uvec[1] = SUDO_USAGE2;
        !          1437:        uvec[2] = SUDO_USAGE3;
        !          1438:        uvec[3] = SUDO_USAGE4;
        !          1439:        uvec[4] = NULL;
1.23      millert  1440:     }
                   1441:
                   1442:     /*
1.34    ! millert  1443:      * Print usage and wrap lines as needed, depending on the
        !          1444:      * tty width.
1.23      millert  1445:      */
1.34    ! millert  1446:     ulen = (int)strlen(getprogname()) + 8;
        !          1447:     lbuf_init(&lbuf, NULL, ulen, 0);
1.27      millert  1448:     for (i = 0; uvec[i] != NULL; i++) {
1.34    ! millert  1449:        lbuf_append(&lbuf, "usage: ", getprogname(), uvec[i], NULL);
        !          1450:        lbuf_print(&lbuf);
1.23      millert  1451:     }
1.34    ! millert  1452:     lbuf_destroy(&lbuf);
1.1       millert  1453:     exit(exit_val);
                   1454: }