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

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.37    ! millert   105: __unused static const char rcsid[] = "$Sudo: sudo.c,v 1.501 2009/01/09 00:13:37 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.35      deraadt   174:     struct sudo_nss *nss;
1.34      millert   175: #if defined(SUDO_DEVEL) && defined(__OpenBSD__)
                    176:     extern char *malloc_options;
                    177:     malloc_options = "AFGJPR";
                    178: #endif
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);
1.37    ! millert  1080:     else {
1.34      millert  1081:        /*
                   1082:         * Make sure we can actually read sudoers so we can present the
1.37    ! millert  1083:         * user with a reasonable error message (unlike the lexer).
1.34      millert  1084:         */
1.37    ! millert  1085:        if (statbuf.st_size != 0) {
        !          1086:            if (fgetc(fp) == EOF)
        !          1087:                log_error(USE_ERRNO, "can't read %s", sudoers);
        !          1088:            rewind(fp);
        !          1089:        }
        !          1090:        (void) fcntl(fileno(fp), F_SETFD, 1);
1.1       millert  1091:     }
                   1092:
1.17      millert  1093:     set_perms(PERM_ROOT);              /* change back to root */
1.34      millert  1094:     return(fp);
1.1       millert  1095: }
                   1096:
                   1097: /*
                   1098:  * Close all open files (except std*) and turn off core dumps.
1.34      millert  1099:  * Also sets the set_perms() pointer to the correct function.
1.1       millert  1100:  */
                   1101: static void
                   1102: initial_setup()
                   1103: {
1.27      millert  1104:     int miss[3], devnull = -1;
1.33      millert  1105: #if defined(__linux__) || (defined(RLIMIT_CORE) && !defined(SUDO_DEVEL))
1.1       millert  1106:     struct rlimit rl;
1.33      millert  1107: #endif
1.1       millert  1108:
1.33      millert  1109: #if defined(__linux__)
                   1110:     /*
                   1111:      * Unlimit the number of processes since Linux's setuid() will
                   1112:      * apply resource limits when changing uid and return EAGAIN if
                   1113:      * nproc would be violated by the uid switch.
                   1114:      */
                   1115:     rl.rlim_cur = rl.rlim_max = RLIM_INFINITY;
                   1116:     if (setrlimit(RLIMIT_NPROC, &rl)) {
                   1117:        if (getrlimit(RLIMIT_NPROC, &rl) == 0) {
                   1118:            rl.rlim_cur = rl.rlim_max;
                   1119:            (void)setrlimit(RLIMIT_NPROC, &rl);
                   1120:        }
                   1121:     }
                   1122: #endif /* __linux__ */
                   1123: #if defined(RLIMIT_CORE) && !defined(SUDO_DEVEL)
1.1       millert  1124:     /*
                   1125:      * Turn off core dumps.
                   1126:      */
1.4       millert  1127:     (void) getrlimit(RLIMIT_CORE, &corelimit);
1.20      millert  1128:     memcpy(&rl, &corelimit, sizeof(struct rlimit));
                   1129:     rl.rlim_cur = 0;
1.1       millert  1130:     (void) setrlimit(RLIMIT_CORE, &rl);
1.20      millert  1131: #endif /* RLIMIT_CORE && !SUDO_DEVEL */
1.1       millert  1132:
1.17      millert  1133:     /*
1.27      millert  1134:      * stdin, stdout and stderr must be open; set them to /dev/null
                   1135:      * if they are closed and close all other fds.
1.17      millert  1136:      */
1.27      millert  1137:     miss[STDIN_FILENO] = fcntl(STDIN_FILENO, F_GETFL, 0) == -1;
                   1138:     miss[STDOUT_FILENO] = fcntl(STDOUT_FILENO, F_GETFL, 0) == -1;
                   1139:     miss[STDERR_FILENO] = fcntl(STDERR_FILENO, F_GETFL, 0) == -1;
                   1140:     if (miss[STDIN_FILENO] || miss[STDOUT_FILENO] || miss[STDERR_FILENO]) {
                   1141:        if ((devnull = open(_PATH_DEVNULL, O_RDWR, 0644)) != -1) {
                   1142:            if (miss[STDIN_FILENO])
                   1143:                (void) dup2(devnull, STDIN_FILENO);
                   1144:            if (miss[STDOUT_FILENO])
                   1145:                (void) dup2(devnull, STDOUT_FILENO);
                   1146:            if (miss[STDERR_FILENO])
                   1147:                (void) dup2(devnull, STDERR_FILENO);
1.34      millert  1148:            if (devnull > STDERR_FILENO)
                   1149:                close(devnull);
1.27      millert  1150:        }
                   1151:     }
1.1       millert  1152: }
                   1153:
1.8       millert  1154: #ifdef HAVE_LOGIN_CAP_H
                   1155: static void
1.4       millert  1156: set_loginclass(pw)
                   1157:     struct passwd *pw;
                   1158: {
                   1159:     int errflags;
                   1160:
                   1161:     /*
                   1162:      * Don't make it a fatal error if the user didn't specify the login
                   1163:      * class themselves.  We do this because if login.conf gets
                   1164:      * corrupted we want the admin to be able to use sudo to fix it.
                   1165:      */
                   1166:     if (login_class)
                   1167:        errflags = NO_MAIL|MSG_ONLY;
                   1168:     else
                   1169:        errflags = NO_MAIL|MSG_ONLY|NO_EXIT;
                   1170:
                   1171:     if (login_class && strcmp(login_class, "-") != 0) {
1.34      millert  1172:        if (user_uid != 0 &&
                   1173:            strcmp(runas_user ? runas_user : def_runas_default, "root") != 0)
                   1174:            errorx(1, "only root can use -c %s", login_class);
1.4       millert  1175:     } else {
                   1176:        login_class = pw->pw_class;
                   1177:        if (!login_class || !*login_class)
                   1178:            login_class =
                   1179:                (pw->pw_uid == 0) ? LOGIN_DEFROOTCLASS : LOGIN_DEFCLASS;
                   1180:     }
                   1181:
                   1182:     lc = login_getclass(login_class);
1.10      millert  1183:     if (!lc || !lc->lc_class || strcmp(lc->lc_class, login_class) != 0) {
1.4       millert  1184:        log_error(errflags, "unknown login class: %s", login_class);
1.11      millert  1185:        if (!lc)
                   1186:            lc = login_getclass(NULL);  /* needed for login_getstyle() later */
1.10      millert  1187:     }
1.4       millert  1188: }
                   1189: #else
1.8       millert  1190: static void
1.4       millert  1191: set_loginclass(pw)
                   1192:     struct passwd *pw;
                   1193: {
                   1194: }
1.8       millert  1195: #endif /* HAVE_LOGIN_CAP_H */
1.4       millert  1196:
1.27      millert  1197: #ifdef HAVE_PROJECT_H
                   1198: static void
                   1199: set_project(pw)
                   1200:     struct passwd *pw;
                   1201: {
                   1202:     int errflags = NO_MAIL|MSG_ONLY|NO_EXIT;
                   1203:     int errval;
                   1204:     struct project proj;
                   1205:     struct project *resultp = '\0';
                   1206:     char buf[1024];
                   1207:
                   1208:     /*
                   1209:      * Collect the default project for the user and settaskid
                   1210:      */
                   1211:     setprojent();
                   1212:     if (resultp = getdefaultproj(pw->pw_name, &proj, buf, sizeof(buf))) {
                   1213:        errval = setproject(resultp->pj_name, pw->pw_name, TASK_NORMAL);
                   1214:        if (errval != 0) {
                   1215:            switch(errval) {
                   1216:            case SETPROJ_ERR_TASK:
                   1217:                if (errno == EAGAIN)
                   1218:                    log_error(errflags, "resource control limit has been reached");
                   1219:                else if (errno == ESRCH)
                   1220:                    log_error(errflags, "user \"%s\" is not a member of "
                   1221:                        "project \"%s\"", pw->pw_name, resultp->pj_name);
                   1222:                else if (errno == EACCES)
                   1223:                    log_error(errflags, "the invoking task is final");
                   1224:                else
                   1225:                    log_error(errflags, "could not join project \"%s\"",
                   1226:                        resultp->pj_name);
                   1227:                break;
                   1228:            case SETPROJ_ERR_POOL:
                   1229:                if (errno == EACCES)
                   1230:                    log_error(errflags, "no resource pool accepting "
                   1231:                            "default bindings exists for project \"%s\"",
                   1232:                            resultp->pj_name);
                   1233:                else if (errno == ESRCH)
                   1234:                    log_error(errflags, "specified resource pool does "
                   1235:                            "not exist for project \"%s\"", resultp->pj_name);
                   1236:                else
                   1237:                    log_error(errflags, "could not bind to default "
                   1238:                            "resource pool for project \"%s\"", resultp->pj_name);
                   1239:                break;
                   1240:            default:
                   1241:                if (errval <= 0) {
                   1242:                    log_error(errflags, "setproject failed for project \"%s\"",
                   1243:                        resultp->pj_name);
                   1244:                } else {
                   1245:                    log_error(errflags, "warning, resource control assignment "
                   1246:                        "failed for project \"%s\"", resultp->pj_name);
                   1247:                }
                   1248:            }
                   1249:        }
                   1250:     } else {
                   1251:        log_error(errflags, "getdefaultproj() error: %s", strerror(errno));
                   1252:     }
                   1253:     endprojent();
                   1254: }
                   1255: #else
                   1256: static void
                   1257: set_project(pw)
                   1258:     struct passwd *pw;
                   1259: {
                   1260: }
                   1261: #endif /* HAVE_PROJECT_H */
                   1262:
1.1       millert  1263: /*
1.2       millert  1264:  * Look up the fully qualified domain name and set user_host and user_shost.
                   1265:  */
                   1266: void
                   1267: set_fqdn()
                   1268: {
1.28      millert  1269: #ifdef HAVE_GETADDRINFO
                   1270:     struct addrinfo *res0, hint;
                   1271: #else
1.2       millert  1272:     struct hostent *hp;
1.28      millert  1273: #endif
1.2       millert  1274:     char *p;
                   1275:
1.28      millert  1276: #ifdef HAVE_GETADDRINFO
1.34      millert  1277:     zero_bytes(&hint, sizeof(hint));
1.28      millert  1278:     hint.ai_family = PF_UNSPEC;
                   1279:     hint.ai_flags = AI_CANONNAME;
                   1280:     if (getaddrinfo(user_host, NULL, &hint, &res0) != 0) {
                   1281: #else
1.14      millert  1282:     if (!(hp = gethostbyname(user_host))) {
1.28      millert  1283: #endif
1.14      millert  1284:        log_error(MSG_ONLY|NO_EXIT,
1.28      millert  1285:            "unable to resolve host %s", user_host);
1.14      millert  1286:     } else {
                   1287:        if (user_shost != user_host)
1.27      millert  1288:            efree(user_shost);
                   1289:        efree(user_host);
1.28      millert  1290: #ifdef HAVE_GETADDRINFO
                   1291:        user_host = estrdup(res0->ai_canonname);
                   1292:        freeaddrinfo(res0);
                   1293: #else
1.14      millert  1294:        user_host = estrdup(hp->h_name);
1.28      millert  1295: #endif
1.2       millert  1296:     }
                   1297:     if ((p = strchr(user_host, '.'))) {
                   1298:        *p = '\0';
                   1299:        user_shost = estrdup(user_host);
                   1300:        *p = '.';
                   1301:     } else {
                   1302:        user_shost = user_host;
                   1303:     }
                   1304: }
                   1305:
                   1306: /*
1.23      millert  1307:  * Get passwd entry for the user we are going to run commands as.
                   1308:  * By default, this is "root".  Updates runas_pw as a side effect.
                   1309:  */
1.34      millert  1310: static void
1.23      millert  1311: set_runaspw(user)
                   1312:     char *user;
                   1313: {
1.34      millert  1314:     if (*user == '#') {
                   1315:        if ((runas_pw = sudo_getpwuid(atoi(user + 1))) == NULL)
                   1316:            runas_pw = sudo_fakepwnam(user, runas_gr ? runas_gr->gr_gid : 0);
                   1317:     } else {
                   1318:        if ((runas_pw = sudo_getpwnam(user)) == NULL)
                   1319:            log_error(NO_MAIL|MSG_ONLY, "unknown user: %s", user);
1.23      millert  1320:     }
1.34      millert  1321: }
                   1322:
                   1323: /*
                   1324:  * Get group entry for the group we are going to run commands as.
                   1325:  * Updates runas_pw as a side effect.
                   1326:  */
                   1327: static void
                   1328: set_runasgr(group)
                   1329:     char *group;
                   1330: {
                   1331:     if (*group == '#') {
                   1332:        if ((runas_gr = sudo_getgrgid(atoi(group + 1))) == NULL)
                   1333:            runas_gr = sudo_fakegrnam(group);
1.23      millert  1334:     } else {
1.34      millert  1335:        if ((runas_gr = sudo_getgrnam(group)) == NULL)
                   1336:            log_error(NO_MAIL|MSG_ONLY, "unknown group: %s", group);
1.23      millert  1337:     }
                   1338: }
                   1339:
                   1340: /*
1.6       millert  1341:  * Get passwd entry for the user we are going to authenticate as.
1.23      millert  1342:  * By default, this is the user invoking sudo.  In the most common
                   1343:  * case, this matches sudo_user.pw or runas_pw.
1.4       millert  1344:  */
1.6       millert  1345: static struct passwd *
                   1346: get_authpw()
1.4       millert  1347: {
                   1348:     struct passwd *pw;
                   1349:
1.23      millert  1350:     if (def_rootpw) {
1.34      millert  1351:        if ((pw = sudo_getpwuid(0)) == NULL)
                   1352:            log_error(0, "unknown uid: 0");
1.23      millert  1353:     } else if (def_runaspw) {
1.34      millert  1354:        if ((pw = sudo_getpwnam(def_runas_default)) == NULL)
                   1355:            log_error(0, "unknown user: %s", def_runas_default);
1.23      millert  1356:     } else if (def_targetpw) {
                   1357:        if (runas_pw->pw_name == NULL)
1.34      millert  1358:            log_error(NO_MAIL|MSG_ONLY, "unknown uid: %lu",
1.25      millert  1359:                (unsigned long) runas_pw->pw_uid);
1.23      millert  1360:        pw = runas_pw;
1.6       millert  1361:     } else
                   1362:        pw = sudo_user.pw;
                   1363:
                   1364:     return(pw);
1.4       millert  1365: }
                   1366:
                   1367: /*
1.34      millert  1368:  * Cleanup hook for error()/errorx()
                   1369:  */
                   1370: void
                   1371: cleanup(gotsignal)
                   1372:     int gotsignal;
                   1373: {
                   1374:     struct sudo_nss *nss;
                   1375:
                   1376:     if (!gotsignal) {
                   1377:        if (snl != NULL) {
                   1378:            tq_foreach_fwd(snl, nss)
                   1379:                nss->close(nss);
                   1380:        }
                   1381:        sudo_endpwent();
                   1382:        sudo_endgrent();
                   1383:     }
                   1384: }
                   1385:
                   1386: static void
                   1387: show_version()
                   1388: {
                   1389:     (void) printf("Sudo version %s\n", version);
                   1390:     if (getuid() == 0) {
                   1391:        putchar('\n');
                   1392:        (void) printf("Sudoers path: %s\n", _PATH_SUDOERS);
                   1393: #ifdef HAVE_LDAP
                   1394: # ifdef _PATH_NSSWITCH_CONF
                   1395:        (void) printf("nsswitch path: %s\n", _PATH_NSSWITCH_CONF);
                   1396: # endif
                   1397:        (void) printf("ldap.conf path: %s\n", _PATH_LDAP_CONF);
                   1398:        (void) printf("ldap.secret path: %s\n", _PATH_LDAP_SECRET);
                   1399: #endif
                   1400:        dump_auth_methods();
                   1401:        dump_defaults();
                   1402:        dump_interfaces();
                   1403:     }
                   1404:     exit(0);
                   1405: }
                   1406:
                   1407: /*
1.1       millert  1408:  * Tell which options are mutually exclusive and exit.
                   1409:  */
                   1410: static void
                   1411: usage_excl(exit_val)
                   1412:     int exit_val;
                   1413: {
1.34      millert  1414:     warningx("Only one of the -e, -h, -i, -k, -K, -l, -s, -v or -V options may be specified");
1.1       millert  1415:     usage(exit_val);
                   1416: }
                   1417:
                   1418: /*
                   1419:  * Give usage message and exit.
1.34      millert  1420:  * The actual usage strings are in sudo_usage.h for configure substitution.
1.1       millert  1421:  */
                   1422: static void
                   1423: usage(exit_val)
                   1424:     int exit_val;
                   1425: {
1.34      millert  1426:     struct lbuf lbuf;
                   1427:     char *uvec[5];
                   1428:     int i, ulen;
1.23      millert  1429:
                   1430:     /*
1.27      millert  1431:      * Use usage vectors appropriate to the progname.
1.23      millert  1432:      */
                   1433:     if (strcmp(getprogname(), "sudoedit") == 0) {
1.34      millert  1434:        uvec[0] = SUDO_USAGE4 + 3;
1.27      millert  1435:        uvec[1] = NULL;
1.23      millert  1436:     } else {
1.34      millert  1437:        uvec[0] = SUDO_USAGE1;
                   1438:        uvec[1] = SUDO_USAGE2;
                   1439:        uvec[2] = SUDO_USAGE3;
                   1440:        uvec[3] = SUDO_USAGE4;
                   1441:        uvec[4] = NULL;
1.23      millert  1442:     }
                   1443:
                   1444:     /*
1.34      millert  1445:      * Print usage and wrap lines as needed, depending on the
                   1446:      * tty width.
1.23      millert  1447:      */
1.34      millert  1448:     ulen = (int)strlen(getprogname()) + 8;
                   1449:     lbuf_init(&lbuf, NULL, ulen, 0);
1.27      millert  1450:     for (i = 0; uvec[i] != NULL; i++) {
1.34      millert  1451:        lbuf_append(&lbuf, "usage: ", getprogname(), uvec[i], NULL);
                   1452:        lbuf_print(&lbuf);
1.23      millert  1453:     }
1.34      millert  1454:     lbuf_destroy(&lbuf);
1.1       millert  1455:     exit(exit_val);
                   1456: }