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

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:
1.40    ! millert   651:     if ((p = ttyname(STDIN_FILENO)) || (p = ttyname(STDOUT_FILENO)) ||
        !           652:        (p = ttyname(STDERR_FILENO))) {
1.30      millert   653:        user_tty = user_ttypath = estrdup(p);
                    654:        if (strncmp(user_tty, _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0)
                    655:            user_tty += sizeof(_PATH_DEV) - 1;
1.1       millert   656:     } else
                    657:        user_tty = "unknown";
                    658:
1.27      millert   659:     for (ep = envp; *ep; ep++) {
1.34      millert   660:        /* XXX - don't fill in if empty string */
1.27      millert   661:        switch (**ep) {
1.34      millert   662:            case 'D':
                    663:                if (strncmp("DISPLAY=", *ep, 8) == 0)
                    664:                    user_display = *ep + 8;
                    665:                break;
                    666:            case 'K':
                    667:                if (strncmp("KRB5CCNAME=", *ep, 11) == 0)
                    668:                    user_ccname = *ep + 11;
                    669:                break;
1.27      millert   670:            case 'P':
                    671:                if (strncmp("PATH=", *ep, 5) == 0)
                    672:                    user_path = *ep + 5;
                    673:                break;
                    674:            case 'S':
                    675:                if (strncmp("SHELL=", *ep, 6) == 0)
                    676:                    user_shell = *ep + 6;
                    677:                else if (!user_prompt && strncmp("SUDO_PROMPT=", *ep, 12) == 0)
                    678:                    user_prompt = *ep + 12;
                    679:                else if (strncmp("SUDO_USER=", *ep, 10) == 0)
                    680:                    prev_user = *ep + 10;
1.34      millert   681:                else if (strncmp("SUDO_ASKPASS=", *ep, 13) == 0)
                    682:                    user_askpass = *ep + 13;
1.27      millert   683:                break;
                    684:            }
                    685:     }
                    686:
1.1       millert   687:     /*
                    688:      * Get a local copy of the user's struct passwd with the shadow password
                    689:      * if necessary.  It is assumed that euid is 0 at this point so we
                    690:      * can read the shadow passwd file if necessary.
                    691:      */
                    692:     if ((sudo_user.pw = sudo_getpwuid(getuid())) == NULL) {
                    693:        /* Need to make a fake struct passwd for logging to work. */
                    694:        struct passwd pw;
                    695:        char pw_name[MAX_UID_T_LEN + 1];
                    696:
                    697:        pw.pw_uid = getuid();
1.17      millert   698:        (void) snprintf(pw_name, sizeof(pw_name), "%lu",
                    699:            (unsigned long) pw.pw_uid);
1.1       millert   700:        pw.pw_name = pw_name;
                    701:        sudo_user.pw = &pw;
                    702:
1.21      millert   703:        /*
                    704:         * If we are in -k/-K mode, just spew to stderr.  It is not unusual for
                    705:         * users to place "sudo -k" in a .logout file which can cause sudo to
                    706:         * be run during reboot after the YP/NIS/NIS+/LDAP/etc daemon has died.
                    707:         */
1.38      millert   708:        if (sudo_mode == MODE_KILL || sudo_mode == MODE_INVALIDATE)
1.34      millert   709:            errorx(1, "unknown uid: %s", pw_name);
                    710:        log_error(0, "unknown uid: %s", pw_name);
1.1       millert   711:     }
1.15      millert   712:     if (user_shell == NULL || *user_shell == '\0')
1.34      millert   713:        user_shell = estrdup(sudo_user.pw->pw_shell);
1.1       millert   714:
                    715:     /* It is now safe to use log_error() and set_perms() */
                    716:
1.27      millert   717: #ifdef HAVE_GETGROUPS
                    718:     if ((user_ngroups = getgroups(0, NULL)) > 0) {
1.31      millert   719:        user_groups = emalloc2(user_ngroups, sizeof(GETGROUPS_T));
1.27      millert   720:        if (getgroups(user_ngroups, user_groups) < 0)
                    721:            log_error(USE_ERRNO|MSG_ONLY, "can't get group vector");
                    722:     } else
                    723:        user_ngroups = 0;
                    724: #endif
                    725:
1.23      millert   726:     if (def_fqdn)
                    727:        set_fqdn();                     /* may call log_error() */
1.11      millert   728:
                    729:     if (nohostname)
                    730:        log_error(USE_ERRNO|MSG_ONLY, "can't get hostname");
                    731:
                    732:     /*
1.1       millert   733:      * Get current working directory.  Try as user, fall back to root.
                    734:      */
1.17      millert   735:     set_perms(PERM_USER);
1.1       millert   736:     if (!getcwd(user_cwd, sizeof(user_cwd))) {
1.17      millert   737:        set_perms(PERM_ROOT);
1.1       millert   738:        if (!getcwd(user_cwd, sizeof(user_cwd))) {
1.34      millert   739:            warningx("cannot get working directory");
1.17      millert   740:            (void) strlcpy(user_cwd, "unknown", sizeof(user_cwd));
1.1       millert   741:        }
                    742:     } else
1.17      millert   743:        set_perms(PERM_ROOT);
1.1       millert   744:
                    745:     /*
1.23      millert   746:      * If we were given the '-e', '-i' or '-s' options we need to redo
1.1       millert   747:      * NewArgv and NewArgc.
                    748:      */
1.34      millert   749:     if (ISSET(sudo_mode, MODE_EDIT)) {
                    750:        NewArgv--;
                    751:        NewArgc++;
                    752:        NewArgv[0] = "sudoedit";
                    753:     } else if (ISSET(sudo_mode, MODE_SHELL)) {
                    754:        char **av;
1.1       millert   755:
1.27      millert   756:        /* Allocate an extra slot for execve() failure (ENOEXEC). */
1.34      millert   757:        av = (char **) emalloc2(5, sizeof(char *));
                    758:        av++;
1.1       millert   759:
1.34      millert   760:        av[0] = user_shell;     /* may be updated later */
                    761:        if (NewArgc > 0) {
                    762:            size_t size;
                    763:            char *cmnd, *src, *dst, *end;
                    764:            size = (size_t) (NewArgv[NewArgc - 1] - NewArgv[0]) +
                    765:                    strlen(NewArgv[NewArgc - 1]) + 1;
                    766:            cmnd = emalloc(size);
                    767:            src = NewArgv[0];
                    768:            dst = cmnd;
                    769:            for (end = src + size - 1; src < end; src++, dst++)
                    770:                *dst = *src == 0 ? ' ' : *src;
                    771:            *dst = '\0';
                    772:            av[1] = "-c";
                    773:            av[2] = cmnd;
                    774:            NewArgc = 2;
                    775:        }
                    776:        av[++NewArgc] = NULL;
                    777:        NewArgv = av;
1.1       millert   778:     }
1.34      millert   779: }
1.1       millert   780:
1.34      millert   781: /*
                    782:  * Fill in user_cmnd, user_args, user_base and user_stat variables
                    783:  * and apply any command-specific defaults entries.
                    784:  */
                    785: static int
                    786: set_cmnd(sudo_mode)
                    787:     int sudo_mode;
                    788: {
                    789:     int rval;
1.8       millert   790:
1.27      millert   791:     /* Set project if applicable. */
                    792:     set_project(runas_pw);
                    793:
1.1       millert   794:     /* Resolve the path and return. */
1.23      millert   795:     rval = FOUND;
                    796:     user_stat = emalloc(sizeof(struct stat));
1.34      millert   797:     if (sudo_mode & (MODE_RUN | MODE_EDIT | MODE_CHECK)) {
                    798:        if (ISSET(sudo_mode, MODE_RUN | MODE_CHECK)) {
1.23      millert   799:            set_perms(PERM_RUNAS);
                    800:            rval = find_path(NewArgv[0], &user_cmnd, user_stat, user_path);
1.17      millert   801:            set_perms(PERM_ROOT);
1.23      millert   802:            if (rval != FOUND) {
                    803:                /* Failed as root, try as invoking user. */
                    804:                set_perms(PERM_USER);
                    805:                rval = find_path(NewArgv[0], &user_cmnd, user_stat, user_path);
                    806:                set_perms(PERM_ROOT);
                    807:            }
1.11      millert   808:        }
                    809:
                    810:        /* set user_args */
                    811:        if (NewArgc > 1) {
                    812:            char *to, **from;
1.17      millert   813:            size_t size, n;
1.11      millert   814:
1.23      millert   815:            /* If we didn't realloc NewArgv it is contiguous so just count. */
1.34      millert   816:            if (!ISSET(sudo_mode, MODE_SHELL)) {
1.11      millert   817:                size = (size_t) (NewArgv[NewArgc-1] - NewArgv[1]) +
                    818:                        strlen(NewArgv[NewArgc-1]) + 1;
                    819:            } else {
                    820:                for (size = 0, from = NewArgv + 1; *from; from++)
                    821:                    size += strlen(*from) + 1;
                    822:            }
                    823:
1.23      millert   824:            /* Alloc and build up user_args. */
1.17      millert   825:            user_args = (char *) emalloc(size);
                    826:            for (to = user_args, from = NewArgv + 1; *from; from++) {
                    827:                n = strlcpy(to, *from, size - (to - user_args));
1.19      millert   828:                if (n >= size - (to - user_args))
1.34      millert   829:                    errorx(1, "internal error, init_vars() overflow");
1.17      millert   830:                to += n;
1.11      millert   831:                *to++ = ' ';
                    832:            }
                    833:            *--to = '\0';
                    834:        }
1.23      millert   835:     }
                    836:     if ((user_base = strrchr(user_cmnd, '/')) != NULL)
                    837:        user_base++;
                    838:     else
                    839:        user_base = user_cmnd;
1.11      millert   840:
1.34      millert   841:     if (!update_defaults(SETDEF_CMND))
                    842:        log_error(NO_STDERR|NO_EXIT, "problem with defaults entries");
                    843:
1.39      millert   844:     if (!runas_user && !runas_group)
1.38      millert   845:        set_runaspw(def_runas_default); /* may have been updated above */
                    846:
1.11      millert   847:     return(rval);
1.1       millert   848: }
                    849:
                    850: /*
1.34      millert   851:  * Command line argument parsing.
                    852:  * Sets NewArgc and NewArgv which corresponds to the argc/argv we'll use
                    853:  * for the command to be run (if we are running one).
1.1       millert   854:  */
                    855: static int
1.19      millert   856: parse_args(argc, argv)
                    857:     int argc;
                    858:     char **argv;
1.1       millert   859: {
1.34      millert   860:     int mode = 0;              /* what mode is sudo to be run in? */
                    861:     int flags = 0;             /* mode flags */
1.38      millert   862:     int valid_flags, ch;
1.1       millert   863:
1.23      millert   864:     /* First, check to see if we were invoked as "sudoedit". */
1.34      millert   865:     if (strcmp(getprogname(), "sudoedit") == 0)
                    866:        mode = MODE_EDIT;
1.23      millert   867:
1.34      millert   868:     /* Returns true if the last option string was "--" */
                    869: #define got_end_of_args        (optind > 1 && argv[optind - 1][0] == '-' && \
                    870:            argv[optind - 1][1] == '-' && argv[optind - 1][2] == '\0')
                    871:
                    872:     /* Returns true if next option is an environment variable */
                    873: #define is_envar (optind < argc && argv[optind][0] != '/' && \
                    874:            strchr(argv[optind], '=') != NULL)
1.27      millert   875:
1.38      millert   876:     /* Flags allowed when running a command */
                    877:     valid_flags = MODE_BACKGROUND|MODE_PRESERVE_ENV|MODE_RESET_HOME|
                    878:                  MODE_LOGIN_SHELL|MODE_INVALIDATE|MODE_NONINTERACTIVE|
                    879:                  MODE_PRESERVE_GROUPS|MODE_SHELL;
1.34      millert   880:     for (;;) {
                    881:        /*
                    882:         * We disable arg permutation for GNU getopt().
                    883:         * Some trickiness is required to allow environment variables
                    884:         * to be interspersed with command line options.
                    885:         */
                    886:        if ((ch = getopt(argc, argv, "+Aa:bC:c:Eeg:HhiKkLlnPp:r:Sst:U:u:Vv")) != -1) {
                    887:            switch (ch) {
                    888:                case 'A':
                    889:                    SET(tgetpass_flags, TGP_ASKPASS);
1.27      millert   890:                    break;
1.8       millert   891: #ifdef HAVE_BSD_AUTH_H
1.27      millert   892:                case 'a':
1.34      millert   893:                    login_style = optarg;
                    894:                    break;
                    895: #endif
                    896:                case 'b':
                    897:                    SET(flags, MODE_BACKGROUND);
                    898:                    break;
                    899:                case 'C':
                    900:                    if ((user_closefrom = atoi(optarg)) < 3) {
                    901:                        warningx("the argument to -C must be at least 3");
1.27      millert   902:                        usage(1);
1.34      millert   903:                    }
1.27      millert   904:                    break;
1.8       millert   905: #ifdef HAVE_LOGIN_CAP_H
1.27      millert   906:                case 'c':
1.34      millert   907:                    login_class = optarg;
1.27      millert   908:                    def_use_loginclass = TRUE;
                    909:                    break;
1.4       millert   910: #endif
1.34      millert   911:                case 'E':
                    912:                    SET(flags, MODE_PRESERVE_ENV);
1.27      millert   913:                    break;
                    914:                case 'e':
1.34      millert   915:                    if (mode && mode != MODE_EDIT)
1.27      millert   916:                        usage_excl(1);
1.34      millert   917:                    mode = MODE_EDIT;
1.38      millert   918:                    valid_flags = MODE_INVALIDATE|MODE_NONINTERACTIVE;
1.34      millert   919:                    break;
                    920:                case 'g':
                    921:                    runas_group = optarg;
                    922:                    break;
                    923:                case 'H':
                    924:                    SET(flags, MODE_RESET_HOME);
1.27      millert   925:                    break;
1.34      millert   926:                case 'h':
1.38      millert   927:                    if (mode && mode != MODE_HELP) {
                    928:                        if (strcmp(getprogname(), "sudoedit") != 0)
                    929:                            usage_excl(1);
                    930:                    }
1.34      millert   931:                    mode = MODE_HELP;
1.38      millert   932:                    valid_flags = 0;
1.27      millert   933:                    break;
                    934:                case 'i':
1.34      millert   935:                    SET(flags, MODE_LOGIN_SHELL);
1.27      millert   936:                    def_env_reset = TRUE;
                    937:                    break;
                    938:                case 'k':
1.38      millert   939:                    SET(flags, MODE_INVALIDATE);
1.27      millert   940:                    break;
                    941:                case 'K':
1.34      millert   942:                    if (mode && mode != MODE_KILL)
1.27      millert   943:                        usage_excl(1);
1.34      millert   944:                    mode = MODE_KILL;
1.38      millert   945:                    valid_flags = 0;
1.27      millert   946:                    break;
                    947:                case 'L':
1.34      millert   948:                    if (mode && mode != MODE_LISTDEFS)
1.27      millert   949:                        usage_excl(1);
1.34      millert   950:                    mode = MODE_LISTDEFS;
1.38      millert   951:                    valid_flags = MODE_INVALIDATE|MODE_NONINTERACTIVE;
1.27      millert   952:                    break;
                    953:                case 'l':
1.34      millert   954:                    if (mode) {
                    955:                        if (mode == MODE_LIST)
                    956:                            long_list = 1;
                    957:                        else
                    958:                            usage_excl(1);
                    959:                    }
                    960:                    mode = MODE_LIST;
1.38      millert   961:                    valid_flags = MODE_INVALIDATE|MODE_NONINTERACTIVE;
1.27      millert   962:                    break;
1.34      millert   963:                case 'n':
                    964:                    SET(flags, MODE_NONINTERACTIVE);
1.27      millert   965:                    break;
1.34      millert   966:                case 'P':
                    967:                    SET(flags, MODE_PRESERVE_GROUPS);
1.27      millert   968:                    break;
1.34      millert   969:                case 'p':
                    970:                    user_prompt = optarg;
                    971:                    def_passprompt_override = TRUE;
1.27      millert   972:                    break;
1.34      millert   973: #ifdef HAVE_SELINUX
                    974:                case 'r':
                    975:                    user_role = optarg;
1.27      millert   976:                    break;
1.34      millert   977:                case 't':
                    978:                    user_type = optarg;
1.27      millert   979:                    break;
1.34      millert   980: #endif
1.27      millert   981:                case 'S':
                    982:                    SET(tgetpass_flags, TGP_STDIN);
                    983:                    break;
1.34      millert   984:                case 's':
                    985:                    SET(flags, MODE_SHELL);
                    986:                    break;
                    987:                case 'U':
                    988:                    if ((list_pw = sudo_getpwnam(optarg)) == NULL)
                    989:                        errorx(1, "unknown user: %s", optarg);
                    990:                    break;
                    991:                case 'u':
                    992:                    runas_user = optarg;
1.27      millert   993:                    break;
1.34      millert   994:                case 'v':
                    995:                    if (mode && mode != MODE_VALIDATE)
                    996:                        usage_excl(1);
                    997:                    mode = MODE_VALIDATE;
1.38      millert   998:                    valid_flags = MODE_INVALIDATE|MODE_NONINTERACTIVE;
1.33      millert   999:                    break;
1.34      millert  1000:                case 'V':
                   1001:                    if (mode && mode != MODE_VERSION)
                   1002:                        usage_excl(1);
                   1003:                    mode = MODE_VERSION;
1.38      millert  1004:                    valid_flags = 0;
1.33      millert  1005:                    break;
1.27      millert  1006:                default:
                   1007:                    usage(1);
                   1008:            }
1.34      millert  1009:        } else if (!got_end_of_args && is_envar) {
1.27      millert  1010:            struct list_member *ev;
1.34      millert  1011:
                   1012:            /* Store environment variable. */
1.27      millert  1013:            ev = emalloc(sizeof(*ev));
1.34      millert  1014:            ev->value = argv[optind];
1.27      millert  1015:            ev->next = sudo_user.env_vars;
                   1016:            sudo_user.env_vars = ev;
1.34      millert  1017:
                   1018:            /* Crank optind and resume getopt. */
                   1019:            optind++;
1.27      millert  1020:        } else {
1.34      millert  1021:            /* Not an option or an environment variable -- we're done. */
1.27      millert  1022:            break;
1.1       millert  1023:        }
                   1024:     }
1.27      millert  1025:
1.34      millert  1026:     NewArgc = argc - optind;
                   1027:     NewArgv = argv + optind;
                   1028:
1.38      millert  1029:     if (!mode) {
                   1030:        /* Defer -k mode setting until we know whether it is a flag or not */
                   1031:        if (ISSET(flags, MODE_INVALIDATE) && NewArgc == 0) {
                   1032:            mode = MODE_INVALIDATE;     /* -k by itself */
                   1033:            CLR(flags, MODE_INVALIDATE);
                   1034:            valid_flags = 0;
                   1035:        } else {
                   1036:            mode = MODE_RUN;            /* running a command */
                   1037:        }
                   1038:     }
1.34      millert  1039:
                   1040:     if (NewArgc > 0 && mode == MODE_LIST)
                   1041:        mode = MODE_CHECK;
                   1042:
                   1043:     if (ISSET(flags, MODE_LOGIN_SHELL)) {
                   1044:        if (ISSET(flags, MODE_SHELL)) {
                   1045:            warningx("you may not specify both the `-i' and `-s' options");
                   1046:            usage(1);
                   1047:        }
                   1048:        if (ISSET(flags, MODE_PRESERVE_ENV)) {
                   1049:            warningx("you may not specify both the `-i' and `-E' options");
                   1050:            usage(1);
                   1051:        }
                   1052:        SET(flags, MODE_SHELL);
                   1053:     }
1.38      millert  1054:     if ((flags & valid_flags) != flags)
                   1055:        usage(1);
1.34      millert  1056:     if (mode == MODE_EDIT &&
                   1057:        (ISSET(flags, MODE_PRESERVE_ENV) || sudo_user.env_vars != NULL)) {
                   1058:        if (ISSET(mode, MODE_PRESERVE_ENV))
                   1059:            warningx("the `-E' option is not valid in edit mode");
1.27      millert  1060:        if (sudo_user.env_vars != NULL)
1.34      millert  1061:            warningx("you may not specify environment variables in edit mode");
                   1062:        usage(1);
                   1063:     }
                   1064:     if ((runas_user != NULL || runas_group != NULL) &&
                   1065:        !ISSET(mode, MODE_EDIT | MODE_RUN | MODE_CHECK)) {
1.27      millert  1066:        usage(1);
                   1067:     }
1.34      millert  1068:     if (list_pw != NULL && mode != MODE_LIST && mode != MODE_CHECK) {
                   1069:        warningx("the `-U' option may only be used with the `-l' option");
1.33      millert  1070:        usage(1);
                   1071:     }
1.34      millert  1072:     if (ISSET(tgetpass_flags, TGP_STDIN) && ISSET(tgetpass_flags, TGP_ASKPASS)) {
                   1073:        warningx("the `-A' and `-S' options may not be used together");
1.24      millert  1074:        usage(1);
                   1075:     }
1.34      millert  1076:     if ((NewArgc == 0 && mode == MODE_EDIT) ||
                   1077:        (NewArgc > 0 && !ISSET(mode, MODE_RUN | MODE_EDIT | MODE_CHECK)))
1.1       millert  1078:        usage(1);
1.34      millert  1079:     if (NewArgc == 0 && mode == MODE_RUN && !ISSET(flags, MODE_SHELL))
                   1080:        SET(flags, (MODE_IMPLIED_SHELL | MODE_SHELL));
1.1       millert  1081:
1.34      millert  1082:     return(mode | flags);
1.1       millert  1083: }
                   1084:
                   1085: /*
1.34      millert  1086:  * Open sudoers and sanity check mode/owner/type.
                   1087:  * Returns a handle to the sudoers file or NULL on error.
1.1       millert  1088:  */
1.34      millert  1089: FILE *
1.39      millert  1090: open_sudoers(sudoers, doedit, keepopen)
1.34      millert  1091:     const char *sudoers;
1.39      millert  1092:     int doedit;
1.34      millert  1093:     int *keepopen;
1.1       millert  1094: {
                   1095:     struct stat statbuf;
1.34      millert  1096:     FILE *fp = NULL;
                   1097:     int rootstat;
1.1       millert  1098:
                   1099:     /*
                   1100:      * Fix the mode and group on sudoers file from old default.
1.23      millert  1101:      * Only works if file system is readable/writable by root.
1.1       millert  1102:      */
1.34      millert  1103:     if ((rootstat = stat_sudoers(sudoers, &statbuf)) == 0 &&
1.1       millert  1104:        SUDOERS_UID == statbuf.st_uid && SUDOERS_MODE != 0400 &&
                   1105:        (statbuf.st_mode & 0007777) == 0400) {
                   1106:
1.34      millert  1107:        if (chmod(sudoers, SUDOERS_MODE) == 0) {
                   1108:            warningx("fixed mode on %s", sudoers);
1.23      millert  1109:            SET(statbuf.st_mode, SUDOERS_MODE);
1.1       millert  1110:            if (statbuf.st_gid != SUDOERS_GID) {
1.34      millert  1111:                if (chown(sudoers, (uid_t) -1, SUDOERS_GID) == 0) {
                   1112:                    warningx("set group on %s", sudoers);
1.1       millert  1113:                    statbuf.st_gid = SUDOERS_GID;
1.19      millert  1114:                } else
1.34      millert  1115:                    warning("unable to set group on %s", sudoers);
1.1       millert  1116:            }
1.19      millert  1117:        } else
1.34      millert  1118:            warning("unable to fix mode on %s", sudoers);
1.1       millert  1119:     }
                   1120:
                   1121:     /*
                   1122:      * Sanity checks on sudoers file.  Must be done as sudoers
                   1123:      * file owner.  We already did a stat as root, so use that
                   1124:      * data if we can't stat as sudoers file owner.
                   1125:      */
1.17      millert  1126:     set_perms(PERM_SUDOERS);
1.1       millert  1127:
1.34      millert  1128:     if (rootstat != 0 && stat_sudoers(sudoers, &statbuf) != 0)
                   1129:        log_error(USE_ERRNO|NO_EXIT, "can't stat %s", sudoers);
1.1       millert  1130:     else if (!S_ISREG(statbuf.st_mode))
1.34      millert  1131:        log_error(NO_EXIT, "%s is not a regular file", sudoers);
1.1       millert  1132:     else if ((statbuf.st_mode & 07777) != SUDOERS_MODE)
1.34      millert  1133:        log_error(NO_EXIT, "%s is mode 0%o, should be 0%o", sudoers,
1.27      millert  1134:            (unsigned int) (statbuf.st_mode & 07777),
                   1135:            (unsigned int) SUDOERS_MODE);
1.1       millert  1136:     else if (statbuf.st_uid != SUDOERS_UID)
1.34      millert  1137:        log_error(NO_EXIT, "%s is owned by uid %lu, should be %lu", sudoers,
1.25      millert  1138:            (unsigned long) statbuf.st_uid, (unsigned long) SUDOERS_UID);
1.1       millert  1139:     else if (statbuf.st_gid != SUDOERS_GID)
1.34      millert  1140:        log_error(NO_EXIT, "%s is owned by gid %lu, should be %lu", sudoers,
1.25      millert  1141:            (unsigned long) statbuf.st_gid, (unsigned long) SUDOERS_GID);
1.34      millert  1142:     else if ((fp = fopen(sudoers, "r")) == NULL)
1.40    ! millert  1143:        log_error(USE_ERRNO|NO_EXIT, "can't open %s", sudoers);
1.37      millert  1144:     else {
1.34      millert  1145:        /*
                   1146:         * Make sure we can actually read sudoers so we can present the
1.37      millert  1147:         * user with a reasonable error message (unlike the lexer).
1.34      millert  1148:         */
1.40    ! millert  1149:        if (statbuf.st_size != 0 && fgetc(fp) == EOF) {
        !          1150:            log_error(USE_ERRNO|NO_EXIT, "can't read %s", sudoers);
        !          1151:            fclose(fp);
        !          1152:            fp = NULL;
1.37      millert  1153:        }
1.40    ! millert  1154:     }
        !          1155:
        !          1156:     if (fp != NULL) {
        !          1157:        rewind(fp);
1.37      millert  1158:        (void) fcntl(fileno(fp), F_SETFD, 1);
1.1       millert  1159:     }
                   1160:
1.17      millert  1161:     set_perms(PERM_ROOT);              /* change back to root */
1.34      millert  1162:     return(fp);
1.1       millert  1163: }
                   1164:
                   1165: /*
                   1166:  * Close all open files (except std*) and turn off core dumps.
1.34      millert  1167:  * Also sets the set_perms() pointer to the correct function.
1.1       millert  1168:  */
                   1169: static void
                   1170: initial_setup()
                   1171: {
1.27      millert  1172:     int miss[3], devnull = -1;
1.33      millert  1173: #if defined(__linux__) || (defined(RLIMIT_CORE) && !defined(SUDO_DEVEL))
1.1       millert  1174:     struct rlimit rl;
1.33      millert  1175: #endif
1.1       millert  1176:
1.33      millert  1177: #if defined(__linux__)
                   1178:     /*
                   1179:      * Unlimit the number of processes since Linux's setuid() will
                   1180:      * apply resource limits when changing uid and return EAGAIN if
                   1181:      * nproc would be violated by the uid switch.
                   1182:      */
                   1183:     rl.rlim_cur = rl.rlim_max = RLIM_INFINITY;
                   1184:     if (setrlimit(RLIMIT_NPROC, &rl)) {
                   1185:        if (getrlimit(RLIMIT_NPROC, &rl) == 0) {
                   1186:            rl.rlim_cur = rl.rlim_max;
                   1187:            (void)setrlimit(RLIMIT_NPROC, &rl);
                   1188:        }
                   1189:     }
                   1190: #endif /* __linux__ */
                   1191: #if defined(RLIMIT_CORE) && !defined(SUDO_DEVEL)
1.1       millert  1192:     /*
                   1193:      * Turn off core dumps.
                   1194:      */
1.4       millert  1195:     (void) getrlimit(RLIMIT_CORE, &corelimit);
1.20      millert  1196:     memcpy(&rl, &corelimit, sizeof(struct rlimit));
                   1197:     rl.rlim_cur = 0;
1.1       millert  1198:     (void) setrlimit(RLIMIT_CORE, &rl);
1.20      millert  1199: #endif /* RLIMIT_CORE && !SUDO_DEVEL */
1.1       millert  1200:
1.17      millert  1201:     /*
1.27      millert  1202:      * stdin, stdout and stderr must be open; set them to /dev/null
                   1203:      * if they are closed and close all other fds.
1.17      millert  1204:      */
1.27      millert  1205:     miss[STDIN_FILENO] = fcntl(STDIN_FILENO, F_GETFL, 0) == -1;
                   1206:     miss[STDOUT_FILENO] = fcntl(STDOUT_FILENO, F_GETFL, 0) == -1;
                   1207:     miss[STDERR_FILENO] = fcntl(STDERR_FILENO, F_GETFL, 0) == -1;
                   1208:     if (miss[STDIN_FILENO] || miss[STDOUT_FILENO] || miss[STDERR_FILENO]) {
                   1209:        if ((devnull = open(_PATH_DEVNULL, O_RDWR, 0644)) != -1) {
                   1210:            if (miss[STDIN_FILENO])
                   1211:                (void) dup2(devnull, STDIN_FILENO);
                   1212:            if (miss[STDOUT_FILENO])
                   1213:                (void) dup2(devnull, STDOUT_FILENO);
                   1214:            if (miss[STDERR_FILENO])
                   1215:                (void) dup2(devnull, STDERR_FILENO);
1.34      millert  1216:            if (devnull > STDERR_FILENO)
                   1217:                close(devnull);
1.27      millert  1218:        }
                   1219:     }
1.1       millert  1220: }
                   1221:
1.8       millert  1222: #ifdef HAVE_LOGIN_CAP_H
                   1223: static void
1.4       millert  1224: set_loginclass(pw)
                   1225:     struct passwd *pw;
                   1226: {
                   1227:     int errflags;
                   1228:
                   1229:     /*
                   1230:      * Don't make it a fatal error if the user didn't specify the login
                   1231:      * class themselves.  We do this because if login.conf gets
                   1232:      * corrupted we want the admin to be able to use sudo to fix it.
                   1233:      */
                   1234:     if (login_class)
                   1235:        errflags = NO_MAIL|MSG_ONLY;
                   1236:     else
                   1237:        errflags = NO_MAIL|MSG_ONLY|NO_EXIT;
                   1238:
                   1239:     if (login_class && strcmp(login_class, "-") != 0) {
1.34      millert  1240:        if (user_uid != 0 &&
                   1241:            strcmp(runas_user ? runas_user : def_runas_default, "root") != 0)
                   1242:            errorx(1, "only root can use -c %s", login_class);
1.4       millert  1243:     } else {
                   1244:        login_class = pw->pw_class;
                   1245:        if (!login_class || !*login_class)
                   1246:            login_class =
                   1247:                (pw->pw_uid == 0) ? LOGIN_DEFROOTCLASS : LOGIN_DEFCLASS;
                   1248:     }
                   1249:
                   1250:     lc = login_getclass(login_class);
1.10      millert  1251:     if (!lc || !lc->lc_class || strcmp(lc->lc_class, login_class) != 0) {
1.4       millert  1252:        log_error(errflags, "unknown login class: %s", login_class);
1.11      millert  1253:        if (!lc)
                   1254:            lc = login_getclass(NULL);  /* needed for login_getstyle() later */
1.10      millert  1255:     }
1.4       millert  1256: }
                   1257: #else
1.8       millert  1258: static void
1.4       millert  1259: set_loginclass(pw)
                   1260:     struct passwd *pw;
                   1261: {
                   1262: }
1.8       millert  1263: #endif /* HAVE_LOGIN_CAP_H */
1.4       millert  1264:
1.27      millert  1265: #ifdef HAVE_PROJECT_H
                   1266: static void
                   1267: set_project(pw)
                   1268:     struct passwd *pw;
                   1269: {
                   1270:     int errflags = NO_MAIL|MSG_ONLY|NO_EXIT;
                   1271:     int errval;
                   1272:     struct project proj;
                   1273:     struct project *resultp = '\0';
                   1274:     char buf[1024];
                   1275:
                   1276:     /*
                   1277:      * Collect the default project for the user and settaskid
                   1278:      */
                   1279:     setprojent();
                   1280:     if (resultp = getdefaultproj(pw->pw_name, &proj, buf, sizeof(buf))) {
                   1281:        errval = setproject(resultp->pj_name, pw->pw_name, TASK_NORMAL);
                   1282:        if (errval != 0) {
                   1283:            switch(errval) {
                   1284:            case SETPROJ_ERR_TASK:
                   1285:                if (errno == EAGAIN)
                   1286:                    log_error(errflags, "resource control limit has been reached");
                   1287:                else if (errno == ESRCH)
                   1288:                    log_error(errflags, "user \"%s\" is not a member of "
                   1289:                        "project \"%s\"", pw->pw_name, resultp->pj_name);
                   1290:                else if (errno == EACCES)
                   1291:                    log_error(errflags, "the invoking task is final");
                   1292:                else
                   1293:                    log_error(errflags, "could not join project \"%s\"",
                   1294:                        resultp->pj_name);
                   1295:                break;
                   1296:            case SETPROJ_ERR_POOL:
                   1297:                if (errno == EACCES)
                   1298:                    log_error(errflags, "no resource pool accepting "
                   1299:                            "default bindings exists for project \"%s\"",
                   1300:                            resultp->pj_name);
                   1301:                else if (errno == ESRCH)
                   1302:                    log_error(errflags, "specified resource pool does "
                   1303:                            "not exist for project \"%s\"", resultp->pj_name);
                   1304:                else
                   1305:                    log_error(errflags, "could not bind to default "
                   1306:                            "resource pool for project \"%s\"", resultp->pj_name);
                   1307:                break;
                   1308:            default:
                   1309:                if (errval <= 0) {
                   1310:                    log_error(errflags, "setproject failed for project \"%s\"",
                   1311:                        resultp->pj_name);
                   1312:                } else {
                   1313:                    log_error(errflags, "warning, resource control assignment "
                   1314:                        "failed for project \"%s\"", resultp->pj_name);
                   1315:                }
                   1316:            }
                   1317:        }
                   1318:     } else {
                   1319:        log_error(errflags, "getdefaultproj() error: %s", strerror(errno));
                   1320:     }
                   1321:     endprojent();
                   1322: }
                   1323: #else
                   1324: static void
                   1325: set_project(pw)
                   1326:     struct passwd *pw;
                   1327: {
                   1328: }
                   1329: #endif /* HAVE_PROJECT_H */
                   1330:
1.1       millert  1331: /*
1.2       millert  1332:  * Look up the fully qualified domain name and set user_host and user_shost.
                   1333:  */
                   1334: void
                   1335: set_fqdn()
                   1336: {
1.28      millert  1337: #ifdef HAVE_GETADDRINFO
                   1338:     struct addrinfo *res0, hint;
                   1339: #else
1.2       millert  1340:     struct hostent *hp;
1.28      millert  1341: #endif
1.2       millert  1342:     char *p;
                   1343:
1.28      millert  1344: #ifdef HAVE_GETADDRINFO
1.34      millert  1345:     zero_bytes(&hint, sizeof(hint));
1.28      millert  1346:     hint.ai_family = PF_UNSPEC;
                   1347:     hint.ai_flags = AI_CANONNAME;
                   1348:     if (getaddrinfo(user_host, NULL, &hint, &res0) != 0) {
                   1349: #else
1.14      millert  1350:     if (!(hp = gethostbyname(user_host))) {
1.28      millert  1351: #endif
1.14      millert  1352:        log_error(MSG_ONLY|NO_EXIT,
1.28      millert  1353:            "unable to resolve host %s", user_host);
1.14      millert  1354:     } else {
                   1355:        if (user_shost != user_host)
1.27      millert  1356:            efree(user_shost);
                   1357:        efree(user_host);
1.28      millert  1358: #ifdef HAVE_GETADDRINFO
                   1359:        user_host = estrdup(res0->ai_canonname);
                   1360:        freeaddrinfo(res0);
                   1361: #else
1.14      millert  1362:        user_host = estrdup(hp->h_name);
1.28      millert  1363: #endif
1.2       millert  1364:     }
                   1365:     if ((p = strchr(user_host, '.'))) {
                   1366:        *p = '\0';
                   1367:        user_shost = estrdup(user_host);
                   1368:        *p = '.';
                   1369:     } else {
                   1370:        user_shost = user_host;
                   1371:     }
                   1372: }
                   1373:
                   1374: /*
1.23      millert  1375:  * Get passwd entry for the user we are going to run commands as.
                   1376:  * By default, this is "root".  Updates runas_pw as a side effect.
                   1377:  */
1.34      millert  1378: static void
1.23      millert  1379: set_runaspw(user)
                   1380:     char *user;
                   1381: {
1.34      millert  1382:     if (*user == '#') {
                   1383:        if ((runas_pw = sudo_getpwuid(atoi(user + 1))) == NULL)
                   1384:            runas_pw = sudo_fakepwnam(user, runas_gr ? runas_gr->gr_gid : 0);
                   1385:     } else {
1.38      millert  1386:        if ((runas_pw = sudo_getpwnam(user)) == NULL) {
                   1387:            audit_failure(NewArgv, "unknown user: %s", user);
1.34      millert  1388:            log_error(NO_MAIL|MSG_ONLY, "unknown user: %s", user);
1.38      millert  1389:        }
1.23      millert  1390:     }
1.34      millert  1391: }
                   1392:
                   1393: /*
                   1394:  * Get group entry for the group we are going to run commands as.
                   1395:  * Updates runas_pw as a side effect.
                   1396:  */
                   1397: static void
                   1398: set_runasgr(group)
                   1399:     char *group;
                   1400: {
                   1401:     if (*group == '#') {
                   1402:        if ((runas_gr = sudo_getgrgid(atoi(group + 1))) == NULL)
                   1403:            runas_gr = sudo_fakegrnam(group);
1.23      millert  1404:     } else {
1.34      millert  1405:        if ((runas_gr = sudo_getgrnam(group)) == NULL)
                   1406:            log_error(NO_MAIL|MSG_ONLY, "unknown group: %s", group);
1.23      millert  1407:     }
                   1408: }
                   1409:
                   1410: /*
1.6       millert  1411:  * Get passwd entry for the user we are going to authenticate as.
1.23      millert  1412:  * By default, this is the user invoking sudo.  In the most common
                   1413:  * case, this matches sudo_user.pw or runas_pw.
1.4       millert  1414:  */
1.6       millert  1415: static struct passwd *
                   1416: get_authpw()
1.4       millert  1417: {
                   1418:     struct passwd *pw;
                   1419:
1.23      millert  1420:     if (def_rootpw) {
1.34      millert  1421:        if ((pw = sudo_getpwuid(0)) == NULL)
                   1422:            log_error(0, "unknown uid: 0");
1.23      millert  1423:     } else if (def_runaspw) {
1.34      millert  1424:        if ((pw = sudo_getpwnam(def_runas_default)) == NULL)
                   1425:            log_error(0, "unknown user: %s", def_runas_default);
1.23      millert  1426:     } else if (def_targetpw) {
                   1427:        if (runas_pw->pw_name == NULL)
1.34      millert  1428:            log_error(NO_MAIL|MSG_ONLY, "unknown uid: %lu",
1.25      millert  1429:                (unsigned long) runas_pw->pw_uid);
1.23      millert  1430:        pw = runas_pw;
1.6       millert  1431:     } else
                   1432:        pw = sudo_user.pw;
                   1433:
                   1434:     return(pw);
1.4       millert  1435: }
                   1436:
                   1437: /*
1.34      millert  1438:  * Cleanup hook for error()/errorx()
                   1439:  */
                   1440: void
                   1441: cleanup(gotsignal)
                   1442:     int gotsignal;
                   1443: {
                   1444:     struct sudo_nss *nss;
                   1445:
                   1446:     if (!gotsignal) {
                   1447:        if (snl != NULL) {
                   1448:            tq_foreach_fwd(snl, nss)
                   1449:                nss->close(nss);
                   1450:        }
                   1451:        sudo_endpwent();
                   1452:        sudo_endgrent();
                   1453:     }
                   1454: }
                   1455:
                   1456: static void
                   1457: show_version()
                   1458: {
1.39      millert  1459:     (void) printf("Sudo version %s\n", PACKAGE_VERSION);
1.34      millert  1460:     if (getuid() == 0) {
                   1461:        putchar('\n');
                   1462:        (void) printf("Sudoers path: %s\n", _PATH_SUDOERS);
                   1463: #ifdef HAVE_LDAP
                   1464: # ifdef _PATH_NSSWITCH_CONF
                   1465:        (void) printf("nsswitch path: %s\n", _PATH_NSSWITCH_CONF);
                   1466: # endif
                   1467:        (void) printf("ldap.conf path: %s\n", _PATH_LDAP_CONF);
                   1468:        (void) printf("ldap.secret path: %s\n", _PATH_LDAP_SECRET);
                   1469: #endif
                   1470:        dump_auth_methods();
                   1471:        dump_defaults();
                   1472:        dump_interfaces();
                   1473:     }
                   1474:     exit(0);
                   1475: }
                   1476:
                   1477: /*
1.1       millert  1478:  * Tell which options are mutually exclusive and exit.
                   1479:  */
                   1480: static void
                   1481: usage_excl(exit_val)
                   1482:     int exit_val;
                   1483: {
1.38      millert  1484:     warningx("Only one of the -e, -h, -i, -K, -l, -s, -v or -V options may be specified");
1.1       millert  1485:     usage(exit_val);
                   1486: }
                   1487:
                   1488: /*
                   1489:  * Give usage message and exit.
1.34      millert  1490:  * The actual usage strings are in sudo_usage.h for configure substitution.
1.1       millert  1491:  */
                   1492: static void
                   1493: usage(exit_val)
                   1494:     int exit_val;
                   1495: {
1.34      millert  1496:     struct lbuf lbuf;
1.38      millert  1497:     char *uvec[6];
1.34      millert  1498:     int i, ulen;
1.23      millert  1499:
                   1500:     /*
1.27      millert  1501:      * Use usage vectors appropriate to the progname.
1.23      millert  1502:      */
                   1503:     if (strcmp(getprogname(), "sudoedit") == 0) {
1.38      millert  1504:        uvec[0] = SUDO_USAGE5 + 3;
1.27      millert  1505:        uvec[1] = NULL;
1.23      millert  1506:     } else {
1.34      millert  1507:        uvec[0] = SUDO_USAGE1;
                   1508:        uvec[1] = SUDO_USAGE2;
                   1509:        uvec[2] = SUDO_USAGE3;
                   1510:        uvec[3] = SUDO_USAGE4;
1.38      millert  1511:        uvec[4] = SUDO_USAGE5;
                   1512:        uvec[5] = NULL;
1.23      millert  1513:     }
                   1514:
                   1515:     /*
1.34      millert  1516:      * Print usage and wrap lines as needed, depending on the
                   1517:      * tty width.
1.23      millert  1518:      */
1.34      millert  1519:     ulen = (int)strlen(getprogname()) + 8;
                   1520:     lbuf_init(&lbuf, NULL, ulen, 0);
1.27      millert  1521:     for (i = 0; uvec[i] != NULL; i++) {
1.34      millert  1522:        lbuf_append(&lbuf, "usage: ", getprogname(), uvec[i], NULL);
                   1523:        lbuf_print(&lbuf);
1.23      millert  1524:     }
1.34      millert  1525:     lbuf_destroy(&lbuf);
1.1       millert  1526:     exit(exit_val);
                   1527: }