Annotation of embedaddon/sudo/plugins/sudoers/sudoers.c, revision 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>