Annotation of embedaddon/sudo/plugins/sudoers/sudoers.c, revision 1.1.1.1

1.1       misho       1: /*
                      2:  * Copyright (c) 1993-1996, 1998-2011 Todd C. Miller <Todd.Miller@courtesan.com>
                      3:  *
                      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.
                      7:  *
                      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.
                     15:  *
                     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:  *
                     20:  * For a brief history of sudo, please see the HISTORY file included
                     21:  * with this distribution.
                     22:  */
                     23: 
                     24: #define _SUDO_MAIN
                     25: 
                     26: #ifdef __TANDEM
                     27: # include <floss.h>
                     28: #endif
                     29: 
                     30: #include <config.h>
                     31: 
                     32: #include <sys/types.h>
                     33: #include <sys/stat.h>
                     34: #include <sys/param.h>
                     35: #include <sys/socket.h>
                     36: #include <stdio.h>
                     37: #ifdef STDC_HEADERS
                     38: # include <stdlib.h>
                     39: # include <stddef.h>
                     40: #else
                     41: # ifdef HAVE_STDLIB_H
                     42: #  include <stdlib.h>
                     43: # endif
                     44: #endif /* STDC_HEADERS */
                     45: #ifdef HAVE_STRING_H
                     46: # if defined(HAVE_MEMORY_H) && !defined(STDC_HEADERS)
                     47: #  include <memory.h>
                     48: # endif
                     49: # include <string.h>
                     50: #endif /* HAVE_STRING_H */
                     51: #ifdef HAVE_STRINGS_H
                     52: # include <strings.h>
                     53: #endif /* HAVE_STRINGS_H */
                     54: #ifdef HAVE_UNISTD_H
                     55: # include <unistd.h>
                     56: #endif /* HAVE_UNISTD_H */
                     57: #include <pwd.h>
                     58: #include <errno.h>
                     59: #include <fcntl.h>
                     60: #include <signal.h>
                     61: #include <grp.h>
                     62: #include <time.h>
                     63: #ifdef HAVE_SETLOCALE
                     64: # include <locale.h>
                     65: #endif
                     66: #include <netinet/in.h>
                     67: #include <netdb.h>
                     68: #ifdef HAVE_LOGIN_CAP_H
                     69: # include <login_cap.h>
                     70: # ifndef LOGIN_DEFROOTCLASS
                     71: #  define LOGIN_DEFROOTCLASS   "daemon"
                     72: # endif
                     73: #endif
                     74: #ifdef HAVE_SELINUX
                     75: # include <selinux/selinux.h>
                     76: #endif
                     77: #include <ctype.h>
                     78: #include <setjmp.h>
                     79: 
                     80: #include "sudoers.h"
                     81: #include "interfaces.h"
                     82: #include "sudoers_version.h"
                     83: #include "auth/sudo_auth.h"
                     84: 
                     85: /*
                     86:  * Prototypes
                     87:  */
                     88: static void init_vars(char * const *);
                     89: static int set_cmnd(void);
                     90: static void set_loginclass(struct passwd *);
                     91: static void set_runaspw(const char *);
                     92: static void set_runasgr(const char *);
                     93: static int cb_runas_default(const char *);
                     94: static int sudoers_policy_version(int verbose);
                     95: static int deserialize_info(char * const settings[], char * const user_info[]);
                     96: static char *find_editor(int nfiles, char **files, char ***argv_out);
                     97: static void create_admin_success_flag(void);
                     98: 
                     99: /*
                    100:  * Globals
                    101:  */
                    102: const char *sudoers_file = _PATH_SUDOERS;
                    103: mode_t sudoers_mode = SUDOERS_MODE;
                    104: uid_t sudoers_uid = SUDOERS_UID;
                    105: gid_t sudoers_gid = SUDOERS_GID;
                    106: struct sudo_user sudo_user;
                    107: struct passwd *list_pw;
                    108: struct interface *interfaces;
                    109: int long_list;
                    110: int debug_level;
                    111: uid_t timestamp_uid;
                    112: extern int errorlineno;
                    113: extern int parse_error;
                    114: extern char *errorfile;
                    115: #ifdef HAVE_LOGIN_CAP_H
                    116: login_cap_t *lc;
                    117: #endif /* HAVE_LOGIN_CAP_H */
                    118: #ifdef HAVE_BSD_AUTH_H
                    119: char *login_style;
                    120: #endif /* HAVE_BSD_AUTH_H */
                    121: sudo_conv_t sudo_conv;
                    122: sudo_printf_t sudo_printf;
                    123: int sudo_mode;
                    124: 
                    125: static char *prev_user;
                    126: static char *runas_user;
                    127: static char *runas_group;
                    128: static struct sudo_nss_list *snl;
                    129: static const char *interfaces_string;
                    130: static sigaction_t saved_sa_int, saved_sa_quit, saved_sa_tstp;
                    131: 
                    132: /* XXX - must be extern for audit bits of sudo_auth.c */
                    133: int NewArgc;
                    134: char **NewArgv;
                    135: 
                    136: /* plugin_error.c */
                    137: extern sigjmp_buf error_jmp;
                    138: 
                    139: static int
                    140: sudoers_policy_open(unsigned int version, sudo_conv_t conversation,
                    141:     sudo_printf_t plugin_printf, char * const settings[],
                    142:     char * const user_info[], char * const envp[])
                    143: {
                    144:     volatile int sources = 0;
                    145:     sigaction_t sa;
                    146:     struct sudo_nss *nss;
                    147: 
                    148:     if (!sudo_conv)
                    149:        sudo_conv = conversation;
                    150:     if (!sudo_printf)
                    151:        sudo_printf = plugin_printf;
                    152: 
                    153:     if (sigsetjmp(error_jmp, 1)) {
                    154:        /* called via error(), errorx() or log_error() */
                    155:        rewind_perms();
                    156:        return -1;
                    157:     }
                    158: 
                    159:     bindtextdomain("sudoers", LOCALEDIR);
                    160: 
                    161:     /*
                    162:      * Signal setup:
                    163:      * Ignore keyboard-generated signals so the user cannot interrupt
                    164:      *  us at some point and avoid the logging.
                    165:      *  Install handler to wait for children when they exit.
                    166:      */
                    167:     zero_bytes(&sa, sizeof(sa));
                    168:     sigemptyset(&sa.sa_mask);
                    169:     sa.sa_flags = SA_RESTART;
                    170:     sa.sa_handler = SIG_IGN;
                    171:     (void) sigaction(SIGINT, &sa, &saved_sa_int);
                    172:     (void) sigaction(SIGQUIT, &sa, &saved_sa_quit);
                    173:     (void) sigaction(SIGTSTP, &sa, &saved_sa_tstp);
                    174: 
                    175:     sudo_setpwent();
                    176:     sudo_setgrent();
                    177: 
                    178:     /* Initialize environment functions (including replacements). */
                    179:     env_init(envp);
                    180: 
                    181:     /* Setup defaults data structures. */
                    182:     init_defaults();
                    183: 
                    184:     /* Parse settings and user_info */
                    185:     sudo_mode = deserialize_info(settings, user_info);
                    186: 
                    187:     init_vars(envp);           /* XXX - move this later? */
                    188: 
                    189:     /* Parse nsswitch.conf for sudoers order. */
                    190:     snl = sudo_read_nss();
                    191: 
                    192:     /* LDAP or NSS may modify the euid so we need to be root for the open. */
                    193:     set_perms(PERM_INITIAL);
                    194:     set_perms(PERM_ROOT);
                    195: 
                    196:     /* Open and parse sudoers, set global defaults */
                    197:     tq_foreach_fwd(snl, nss) {
                    198:        if (nss->open(nss) == 0 && nss->parse(nss) == 0) {
                    199:            sources++;
                    200:            if (nss->setdefs(nss) != 0)
                    201:                log_error(NO_STDERR|NO_EXIT, _("problem with defaults entries"));
                    202:        }
                    203:     }
                    204:     if (sources == 0) {
                    205:        warningx(_("no valid sudoers sources found, quitting"));
                    206:        return -1;
                    207:     }
                    208: 
                    209:     /* XXX - collect post-sudoers parse settings into a function */
                    210: 
                    211:     /*
                    212:      * Initialize external group plugin, if any.
                    213:      */
                    214:     if (def_group_plugin) {
                    215:        if (group_plugin_load(def_group_plugin) != TRUE)
                    216:            def_group_plugin = NULL;
                    217:     }
                    218: 
                    219:     /*
                    220:      * Set runas passwd/group entries based on command line or sudoers.
                    221:      * Note that if runas_group was specified without runas_user we
                    222:      * defer setting runas_pw so the match routines know to ignore it.
                    223:      */
                    224:     if (runas_group != NULL) {
                    225:        set_runasgr(runas_group);
                    226:        if (runas_user != NULL)
                    227:            set_runaspw(runas_user);
                    228:     } else
                    229:        set_runaspw(runas_user ? runas_user : def_runas_default);
                    230: 
                    231:     if (!update_defaults(SETDEF_RUNAS))
                    232:        log_error(NO_STDERR|NO_EXIT, _("problem with defaults entries"));
                    233: 
                    234:     if (def_fqdn)
                    235:        set_fqdn();     /* deferred until after sudoers is parsed */
                    236: 
                    237:     /* Set login class if applicable. */
                    238:     set_loginclass(sudo_user.pw);
                    239: 
                    240:     restore_perms();
                    241: 
                    242:     return TRUE;
                    243: }
                    244: 
                    245: static void
                    246: sudoers_policy_close(int exit_status, int error_code)
                    247: {
                    248:     if (sigsetjmp(error_jmp, 1)) {
                    249:        /* called via error(), errorx() or log_error() */
                    250:        return;
                    251:     }
                    252: 
                    253:     /* We do not currently log the exit status. */
                    254:     if (error_code)
                    255:        warningx(_("unable to execute %s: %s"), safe_cmnd, strerror(error_code));
                    256: 
                    257:     /* Close the session we opened in sudoers_policy_init_session(). */
                    258:     if (ISSET(sudo_mode, MODE_RUN|MODE_EDIT))
                    259:        (void)sudo_auth_end_session(runas_pw);
                    260: 
                    261:     /* Free remaining references to password and group entries. */
                    262:     pw_delref(sudo_user.pw);
                    263:     pw_delref(runas_pw);
                    264:     if (runas_gr != NULL)
                    265:        gr_delref(runas_gr);
                    266:     if (user_group_list != NULL)
                    267:        grlist_delref(user_group_list);
                    268: }
                    269: 
                    270: /*
                    271:  * The init_session function is called before executing the command
                    272:  * and before uid/gid changes occur.
                    273:  */
                    274: static int
                    275: sudoers_policy_init_session(struct passwd *pwd)
                    276: {
                    277:     if (sigsetjmp(error_jmp, 1)) {
                    278:        /* called via error(), errorx() or log_error() */
                    279:        return -1;
                    280:     }
                    281: 
                    282:     return sudo_auth_begin_session(pwd);
                    283: }
                    284: 
                    285: static int
                    286: sudoers_policy_main(int argc, char * const argv[], int pwflag, char *env_add[],
                    287:     char **command_infop[], char **argv_out[], char **user_env_out[])
                    288: {
                    289:     static char *command_info[32]; /* XXX */
                    290:     char **edit_argv = NULL;
                    291:     struct sudo_nss *nss;
                    292:     int cmnd_status = -1, validated;
                    293:     volatile int info_len = 0;
                    294:     volatile int rval = TRUE;
                    295: 
                    296:     if (sigsetjmp(error_jmp, 1)) {
                    297:        /* error recovery via error(), errorx() or log_error() */
                    298:        rval = -1;
                    299:        goto done;
                    300:     }
                    301: 
                    302:     /* Is root even allowed to run sudo? */
                    303:     if (user_uid == 0 && !def_root_sudo) {
                    304:         warningx(_("sudoers specifies that root is not allowed to sudo"));
                    305:         goto bad;
                    306:     }    
                    307: 
                    308:     /* Check for -C overriding def_closefrom. */
                    309:     if (user_closefrom >= 0 && user_closefrom != def_closefrom) {
                    310:        if (!def_closefrom_override) {
                    311:            warningx(_("you are not permitted to use the -C option"));
                    312:            goto bad;
                    313:        }
                    314:        def_closefrom = user_closefrom;
                    315:     }
                    316: 
                    317:     set_perms(PERM_INITIAL);
                    318: 
                    319:     /* Environment variables specified on the command line. */
                    320:     if (env_add != NULL && env_add[0] != NULL)
                    321:        sudo_user.env_vars = env_add;
                    322: 
                    323:     /*
                    324:      * Make a local copy of argc/argv, with special handling
                    325:      * for pseudo-commands and the '-i' option.
                    326:      */
                    327:     if (argc == 0) {
                    328:        NewArgc = 1;
                    329:        NewArgv = emalloc2(NewArgc + 1, sizeof(char *));
                    330:        NewArgv[0] = user_cmnd;
                    331:        NewArgv[1] = NULL;
                    332:     } else {
                    333:        /* Must leave an extra slot before NewArgv for bash's --login */
                    334:        NewArgc = argc;
                    335:        NewArgv = emalloc2(NewArgc + 2, sizeof(char *));
                    336:        memcpy(++NewArgv, argv, argc * sizeof(char *));
                    337:        NewArgv[NewArgc] = NULL;
                    338:        if (ISSET(sudo_mode, MODE_LOGIN_SHELL))
                    339:            NewArgv[0] = estrdup(runas_pw->pw_shell);
                    340:     }
                    341: 
                    342:     /* If given the -P option, set the "preserve_groups" flag. */
                    343:     if (ISSET(sudo_mode, MODE_PRESERVE_GROUPS))
                    344:        def_preserve_groups = TRUE;
                    345: 
                    346:     /* Find command in path */
                    347:     cmnd_status = set_cmnd();
                    348:     if (cmnd_status == -1) {
                    349:        rval = -1;
                    350:        goto done;
                    351:     }
                    352: 
                    353: #ifdef HAVE_SETLOCALE
                    354:     if (!setlocale(LC_ALL, def_sudoers_locale)) {
                    355:        warningx(_("unable to set locale to \"%s\", using \"C\""),
                    356:            def_sudoers_locale);
                    357:        setlocale(LC_ALL, "C");
                    358:     }
                    359: #endif
                    360: 
                    361:     /*
                    362:      * Check sudoers sources.
                    363:      */
                    364:     validated = FLAG_NO_USER | FLAG_NO_HOST;
                    365:     tq_foreach_fwd(snl, nss) {
                    366:        validated = nss->lookup(nss, validated, pwflag);
                    367: 
                    368:        if (ISSET(validated, VALIDATE_OK)) {
                    369:            /* Handle "= auth" in netsvc.conf */
                    370:            if (nss->ret_if_found)
                    371:                break;
                    372:        } else {
                    373:            /* Handle [NOTFOUND=return] */
                    374:            if (nss->ret_if_notfound)
                    375:                break;
                    376:        }
                    377:     }
                    378: 
                    379:     if (safe_cmnd == NULL)
                    380:        safe_cmnd = estrdup(user_cmnd);
                    381: 
                    382: #ifdef HAVE_SETLOCALE
                    383:     setlocale(LC_ALL, "");
                    384: #endif
                    385: 
                    386:     /* If only a group was specified, set runas_pw based on invoking user. */
                    387:     if (runas_pw == NULL)
                    388:        set_runaspw(user_name);
                    389: 
                    390:     /*
                    391:      * Look up the timestamp dir owner if one is specified.
                    392:      */
                    393:     if (def_timestampowner) {
                    394:        struct passwd *pw;
                    395: 
                    396:        if (*def_timestampowner == '#')
                    397:            pw = sudo_getpwuid(atoi(def_timestampowner + 1));
                    398:        else
                    399:            pw = sudo_getpwnam(def_timestampowner);
                    400:        if (!pw)
                    401:            log_error(0, _("timestamp owner (%s): No such user"),
                    402:                def_timestampowner);
                    403:        timestamp_uid = pw->pw_uid;
                    404:        pw_delref(pw);
                    405:     }
                    406: 
                    407:     /* If no command line args and "shell_noargs" is not set, error out. */
                    408:     if (ISSET(sudo_mode, MODE_IMPLIED_SHELL) && !def_shell_noargs) {
                    409:        rval = -2; /* usage error */
                    410:        goto done;
                    411:     }
                    412: 
                    413:     /* Bail if a tty is required and we don't have one.  */
                    414:     if (def_requiretty) {
                    415:        int fd = open(_PATH_TTY, O_RDWR|O_NOCTTY);
                    416:        if (fd == -1) {
                    417:            audit_failure(NewArgv, _("no tty"));
                    418:            warningx(_("sorry, you must have a tty to run sudo"));
                    419:            goto bad;
                    420:        } else
                    421:            (void) close(fd);
                    422:     }
                    423: 
                    424:     /*
                    425:      * We don't reset the environment for sudoedit or if the user
                    426:      * specified the -E command line flag and they have setenv privs.
                    427:      */
                    428:     if (ISSET(sudo_mode, MODE_EDIT) ||
                    429:        (ISSET(sudo_mode, MODE_PRESERVE_ENV) && def_setenv))
                    430:        def_env_reset = FALSE;
                    431: 
                    432:     /* Build a new environment that avoids any nasty bits. */
                    433:     rebuild_env();
                    434: 
                    435:     /* Require a password if sudoers says so.  */
                    436:     rval = check_user(validated, sudo_mode);
                    437:     if (rval != TRUE)
                    438:        goto done;
                    439: 
                    440:     /* If run as root with SUDO_USER set, set sudo_user.pw to that user. */
                    441:     /* XXX - causes confusion when root is not listed in sudoers */
                    442:     if (sudo_mode & (MODE_RUN | MODE_EDIT) && prev_user != NULL) {
                    443:        if (user_uid == 0 && strcmp(prev_user, "root") != 0) {
                    444:            struct passwd *pw;
                    445: 
                    446:            if ((pw = sudo_getpwnam(prev_user)) != NULL) {
                    447:                    if (sudo_user.pw != NULL)
                    448:                        pw_delref(sudo_user.pw);
                    449:                    sudo_user.pw = pw;
                    450:            }
                    451:        }
                    452:     }
                    453: 
                    454:     /* If the user was not allowed to run the command we are done. */
                    455:     if (!ISSET(validated, VALIDATE_OK)) {
                    456:        if (ISSET(validated, FLAG_NO_USER | FLAG_NO_HOST)) {
                    457:            audit_failure(NewArgv, _("No user or host"));
                    458:            log_denial(validated, 1);
                    459:        } else {
                    460:            if (def_path_info) {
                    461:                /*
                    462:                 * We'd like to not leak path info at all here, but that can
                    463:                 * *really* confuse the users.  To really close the leak we'd
                    464:                 * have to say "not allowed to run foo" even when the problem
                    465:                 * is just "no foo in path" since the user can trivially set
                    466:                 * their path to just contain a single dir.
                    467:                 */
                    468:                log_denial(validated,
                    469:                    !(cmnd_status == NOT_FOUND_DOT || cmnd_status == NOT_FOUND));
                    470:                if (cmnd_status == NOT_FOUND)
                    471:                    warningx(_("%s: command not found"), user_cmnd);
                    472:                else if (cmnd_status == NOT_FOUND_DOT)
                    473:                    warningx(_("ignoring `%s' found in '.'\nUse `sudo ./%s' if this is the `%s' you wish to run."), user_cmnd, user_cmnd, user_cmnd);
                    474:            } else {
                    475:                /* Just tell the user they are not allowed to run foo. */
                    476:                log_denial(validated, 1);
                    477:            }
                    478:            audit_failure(NewArgv, _("validation failure"));
                    479:        }
                    480:        goto bad;
                    481:     }
                    482: 
                    483:     /* Create Ubuntu-style dot file to indicate sudo was successful. */
                    484:     create_admin_success_flag();
                    485: 
                    486:     /* Finally tell the user if the command did not exist. */
                    487:     if (cmnd_status == NOT_FOUND_DOT) {
                    488:        audit_failure(NewArgv, _("command in current directory"));
                    489:        warningx(_("ignoring `%s' found in '.'\nUse `sudo ./%s' if this is the `%s' you wish to run."), user_cmnd, user_cmnd, user_cmnd);
                    490:        goto bad;
                    491:     } else if (cmnd_status == NOT_FOUND) {
                    492:        audit_failure(NewArgv, _("%s: command not found"), user_cmnd);
                    493:        warningx(_("%s: command not found"), user_cmnd);
                    494:        goto bad;
                    495:     }
                    496: 
                    497:     /* If user specified env vars make sure sudoers allows it. */
                    498:     if (ISSET(sudo_mode, MODE_RUN) && !def_setenv) {
                    499:        if (ISSET(sudo_mode, MODE_PRESERVE_ENV)) {
                    500:            warningx(_("sorry, you are not allowed to preserve the environment"));
                    501:            goto bad;
                    502:        } else
                    503:            validate_env_vars(sudo_user.env_vars);
                    504:     }
                    505: 
                    506:     if (ISSET(sudo_mode, (MODE_RUN | MODE_EDIT)) && (def_log_input || def_log_output)) {
                    507:        if (def_iolog_file && def_iolog_dir) {
                    508:            command_info[info_len++] = expand_iolog_path("iolog_path=",
                    509:                def_iolog_dir, def_iolog_file, &sudo_user.iolog_file);
                    510:            sudo_user.iolog_file++;
                    511:        }
                    512:        if (def_log_input) {
                    513:            command_info[info_len++] = estrdup("iolog_stdin=true");
                    514:            command_info[info_len++] = estrdup("iolog_ttyin=true");
                    515:        }
                    516:        if (def_log_output) {
                    517:            command_info[info_len++] = estrdup("iolog_stdout=true");
                    518:            command_info[info_len++] = estrdup("iolog_stderr=true");
                    519:            command_info[info_len++] = estrdup("iolog_ttyout=true");
                    520:        }
                    521:        if (def_compress_io)
                    522:            command_info[info_len++] = estrdup("iolog_compress=true");
                    523:     }
                    524: 
                    525:     log_allowed(validated);
                    526:     if (ISSET(sudo_mode, MODE_CHECK))
                    527:        rval = display_cmnd(snl, list_pw ? list_pw : sudo_user.pw);
                    528:     else if (ISSET(sudo_mode, MODE_LIST))
                    529:        display_privs(snl, list_pw ? list_pw : sudo_user.pw); /* XXX - return val */
                    530: 
                    531:     /* Cleanup sudoers sources */
                    532:     tq_foreach_fwd(snl, nss) {
                    533:        nss->close(nss);
                    534:     }
                    535:     if (def_group_plugin)
                    536:        group_plugin_unload();
                    537: 
                    538:     if (ISSET(sudo_mode, (MODE_VALIDATE|MODE_CHECK|MODE_LIST))) {
                    539:        /* rval already set appropriately */
                    540:        goto done;
                    541:     }
                    542: 
                    543:     /*
                    544:      * Set umask based on sudoers.
                    545:      * If user's umask is more restrictive, OR in those bits too
                    546:      * unless umask_override is set.
                    547:      */
                    548:     if (def_umask != 0777) {
                    549:        mode_t mask = def_umask;
                    550:        if (!def_umask_override) {
                    551:            mode_t omask = umask(mask);
                    552:            mask |= omask;
                    553:            umask(omask);
                    554:        }
                    555:        easprintf(&command_info[info_len++], "umask=0%o", (unsigned int)mask);
                    556:     }
                    557: 
                    558:     if (ISSET(sudo_mode, MODE_LOGIN_SHELL)) {
                    559:        char *p;
                    560: 
                    561:        /* Convert /bin/sh -> -sh so shell knows it is a login shell */
                    562:        if ((p = strrchr(NewArgv[0], '/')) == NULL)
                    563:            p = NewArgv[0];
                    564:        *p = '-';
                    565:        NewArgv[0] = p;
                    566: 
                    567:        /* Set cwd to run user's homedir. */
                    568:        command_info[info_len++] = fmt_string("cwd", runas_pw->pw_dir);
                    569: 
                    570:        /*
                    571:         * Newer versions of bash require the --login option to be used
                    572:         * in conjunction with the -c option even if the shell name starts
                    573:         * with a '-'.  Unfortunately, bash 1.x uses -login, not --login
                    574:         * so this will cause an error for that.
                    575:         */
                    576:        if (NewArgc > 1 && strcmp(NewArgv[0], "-bash") == 0 &&
                    577:            strcmp(NewArgv[1], "-c") == 0) {
                    578:            /* Use the extra slot before NewArgv so we can store --login. */
                    579:            NewArgv--;
                    580:            NewArgc++;
                    581:            NewArgv[0] = NewArgv[1];
                    582:            NewArgv[1] = "--login";
                    583:        }
                    584: 
                    585: #if defined(__linux__) || defined(_AIX)
                    586:        /* Insert system-wide environment variables. */
                    587:        read_env_file(_PATH_ENVIRONMENT, TRUE);
                    588: #endif
                    589:     }
                    590: 
                    591:     /* Insert system-wide environment variables. */
                    592:     if (def_env_file)
                    593:        read_env_file(def_env_file, FALSE);
                    594: 
                    595:     /* Insert user-specified environment variables. */
                    596:     insert_env_vars(sudo_user.env_vars);
                    597: 
                    598:     /* Restore signal handlers before we exec. */
                    599:     (void) sigaction(SIGINT, &saved_sa_int, NULL);
                    600:     (void) sigaction(SIGQUIT, &saved_sa_quit, NULL);
                    601:     (void) sigaction(SIGTSTP, &saved_sa_tstp, NULL);
                    602: 
                    603:     if (ISSET(sudo_mode, MODE_EDIT)) {
                    604:        char *editor = find_editor(NewArgc - 1, NewArgv + 1, &edit_argv);
                    605:        if (editor == NULL)
                    606:            goto bad;
                    607:        command_info[info_len++] = fmt_string("command", editor);
                    608:        command_info[info_len++] = estrdup("sudoedit=true");
                    609:     } else {
                    610:        command_info[info_len++] = fmt_string("command", safe_cmnd);
                    611:     }
                    612:     if (def_stay_setuid) {
                    613:        easprintf(&command_info[info_len++], "runas_uid=%u",
                    614:            (unsigned int)user_uid);
                    615:        easprintf(&command_info[info_len++], "runas_gid=%u",
                    616:            (unsigned int)user_gid);
                    617:        easprintf(&command_info[info_len++], "runas_euid=%u",
                    618:            (unsigned int)runas_pw->pw_uid);
                    619:        easprintf(&command_info[info_len++], "runas_egid=%u",
                    620:            runas_gr ? (unsigned int)runas_gr->gr_gid :
                    621:            (unsigned int)runas_pw->pw_gid);
                    622:     } else {
                    623:        easprintf(&command_info[info_len++], "runas_uid=%u",
                    624:            (unsigned int)runas_pw->pw_uid);
                    625:        easprintf(&command_info[info_len++], "runas_gid=%u",
                    626:            runas_gr ? (unsigned int)runas_gr->gr_gid :
                    627:            (unsigned int)runas_pw->pw_gid);
                    628:     }
                    629:     if (def_preserve_groups) {
                    630:        command_info[info_len++] = "preserve_groups=true";
                    631:     } else {
                    632:        int i, len;
                    633:        size_t glsize;
                    634:        char *cp, *gid_list;
                    635:        struct group_list *grlist = get_group_list(runas_pw);
                    636: 
                    637:        glsize = sizeof("runas_groups=") - 1 + (grlist->ngids * (MAX_UID_T_LEN + 1));
                    638:        gid_list = emalloc(glsize);
                    639:        memcpy(gid_list, "runas_groups=", sizeof("runas_groups=") - 1);
                    640:        cp = gid_list + sizeof("runas_groups=") - 1;
                    641:        for (i = 0; i < grlist->ngids; i++) {
                    642:            /* XXX - check rval */
                    643:            len = snprintf(cp, glsize - (cp - gid_list), "%s%u",
                    644:                 i ? "," : "", (unsigned int) grlist->gids[i]);
                    645:            cp += len;
                    646:        }
                    647:        command_info[info_len++] = gid_list;
                    648:        grlist_delref(grlist);
                    649:     }
                    650:     if (def_closefrom >= 0)
                    651:        easprintf(&command_info[info_len++], "closefrom=%d", def_closefrom);
                    652:     if (def_noexec)
                    653:        command_info[info_len++] = estrdup("noexec=true");
                    654:     if (def_noexec_file)
                    655:        command_info[info_len++] = fmt_string("noexec_file", def_noexec_file);
                    656:     if (def_set_utmp)
                    657:        command_info[info_len++] = estrdup("set_utmp=true");
                    658:     if (def_use_pty)
                    659:        command_info[info_len++] = estrdup("use_pty=true");
                    660:     if (def_utmp_runas)
                    661:        command_info[info_len++] = fmt_string("utmp_user", runas_pw->pw_name);
                    662: #ifdef HAVE_LOGIN_CAP_H
                    663:     if (lc != NULL)
                    664:        command_info[info_len++] = fmt_string("login_class", lc->lc_class);
                    665: #endif /* HAVE_LOGIN_CAP_H */
                    666: #ifdef HAVE_SELINUX
                    667:     if (user_role != NULL)
                    668:        command_info[info_len++] = fmt_string("selinux_role", user_role);
                    669:     if (user_type != NULL)
                    670:        command_info[info_len++] = fmt_string("selinux_type", user_type);
                    671: #endif /* HAVE_SELINUX */
                    672: 
                    673:     /* Must audit before uid change. */
                    674:     audit_success(NewArgv);
                    675: 
                    676:     *command_infop = command_info;
                    677: 
                    678:     *argv_out = edit_argv ? edit_argv : NewArgv;
                    679:     *user_env_out = env_get(); /* our private copy */
                    680: 
                    681:     goto done;
                    682: 
                    683: bad:
                    684:     rval = FALSE;
                    685: 
                    686: done:
                    687:     rewind_perms();
                    688: 
                    689:     /* Close the password and group files and free up memory. */
                    690:     sudo_endpwent();
                    691:     sudo_endgrent();
                    692: 
                    693:     return rval;
                    694: }
                    695: 
                    696: static int
                    697: sudoers_policy_check(int argc, char * const argv[], char *env_add[],
                    698:     char **command_infop[], char **argv_out[], char **user_env_out[])
                    699: {
                    700:     if (!ISSET(sudo_mode, MODE_EDIT))
                    701:        SET(sudo_mode, MODE_RUN);
                    702: 
                    703:     return sudoers_policy_main(argc, argv, 0, env_add, command_infop,
                    704:        argv_out, user_env_out);
                    705: }
                    706: 
                    707: static int
                    708: sudoers_policy_validate(void)
                    709: {
                    710:     user_cmnd = "validate";
                    711:     SET(sudo_mode, MODE_VALIDATE);
                    712: 
                    713:     return sudoers_policy_main(0, NULL, I_VERIFYPW, NULL, NULL, NULL, NULL);
                    714: }
                    715: 
                    716: static void
                    717: sudoers_policy_invalidate(int remove)
                    718: {
                    719:     user_cmnd = "kill";
                    720:     if (sigsetjmp(error_jmp, 1) == 0) {
                    721:        remove_timestamp(remove);
                    722:        plugin_cleanup(0);
                    723:     }
                    724: }
                    725: 
                    726: static int
                    727: sudoers_policy_list(int argc, char * const argv[], int verbose,
                    728:     const char *list_user)
                    729: {
                    730:     int rval;
                    731: 
                    732:     user_cmnd = "list";
                    733:     if (argc)
                    734:        SET(sudo_mode, MODE_CHECK);
                    735:     else
                    736:        SET(sudo_mode, MODE_LIST);
                    737:     if (verbose)
                    738:        long_list = 1;
                    739:     if (list_user) {
                    740:        list_pw = sudo_getpwnam(list_user);
                    741:        if (list_pw == NULL) {
                    742:            warningx(_("unknown user: %s"), list_user);
                    743:            return -1;
                    744:        }
                    745:     }
                    746:     rval = sudoers_policy_main(argc, argv, I_LISTPW, NULL, NULL, NULL, NULL);
                    747:     if (list_user) {
                    748:        pw_delref(list_pw);
                    749:        list_pw = NULL;
                    750:     }
                    751: 
                    752:     return rval;
                    753: }
                    754: 
                    755: /*
                    756:  * Initialize timezone, set umask, fill in ``sudo_user'' struct and
                    757:  * load the ``interfaces'' array.
                    758:  */
                    759: static void
                    760: init_vars(char * const envp[])
                    761: {
                    762:     char * const * ep;
                    763: 
                    764: #ifdef HAVE_TZSET
                    765:     (void) tzset();            /* set the timezone if applicable */
                    766: #endif /* HAVE_TZSET */
                    767: 
                    768:     for (ep = envp; *ep; ep++) {
                    769:        /* XXX - don't fill in if empty string */
                    770:        switch (**ep) {
                    771:            case 'K':
                    772:                if (strncmp("KRB5CCNAME=", *ep, 11) == 0)
                    773:                    user_ccname = *ep + 11;
                    774:                break;
                    775:            case 'P':
                    776:                if (strncmp("PATH=", *ep, 5) == 0)
                    777:                    user_path = *ep + 5;
                    778:                break;
                    779:            case 'S':
                    780:                if (!user_prompt && strncmp("SUDO_PROMPT=", *ep, 12) == 0)
                    781:                    user_prompt = *ep + 12;
                    782:                else if (strncmp("SUDO_USER=", *ep, 10) == 0)
                    783:                    prev_user = *ep + 10;
                    784:                break;
                    785:            }
                    786:     }
                    787: 
                    788:     /*
                    789:      * Get a local copy of the user's struct passwd with the shadow password
                    790:      * if necessary.  It is assumed that euid is 0 at this point so we
                    791:      * can read the shadow passwd file if necessary.
                    792:      */
                    793:     if ((sudo_user.pw = sudo_getpwuid(user_uid)) == NULL) {
                    794:        /*
                    795:         * It is not unusual for users to place "sudo -k" in a .logout
                    796:         * file which can cause sudo to be run during reboot after the
                    797:         * YP/NIS/NIS+/LDAP/etc daemon has died.
                    798:         */
                    799:        if (sudo_mode == MODE_KILL || sudo_mode == MODE_INVALIDATE)
                    800:            errorx(1, _("unknown uid: %u"), (unsigned int) user_uid);
                    801: 
                    802:        /* Need to make a fake struct passwd for the call to log_error(). */
                    803:        sudo_user.pw = sudo_fakepwnamid(user_name, user_uid, user_gid);
                    804:        log_error(0, _("unknown uid: %u"), (unsigned int) user_uid);
                    805:        /* NOTREACHED */
                    806:     }
                    807: 
                    808:     /*
                    809:      * Get group list.
                    810:      */
                    811:     if (user_group_list == NULL)
                    812:        user_group_list = get_group_list(sudo_user.pw);
                    813: 
                    814:     /* Set runas callback. */
                    815:     sudo_defs_table[I_RUNAS_DEFAULT].callback = cb_runas_default;
                    816: 
                    817:     /* It is now safe to use log_error() and set_perms() */
                    818: }
                    819: 
                    820: /*
                    821:  * Fill in user_cmnd, user_args, user_base and user_stat variables
                    822:  * and apply any command-specific defaults entries.
                    823:  */
                    824: static int
                    825: set_cmnd(void)
                    826: {
                    827:     int rval;
                    828:     char *path = user_path;
                    829: 
                    830:     /* Resolve the path and return. */
                    831:     rval = FOUND;
                    832:     user_stat = emalloc(sizeof(struct stat));
                    833: 
                    834:     /* Default value for cmnd, overridden below. */
                    835:     if (user_cmnd == NULL)
                    836:        user_cmnd = NewArgv[0];
                    837: 
                    838:     if (sudo_mode & (MODE_RUN | MODE_EDIT | MODE_CHECK)) {
                    839:        if (ISSET(sudo_mode, MODE_RUN | MODE_CHECK)) {
                    840:            if (def_secure_path && !user_is_exempt())
                    841:                path = def_secure_path;
                    842:            set_perms(PERM_RUNAS);
                    843:            rval = find_path(NewArgv[0], &user_cmnd, user_stat, path,
                    844:                def_ignore_dot);
                    845:            restore_perms();
                    846:            if (rval != FOUND) {
                    847:                /* Failed as root, try as invoking user. */
                    848:                set_perms(PERM_USER);
                    849:                rval = find_path(NewArgv[0], &user_cmnd, user_stat, path,
                    850:                    def_ignore_dot);
                    851:                restore_perms();
                    852:            }
                    853:        }
                    854: 
                    855:        /* set user_args */
                    856:        if (NewArgc > 1) {
                    857:            char *to, *from, **av;
                    858:            size_t size, n;
                    859: 
                    860:            /* Alloc and build up user_args. */
                    861:            for (size = 0, av = NewArgv + 1; *av; av++)
                    862:                size += strlen(*av) + 1;
                    863:            user_args = emalloc(size);
                    864:            if (ISSET(sudo_mode, MODE_SHELL|MODE_LOGIN_SHELL)) {
                    865:                /*
                    866:                 * When running a command via a shell, the sudo front-end
                    867:                 * escapes potential meta chars.  We unescape non-spaces
                    868:                 * for sudoers matching and logging purposes.
                    869:                 */
                    870:                for (to = user_args, av = NewArgv + 1; (from = *av); av++) {
                    871:                    while (*from) {
                    872:                        if (from[0] == '\\' && !isspace((unsigned char)from[1]))
                    873:                            from++;
                    874:                        *to++ = *from++;
                    875:                    }
                    876:                    *to++ = ' ';
                    877:                }
                    878:                *--to = '\0';
                    879:            } else {
                    880:                for (to = user_args, av = NewArgv + 1; *av; av++) {
                    881:                    n = strlcpy(to, *av, size - (to - user_args));
                    882:                    if (n >= size - (to - user_args))
                    883:                        errorx(1, _("internal error, set_cmnd() overflow"));
                    884:                    to += n;
                    885:                    *to++ = ' ';
                    886:                }
                    887:                *--to = '\0';
                    888:            }
                    889:        }
                    890:     }
                    891:     if (strlen(user_cmnd) >= PATH_MAX)
                    892:        errorx(1, _("%s: %s"), user_cmnd, strerror(ENAMETOOLONG));
                    893: 
                    894:     if ((user_base = strrchr(user_cmnd, '/')) != NULL)
                    895:        user_base++;
                    896:     else
                    897:        user_base = user_cmnd;
                    898: 
                    899:     if (!update_defaults(SETDEF_CMND))
                    900:        log_error(NO_STDERR|NO_EXIT, _("problem with defaults entries"));
                    901: 
                    902:     return rval;
                    903: }
                    904: 
                    905: /*
                    906:  * Open sudoers and sanity check mode/owner/type.
                    907:  * Returns a handle to the sudoers file or NULL on error.
                    908:  */
                    909: FILE *
                    910: open_sudoers(const char *sudoers, int doedit, int *keepopen)
                    911: {
                    912:     struct stat statbuf;
                    913:     FILE *fp = NULL;
                    914:     int rootstat;
                    915: 
                    916:     /*
                    917:      * Fix the mode and group on sudoers file from old default.
                    918:      * Only works if file system is readable/writable by root.
                    919:      */
                    920:     if ((rootstat = stat_sudoers(sudoers, &statbuf)) == 0 &&
                    921:        sudoers_uid == statbuf.st_uid && sudoers_mode != 0400 &&
                    922:        (statbuf.st_mode & 0007777) == 0400) {
                    923: 
                    924:        if (chmod(sudoers, sudoers_mode) == 0) {
                    925:            warningx(_("fixed mode on %s"), sudoers);
                    926:            SET(statbuf.st_mode, sudoers_mode);
                    927:            if (statbuf.st_gid != sudoers_gid) {
                    928:                if (chown(sudoers, (uid_t) -1, sudoers_gid) == 0) {
                    929:                    warningx(_("set group on %s"), sudoers);
                    930:                    statbuf.st_gid = sudoers_gid;
                    931:                } else
                    932:                    warning(_("unable to set group on %s"), sudoers);
                    933:            }
                    934:        } else
                    935:            warning(_("unable to fix mode on %s"), sudoers);
                    936:     }
                    937: 
                    938:     /*
                    939:      * Sanity checks on sudoers file.  Must be done as sudoers
                    940:      * file owner.  We already did a stat as root, so use that
                    941:      * data if we can't stat as sudoers file owner.
                    942:      */
                    943:     set_perms(PERM_SUDOERS);
                    944: 
                    945:     if (rootstat != 0 && stat_sudoers(sudoers, &statbuf) != 0)
                    946:        log_error(USE_ERRNO|NO_EXIT, _("unable to stat %s"), sudoers);
                    947:     else if (!S_ISREG(statbuf.st_mode))
                    948:        log_error(NO_EXIT, _("%s is not a regular file"), sudoers);
                    949:     else if ((statbuf.st_mode & 07577) != sudoers_mode)
                    950:        log_error(NO_EXIT, _("%s is mode 0%o, should be 0%o"), sudoers,
                    951:            (unsigned int) (statbuf.st_mode & 07777),
                    952:            (unsigned int) sudoers_mode);
                    953:     else if (statbuf.st_uid != sudoers_uid)
                    954:        log_error(NO_EXIT, _("%s is owned by uid %u, should be %u"), sudoers,
                    955:            (unsigned int) statbuf.st_uid, (unsigned int) sudoers_uid);
                    956:     else if (statbuf.st_gid != sudoers_gid && ISSET(statbuf.st_mode, S_IRGRP|S_IWGRP))
                    957:        log_error(NO_EXIT, _("%s is owned by gid %u, should be %u"), sudoers,
                    958:            (unsigned int) statbuf.st_gid, (unsigned int) sudoers_gid);
                    959:     else if ((fp = fopen(sudoers, "r")) == NULL)
                    960:        log_error(USE_ERRNO|NO_EXIT, _("unable to open %s"), sudoers);
                    961:     else {
                    962:        /*
                    963:         * Make sure we can actually read sudoers so we can present the
                    964:         * user with a reasonable error message (unlike the lexer).
                    965:         */
                    966:        if (statbuf.st_size != 0 && fgetc(fp) == EOF) {
                    967:            log_error(USE_ERRNO|NO_EXIT, _("unable to read %s"), sudoers);
                    968:            fclose(fp);
                    969:            fp = NULL;
                    970:        }
                    971:     }
                    972: 
                    973:     if (fp != NULL) {
                    974:        rewind(fp);
                    975:        (void) fcntl(fileno(fp), F_SETFD, 1);
                    976:     }
                    977: 
                    978:     restore_perms();           /* change back to root */
                    979:     return fp;
                    980: }
                    981: 
                    982: #ifdef HAVE_LOGIN_CAP_H
                    983: static void
                    984: set_loginclass(struct passwd *pw)
                    985: {
                    986:     int errflags;
                    987: 
                    988:     /*
                    989:      * Don't make it a fatal error if the user didn't specify the login
                    990:      * class themselves.  We do this because if login.conf gets
                    991:      * corrupted we want the admin to be able to use sudo to fix it.
                    992:      */
                    993:     if (login_class)
                    994:        errflags = NO_MAIL|MSG_ONLY;
                    995:     else
                    996:        errflags = NO_MAIL|MSG_ONLY|NO_EXIT;
                    997: 
                    998:     if (login_class && strcmp(login_class, "-") != 0) {
                    999:        if (user_uid != 0 &&
                   1000:            strcmp(runas_user ? runas_user : def_runas_default, "root") != 0)
                   1001:            errorx(1, _("only root can use `-c %s'"), login_class);
                   1002:     } else {
                   1003:        login_class = pw->pw_class;
                   1004:        if (!login_class || !*login_class)
                   1005:            login_class =
                   1006:                (pw->pw_uid == 0) ? LOGIN_DEFROOTCLASS : LOGIN_DEFCLASS;
                   1007:     }
                   1008: 
                   1009:     lc = login_getclass(login_class);
                   1010:     if (!lc || !lc->lc_class || strcmp(lc->lc_class, login_class) != 0) {
                   1011:        log_error(errflags, _("unknown login class: %s"), login_class);
                   1012:        if (!lc)
                   1013:            lc = login_getclass(NULL);  /* needed for login_getstyle() later */
                   1014:     }
                   1015: }
                   1016: #else
                   1017: static void
                   1018: set_loginclass(struct passwd *pw)
                   1019: {
                   1020: }
                   1021: #endif /* HAVE_LOGIN_CAP_H */
                   1022: 
                   1023: /*
                   1024:  * Look up the fully qualified domain name and set user_host and user_shost.
                   1025:  */
                   1026: void
                   1027: set_fqdn(void)
                   1028: {
                   1029: #ifdef HAVE_GETADDRINFO
                   1030:     struct addrinfo *res0, hint;
                   1031: #else
                   1032:     struct hostent *hp;
                   1033: #endif
                   1034:     char *p;
                   1035: 
                   1036: #ifdef HAVE_GETADDRINFO
                   1037:     zero_bytes(&hint, sizeof(hint));
                   1038:     hint.ai_family = PF_UNSPEC;
                   1039:     hint.ai_flags = AI_CANONNAME;
                   1040:     if (getaddrinfo(user_host, NULL, &hint, &res0) != 0) {
                   1041: #else
                   1042:     if (!(hp = gethostbyname(user_host))) {
                   1043: #endif
                   1044:        log_error(MSG_ONLY|NO_EXIT,
                   1045:            _("unable to resolve host %s"), user_host);
                   1046:     } else {
                   1047:        if (user_shost != user_host)
                   1048:            efree(user_shost);
                   1049:        efree(user_host);
                   1050: #ifdef HAVE_GETADDRINFO
                   1051:        user_host = estrdup(res0->ai_canonname);
                   1052:        freeaddrinfo(res0);
                   1053: #else
                   1054:        user_host = estrdup(hp->h_name);
                   1055: #endif
                   1056:     }
                   1057:     if ((p = strchr(user_host, '.')) != NULL)
                   1058:        user_shost = estrndup(user_host, (size_t)(p - user_host));
                   1059:     else
                   1060:        user_shost = user_host;
                   1061: }
                   1062: 
                   1063: /*
                   1064:  * Get passwd entry for the user we are going to run commands as
                   1065:  * and store it in runas_pw.  By default, commands run as "root".
                   1066:  */
                   1067: void
                   1068: set_runaspw(const char *user)
                   1069: {
                   1070:     if (runas_pw != NULL)
                   1071:        pw_delref(runas_pw);
                   1072:     if (*user == '#') {
                   1073:        if ((runas_pw = sudo_getpwuid(atoi(user + 1))) == NULL)
                   1074:            runas_pw = sudo_fakepwnam(user, runas_gr ? runas_gr->gr_gid : 0);
                   1075:     } else {
                   1076:        if ((runas_pw = sudo_getpwnam(user)) == NULL)
                   1077:            log_error(NO_MAIL|MSG_ONLY, _("unknown user: %s"), user);
                   1078:     }
                   1079: }
                   1080: 
                   1081: /*
                   1082:  * Get group entry for the group we are going to run commands as
                   1083:  * and store it in runas_gr.
                   1084:  */
                   1085: static void
                   1086: set_runasgr(const char *group)
                   1087: {
                   1088:     if (runas_gr != NULL)
                   1089:        gr_delref(runas_gr);
                   1090:     if (*group == '#') {
                   1091:        if ((runas_gr = sudo_getgrgid(atoi(group + 1))) == NULL)
                   1092:            runas_gr = sudo_fakegrnam(group);
                   1093:     } else {
                   1094:        if ((runas_gr = sudo_getgrnam(group)) == NULL)
                   1095:            log_error(NO_MAIL|MSG_ONLY, _("unknown group: %s"), group);
                   1096:     }
                   1097: }
                   1098: 
                   1099: /*
                   1100:  * Callback for runas_default sudoers setting.
                   1101:  */
                   1102: static int
                   1103: cb_runas_default(const char *user)
                   1104: {
                   1105:     /* Only reset runaspw if user didn't specify one. */
                   1106:     if (!runas_user && !runas_group)
                   1107:        set_runaspw(user);
                   1108:     return TRUE;
                   1109: }
                   1110: 
                   1111: /*
                   1112:  * Cleanup hook for error()/errorx()
                   1113:  */
                   1114: void
                   1115: plugin_cleanup(int gotsignal)
                   1116: {
                   1117:     struct sudo_nss *nss;
                   1118: 
                   1119:     if (!gotsignal) {
                   1120:        if (snl != NULL) {
                   1121:            tq_foreach_fwd(snl, nss)
                   1122:                nss->close(nss);
                   1123:        }
                   1124:        if (def_group_plugin)
                   1125:            group_plugin_unload();
                   1126:        sudo_endpwent();
                   1127:        sudo_endgrent();
                   1128:     }
                   1129: }
                   1130: 
                   1131: static int
                   1132: sudoers_policy_version(int verbose)
                   1133: {
                   1134:     if (sigsetjmp(error_jmp, 1)) {
                   1135:        /* error recovery via error(), errorx() or log_error() */
                   1136:        return -1;
                   1137:     }
                   1138: 
                   1139:     sudo_printf(SUDO_CONV_INFO_MSG, _("Sudoers policy plugin version %s\n"),
                   1140:        PACKAGE_VERSION);
                   1141:     sudo_printf(SUDO_CONV_INFO_MSG, _("Sudoers file grammar version %d\n"),
                   1142:        SUDOERS_GRAMMAR_VERSION);
                   1143: 
                   1144:     if (verbose) {
                   1145:        sudo_printf(SUDO_CONV_INFO_MSG, _("\nSudoers path: %s\n"), sudoers_file);
                   1146: #ifdef HAVE_LDAP
                   1147: # ifdef _PATH_NSSWITCH_CONF
                   1148:        sudo_printf(SUDO_CONV_INFO_MSG, _("nsswitch path: %s\n"), _PATH_NSSWITCH_CONF);
                   1149: # endif
                   1150:        sudo_printf(SUDO_CONV_INFO_MSG, _("ldap.conf path: %s\n"), _PATH_LDAP_CONF);
                   1151:        sudo_printf(SUDO_CONV_INFO_MSG, _("ldap.secret path: %s\n"), _PATH_LDAP_SECRET);
                   1152: #endif
                   1153:        dump_auth_methods();
                   1154:        dump_defaults();
                   1155:        sudo_printf(SUDO_CONV_INFO_MSG, "\n");
                   1156:        dump_interfaces(interfaces_string);
                   1157:        sudo_printf(SUDO_CONV_INFO_MSG, "\n");
                   1158:     }
                   1159:     return TRUE;
                   1160: }
                   1161: 
                   1162: static int
                   1163: deserialize_info(char * const settings[], char * const user_info[])
                   1164: {
                   1165:     char * const *cur;
                   1166:     const char *p, *groups = NULL;
                   1167:     int flags = 0;
                   1168: 
                   1169: #define MATCHES(s, v) (strncmp(s, v, sizeof(v) - 1) == 0)
                   1170: 
                   1171:     /* Parse command line settings. */
                   1172:     user_closefrom = -1;
                   1173:     for (cur = settings; *cur != NULL; cur++) {
                   1174:        if (MATCHES(*cur, "closefrom=")) {
                   1175:            user_closefrom = atoi(*cur + sizeof("closefrom=") - 1);
                   1176:            continue;
                   1177:        }
                   1178:        if (MATCHES(*cur, "debug_level=")) {
                   1179:            debug_level = atoi(*cur + sizeof("debug_level=") - 1);
                   1180:            continue;
                   1181:        }
                   1182:        if (MATCHES(*cur, "runas_user=")) {
                   1183:            runas_user = *cur + sizeof("runas_user=") - 1;
                   1184:            continue;
                   1185:        }
                   1186:        if (MATCHES(*cur, "runas_group=")) {
                   1187:            runas_group = *cur + sizeof("runas_group=") - 1;
                   1188:            continue;
                   1189:        }
                   1190:        if (MATCHES(*cur, "prompt=")) {
                   1191:            user_prompt = *cur + sizeof("prompt=") - 1;
                   1192:            def_passprompt_override = TRUE;
                   1193:            continue;
                   1194:        }
                   1195:        if (MATCHES(*cur, "set_home=")) {
                   1196:            if (atobool(*cur + sizeof("set_home=") - 1) == TRUE)
                   1197:                SET(flags, MODE_RESET_HOME);
                   1198:            continue;
                   1199:        }
                   1200:        if (MATCHES(*cur, "preserve_environment=")) {
                   1201:            if (atobool(*cur + sizeof("preserve_environment=") - 1) == TRUE)
                   1202:                SET(flags, MODE_PRESERVE_ENV);
                   1203:            continue;
                   1204:        }
                   1205:        if (MATCHES(*cur, "run_shell=")) {
                   1206:            if (atobool(*cur + sizeof("run_shell=") - 1) == TRUE)
                   1207:                SET(flags, MODE_SHELL);
                   1208:            continue;
                   1209:        }
                   1210:        if (MATCHES(*cur, "login_shell=")) {
                   1211:            if (atobool(*cur + sizeof("login_shell=") - 1) == TRUE) {
                   1212:                SET(flags, MODE_LOGIN_SHELL);
                   1213:                def_env_reset = TRUE;
                   1214:            }
                   1215:            continue;
                   1216:        }
                   1217:        if (MATCHES(*cur, "implied_shell=")) {
                   1218:            if (atobool(*cur + sizeof("implied_shell=") - 1) == TRUE)
                   1219:                SET(flags, MODE_IMPLIED_SHELL);
                   1220:            continue;
                   1221:        }
                   1222:        if (MATCHES(*cur, "preserve_groups=")) {
                   1223:            if (atobool(*cur + sizeof("preserve_groups=") - 1) == TRUE)
                   1224:                SET(flags, MODE_PRESERVE_GROUPS);
                   1225:            continue;
                   1226:        }
                   1227:        if (MATCHES(*cur, "ignore_ticket=")) {
                   1228:            if (atobool(*cur + sizeof("ignore_ticket=") - 1) == TRUE)
                   1229:                SET(flags, MODE_IGNORE_TICKET);
                   1230:            continue;
                   1231:        }
                   1232:        if (MATCHES(*cur, "noninteractive=")) {
                   1233:            if (atobool(*cur + sizeof("noninteractive=") - 1) == TRUE)
                   1234:                SET(flags, MODE_NONINTERACTIVE);
                   1235:            continue;
                   1236:        }
                   1237:        if (MATCHES(*cur, "sudoedit=")) {
                   1238:            if (atobool(*cur + sizeof("sudoedit=") - 1) == TRUE)
                   1239:                SET(flags, MODE_EDIT);
                   1240:            continue;
                   1241:        }
                   1242:        if (MATCHES(*cur, "login_class=")) {
                   1243:            login_class = *cur + sizeof("login_class=") - 1;
                   1244:            def_use_loginclass = TRUE;
                   1245:            continue;
                   1246:        }
                   1247: #ifdef HAVE_SELINUX
                   1248:        if (MATCHES(*cur, "selinux_role=")) {
                   1249:            user_role = *cur + sizeof("selinux_role=") - 1;
                   1250:            continue;
                   1251:        }
                   1252:        if (MATCHES(*cur, "selinux_type=")) {
                   1253:            user_type = *cur + sizeof("selinux_type=") - 1;
                   1254:            continue;
                   1255:        }
                   1256: #endif /* HAVE_SELINUX */
                   1257: #ifdef HAVE_BSD_AUTH_H
                   1258:        if (MATCHES(*cur, "bsdauth_type=")) {
                   1259:            login_style = *cur + sizeof("bsdauth_type=") - 1;
                   1260:            continue;
                   1261:        }
                   1262: #endif /* HAVE_BSD_AUTH_H */
                   1263: #if !defined(HAVE_GETPROGNAME) && !defined(HAVE___PROGNAME)
                   1264:        if (MATCHES(*cur, "progname=")) {
                   1265:            setprogname(*cur + sizeof("progname=") - 1);
                   1266:            continue;
                   1267:        }
                   1268: #endif
                   1269:        if (MATCHES(*cur, "network_addrs=")) {
                   1270:            interfaces_string = *cur + sizeof("network_addrs=") - 1;
                   1271:            set_interfaces(interfaces_string);
                   1272:            continue;
                   1273:        }
                   1274:        if (MATCHES(*cur, "sudoers_file=")) {
                   1275:            sudoers_file = *cur + sizeof("sudoers_file=") - 1;
                   1276:            continue;
                   1277:        }
                   1278:        if (MATCHES(*cur, "sudoers_uid=")) {
                   1279:            sudoers_uid = (uid_t) atoi(*cur + sizeof("sudoers_uid=") - 1);
                   1280:            continue;
                   1281:        }
                   1282:        if (MATCHES(*cur, "sudoers_gid=")) {
                   1283:            sudoers_gid = (gid_t) atoi(*cur + sizeof("sudoers_gid=") - 1);
                   1284:            continue;
                   1285:        }
                   1286:        if (MATCHES(*cur, "sudoers_mode=")) {
                   1287:            sudoers_mode = (mode_t) strtol(*cur + sizeof("sudoers_mode=") - 1,
                   1288:                NULL, 8);
                   1289:            continue;
                   1290:        }
                   1291:     }
                   1292: 
                   1293:     for (cur = user_info; *cur != NULL; cur++) {
                   1294:        if (MATCHES(*cur, "user=")) {
                   1295:            user_name = estrdup(*cur + sizeof("user=") - 1);
                   1296:            continue;
                   1297:        }
                   1298:        if (MATCHES(*cur, "uid=")) {
                   1299:            user_uid = (uid_t) atoi(*cur + sizeof("uid=") - 1);
                   1300:            continue;
                   1301:        }
                   1302:        if (MATCHES(*cur, "gid=")) {
                   1303:            p = *cur + sizeof("gid=") - 1;
                   1304:            user_gid = (gid_t) atoi(p);
                   1305:            continue;
                   1306:        }
                   1307:        if (MATCHES(*cur, "groups=")) {
                   1308:            groups = *cur + sizeof("groups=") - 1;
                   1309:            continue;
                   1310:        }
                   1311:        if (MATCHES(*cur, "cwd=")) {
                   1312:            user_cwd = estrdup(*cur + sizeof("cwd=") - 1);
                   1313:            continue;
                   1314:        }
                   1315:        if (MATCHES(*cur, "tty=")) {
                   1316:            user_tty = user_ttypath = estrdup(*cur + sizeof("tty=") - 1);
                   1317:            if (strncmp(user_tty, _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0)
                   1318:                user_tty += sizeof(_PATH_DEV) - 1;
                   1319:            continue;
                   1320:        }
                   1321:        if (MATCHES(*cur, "host=")) {
                   1322:            user_host = user_shost = estrdup(*cur + sizeof("host=") - 1);
                   1323:            if ((p = strchr(user_host, '.')))
                   1324:                user_shost = estrndup(user_host, (size_t)(p - user_host));
                   1325:            continue;
                   1326:        }
                   1327:        if (MATCHES(*cur, "lines=")) {
                   1328:            sudo_user.lines = atoi(*cur + sizeof("lines=") - 1);
                   1329:            continue;
                   1330:        }
                   1331:        if (MATCHES(*cur, "cols=")) {
                   1332:            sudo_user.cols = atoi(*cur + sizeof("cols=") - 1);
                   1333:            continue;
                   1334:        }
                   1335:     }
                   1336:     if (user_cwd == NULL)
                   1337:        user_cwd = "unknown";
                   1338:     if (user_tty == NULL)
                   1339:        user_tty = "unknown"; /* user_ttypath remains NULL */
                   1340: 
                   1341:     if (groups != NULL && groups[0] != '\0') {
                   1342:        const char *cp;
                   1343:        GETGROUPS_T *gids;
                   1344:        int ngids;
                   1345: 
                   1346:        /* Count number of groups, including passwd gid. */
                   1347:        ngids = 2;
                   1348:        for (cp = groups; *cp != '\0'; cp++) {
                   1349:            if (*cp == ',')
                   1350:                ngids++;
                   1351:        }
                   1352: 
                   1353:        /* The first gid in the list is the passwd group gid. */
                   1354:        gids = emalloc2(ngids, sizeof(GETGROUPS_T));
                   1355:        gids[0] = user_gid;
                   1356:        ngids = 1;
                   1357:        cp = groups;
                   1358:        for (;;) {
                   1359:            gids[ngids] = atoi(cp);
                   1360:            if (gids[0] != gids[ngids])
                   1361:                ngids++;
                   1362:            cp = strchr(cp, ',');
                   1363:            if (cp == NULL)
                   1364:                break;
                   1365:            cp++; /* skip over comma */
                   1366:        }
                   1367:        set_group_list(user_name, gids, ngids);
                   1368:        efree(gids);
                   1369:     }
                   1370: 
                   1371: #undef MATCHES
                   1372:     return flags;
                   1373: }
                   1374: 
                   1375: static char *
                   1376: resolve_editor(char *editor, int nfiles, char **files, char ***argv_out)
                   1377: {
                   1378:     char *cp, **nargv, *editor_path = NULL;
                   1379:     int ac, i, nargc, wasblank;
                   1380: 
                   1381:     editor = estrdup(editor); /* becomes part of argv_out */
                   1382: 
                   1383:     /*
                   1384:      * Split editor into an argument vector; editor is reused (do not free).
                   1385:      * The EDITOR and VISUAL environment variables may contain command
                   1386:      * line args so look for those and alloc space for them too.
                   1387:      */
                   1388:     nargc = 1;
                   1389:     for (wasblank = FALSE, cp = editor; *cp != '\0'; cp++) {
                   1390:        if (isblank((unsigned char) *cp))
                   1391:            wasblank = TRUE;
                   1392:        else if (wasblank) {
                   1393:            wasblank = FALSE;
                   1394:            nargc++;
                   1395:        }
                   1396:     }
                   1397:     /* If we can't find the editor in the user's PATH, give up. */
                   1398:     cp = strtok(editor, " \t");
                   1399:     if (cp == NULL ||
                   1400:        find_path(cp, &editor_path, NULL, getenv("PATH"), 0) != FOUND) {
                   1401:        efree(editor);
                   1402:        return NULL;
                   1403:     }
                   1404:     nargv = (char **) emalloc2(nargc + 1 + nfiles + 1, sizeof(char *));
                   1405:     for (ac = 0; cp != NULL && ac < nargc; ac++) {
                   1406:        nargv[ac] = cp;
                   1407:        cp = strtok(NULL, " \t");
                   1408:     }
                   1409:     nargv[ac++] = "--";
                   1410:     for (i = 0; i < nfiles; )
                   1411:        nargv[ac++] = files[i++];
                   1412:     nargv[ac] = NULL;
                   1413: 
                   1414:     *argv_out = nargv;
                   1415:     return editor_path;
                   1416: }
                   1417: 
                   1418: /*
                   1419:  * Determine which editor to use.  We don't need to worry about restricting
                   1420:  * this to a "safe" editor since it runs with the uid of the invoking user,
                   1421:  * not the runas (privileged) user.
                   1422:  */
                   1423: static char *
                   1424: find_editor(int nfiles, char **files, char ***argv_out)
                   1425: {
                   1426:     char *cp, *editor, *editor_path = NULL, **ev, *ev0[4];
                   1427: 
                   1428:     /*
                   1429:      * If any of SUDO_EDITOR, VISUAL or EDITOR are set, choose the first one.
                   1430:      */
                   1431:     ev0[0] = "SUDO_EDITOR";
                   1432:     ev0[1] = "VISUAL";
                   1433:     ev0[2] = "EDITOR";
                   1434:     ev0[3] = NULL;
                   1435:     for (ev = ev0; *ev != NULL; ev++) {
                   1436:        if ((editor = getenv(*ev)) != NULL && *editor != '\0') {
                   1437:            editor_path = resolve_editor(editor, nfiles, files, argv_out);
                   1438:            if (editor_path != NULL)
                   1439:                break;
                   1440:        }
                   1441:     }
                   1442:     if (editor_path == NULL) {
                   1443:        /* def_editor could be a path, split it up */
                   1444:        editor = estrdup(def_editor);
                   1445:        cp = strtok(editor, ":");
                   1446:        while (cp != NULL && editor_path == NULL) {
                   1447:            editor_path = resolve_editor(cp, nfiles, files, argv_out);
                   1448:            cp = strtok(NULL, ":");
                   1449:        }
                   1450:        if (editor_path)
                   1451:            efree(editor);
                   1452:     }
                   1453:     if (!editor_path) {
                   1454:        audit_failure(NewArgv, _("%s: command not found"), editor);
                   1455:        warningx(_("%s: command not found"), editor);
                   1456:     }
                   1457:     return editor_path;
                   1458: }
                   1459: 
                   1460: #ifdef USE_ADMIN_FLAG
                   1461: static void
                   1462: create_admin_success_flag(void)
                   1463: {
                   1464:     struct stat statbuf;
                   1465:     char flagfile[PATH_MAX];
                   1466:     int fd, n;
                   1467: 
                   1468:     /* Check whether the user is in the admin group. */
                   1469:     if (!user_in_group(sudo_user.pw, "admin"))
                   1470:        return;
                   1471: 
                   1472:     /* Build path to flag file. */
                   1473:     n = snprintf(flagfile, sizeof(flagfile), "%s/.sudo_as_admin_successful",
                   1474:        user_dir);
                   1475:     if (n <= 0 || n >= sizeof(flagfile))
                   1476:        return;
                   1477: 
                   1478:     /* Create admin flag file if it doesn't already exist. */
                   1479:     set_perms(PERM_USER);
                   1480:     if (stat(flagfile, &statbuf) != 0) {
                   1481:        fd = open(flagfile, O_CREAT|O_WRONLY|O_EXCL, 0644);
                   1482:        close(fd);
                   1483:     }
                   1484:     restore_perms();
                   1485: }
                   1486: #else /* !USE_ADMIN_FLAG */
                   1487: static void
                   1488: create_admin_success_flag(void)
                   1489: {
                   1490:     /* STUB */
                   1491: }
                   1492: #endif /* USE_ADMIN_FLAG */
                   1493: 
                   1494: struct policy_plugin sudoers_policy = {
                   1495:     SUDO_POLICY_PLUGIN,
                   1496:     SUDO_API_VERSION,
                   1497:     sudoers_policy_open,
                   1498:     sudoers_policy_close,
                   1499:     sudoers_policy_version,
                   1500:     sudoers_policy_check,
                   1501:     sudoers_policy_list,
                   1502:     sudoers_policy_validate,
                   1503:     sudoers_policy_invalidate,
                   1504:     sudoers_policy_init_session
                   1505: };

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>