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

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