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

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