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

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

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