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

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