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

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

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