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

1.1       misho       1: /*
1.1.1.4   misho       2:  * Copyright (c) 1993-1996, 1998-2013 Todd C. Miller <Todd.Miller@courtesan.com>
1.1       misho       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: 
                     21: #define _SUDO_MAIN
                     22: 
                     23: #ifdef __TANDEM
                     24: # include <floss.h>
                     25: #endif
                     26: 
                     27: #include <config.h>
                     28: 
                     29: #include <sys/types.h>
                     30: #include <sys/stat.h>
                     31: #include <sys/socket.h>
                     32: #include <stdio.h>
                     33: #ifdef STDC_HEADERS
                     34: # include <stdlib.h>
                     35: # include <stddef.h>
                     36: #else
                     37: # ifdef HAVE_STDLIB_H
                     38: #  include <stdlib.h>
                     39: # endif
                     40: #endif /* STDC_HEADERS */
                     41: #ifdef HAVE_STRING_H
                     42: # if defined(HAVE_MEMORY_H) && !defined(STDC_HEADERS)
                     43: #  include <memory.h>
                     44: # endif
                     45: # include <string.h>
                     46: #endif /* HAVE_STRING_H */
                     47: #ifdef HAVE_STRINGS_H
                     48: # include <strings.h>
                     49: #endif /* HAVE_STRINGS_H */
                     50: #ifdef HAVE_UNISTD_H
                     51: # include <unistd.h>
                     52: #endif /* HAVE_UNISTD_H */
                     53: #include <pwd.h>
                     54: #include <errno.h>
                     55: #include <fcntl.h>
                     56: #include <signal.h>
                     57: #include <grp.h>
                     58: #include <time.h>
                     59: #include <netdb.h>
                     60: #ifdef HAVE_LOGIN_CAP_H
                     61: # include <login_cap.h>
                     62: # ifndef LOGIN_DEFROOTCLASS
                     63: #  define LOGIN_DEFROOTCLASS   "daemon"
                     64: # endif
1.1.1.2   misho      65: # ifndef LOGIN_SETENV
                     66: #  define LOGIN_SETENV 0
                     67: # endif
1.1       misho      68: #endif
                     69: #ifdef HAVE_SELINUX
                     70: # include <selinux/selinux.h>
                     71: #endif
                     72: #include <ctype.h>
1.1.1.2   misho      73: #ifndef HAVE_GETADDRINFO
                     74: # include "compat/getaddrinfo.h"
                     75: #endif
1.1       misho      76: 
                     77: #include "sudoers.h"
                     78: #include "auth/sudo_auth.h"
1.1.1.2   misho      79: #include "secure_path.h"
1.1       misho      80: 
                     81: /*
                     82:  * Prototypes
                     83:  */
1.1.1.4   misho      84: static char *find_editor(int nfiles, char **files, char ***argv_out);
                     85: static int cb_runas_default(const char *);
                     86: static int cb_sudoers_locale(const char *);
1.1       misho      87: static int set_cmnd(void);
1.1.1.4   misho      88: static void create_admin_success_flag(void);
                     89: static void init_vars(char * const *);
                     90: static void set_fqdn(void);
1.1       misho      91: static void set_loginclass(struct passwd *);
                     92: static void set_runasgr(const char *);
1.1.1.4   misho      93: static void set_runaspw(const char *);
                     94: static bool tty_present(void);
1.1       misho      95: 
                     96: /*
                     97:  * Globals
                     98:  */
                     99: struct sudo_user sudo_user;
                    100: struct passwd *list_pw;
                    101: int long_list;
                    102: uid_t timestamp_uid;
                    103: #ifdef HAVE_BSD_AUTH_H
                    104: char *login_style;
                    105: #endif /* HAVE_BSD_AUTH_H */
                    106: int sudo_mode;
                    107: 
                    108: static char *prev_user;
                    109: static char *runas_user;
                    110: static char *runas_group;
                    111: static struct sudo_nss_list *snl;
                    112: 
                    113: /* XXX - must be extern for audit bits of sudo_auth.c */
                    114: int NewArgc;
                    115: char **NewArgv;
                    116: 
1.1.1.4   misho     117: int
                    118: sudoers_policy_init(void *info, char * const envp[])
1.1       misho     119: {
                    120:     volatile int sources = 0;
1.1.1.4   misho     121:     struct sudo_nss *nss, *nss_next;
                    122:     debug_decl(sudoers_policy_init, SUDO_DEBUG_PLUGIN)
1.1       misho     123: 
                    124:     bindtextdomain("sudoers", LOCALEDIR);
                    125: 
                    126:     sudo_setpwent();
                    127:     sudo_setgrent();
                    128: 
1.1.1.4   misho     129:     /* Register fatal/fatalx callback. */
                    130:     fatal_callback_register(sudoers_cleanup);
                    131: 
1.1       misho     132:     /* Initialize environment functions (including replacements). */
                    133:     env_init(envp);
                    134: 
                    135:     /* Setup defaults data structures. */
                    136:     init_defaults();
                    137: 
1.1.1.4   misho     138:     /* Parse info from front-end. */
                    139:     sudo_mode = sudoers_policy_deserialize_info(info, &runas_user, &runas_group);
1.1       misho     140: 
                    141:     init_vars(envp);           /* XXX - move this later? */
                    142: 
                    143:     /* Parse nsswitch.conf for sudoers order. */
                    144:     snl = sudo_read_nss();
                    145: 
                    146:     /* LDAP or NSS may modify the euid so we need to be root for the open. */
                    147:     set_perms(PERM_ROOT);
                    148: 
                    149:     /* Open and parse sudoers, set global defaults */
1.1.1.6 ! misho     150:     TAILQ_FOREACH_SAFE(nss, snl, entries, nss_next) {
1.1.1.3   misho     151:         if (nss->open(nss) == 0 && nss->parse(nss) == 0) {
                    152:             sources++;
                    153:             if (nss->setdefs(nss) != 0)
1.1.1.4   misho     154:                 log_warning(NO_STDERR, N_("problem with defaults entries"));
1.1.1.3   misho     155:         } else {
1.1.1.6 ! misho     156:            TAILQ_REMOVE(snl, nss, entries);
1.1.1.3   misho     157:         }
1.1       misho     158:     }
                    159:     if (sources == 0) {
1.1.1.6 ! misho     160:        warningx(U_("no valid sudoers sources found, quitting"));
1.1.1.2   misho     161:        debug_return_bool(-1);
1.1       misho     162:     }
                    163: 
                    164:     /* XXX - collect post-sudoers parse settings into a function */
                    165: 
                    166:     /*
                    167:      * Initialize external group plugin, if any.
                    168:      */
                    169:     if (def_group_plugin) {
1.1.1.2   misho     170:        if (group_plugin_load(def_group_plugin) != true)
1.1       misho     171:            def_group_plugin = NULL;
                    172:     }
                    173: 
                    174:     /*
                    175:      * Set runas passwd/group entries based on command line or sudoers.
                    176:      * Note that if runas_group was specified without runas_user we
                    177:      * defer setting runas_pw so the match routines know to ignore it.
                    178:      */
1.1.1.4   misho     179:     /* XXX - qpm4u does more here as it may have already set runas_pw */
1.1       misho     180:     if (runas_group != NULL) {
                    181:        set_runasgr(runas_group);
                    182:        if (runas_user != NULL)
                    183:            set_runaspw(runas_user);
                    184:     } else
                    185:        set_runaspw(runas_user ? runas_user : def_runas_default);
                    186: 
                    187:     if (!update_defaults(SETDEF_RUNAS))
1.1.1.4   misho     188:        log_warning(NO_STDERR, N_("problem with defaults entries"));
1.1       misho     189: 
                    190:     if (def_fqdn)
                    191:        set_fqdn();     /* deferred until after sudoers is parsed */
                    192: 
                    193:     /* Set login class if applicable. */
1.1.1.2   misho     194:     set_loginclass(runas_pw ? runas_pw : sudo_user.pw);
1.1       misho     195: 
                    196:     restore_perms();
                    197: 
1.1.1.2   misho     198:     debug_return_bool(true);
1.1       misho     199: }
                    200: 
1.1.1.4   misho     201: int
1.1       misho     202: sudoers_policy_main(int argc, char * const argv[], int pwflag, char *env_add[],
1.1.1.4   misho     203:     void *closure)
1.1       misho     204: {
                    205:     char **edit_argv = NULL;
1.1.1.4   misho     206:     char *iolog_path = NULL;
                    207:     mode_t cmnd_umask = 0777;
1.1       misho     208:     struct sudo_nss *nss;
1.1.1.4   misho     209:     int cmnd_status = -1, oldlocale, validated;
1.1.1.2   misho     210:     volatile int rval = true;
                    211:     debug_decl(sudoers_policy_main, SUDO_DEBUG_PLUGIN)
1.1       misho     212: 
1.1.1.4   misho     213:     /* XXX - would like to move this to policy.c but need the cleanup. */
                    214:     if (fatal_setjmp() != 0) {
                    215:        /* error recovery via fatal(), fatalx() or log_fatal() */
1.1       misho     216:        rval = -1;
                    217:        goto done;
                    218:     }
                    219: 
                    220:     /* Is root even allowed to run sudo? */
                    221:     if (user_uid == 0 && !def_root_sudo) {
1.1.1.6 ! misho     222:         warningx(U_("sudoers specifies that root is not allowed to sudo"));
1.1       misho     223:         goto bad;
                    224:     }    
                    225: 
                    226:     set_perms(PERM_INITIAL);
                    227: 
                    228:     /* Environment variables specified on the command line. */
                    229:     if (env_add != NULL && env_add[0] != NULL)
                    230:        sudo_user.env_vars = env_add;
                    231: 
                    232:     /*
                    233:      * Make a local copy of argc/argv, with special handling
                    234:      * for pseudo-commands and the '-i' option.
                    235:      */
                    236:     if (argc == 0) {
                    237:        NewArgc = 1;
                    238:        NewArgv = emalloc2(NewArgc + 1, sizeof(char *));
                    239:        NewArgv[0] = user_cmnd;
                    240:        NewArgv[1] = NULL;
                    241:     } else {
                    242:        /* Must leave an extra slot before NewArgv for bash's --login */
                    243:        NewArgc = argc;
                    244:        NewArgv = emalloc2(NewArgc + 2, sizeof(char *));
                    245:        memcpy(++NewArgv, argv, argc * sizeof(char *));
                    246:        NewArgv[NewArgc] = NULL;
1.1.1.2   misho     247:        if (ISSET(sudo_mode, MODE_LOGIN_SHELL) && runas_pw != NULL)
1.1       misho     248:            NewArgv[0] = estrdup(runas_pw->pw_shell);
                    249:     }
                    250: 
                    251:     /* If given the -P option, set the "preserve_groups" flag. */
                    252:     if (ISSET(sudo_mode, MODE_PRESERVE_GROUPS))
1.1.1.2   misho     253:        def_preserve_groups = true;
1.1       misho     254: 
1.1.1.5   misho     255:     /* Find command in path and apply per-command Defaults. */
1.1       misho     256:     cmnd_status = set_cmnd();
                    257: 
1.1.1.5   misho     258:     /* Check for -C overriding def_closefrom. */
                    259:     if (user_closefrom >= 0 && user_closefrom != def_closefrom) {
                    260:        if (!def_closefrom_override) {
1.1.1.6 ! misho     261:            warningx(U_("you are not permitted to use the -C option"));
1.1.1.5   misho     262:            goto bad;
                    263:        }
                    264:        def_closefrom = user_closefrom;
                    265:     }
                    266: 
1.1       misho     267:     /*
1.1.1.4   misho     268:      * Check sudoers sources, using the locale specified in sudoers.
1.1       misho     269:      */
1.1.1.4   misho     270:     sudoers_setlocale(SUDOERS_LOCALE_SUDOERS, &oldlocale);
1.1       misho     271:     validated = FLAG_NO_USER | FLAG_NO_HOST;
1.1.1.6 ! misho     272:     TAILQ_FOREACH(nss, snl, entries) {
1.1       misho     273:        validated = nss->lookup(nss, validated, pwflag);
                    274: 
                    275:        if (ISSET(validated, VALIDATE_OK)) {
1.1.1.3   misho     276:            /* Handle [SUCCESS=return] */
1.1       misho     277:            if (nss->ret_if_found)
                    278:                break;
                    279:        } else {
                    280:            /* Handle [NOTFOUND=return] */
                    281:            if (nss->ret_if_notfound)
                    282:                break;
                    283:        }
                    284:     }
                    285: 
1.1.1.4   misho     286:     /* Restore user's locale. */
                    287:     sudoers_setlocale(oldlocale, NULL);
                    288: 
1.1       misho     289:     if (safe_cmnd == NULL)
                    290:        safe_cmnd = estrdup(user_cmnd);
                    291: 
                    292:     /* If only a group was specified, set runas_pw based on invoking user. */
                    293:     if (runas_pw == NULL)
                    294:        set_runaspw(user_name);
                    295: 
                    296:     /*
                    297:      * Look up the timestamp dir owner if one is specified.
                    298:      */
                    299:     if (def_timestampowner) {
1.1.1.6 ! misho     300:        struct passwd *pw = NULL;
1.1       misho     301: 
1.1.1.6 ! misho     302:        if (*def_timestampowner == '#') {
        !           303:            const char *errstr;
        !           304:            uid_t uid = atoid(def_timestampowner + 1, NULL, NULL, &errstr);
        !           305:            if (errstr == NULL)
        !           306:                pw = sudo_getpwuid(uid);
        !           307:        }
        !           308:        if (pw == NULL)
1.1       misho     309:            pw = sudo_getpwnam(def_timestampowner);
1.1.1.2   misho     310:        if (pw != NULL) {
                    311:            timestamp_uid = pw->pw_uid;
1.1.1.3   misho     312:            sudo_pw_delref(pw);
1.1.1.2   misho     313:        } else {
1.1.1.4   misho     314:            log_warning(0, N_("timestamp owner (%s): No such user"),
1.1       misho     315:                def_timestampowner);
1.1.1.2   misho     316:            timestamp_uid = ROOT_UID;
                    317:        }
1.1       misho     318:     }
                    319: 
                    320:     /* If no command line args and "shell_noargs" is not set, error out. */
                    321:     if (ISSET(sudo_mode, MODE_IMPLIED_SHELL) && !def_shell_noargs) {
                    322:        rval = -2; /* usage error */
                    323:        goto done;
                    324:     }
                    325: 
                    326:     /* Bail if a tty is required and we don't have one.  */
1.1.1.4   misho     327:     if (def_requiretty && !tty_present()) {
                    328:        audit_failure(NewArgv, N_("no tty"));
1.1.1.6 ! misho     329:        warningx(U_("sorry, you must have a tty to run sudo"));
1.1.1.4   misho     330:        goto bad;
1.1       misho     331:     }
                    332: 
                    333:     /*
                    334:      * We don't reset the environment for sudoedit or if the user
                    335:      * specified the -E command line flag and they have setenv privs.
                    336:      */
                    337:     if (ISSET(sudo_mode, MODE_EDIT) ||
                    338:        (ISSET(sudo_mode, MODE_PRESERVE_ENV) && def_setenv))
1.1.1.2   misho     339:        def_env_reset = false;
1.1       misho     340: 
                    341:     /* Build a new environment that avoids any nasty bits. */
                    342:     rebuild_env();
                    343: 
                    344:     /* Require a password if sudoers says so.  */
                    345:     rval = check_user(validated, sudo_mode);
1.1.1.3   misho     346:     if (rval != true) {
                    347:        if (!ISSET(validated, VALIDATE_OK))
1.1.1.4   misho     348:            log_denial(validated, false);
1.1       misho     349:        goto done;
1.1.1.3   misho     350:     }
1.1       misho     351: 
                    352:     /* If run as root with SUDO_USER set, set sudo_user.pw to that user. */
                    353:     /* XXX - causes confusion when root is not listed in sudoers */
                    354:     if (sudo_mode & (MODE_RUN | MODE_EDIT) && prev_user != NULL) {
                    355:        if (user_uid == 0 && strcmp(prev_user, "root") != 0) {
                    356:            struct passwd *pw;
                    357: 
                    358:            if ((pw = sudo_getpwnam(prev_user)) != NULL) {
                    359:                    if (sudo_user.pw != NULL)
1.1.1.3   misho     360:                        sudo_pw_delref(sudo_user.pw);
1.1       misho     361:                    sudo_user.pw = pw;
                    362:            }
                    363:        }
                    364:     }
                    365: 
                    366:     /* If the user was not allowed to run the command we are done. */
                    367:     if (!ISSET(validated, VALIDATE_OK)) {
1.1.1.3   misho     368:        log_failure(validated, cmnd_status);
1.1       misho     369:        goto bad;
                    370:     }
                    371: 
                    372:     /* Create Ubuntu-style dot file to indicate sudo was successful. */
                    373:     create_admin_success_flag();
                    374: 
                    375:     /* Finally tell the user if the command did not exist. */
                    376:     if (cmnd_status == NOT_FOUND_DOT) {
1.1.1.4   misho     377:        audit_failure(NewArgv, N_("command in current directory"));
1.1.1.6 ! misho     378:        warningx(U_("ignoring `%s' found in '.'\nUse `sudo ./%s' if this is the `%s' you wish to run."), user_cmnd, user_cmnd, user_cmnd);
1.1       misho     379:        goto bad;
                    380:     } else if (cmnd_status == NOT_FOUND) {
1.1.1.4   misho     381:        if (ISSET(sudo_mode, MODE_CHECK)) {
                    382:            audit_failure(NewArgv, N_("%s: command not found"), NewArgv[0]);
1.1.1.6 ! misho     383:            warningx(U_("%s: command not found"), NewArgv[0]);
1.1.1.4   misho     384:        } else {
                    385:            audit_failure(NewArgv, N_("%s: command not found"), user_cmnd);
1.1.1.6 ! misho     386:            warningx(U_("%s: command not found"), user_cmnd);
1.1.1.4   misho     387:        }
1.1       misho     388:        goto bad;
                    389:     }
                    390: 
                    391:     /* If user specified env vars make sure sudoers allows it. */
                    392:     if (ISSET(sudo_mode, MODE_RUN) && !def_setenv) {
                    393:        if (ISSET(sudo_mode, MODE_PRESERVE_ENV)) {
1.1.1.6 ! misho     394:            warningx(U_("sorry, you are not allowed to preserve the environment"));
1.1       misho     395:            goto bad;
                    396:        } else
                    397:            validate_env_vars(sudo_user.env_vars);
                    398:     }
                    399: 
1.1.1.4   misho     400:     if (ISSET(sudo_mode, (MODE_RUN | MODE_EDIT))) {
                    401:        if ((def_log_input || def_log_output) && def_iolog_file && def_iolog_dir) {
                    402:            const char prefix[] = "iolog_path=";
                    403:            iolog_path = expand_iolog_path(prefix, def_iolog_dir,
                    404:                def_iolog_file, &sudo_user.iolog_file);
1.1       misho     405:            sudo_user.iolog_file++;
                    406:        }
                    407:     }
                    408: 
                    409:     log_allowed(validated);
                    410:     if (ISSET(sudo_mode, MODE_CHECK))
                    411:        rval = display_cmnd(snl, list_pw ? list_pw : sudo_user.pw);
                    412:     else if (ISSET(sudo_mode, MODE_LIST))
                    413:        display_privs(snl, list_pw ? list_pw : sudo_user.pw); /* XXX - return val */
                    414: 
                    415:     /* Cleanup sudoers sources */
1.1.1.6 ! misho     416:     TAILQ_FOREACH(nss, snl, entries) {
1.1       misho     417:        nss->close(nss);
                    418:     }
                    419:     if (def_group_plugin)
                    420:        group_plugin_unload();
                    421: 
                    422:     if (ISSET(sudo_mode, (MODE_VALIDATE|MODE_CHECK|MODE_LIST))) {
                    423:        /* rval already set appropriately */
                    424:        goto done;
                    425:     }
                    426: 
                    427:     /*
                    428:      * Set umask based on sudoers.
                    429:      * If user's umask is more restrictive, OR in those bits too
                    430:      * unless umask_override is set.
                    431:      */
                    432:     if (def_umask != 0777) {
1.1.1.4   misho     433:        cmnd_umask = def_umask;
                    434:        if (!def_umask_override)
                    435:            cmnd_umask |= user_umask;
1.1       misho     436:     }
                    437: 
                    438:     if (ISSET(sudo_mode, MODE_LOGIN_SHELL)) {
                    439:        char *p;
                    440: 
                    441:        /* Convert /bin/sh -> -sh so shell knows it is a login shell */
                    442:        if ((p = strrchr(NewArgv[0], '/')) == NULL)
                    443:            p = NewArgv[0];
                    444:        *p = '-';
                    445:        NewArgv[0] = p;
                    446: 
                    447:        /*
                    448:         * Newer versions of bash require the --login option to be used
                    449:         * in conjunction with the -c option even if the shell name starts
                    450:         * with a '-'.  Unfortunately, bash 1.x uses -login, not --login
                    451:         * so this will cause an error for that.
                    452:         */
                    453:        if (NewArgc > 1 && strcmp(NewArgv[0], "-bash") == 0 &&
                    454:            strcmp(NewArgv[1], "-c") == 0) {
                    455:            /* Use the extra slot before NewArgv so we can store --login. */
                    456:            NewArgv--;
                    457:            NewArgc++;
                    458:            NewArgv[0] = NewArgv[1];
                    459:            NewArgv[1] = "--login";
                    460:        }
                    461: 
1.1.1.2   misho     462: #if defined(_AIX) || (defined(__linux__) && !defined(HAVE_PAM))
1.1       misho     463:        /* Insert system-wide environment variables. */
1.1.1.2   misho     464:        read_env_file(_PATH_ENVIRONMENT, true);
1.1       misho     465: #endif
1.1.1.2   misho     466: #ifdef HAVE_LOGIN_CAP_H
                    467:        /* Set environment based on login class. */
                    468:        if (login_class) {
                    469:            login_cap_t *lc = login_getclass(login_class);
                    470:            if (lc != NULL) {
                    471:                setusercontext(lc, runas_pw, runas_pw->pw_uid, LOGIN_SETPATH|LOGIN_SETENV);
                    472:                login_close(lc);
                    473:            }
                    474:        }
                    475: #endif /* HAVE_LOGIN_CAP_H */
1.1       misho     476:     }
                    477: 
                    478:     /* Insert system-wide environment variables. */
                    479:     if (def_env_file)
1.1.1.2   misho     480:        read_env_file(def_env_file, false);
1.1       misho     481: 
                    482:     /* Insert user-specified environment variables. */
                    483:     insert_env_vars(sudo_user.env_vars);
                    484: 
                    485:     if (ISSET(sudo_mode, MODE_EDIT)) {
1.1.1.4   misho     486:        efree(safe_cmnd);
                    487:        safe_cmnd = find_editor(NewArgc - 1, NewArgv + 1, &edit_argv);
                    488:        if (safe_cmnd == NULL)
1.1       misho     489:            goto bad;
                    490:     }
                    491: 
                    492:     /* Must audit before uid change. */
                    493:     audit_success(NewArgv);
                    494: 
1.1.1.4   misho     495:     /* Setup execution environment to pass back to front-end. */
                    496:     rval = sudoers_policy_exec_setup(edit_argv ? edit_argv : NewArgv,
                    497:        env_get(), cmnd_umask, iolog_path, closure);
1.1       misho     498: 
1.1.1.4   misho     499:     /* Zero out stashed copy of environment, it is owned by the front-end. */
1.1.1.2   misho     500:     env_init(NULL);
1.1       misho     501: 
                    502:     goto done;
                    503: 
                    504: bad:
1.1.1.2   misho     505:     rval = false;
1.1       misho     506: 
                    507: done:
1.1.1.4   misho     508:     fatal_disable_setjmp();
1.1       misho     509:     rewind_perms();
                    510: 
                    511:     /* Close the password and group files and free up memory. */
                    512:     sudo_endpwent();
                    513:     sudo_endgrent();
                    514: 
1.1.1.2   misho     515:     debug_return_bool(rval);
1.1       misho     516: }
                    517: 
                    518: /*
1.1.1.4   misho     519:  * Initialize timezone and fill in ``sudo_user'' struct.
1.1       misho     520:  */
                    521: static void
                    522: init_vars(char * const envp[])
                    523: {
                    524:     char * const * ep;
1.1.1.5   misho     525:     bool unknown_user = false;
1.1.1.2   misho     526:     debug_decl(init_vars, SUDO_DEBUG_PLUGIN)
1.1       misho     527: 
1.1.1.4   misho     528:     sudoers_initlocale(setlocale(LC_ALL, NULL), def_sudoers_locale);
1.1       misho     529: 
                    530:     for (ep = envp; *ep; ep++) {
                    531:        /* XXX - don't fill in if empty string */
                    532:        switch (**ep) {
                    533:            case 'K':
                    534:                if (strncmp("KRB5CCNAME=", *ep, 11) == 0)
                    535:                    user_ccname = *ep + 11;
                    536:                break;
                    537:            case 'P':
                    538:                if (strncmp("PATH=", *ep, 5) == 0)
                    539:                    user_path = *ep + 5;
                    540:                break;
                    541:            case 'S':
                    542:                if (!user_prompt && strncmp("SUDO_PROMPT=", *ep, 12) == 0)
                    543:                    user_prompt = *ep + 12;
                    544:                else if (strncmp("SUDO_USER=", *ep, 10) == 0)
                    545:                    prev_user = *ep + 10;
                    546:                break;
                    547:            }
                    548:     }
                    549: 
                    550:     /*
1.1.1.4   misho     551:      * Get a local copy of the user's struct passwd if we don't already
                    552:      * have one.
1.1       misho     553:      */
1.1.1.4   misho     554:     if (sudo_user.pw == NULL) {
                    555:        if ((sudo_user.pw = sudo_getpwnam(user_name)) == NULL) {
                    556:            /*
                    557:             * It is not unusual for users to place "sudo -k" in a .logout
                    558:             * file which can cause sudo to be run during reboot after the
                    559:             * YP/NIS/NIS+/LDAP/etc daemon has died.
                    560:             */
                    561:            if (sudo_mode == MODE_KILL || sudo_mode == MODE_INVALIDATE)
1.1.1.6 ! misho     562:                fatalx(U_("unknown uid: %u"), (unsigned int) user_uid);
1.1       misho     563: 
1.1.1.4   misho     564:            /* Need to make a fake struct passwd for the call to log_fatal(). */
                    565:            sudo_user.pw = sudo_mkpwent(user_name, user_uid, user_gid, NULL, NULL);
1.1.1.5   misho     566:            unknown_user = true;
1.1.1.4   misho     567:        }
1.1       misho     568:     }
                    569: 
                    570:     /*
1.1.1.5   misho     571:      * Get group list and store initialize permissions.
1.1       misho     572:      */
                    573:     if (user_group_list == NULL)
1.1.1.3   misho     574:        user_group_list = sudo_get_grlist(sudo_user.pw);
1.1.1.5   misho     575:     set_perms(PERM_INITIAL);
1.1       misho     576: 
                    577:     /* Set runas callback. */
                    578:     sudo_defs_table[I_RUNAS_DEFAULT].callback = cb_runas_default;
                    579: 
1.1.1.4   misho     580:     /* Set locale callback. */
                    581:     sudo_defs_table[I_SUDOERS_LOCALE].callback = cb_sudoers_locale;
                    582: 
                    583:     /* Set maxseq callback. */
                    584:     sudo_defs_table[I_MAXSEQ].callback = io_set_max_sessid;
                    585: 
1.1.1.2   misho     586:     /* It is now safe to use log_fatal() and set_perms() */
1.1.1.5   misho     587:     if (unknown_user)
                    588:        log_fatal(0, N_("unknown uid: %u"), (unsigned int) user_uid);
1.1.1.2   misho     589:     debug_return;
1.1       misho     590: }
                    591: 
                    592: /*
                    593:  * Fill in user_cmnd, user_args, user_base and user_stat variables
                    594:  * and apply any command-specific defaults entries.
                    595:  */
                    596: static int
                    597: set_cmnd(void)
                    598: {
                    599:     int rval;
                    600:     char *path = user_path;
1.1.1.2   misho     601:     debug_decl(set_cmnd, SUDO_DEBUG_PLUGIN)
1.1       misho     602: 
                    603:     /* Resolve the path and return. */
                    604:     rval = FOUND;
1.1.1.2   misho     605:     user_stat = ecalloc(1, sizeof(struct stat));
1.1       misho     606: 
                    607:     /* Default value for cmnd, overridden below. */
                    608:     if (user_cmnd == NULL)
                    609:        user_cmnd = NewArgv[0];
                    610: 
                    611:     if (sudo_mode & (MODE_RUN | MODE_EDIT | MODE_CHECK)) {
                    612:        if (ISSET(sudo_mode, MODE_RUN | MODE_CHECK)) {
                    613:            if (def_secure_path && !user_is_exempt())
                    614:                path = def_secure_path;
                    615:            set_perms(PERM_RUNAS);
                    616:            rval = find_path(NewArgv[0], &user_cmnd, user_stat, path,
                    617:                def_ignore_dot);
                    618:            restore_perms();
                    619:            if (rval != FOUND) {
                    620:                /* Failed as root, try as invoking user. */
                    621:                set_perms(PERM_USER);
                    622:                rval = find_path(NewArgv[0], &user_cmnd, user_stat, path,
                    623:                    def_ignore_dot);
                    624:                restore_perms();
                    625:            }
                    626:        }
                    627: 
                    628:        /* set user_args */
                    629:        if (NewArgc > 1) {
                    630:            char *to, *from, **av;
                    631:            size_t size, n;
                    632: 
                    633:            /* Alloc and build up user_args. */
                    634:            for (size = 0, av = NewArgv + 1; *av; av++)
                    635:                size += strlen(*av) + 1;
                    636:            user_args = emalloc(size);
                    637:            if (ISSET(sudo_mode, MODE_SHELL|MODE_LOGIN_SHELL)) {
                    638:                /*
                    639:                 * When running a command via a shell, the sudo front-end
                    640:                 * escapes potential meta chars.  We unescape non-spaces
                    641:                 * for sudoers matching and logging purposes.
                    642:                 */
                    643:                for (to = user_args, av = NewArgv + 1; (from = *av); av++) {
                    644:                    while (*from) {
                    645:                        if (from[0] == '\\' && !isspace((unsigned char)from[1]))
                    646:                            from++;
                    647:                        *to++ = *from++;
                    648:                    }
                    649:                    *to++ = ' ';
                    650:                }
                    651:                *--to = '\0';
                    652:            } else {
                    653:                for (to = user_args, av = NewArgv + 1; *av; av++) {
                    654:                    n = strlcpy(to, *av, size - (to - user_args));
                    655:                    if (n >= size - (to - user_args))
1.1.1.6 ! misho     656:                        fatalx(U_("internal error, %s overflow"), "set_cmnd()");
1.1       misho     657:                    to += n;
                    658:                    *to++ = ' ';
                    659:                }
                    660:                *--to = '\0';
                    661:            }
                    662:        }
                    663:     }
1.1.1.4   misho     664:     if (strlen(user_cmnd) >= PATH_MAX) {
                    665:        errno = ENAMETOOLONG;
                    666:        fatal("%s", user_cmnd);
                    667:     }
1.1       misho     668: 
                    669:     if ((user_base = strrchr(user_cmnd, '/')) != NULL)
                    670:        user_base++;
                    671:     else
                    672:        user_base = user_cmnd;
                    673: 
                    674:     if (!update_defaults(SETDEF_CMND))
1.1.1.4   misho     675:        log_warning(NO_STDERR, N_("problem with defaults entries"));
1.1       misho     676: 
1.1.1.2   misho     677:     debug_return_int(rval);
1.1       misho     678: }
                    679: 
                    680: /*
                    681:  * Open sudoers and sanity check mode/owner/type.
                    682:  * Returns a handle to the sudoers file or NULL on error.
                    683:  */
                    684: FILE *
1.1.1.2   misho     685: open_sudoers(const char *sudoers, bool doedit, bool *keepopen)
1.1       misho     686: {
1.1.1.2   misho     687:     struct stat sb;
1.1       misho     688:     FILE *fp = NULL;
1.1.1.2   misho     689:     debug_decl(open_sudoers, SUDO_DEBUG_PLUGIN)
1.1       misho     690: 
                    691:     set_perms(PERM_SUDOERS);
                    692: 
1.1.1.2   misho     693:     switch (sudo_secure_file(sudoers, sudoers_uid, sudoers_gid, &sb)) {
                    694:        case SUDO_PATH_SECURE:
1.1.1.3   misho     695:            /*
1.1.1.6 ! misho     696:             * If we are expecting sudoers to be group readable by
        !           697:             * SUDOERS_GID but it is not, we must open the file as root,
        !           698:             * not uid 1.
1.1.1.3   misho     699:             */
1.1.1.6 ! misho     700:            if (sudoers_uid == ROOT_UID && ISSET(sudoers_mode, S_IRGRP)) {
        !           701:                if (!ISSET(sb.st_mode, S_IRGRP) || sb.st_gid != SUDOERS_GID) {
1.1.1.3   misho     702:                    restore_perms();
                    703:                    set_perms(PERM_ROOT);
                    704:                }
                    705:            }
                    706:            /*
                    707:             * Open sudoers and make sure we can read it so we can present
                    708:             * the user with a reasonable error message (unlike the lexer).
                    709:             */
1.1.1.2   misho     710:            if ((fp = fopen(sudoers, "r")) == NULL) {
1.1.1.4   misho     711:                log_warning(USE_ERRNO, N_("unable to open %s"), sudoers);
1.1.1.2   misho     712:            } else {
                    713:                if (sb.st_size != 0 && fgetc(fp) == EOF) {
1.1.1.4   misho     714:                    log_warning(USE_ERRNO, N_("unable to read %s"),
1.1.1.2   misho     715:                        sudoers);
                    716:                    fclose(fp);
                    717:                    fp = NULL;
                    718:                } else {
                    719:                    /* Rewind fp and set close on exec flag. */
                    720:                    rewind(fp);
                    721:                    (void) fcntl(fileno(fp), F_SETFD, 1);
                    722:                }
                    723:            }
                    724:            break;
                    725:        case SUDO_PATH_MISSING:
1.1.1.4   misho     726:            log_warning(USE_ERRNO, N_("unable to stat %s"), sudoers);
1.1.1.2   misho     727:            break;
                    728:        case SUDO_PATH_BAD_TYPE:
1.1.1.4   misho     729:            log_warning(0, N_("%s is not a regular file"), sudoers);
1.1.1.2   misho     730:            break;
                    731:        case SUDO_PATH_WRONG_OWNER:
1.1.1.4   misho     732:            log_warning(0, N_("%s is owned by uid %u, should be %u"),
1.1.1.2   misho     733:                sudoers, (unsigned int) sb.st_uid, (unsigned int) sudoers_uid);
                    734:            break;
                    735:        case SUDO_PATH_WORLD_WRITABLE:
1.1.1.4   misho     736:            log_warning(0, N_("%s is world writable"), sudoers);
1.1.1.2   misho     737:            break;
                    738:        case SUDO_PATH_GROUP_WRITABLE:
1.1.1.4   misho     739:            log_warning(0, N_("%s is owned by gid %u, should be %u"),
1.1.1.2   misho     740:                sudoers, (unsigned int) sb.st_gid, (unsigned int) sudoers_gid);
                    741:            break;
                    742:        default:
                    743:            /* NOTREACHED */
                    744:            break;
1.1       misho     745:     }
                    746: 
                    747:     restore_perms();           /* change back to root */
1.1.1.2   misho     748: 
                    749:     debug_return_ptr(fp);
1.1       misho     750: }
                    751: 
                    752: #ifdef HAVE_LOGIN_CAP_H
                    753: static void
                    754: set_loginclass(struct passwd *pw)
                    755: {
1.1.1.2   misho     756:     const int errflags = NO_MAIL|MSG_ONLY;
                    757:     login_cap_t *lc;
                    758:     debug_decl(set_loginclass, SUDO_DEBUG_PLUGIN)
1.1       misho     759: 
1.1.1.2   misho     760:     if (!def_use_loginclass)
                    761:        debug_return;
1.1       misho     762: 
                    763:     if (login_class && strcmp(login_class, "-") != 0) {
1.1.1.6 ! misho     764:        if (user_uid != 0 && pw->pw_uid != 0)
        !           765:            fatalx(U_("only root can use `-c %s'"), login_class);
1.1       misho     766:     } else {
                    767:        login_class = pw->pw_class;
                    768:        if (!login_class || !*login_class)
                    769:            login_class =
                    770:                (pw->pw_uid == 0) ? LOGIN_DEFROOTCLASS : LOGIN_DEFCLASS;
                    771:     }
                    772: 
1.1.1.2   misho     773:     /* Make sure specified login class is valid. */
1.1       misho     774:     lc = login_getclass(login_class);
                    775:     if (!lc || !lc->lc_class || strcmp(lc->lc_class, login_class) != 0) {
1.1.1.2   misho     776:        /*
                    777:         * Don't make it a fatal error if the user didn't specify the login
                    778:         * class themselves.  We do this because if login.conf gets
                    779:         * corrupted we want the admin to be able to use sudo to fix it.
                    780:         */
                    781:        if (login_class)
1.1.1.4   misho     782:            log_fatal(errflags, N_("unknown login class: %s"), login_class);
1.1.1.2   misho     783:        else
1.1.1.4   misho     784:            log_warning(errflags, N_("unknown login class: %s"), login_class);
1.1.1.2   misho     785:        def_use_loginclass = false;
1.1       misho     786:     }
1.1.1.2   misho     787:     login_close(lc);
                    788:     debug_return;
1.1       misho     789: }
                    790: #else
                    791: static void
                    792: set_loginclass(struct passwd *pw)
                    793: {
                    794: }
                    795: #endif /* HAVE_LOGIN_CAP_H */
                    796: 
1.1.1.3   misho     797: #ifndef AI_FQDN
                    798: # define AI_FQDN AI_CANONNAME
                    799: #endif
                    800: 
1.1       misho     801: /*
                    802:  * Look up the fully qualified domain name and set user_host and user_shost.
1.1.1.3   misho     803:  * Use AI_FQDN if available since "canonical" is not always the same as fqdn.
1.1       misho     804:  */
1.1.1.4   misho     805: static void
1.1       misho     806: set_fqdn(void)
                    807: {
                    808:     struct addrinfo *res0, hint;
                    809:     char *p;
1.1.1.2   misho     810:     debug_decl(set_fqdn, SUDO_DEBUG_PLUGIN)
1.1       misho     811: 
1.1.1.5   misho     812:     memset(&hint, 0, sizeof(hint));
1.1       misho     813:     hint.ai_family = PF_UNSPEC;
1.1.1.3   misho     814:     hint.ai_flags = AI_FQDN;
1.1       misho     815:     if (getaddrinfo(user_host, NULL, &hint, &res0) != 0) {
1.1.1.4   misho     816:        log_warning(MSG_ONLY, N_("unable to resolve host %s"), user_host);
1.1       misho     817:     } else {
                    818:        if (user_shost != user_host)
                    819:            efree(user_shost);
                    820:        efree(user_host);
                    821:        user_host = estrdup(res0->ai_canonname);
                    822:        freeaddrinfo(res0);
1.1.1.3   misho     823:        if ((p = strchr(user_host, '.')) != NULL)
                    824:            user_shost = estrndup(user_host, (size_t)(p - user_host));
                    825:        else
                    826:            user_shost = user_host;
1.1       misho     827:     }
1.1.1.2   misho     828:     debug_return;
1.1       misho     829: }
                    830: 
                    831: /*
                    832:  * Get passwd entry for the user we are going to run commands as
                    833:  * and store it in runas_pw.  By default, commands run as "root".
                    834:  */
1.1.1.2   misho     835: static void
1.1       misho     836: set_runaspw(const char *user)
                    837: {
1.1.1.6 ! misho     838:     struct passwd *pw = NULL;
1.1.1.2   misho     839:     debug_decl(set_runaspw, SUDO_DEBUG_PLUGIN)
                    840: 
1.1       misho     841:     if (*user == '#') {
1.1.1.6 ! misho     842:        const char *errstr;
        !           843:        uid_t uid = atoid(user + 1, NULL, NULL, &errstr);
        !           844:        if (errstr == NULL) {
        !           845:            if ((pw = sudo_getpwuid(uid)) == NULL)
        !           846:                pw = sudo_fakepwnam(user, runas_gr ? runas_gr->gr_gid : 0);
        !           847:        }
        !           848:     }
        !           849:     if (pw == NULL) {
        !           850:        if ((pw = sudo_getpwnam(user)) == NULL)
1.1.1.4   misho     851:            log_fatal(NO_MAIL|MSG_ONLY, N_("unknown user: %s"), user);
1.1       misho     852:     }
1.1.1.6 ! misho     853:     if (runas_pw != NULL)
        !           854:        sudo_pw_delref(runas_pw);
        !           855:     runas_pw = pw;
1.1.1.2   misho     856:     debug_return;
1.1       misho     857: }
                    858: 
                    859: /*
                    860:  * Get group entry for the group we are going to run commands as
                    861:  * and store it in runas_gr.
                    862:  */
                    863: static void
                    864: set_runasgr(const char *group)
                    865: {
1.1.1.6 ! misho     866:     struct group *gr = NULL;
1.1.1.2   misho     867:     debug_decl(set_runasgr, SUDO_DEBUG_PLUGIN)
                    868: 
1.1       misho     869:     if (*group == '#') {
1.1.1.6 ! misho     870:        const char *errstr;
        !           871:        gid_t gid = atoid(group + 1, NULL, NULL, &errstr);
        !           872:        if (errstr == NULL) {
        !           873:            if ((gr = sudo_getgrgid(gid)) == NULL)
        !           874:                gr = sudo_fakegrnam(group);
        !           875:        }
        !           876:     }
        !           877:     if (gr == NULL) {
        !           878:        if ((gr = sudo_getgrnam(group)) == NULL)
1.1.1.4   misho     879:            log_fatal(NO_MAIL|MSG_ONLY, N_("unknown group: %s"), group);
1.1       misho     880:     }
1.1.1.6 ! misho     881:     if (runas_gr != NULL)
        !           882:        sudo_gr_delref(runas_gr);
        !           883:     runas_gr = gr;
1.1.1.2   misho     884:     debug_return;
1.1       misho     885: }
                    886: 
                    887: /*
                    888:  * Callback for runas_default sudoers setting.
                    889:  */
                    890: static int
                    891: cb_runas_default(const char *user)
                    892: {
                    893:     /* Only reset runaspw if user didn't specify one. */
                    894:     if (!runas_user && !runas_group)
                    895:        set_runaspw(user);
1.1.1.2   misho     896:     return true;
1.1       misho     897: }
                    898: 
                    899: /*
1.1.1.4   misho     900:  * Callback for sudoers_locale sudoers setting.
1.1       misho     901:  */
                    902: static int
1.1.1.4   misho     903: cb_sudoers_locale(const char *locale)
1.1       misho     904: {
1.1.1.4   misho     905:     sudoers_initlocale(NULL, locale);
                    906:     return true;
1.1       misho     907: }
                    908: 
1.1.1.4   misho     909: /*
                    910:  * Cleanup hook for fatal()/fatalx()
                    911:  */
                    912: void
                    913: sudoers_cleanup(void)
1.1       misho     914: {
1.1.1.4   misho     915:     struct sudo_nss *nss;
                    916:     debug_decl(sudoers_cleanup, SUDO_DEBUG_PLUGIN)
1.1       misho     917: 
1.1.1.4   misho     918:     if (snl != NULL) {
1.1.1.6 ! misho     919:        TAILQ_FOREACH(nss, snl, entries) {
1.1.1.4   misho     920:            nss->close(nss);
1.1.1.6 ! misho     921:        }
1.1.1.2   misho     922:     }
1.1.1.4   misho     923:     if (def_group_plugin)
                    924:        group_plugin_unload();
                    925:     sudo_endpwent();
                    926:     sudo_endgrent();
1.1.1.2   misho     927: 
1.1.1.4   misho     928:     debug_return;
1.1       misho     929: }
                    930: 
                    931: static char *
1.1.1.4   misho     932: resolve_editor(const char *ed, size_t edlen, int nfiles, char **files, char ***argv_out)
1.1       misho     933: {
1.1.1.4   misho     934:     char *cp, **nargv, *editor, *editor_path = NULL;
1.1.1.2   misho     935:     int ac, i, nargc;
                    936:     bool wasblank;
                    937:     debug_decl(resolve_editor, SUDO_DEBUG_PLUGIN)
1.1       misho     938: 
1.1.1.4   misho     939:     /* Note: editor becomes part of argv_out and is not freed. */
                    940:     editor = emalloc(edlen + 1);
                    941:     memcpy(editor, ed, edlen);
                    942:     editor[edlen] = '\0';
1.1       misho     943: 
                    944:     /*
                    945:      * Split editor into an argument vector; editor is reused (do not free).
                    946:      * The EDITOR and VISUAL environment variables may contain command
                    947:      * line args so look for those and alloc space for them too.
                    948:      */
                    949:     nargc = 1;
1.1.1.2   misho     950:     for (wasblank = false, cp = editor; *cp != '\0'; cp++) {
1.1       misho     951:        if (isblank((unsigned char) *cp))
1.1.1.2   misho     952:            wasblank = true;
1.1       misho     953:        else if (wasblank) {
1.1.1.2   misho     954:            wasblank = false;
1.1       misho     955:            nargc++;
                    956:        }
                    957:     }
                    958:     /* If we can't find the editor in the user's PATH, give up. */
                    959:     cp = strtok(editor, " \t");
                    960:     if (cp == NULL ||
                    961:        find_path(cp, &editor_path, NULL, getenv("PATH"), 0) != FOUND) {
                    962:        efree(editor);
1.1.1.2   misho     963:        debug_return_str(NULL);
1.1       misho     964:     }
                    965:     nargv = (char **) emalloc2(nargc + 1 + nfiles + 1, sizeof(char *));
                    966:     for (ac = 0; cp != NULL && ac < nargc; ac++) {
                    967:        nargv[ac] = cp;
                    968:        cp = strtok(NULL, " \t");
                    969:     }
                    970:     nargv[ac++] = "--";
                    971:     for (i = 0; i < nfiles; )
                    972:        nargv[ac++] = files[i++];
                    973:     nargv[ac] = NULL;
                    974: 
                    975:     *argv_out = nargv;
1.1.1.2   misho     976:     debug_return_str(editor_path);
1.1       misho     977: }
                    978: 
                    979: /*
                    980:  * Determine which editor to use.  We don't need to worry about restricting
                    981:  * this to a "safe" editor since it runs with the uid of the invoking user,
                    982:  * not the runas (privileged) user.
                    983:  */
                    984: static char *
                    985: find_editor(int nfiles, char **files, char ***argv_out)
                    986: {
1.1.1.4   misho     987:     const char *cp, *ep, *editor;
                    988:     char *editor_path = NULL, **ev, *ev0[4];
                    989:     size_t len;
1.1.1.2   misho     990:     debug_decl(find_editor, SUDO_DEBUG_PLUGIN)
1.1       misho     991: 
                    992:     /*
                    993:      * If any of SUDO_EDITOR, VISUAL or EDITOR are set, choose the first one.
                    994:      */
                    995:     ev0[0] = "SUDO_EDITOR";
                    996:     ev0[1] = "VISUAL";
                    997:     ev0[2] = "EDITOR";
                    998:     ev0[3] = NULL;
1.1.1.4   misho     999:     for (ev = ev0; editor_path == NULL && *ev != NULL; ev++) {
1.1       misho    1000:        if ((editor = getenv(*ev)) != NULL && *editor != '\0') {
1.1.1.4   misho    1001:            editor_path = resolve_editor(editor, strlen(editor), nfiles,
                   1002:                files, argv_out);
1.1       misho    1003:        }
                   1004:     }
                   1005:     if (editor_path == NULL) {
1.1.1.4   misho    1006:        /* def_editor could be a path, split it up, avoiding strtok() */
                   1007:        cp = editor = def_editor;
                   1008:        do {
                   1009:            if ((ep = strchr(cp, ':')) != NULL)
                   1010:                len = ep - cp;
                   1011:            else
                   1012:                len = strlen(cp);
                   1013:            editor_path = resolve_editor(cp, len, nfiles, files, argv_out);
                   1014:            cp = ep + 1;
                   1015:        } while (ep != NULL && editor_path == NULL);
1.1       misho    1016:     }
                   1017:     if (!editor_path) {
1.1.1.4   misho    1018:        audit_failure(NewArgv, N_("%s: command not found"), editor);
1.1.1.6 ! misho    1019:        warningx(U_("%s: command not found"), editor);
1.1       misho    1020:     }
1.1.1.2   misho    1021:     debug_return_str(editor_path);
1.1       misho    1022: }
                   1023: 
                   1024: #ifdef USE_ADMIN_FLAG
                   1025: static void
                   1026: create_admin_success_flag(void)
                   1027: {
                   1028:     struct stat statbuf;
                   1029:     char flagfile[PATH_MAX];
                   1030:     int fd, n;
1.1.1.2   misho    1031:     debug_decl(create_admin_success_flag, SUDO_DEBUG_PLUGIN)
1.1       misho    1032: 
                   1033:     /* Check whether the user is in the admin group. */
                   1034:     if (!user_in_group(sudo_user.pw, "admin"))
1.1.1.2   misho    1035:        debug_return;
1.1       misho    1036: 
                   1037:     /* Build path to flag file. */
                   1038:     n = snprintf(flagfile, sizeof(flagfile), "%s/.sudo_as_admin_successful",
                   1039:        user_dir);
1.1.1.6 ! misho    1040:     if (n <= 0 || (size_t)n >= sizeof(flagfile))
1.1.1.2   misho    1041:        debug_return;
1.1       misho    1042: 
                   1043:     /* Create admin flag file if it doesn't already exist. */
                   1044:     set_perms(PERM_USER);
                   1045:     if (stat(flagfile, &statbuf) != 0) {
                   1046:        fd = open(flagfile, O_CREAT|O_WRONLY|O_EXCL, 0644);
                   1047:        close(fd);
                   1048:     }
                   1049:     restore_perms();
1.1.1.2   misho    1050:     debug_return;
1.1       misho    1051: }
                   1052: #else /* !USE_ADMIN_FLAG */
                   1053: static void
                   1054: create_admin_success_flag(void)
                   1055: {
                   1056:     /* STUB */
                   1057: }
                   1058: #endif /* USE_ADMIN_FLAG */
                   1059: 
1.1.1.4   misho    1060: static bool
                   1061: tty_present(void)
1.1.1.2   misho    1062: {
1.1.1.4   misho    1063: #if defined(HAVE_STRUCT_KINFO_PROC2_P_TDEV) || defined(HAVE_STRUCT_KINFO_PROC_P_TDEV) || defined(HAVE_STRUCT_KINFO_PROC_KI_TDEV) || defined(HAVE_STRUCT_KINFO_PROC_KP_EPROC_E_TDEV) || defined(HAVE_STRUCT_PSINFO_PR_TTYDEV) || defined(HAVE_PSTAT_GETPROC) || defined(__linux__)
                   1064:     return user_ttypath != NULL;
                   1065: #else
                   1066:     int fd = open(_PATH_TTY, O_RDWR|O_NOCTTY);
                   1067:     if (fd != -1)
                   1068:        close(fd);
                   1069:     return fd != -1;
                   1070: #endif
1.1.1.2   misho    1071: }

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