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

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

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