Annotation of embedaddon/sudo/src/sudo.c, revision 1.1.1.2

1.1       misho       1: /*
1.1.1.2 ! misho       2:  * Copyright (c) 2009-2012 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: 
                     17: #ifdef __TANDEM
                     18: # include <floss.h>
                     19: #endif
                     20: 
                     21: #include <config.h>
                     22: 
                     23: #include <sys/types.h>
                     24: #include <sys/param.h>
                     25: #include <sys/stat.h>
                     26: #include <sys/wait.h>
                     27: #include <sys/socket.h>
                     28: #include <sys/time.h>
                     29: #include <sys/resource.h>
                     30: #include <stdio.h>
                     31: #ifdef STDC_HEADERS
                     32: # include <stdlib.h>
                     33: # include <stddef.h>
                     34: #else
                     35: # ifdef HAVE_STDLIB_H
                     36: #  include <stdlib.h>
                     37: # endif
                     38: #endif /* STDC_HEADERS */
                     39: #ifdef HAVE_STRING_H
                     40: # if defined(HAVE_MEMORY_H) && !defined(STDC_HEADERS)
                     41: #  include <memory.h>
                     42: # endif
                     43: # include <string.h>
                     44: #endif /* HAVE_STRING_H */
                     45: #ifdef HAVE_STRINGS_H
                     46: # include <strings.h>
                     47: #endif /* HAVE_STRINGS_H */
                     48: #ifdef HAVE_UNISTD_H
                     49: # include <unistd.h>
                     50: #endif /* HAVE_UNISTD_H */
                     51: #include <ctype.h>
                     52: #include <errno.h>
                     53: #include <fcntl.h>
                     54: #include <limits.h>
                     55: #include <signal.h>
                     56: #include <grp.h>
                     57: #include <pwd.h>
                     58: #if TIME_WITH_SYS_TIME
                     59: # include <time.h>
                     60: #endif
                     61: #ifdef HAVE_SETLOCALE
                     62: # include <locale.h>
                     63: #endif
                     64: #ifdef HAVE_LOGIN_CAP_H
                     65: # include <login_cap.h>
1.1.1.2 ! misho      66: # ifndef LOGIN_SETENV
        !            67: #  define LOGIN_SETENV 0
        !            68: # endif
1.1       misho      69: #endif
                     70: #ifdef HAVE_PROJECT_H
                     71: # include <project.h>
                     72: # include <sys/task.h>
                     73: #endif
                     74: #ifdef HAVE_SELINUX
                     75: # include <selinux/selinux.h>
                     76: #endif
                     77: #ifdef HAVE_SETAUTHDB
                     78: # include <usersec.h>
                     79: #endif /* HAVE_SETAUTHDB */
                     80: #if defined(HAVE_GETPRPWNAM) && defined(HAVE_SET_AUTH_PARAMETERS)
                     81: # ifdef __hpux
                     82: #  undef MAXINT
                     83: #  include <hpsecurity.h>
                     84: # else
                     85: #  include <sys/security.h>
                     86: # endif /* __hpux */
                     87: # include <prot.h>
                     88: #endif /* HAVE_GETPRPWNAM && HAVE_SET_AUTH_PARAMETERS */
1.1.1.2 ! misho      89: #if defined(HAVE_STRUCT_KINFO_PROC_P_TDEV) || defined (HAVE_STRUCT_KINFO_PROC_KP_EPROC_E_TDEV)
        !            90: # include <sys/sysctl.h>
        !            91: #elif defined(HAVE_STRUCT_KINFO_PROC_KI_TDEV)
        !            92: # include <sys/sysctl.h>
        !            93: # include <sys/user.h>
1.1       misho      94: #endif
                     95: 
                     96: #include "sudo.h"
                     97: #include "sudo_plugin.h"
                     98: #include "sudo_plugin_int.h"
                     99: #include <sudo_usage.h>
                    100: 
                    101: /*
                    102:  * Local variables
                    103:  */
                    104: struct plugin_container policy_plugin;
                    105: struct plugin_container_list io_plugins;
                    106: struct user_details user_details;
                    107: const char *list_user, *runas_user, *runas_group; /* extern for parse_args.c */
1.1.1.2 ! misho     108: static int sudo_mode;
1.1       misho     109: 
                    110: /*
                    111:  * Local functions
                    112:  */
                    113: static void fix_fds(void);
                    114: static void disable_coredumps(void);
1.1.1.2 ! misho     115: static void sudo_check_suid(const char *path);
1.1       misho     116: static char **get_user_info(struct user_details *);
                    117: static void command_info_to_details(char * const info[],
                    118:     struct command_details *details);
                    119: 
                    120: /* Policy plugin convenience functions. */
                    121: static int policy_open(struct plugin_container *plugin, char * const settings[],
                    122:     char * const user_info[], char * const user_env[]);
                    123: static void policy_close(struct plugin_container *plugin, int exit_status,
                    124:     int error);
                    125: static int policy_show_version(struct plugin_container *plugin, int verbose);
                    126: static int policy_check(struct plugin_container *plugin, int argc,
                    127:     char * const argv[], char *env_add[], char **command_info[],
                    128:     char **argv_out[], char **user_env_out[]);
                    129: static int policy_list(struct plugin_container *plugin, int argc,
                    130:     char * const argv[], int verbose, const char *list_user);
                    131: static int policy_validate(struct plugin_container *plugin);
                    132: static void policy_invalidate(struct plugin_container *plugin, int remove);
                    133: 
                    134: /* I/O log plugin convenience functions. */
                    135: static int iolog_open(struct plugin_container *plugin, char * const settings[],
                    136:     char * const user_info[], char * const command_details[],
                    137:     int argc, char * const argv[], char * const user_env[]);
                    138: static void iolog_close(struct plugin_container *plugin, int exit_status,
                    139:     int error);
                    140: static int iolog_show_version(struct plugin_container *plugin, int verbose);
1.1.1.2 ! misho     141: static void iolog_unlink(struct plugin_container *plugin);
1.1       misho     142: 
1.1.1.2 ! misho     143: #ifdef RLIMIT_CORE
1.1       misho     144: static struct rlimit corelimit;
1.1.1.2 ! misho     145: #endif /* RLIMIT_CORE */
1.1       misho     146: #if defined(__linux__)
                    147: static struct rlimit nproclimit;
                    148: #endif
                    149: 
                    150: int
                    151: main(int argc, char *argv[], char *envp[])
                    152: {
1.1.1.2 ! misho     153:     int nargc, ok, exitcode = 0;
1.1       misho     154:     char **nargv, **settings, **env_add;
                    155:     char **user_info, **command_info, **argv_out, **user_env_out;
                    156:     struct plugin_container *plugin, *next;
                    157:     struct command_details command_details;
                    158:     sigset_t mask;
1.1.1.2 ! misho     159:     debug_decl(main, SUDO_DEBUG_MAIN)
        !           160: 
1.1       misho     161: #if defined(SUDO_DEVEL) && defined(__OpenBSD__)
1.1.1.2 ! misho     162:     {
        !           163:        extern char *malloc_options;
        !           164:        malloc_options = "AFGJPR";
        !           165:     }
1.1       misho     166: #endif
                    167: 
                    168: #if !defined(HAVE_GETPROGNAME) && !defined(HAVE___PROGNAME)
                    169:     if (argc > 0)
                    170:        setprogname(argv[0]);
                    171: #endif
                    172: 
                    173: #ifdef HAVE_SETLOCALE
                    174:     setlocale(LC_ALL, "");
                    175: #endif
                    176:     bindtextdomain(PACKAGE_NAME, LOCALEDIR);
                    177:     textdomain(PACKAGE_NAME);
                    178: 
                    179:     /* Must be done before we do any password lookups */
                    180: #if defined(HAVE_GETPRPWNAM) && defined(HAVE_SET_AUTH_PARAMETERS)
                    181:     (void) set_auth_parameters(argc, argv);
                    182: # ifdef HAVE_INITPRIVS
                    183:     initprivs();
                    184: # endif
                    185: #endif /* HAVE_GETPRPWNAM && HAVE_SET_AUTH_PARAMETERS */
                    186: 
1.1.1.2 ! misho     187:     /* Make sure we are setuid root. */
        !           188:     sudo_check_suid(argv[0]);
1.1       misho     189: 
1.1.1.2 ! misho     190:     /* Reset signal mask and make sure fds 0-2 are open. */
1.1       misho     191:     (void) sigemptyset(&mask);
                    192:     (void) sigprocmask(SIG_SETMASK, &mask, NULL);
                    193:     fix_fds();
                    194: 
                    195:     /* Fill in user_info with user name, uid, cwd, etc. */
                    196:     memset(&user_details, 0, sizeof(user_details));
                    197:     user_info = get_user_info(&user_details);
                    198: 
1.1.1.2 ! misho     199:     /* Read sudo.conf. */
        !           200:     sudo_conf_read();
        !           201: 
        !           202:     /* Disable core dumps if not enabled in sudo.conf. */
        !           203:     disable_coredumps();
        !           204: 
1.1       misho     205:     /* Parse command line arguments. */
                    206:     sudo_mode = parse_args(argc, argv, &nargc, &nargv, &settings, &env_add);
1.1.1.2 ! misho     207:     sudo_debug_printf(SUDO_DEBUG_DEBUG, "sudo_mode %d", sudo_mode);
1.1       misho     208: 
                    209:     /* Print sudo version early, in case of plugin init failure. */
                    210:     if (ISSET(sudo_mode, MODE_VERSION)) {
                    211:        printf(_("Sudo version %s\n"), PACKAGE_VERSION);
                    212:        if (user_details.uid == ROOT_UID)
                    213:            (void) printf(_("Configure options: %s\n"), CONFIGURE_ARGS);
                    214:     }
                    215: 
1.1.1.2 ! misho     216:     /* Load plugins. */
        !           217:     if (!sudo_load_plugins(&policy_plugin, &io_plugins))
1.1       misho     218:        errorx(1, _("fatal error, unable to load plugins"));
                    219: 
                    220:     /* Open policy plugin. */
                    221:     ok = policy_open(&policy_plugin, settings, user_info, envp);
1.1.1.2 ! misho     222:     if (ok != 1) {
1.1       misho     223:        if (ok == -2)
                    224:            usage(1);
                    225:        else
                    226:            errorx(1, _("unable to initialize policy plugin"));
                    227:     }
                    228: 
                    229:     switch (sudo_mode & MODE_MASK) {
                    230:        case MODE_VERSION:
                    231:            policy_show_version(&policy_plugin, !user_details.uid);
                    232:            tq_foreach_fwd(&io_plugins, plugin) {
                    233:                ok = iolog_open(plugin, settings, user_info, NULL,
                    234:                    nargc, nargv, envp);
1.1.1.2 ! misho     235:                if (ok == 1)
1.1       misho     236:                    iolog_show_version(plugin, !user_details.uid);
                    237:            }
                    238:            break;
                    239:        case MODE_VALIDATE:
                    240:        case MODE_VALIDATE|MODE_INVALIDATE:
                    241:            ok = policy_validate(&policy_plugin);
1.1.1.2 ! misho     242:            exit(ok != 1);
1.1       misho     243:        case MODE_KILL:
                    244:        case MODE_INVALIDATE:
                    245:            policy_invalidate(&policy_plugin, sudo_mode == MODE_KILL);
                    246:            exit(0);
                    247:            break;
                    248:        case MODE_CHECK:
                    249:        case MODE_CHECK|MODE_INVALIDATE:
                    250:        case MODE_LIST:
                    251:        case MODE_LIST|MODE_INVALIDATE:
                    252:            ok = policy_list(&policy_plugin, nargc, nargv,
                    253:                ISSET(sudo_mode, MODE_LONG_LIST), list_user);
1.1.1.2 ! misho     254:            exit(ok != 1);
1.1       misho     255:        case MODE_EDIT:
                    256:        case MODE_RUN:
                    257:            ok = policy_check(&policy_plugin, nargc, nargv, env_add,
                    258:                &command_info, &argv_out, &user_env_out);
1.1.1.2 ! misho     259:            sudo_debug_printf(SUDO_DEBUG_INFO, "policy plugin returns %d", ok);
        !           260:            if (ok != 1) {
1.1       misho     261:                if (ok == -2)
                    262:                    usage(1);
                    263:                exit(1); /* plugin printed error message */
                    264:            }
                    265:            /* Open I/O plugins once policy plugin succeeds. */
                    266:            for (plugin = io_plugins.first; plugin != NULL; plugin = next) {
                    267:                next = plugin->next;
                    268:                ok = iolog_open(plugin, settings, user_info,
                    269:                    command_info, nargc, nargv, envp);
                    270:                switch (ok) {
1.1.1.2 ! misho     271:                case 1:
1.1       misho     272:                    break;
1.1.1.2 ! misho     273:                case 0:
        !           274:                    /* I/O plugin asked to be disabled, remove and free. */
        !           275:                    iolog_unlink(plugin);
1.1       misho     276:                    break;
                    277:                case -2:
                    278:                    usage(1);
                    279:                    break;
                    280:                default:
                    281:                    errorx(1, _("error initializing I/O plugin %s"),
                    282:                        plugin->name);
                    283:                }
                    284:            }
1.1.1.2 ! misho     285:            /* Setup command details and run command/edit. */
1.1       misho     286:            command_info_to_details(command_info, &command_details);
                    287:            command_details.argv = argv_out;
                    288:            command_details.envp = user_env_out;
                    289:            if (ISSET(sudo_mode, MODE_BACKGROUND))
                    290:                SET(command_details.flags, CD_BACKGROUND);
1.1.1.2 ! misho     291:            /* Become full root (not just setuid) so user cannot kill us. */
        !           292:            (void) setuid(ROOT_UID);
1.1       misho     293:            /* Restore coredumpsize resource limit before running. */
1.1.1.2 ! misho     294: #ifdef RLIMIT_CORE
        !           295:            if (sudo_conf_disable_coredump())
        !           296:                (void) setrlimit(RLIMIT_CORE, &corelimit);
        !           297: #endif /* RLIMIT_CORE */
1.1       misho     298:            if (ISSET(command_details.flags, CD_SUDOEDIT)) {
                    299:                exitcode = sudo_edit(&command_details);
                    300:            } else {
                    301:                exitcode = run_command(&command_details);
                    302:            }
                    303:            /* The close method was called by sudo_edit/run_command. */
                    304:            break;
                    305:        default:
                    306:            errorx(1, _("unexpected sudo mode 0x%x"), sudo_mode);
                    307:     }
1.1.1.2 ! misho     308:     sudo_debug_exit_int(__func__, __FILE__, __LINE__, sudo_debug_subsys, exitcode);                
1.1       misho     309:     exit(exitcode);
                    310: }
                    311: 
                    312: /*
                    313:  * Ensure that stdin, stdout and stderr are open; set to /dev/null if not.
                    314:  * Some operating systems do this automatically in the kernel or libc.
                    315:  */
                    316: static void
                    317: fix_fds(void)
                    318: {
                    319:     int miss[3], devnull = -1;
1.1.1.2 ! misho     320:     debug_decl(fix_fds, SUDO_DEBUG_UTIL)
1.1       misho     321: 
                    322:     /*
                    323:      * stdin, stdout and stderr must be open; set them to /dev/null
                    324:      * if they are closed.
                    325:      */
                    326:     miss[STDIN_FILENO] = fcntl(STDIN_FILENO, F_GETFL, 0) == -1;
                    327:     miss[STDOUT_FILENO] = fcntl(STDOUT_FILENO, F_GETFL, 0) == -1;
                    328:     miss[STDERR_FILENO] = fcntl(STDERR_FILENO, F_GETFL, 0) == -1;
                    329:     if (miss[STDIN_FILENO] || miss[STDOUT_FILENO] || miss[STDERR_FILENO]) {
                    330:        if ((devnull = open(_PATH_DEVNULL, O_RDWR, 0644)) == -1)
                    331:            error(1, _("unable to open %s"), _PATH_DEVNULL);
                    332:        if (miss[STDIN_FILENO] && dup2(devnull, STDIN_FILENO) == -1)
                    333:            error(1, "dup2");
                    334:        if (miss[STDOUT_FILENO] && dup2(devnull, STDOUT_FILENO) == -1)
                    335:            error(1, "dup2");
                    336:        if (miss[STDERR_FILENO] && dup2(devnull, STDERR_FILENO) == -1)
                    337:            error(1, "dup2");
                    338:        if (devnull > STDERR_FILENO)
                    339:            close(devnull);
                    340:     }
1.1.1.2 ! misho     341:     debug_return;
1.1       misho     342: }
                    343: 
                    344: /*
                    345:  * Allocate space for groups and fill in using getgrouplist()
                    346:  * for when we cannot use getgroups().
                    347:  */
                    348: static int
                    349: fill_group_list(struct user_details *ud)
                    350: {
                    351:     int maxgroups, tries, rval = -1;
1.1.1.2 ! misho     352:     debug_decl(fill_group_list, SUDO_DEBUG_UTIL)
1.1       misho     353: 
                    354: #if defined(HAVE_SYSCONF) && defined(_SC_NGROUPS_MAX)
                    355:     maxgroups = (int)sysconf(_SC_NGROUPS_MAX);
                    356:     if (maxgroups < 0)
                    357: #endif
                    358:        maxgroups = NGROUPS_MAX;
                    359: 
                    360:     /*
                    361:      * It is possible to belong to more groups in the group database
                    362:      * than NGROUPS_MAX.  We start off with NGROUPS_MAX * 2 entries
                    363:      * and double this as needed.
                    364:      */
                    365:     ud->groups = NULL;
                    366:     ud->ngroups = maxgroups;
                    367:     for (tries = 0; tries < 10 && rval == -1; tries++) {
                    368:        ud->ngroups *= 2;
                    369:        efree(ud->groups);
                    370:        ud->groups = emalloc2(ud->ngroups, sizeof(GETGROUPS_T));
                    371:        rval = getgrouplist(ud->username, ud->gid, ud->groups, &ud->ngroups);
                    372:     }
1.1.1.2 ! misho     373:     debug_return_int(rval);
1.1       misho     374: }
                    375: 
                    376: static char *
                    377: get_user_groups(struct user_details *ud)
                    378: {
                    379:     char *cp, *gid_list = NULL;
                    380:     size_t glsize;
                    381:     int i, len;
1.1.1.2 ! misho     382:     debug_decl(get_user_groups, SUDO_DEBUG_UTIL)
1.1       misho     383: 
                    384:     /*
                    385:      * Systems with mbr_check_membership() support more than NGROUPS_MAX
                    386:      * groups so we cannot use getgroups().
                    387:      */
                    388:     ud->groups = NULL;
                    389: #ifndef HAVE_MBR_CHECK_MEMBERSHIP
                    390:     if ((ud->ngroups = getgroups(0, NULL)) > 0) {
                    391:        ud->groups = emalloc2(ud->ngroups, sizeof(GETGROUPS_T));
                    392:        if (getgroups(ud->ngroups, ud->groups) < 0) {
                    393:            efree(ud->groups);
                    394:            ud->groups = NULL;
                    395:        }
                    396:     }
                    397: #endif /* HAVE_MBR_CHECK_MEMBERSHIP */
                    398:     if (ud->groups == NULL) {
                    399:        if (fill_group_list(ud) == -1)
                    400:            error(1, _("unable to get group vector"));
                    401:     }
                    402: 
                    403:     /*
                    404:      * Format group list as a comma-separated string of gids.
                    405:      */
                    406:     glsize = sizeof("groups=") - 1 + (ud->ngroups * (MAX_UID_T_LEN + 1));
                    407:     gid_list = emalloc(glsize);
                    408:     memcpy(gid_list, "groups=", sizeof("groups=") - 1);
                    409:     cp = gid_list + sizeof("groups=") - 1;
                    410:     for (i = 0; i < ud->ngroups; i++) {
                    411:        /* XXX - check rval */
                    412:        len = snprintf(cp, glsize - (cp - gid_list), "%s%u",
                    413:            i ? "," : "", (unsigned int)ud->groups[i]);
                    414:        cp += len;
                    415:     }
1.1.1.2 ! misho     416:     debug_return_str(gid_list);
1.1       misho     417: }
                    418: 
                    419: /*
                    420:  * Return user information as an array of name=value pairs.
                    421:  * and fill in struct user_details (which shares the same strings).
                    422:  */
                    423: static char **
                    424: get_user_info(struct user_details *ud)
                    425: {
1.1.1.2 ! misho     426:     char *cp, **user_info, cwd[PATH_MAX], host[MAXHOSTNAMELEN];
1.1       misho     427:     struct passwd *pw;
1.1.1.2 ! misho     428:     int fd, i = 0;
        !           429:     debug_decl(get_user_info, SUDO_DEBUG_UTIL)
1.1       misho     430: 
                    431:     /* XXX - bound check number of entries */
                    432:     user_info = emalloc2(32, sizeof(char *));
                    433: 
1.1.1.2 ! misho     434:     ud->pid = getpid();
        !           435:     ud->ppid = getppid();
        !           436:     ud->pgid = getpgid(0);
        !           437:     ud->tcpgid = (pid_t)-1;
        !           438:     fd = open(_PATH_TTY, O_RDWR|O_NOCTTY|O_NONBLOCK, 0);
        !           439:     if (fd != -1) {
        !           440:        ud->tcpgid = tcgetpgrp(fd);
        !           441:        close(fd);
        !           442:     }
        !           443:     ud->sid = getsid(0);
        !           444: 
1.1       misho     445:     ud->uid = getuid();
                    446:     ud->euid = geteuid();
                    447:     ud->gid = getgid();
                    448:     ud->egid = getegid();
                    449: 
                    450:     pw = getpwuid(ud->uid);
                    451:     if (pw == NULL)
                    452:        errorx(1, _("unknown uid %u: who are you?"), (unsigned int)ud->uid);
                    453: 
                    454:     user_info[i] = fmt_string("user", pw->pw_name);
                    455:     if (user_info[i] == NULL)
                    456:        errorx(1, _("unable to allocate memory"));
                    457:     ud->username = user_info[i] + sizeof("user=") - 1;
                    458: 
                    459:     /* Stash user's shell for use with the -s flag; don't pass to plugin. */
                    460:     if ((ud->shell = getenv("SHELL")) == NULL || ud->shell[0] == '\0') {
                    461:        ud->shell = pw->pw_shell[0] ? pw->pw_shell : _PATH_BSHELL;
                    462:     }
                    463:     ud->shell = estrdup(ud->shell);
                    464: 
1.1.1.2 ! misho     465:     easprintf(&user_info[++i], "pid=%d", (int)ud->pid);
        !           466:     easprintf(&user_info[++i], "ppid=%d", (int)ud->ppid);
        !           467:     easprintf(&user_info[++i], "pgid=%d", (int)ud->pgid);
        !           468:     easprintf(&user_info[++i], "tcpgid=%d", (int)ud->tcpgid);
        !           469:     easprintf(&user_info[++i], "sid=%d", (int)ud->sid);
        !           470: 
1.1       misho     471:     easprintf(&user_info[++i], "uid=%u", (unsigned int)ud->uid);
                    472:     easprintf(&user_info[++i], "euid=%u", (unsigned int)ud->euid);
                    473:     easprintf(&user_info[++i], "gid=%u", (unsigned int)ud->gid);
                    474:     easprintf(&user_info[++i], "egid=%u", (unsigned int)ud->egid);
                    475: 
                    476:     if ((cp = get_user_groups(ud)) != NULL)
                    477:        user_info[++i] = cp;
                    478: 
                    479:     if (getcwd(cwd, sizeof(cwd)) != NULL) {
                    480:        user_info[++i] = fmt_string("cwd", cwd);
                    481:        if (user_info[i] == NULL)
                    482:            errorx(1, _("unable to allocate memory"));
                    483:        ud->cwd = user_info[i] + sizeof("cwd=") - 1;
                    484:     }
                    485: 
1.1.1.2 ! misho     486:     if ((cp = get_process_ttyname()) != NULL) {
1.1       misho     487:        user_info[++i] = fmt_string("tty", cp);
                    488:        if (user_info[i] == NULL)
                    489:            errorx(1, _("unable to allocate memory"));
                    490:        ud->tty = user_info[i] + sizeof("tty=") - 1;
1.1.1.2 ! misho     491:        efree(cp);
1.1       misho     492:     }
                    493: 
                    494:     if (gethostname(host, sizeof(host)) == 0)
                    495:        host[sizeof(host) - 1] = '\0';
                    496:     else
                    497:        strlcpy(host, "localhost", sizeof(host));
                    498:     user_info[++i] = fmt_string("host", host);
                    499:     if (user_info[i] == NULL)
                    500:        errorx(1, _("unable to allocate memory"));
                    501:     ud->host = user_info[i] + sizeof("host=") - 1;
                    502: 
                    503:     get_ttysize(&ud->ts_lines, &ud->ts_cols);
                    504:     easprintf(&user_info[++i], "lines=%d", ud->ts_lines);
                    505:     easprintf(&user_info[++i], "cols=%d", ud->ts_cols);
                    506: 
                    507:     user_info[++i] = NULL;
                    508: 
1.1.1.2 ! misho     509:     debug_return_ptr(user_info);
1.1       misho     510: }
                    511: 
                    512: /*
                    513:  * Convert a command_info array into a command_details structure.
                    514:  */
                    515: static void
                    516: command_info_to_details(char * const info[], struct command_details *details)
                    517: {
                    518:     int i;
                    519:     long lval;
                    520:     unsigned long ulval;
                    521:     char *cp, *ep;
1.1.1.2 ! misho     522:     debug_decl(command_info_to_details, SUDO_DEBUG_PCOMM)
1.1       misho     523: 
                    524:     memset(details, 0, sizeof(*details));
                    525:     details->closefrom = -1;
                    526: 
                    527: #define SET_STRING(s, n) \
                    528:     if (strncmp(s, info[i], sizeof(s) - 1) == 0 && info[i][sizeof(s) - 1]) { \
                    529:        details->n = info[i] + sizeof(s) - 1; \
                    530:        break; \
                    531:     }
                    532: 
1.1.1.2 ! misho     533:     sudo_debug_printf(SUDO_DEBUG_INFO, "command info from plugin:");
1.1       misho     534:     for (i = 0; info[i] != NULL; i++) {
1.1.1.2 ! misho     535:        sudo_debug_printf(SUDO_DEBUG_INFO, "    %d: %s", i, info[i]);
1.1       misho     536:        switch (info[i][0]) {
                    537:            case 'c':
                    538:                SET_STRING("chroot=", chroot)
                    539:                SET_STRING("command=", command)
                    540:                SET_STRING("cwd=", cwd)
                    541:                if (strncmp("closefrom=", info[i], sizeof("closefrom=") - 1) == 0) {
                    542:                    cp = info[i] + sizeof("closefrom=") - 1;
                    543:                    if (*cp == '\0')
                    544:                        break;
                    545:                    errno = 0;
                    546:                    lval = strtol(cp, &ep, 0);
                    547:                    if (*cp != '\0' && *ep == '\0' &&
                    548:                        !(errno == ERANGE &&
                    549:                        (lval == LONG_MAX || lval == LONG_MIN)) &&
                    550:                        lval < INT_MAX && lval > INT_MIN) {
                    551:                        details->closefrom = (int)lval;
                    552:                    }
                    553:                    break;
                    554:                }
                    555:                break;
                    556:            case 'l':
                    557:                SET_STRING("login_class=", login_class)
                    558:                break;
                    559:            case 'n':
                    560:                /* XXX - bounds check  -NZERO to NZERO (inclusive). */
                    561:                if (strncmp("nice=", info[i], sizeof("nice=") - 1) == 0) {
                    562:                    cp = info[i] + sizeof("nice=") - 1;
                    563:                    if (*cp == '\0')
                    564:                        break;
                    565:                    errno = 0;
                    566:                    lval = strtol(cp, &ep, 0);
                    567:                    if (*cp != '\0' && *ep == '\0' &&
                    568:                        !(errno == ERANGE &&
                    569:                        (lval == LONG_MAX || lval == LONG_MIN)) &&
                    570:                        lval < INT_MAX && lval > INT_MIN) {
                    571:                        details->priority = (int)lval;
                    572:                        SET(details->flags, CD_SET_PRIORITY);
                    573:                    }
                    574:                    break;
                    575:                }
                    576:                if (strncmp("noexec=", info[i], sizeof("noexec=") - 1) == 0) {
1.1.1.2 ! misho     577:                    if (atobool(info[i] + sizeof("noexec=") - 1) == true)
1.1       misho     578:                        SET(details->flags, CD_NOEXEC);
                    579:                    break;
                    580:                }
                    581:                break;
                    582:            case 'p':
                    583:                if (strncmp("preserve_groups=", info[i], sizeof("preserve_groups=") - 1) == 0) {
1.1.1.2 ! misho     584:                    if (atobool(info[i] + sizeof("preserve_groups=") - 1) == true)
1.1       misho     585:                        SET(details->flags, CD_PRESERVE_GROUPS);
                    586:                    break;
                    587:                }
                    588:                break;
                    589:            case 'r':
                    590:                if (strncmp("runas_egid=", info[i], sizeof("runas_egid=") - 1) == 0) {
                    591:                    cp = info[i] + sizeof("runas_egid=") - 1;
                    592:                    if (*cp == '\0')
                    593:                        break;
                    594:                    errno = 0;
                    595:                    ulval = strtoul(cp, &ep, 0);
                    596:                    if (*cp != '\0' && *ep == '\0' &&
                    597:                        (errno != ERANGE || ulval != ULONG_MAX)) {
                    598:                        details->egid = (gid_t)ulval;
                    599:                        SET(details->flags, CD_SET_EGID);
                    600:                    }
                    601:                    break;
                    602:                }
                    603:                if (strncmp("runas_euid=", info[i], sizeof("runas_euid=") - 1) == 0) {
                    604:                    cp = info[i] + sizeof("runas_euid=") - 1;
                    605:                    if (*cp == '\0')
                    606:                        break;
                    607:                    errno = 0;
                    608:                    ulval = strtoul(cp, &ep, 0);
                    609:                    if (*cp != '\0' && *ep == '\0' &&
                    610:                        (errno != ERANGE || ulval != ULONG_MAX)) {
                    611:                        details->euid = (uid_t)ulval;
                    612:                        SET(details->flags, CD_SET_EUID);
                    613:                    }
                    614:                    break;
                    615:                }
                    616:                if (strncmp("runas_gid=", info[i], sizeof("runas_gid=") - 1) == 0) {
                    617:                    cp = info[i] + sizeof("runas_gid=") - 1;
                    618:                    if (*cp == '\0')
                    619:                        break;
                    620:                    errno = 0;
                    621:                    ulval = strtoul(cp, &ep, 0);
                    622:                    if (*cp != '\0' && *ep == '\0' &&
                    623:                        (errno != ERANGE || ulval != ULONG_MAX)) {
                    624:                        details->gid = (gid_t)ulval;
                    625:                        SET(details->flags, CD_SET_GID);
                    626:                    }
                    627:                    break;
                    628:                }
                    629:                if (strncmp("runas_groups=", info[i], sizeof("runas_groups=") - 1) == 0) {
                    630:                    int j;
                    631: 
                    632:                    /* count groups, alloc and fill in */
                    633:                    cp = info[i] + sizeof("runas_groups=") - 1;
                    634:                    if (*cp == '\0')
                    635:                        break;
                    636:                    for (;;) {
                    637:                        details->ngroups++;
                    638:                        if ((cp = strchr(cp, ',')) == NULL)
                    639:                            break;
                    640:                        cp++;
                    641:                    }
                    642:                    if (details->ngroups != 0) {
                    643:                        details->groups =
                    644:                            emalloc2(details->ngroups, sizeof(GETGROUPS_T));
                    645:                        cp = info[i] + sizeof("runas_groups=") - 1;
                    646:                        for (j = 0; j < details->ngroups;) {
                    647:                            errno = 0;
                    648:                            ulval = strtoul(cp, &ep, 0);
                    649:                            if (*cp == '\0' || (*ep != ',' && *ep != '\0') ||
                    650:                                (ulval == ULONG_MAX && errno == ERANGE)) {
                    651:                                break;
                    652:                            }
                    653:                            details->groups[j++] = (gid_t)ulval;
                    654:                            cp = ep + 1;
                    655:                        }
                    656:                        details->ngroups = j;
                    657:                    }
                    658:                    break;
                    659:                }
                    660:                if (strncmp("runas_uid=", info[i], sizeof("runas_uid=") - 1) == 0) {
                    661:                    cp = info[i] + sizeof("runas_uid=") - 1;
                    662:                    if (*cp == '\0')
                    663:                        break;
                    664:                    errno = 0;
                    665:                    ulval = strtoul(cp, &ep, 0);
                    666:                    if (*cp != '\0' && *ep == '\0' &&
                    667:                        (errno != ERANGE || ulval != ULONG_MAX)) {
                    668:                        details->uid = (uid_t)ulval;
                    669:                        SET(details->flags, CD_SET_UID);
                    670:                    }
                    671:                    break;
                    672:                }
                    673:                break;
                    674:            case 's':
                    675:                SET_STRING("selinux_role=", selinux_role)
                    676:                SET_STRING("selinux_type=", selinux_type)
                    677:                if (strncmp("set_utmp=", info[i], sizeof("set_utmp=") - 1) == 0) {
1.1.1.2 ! misho     678:                    if (atobool(info[i] + sizeof("set_utmp=") - 1) == true)
1.1       misho     679:                        SET(details->flags, CD_SET_UTMP);
                    680:                    break;
                    681:                }
                    682:                if (strncmp("sudoedit=", info[i], sizeof("sudoedit=") - 1) == 0) {
1.1.1.2 ! misho     683:                    if (atobool(info[i] + sizeof("sudoedit=") - 1) == true)
1.1       misho     684:                        SET(details->flags, CD_SUDOEDIT);
                    685:                    break;
                    686:                }
                    687:                break;
                    688:            case 't':
                    689:                if (strncmp("timeout=", info[i], sizeof("timeout=") - 1) == 0) {
                    690:                    cp = info[i] + sizeof("timeout=") - 1;
                    691:                    if (*cp == '\0')
                    692:                        break;
                    693:                    errno = 0;
                    694:                    lval = strtol(cp, &ep, 0);
                    695:                    if (*cp != '\0' && *ep == '\0' &&
                    696:                        !(errno == ERANGE &&
                    697:                        (lval == LONG_MAX || lval == LONG_MIN)) &&
                    698:                        lval <= INT_MAX && lval >= 0) {
                    699:                        details->timeout = (int)lval;
                    700:                        SET(details->flags, CD_SET_TIMEOUT);
                    701:                    }
                    702:                    break;
                    703:                }
                    704:                break;
                    705:            case 'u':
                    706:                if (strncmp("umask=", info[i], sizeof("umask=") - 1) == 0) {
                    707:                    cp = info[i] + sizeof("umask=") - 1;
                    708:                    if (*cp == '\0')
                    709:                        break;
                    710:                    errno = 0;
                    711:                    ulval = strtoul(cp, &ep, 8);
                    712:                    if (*cp != '\0' && *ep == '\0' &&
                    713:                        (errno != ERANGE || ulval != ULONG_MAX)) {
                    714:                        details->umask = (uid_t)ulval;
                    715:                        SET(details->flags, CD_SET_UMASK);
                    716:                    }
                    717:                    break;
                    718:                }
                    719:                if (strncmp("use_pty=", info[i], sizeof("use_pty=") - 1) == 0) {
1.1.1.2 ! misho     720:                    if (atobool(info[i] + sizeof("use_pty=") - 1) == true)
1.1       misho     721:                        SET(details->flags, CD_USE_PTY);
                    722:                    break;
                    723:                }
                    724:                SET_STRING("utmp_user=", utmp_user)
                    725:                break;
                    726:        }
                    727:     }
                    728: 
                    729:     if (!ISSET(details->flags, CD_SET_EUID))
                    730:        details->euid = details->uid;
                    731: 
1.1.1.2 ! misho     732: #ifdef HAVE_SETAUTHDB
        !           733:     aix_setauthdb(IDtouser(details->euid));
        !           734: #endif
        !           735:     details->pw = getpwuid(details->euid);
        !           736:     if (details->pw != NULL && (details->pw = pw_dup(details->pw)) == NULL)
        !           737:        errorx(1, _("unable to allocate memory"));
        !           738: #ifdef HAVE_SETAUTHDB
        !           739:     aix_restoreauthdb();
        !           740: #endif
        !           741: 
1.1       misho     742: #ifdef HAVE_SELINUX
                    743:     if (details->selinux_role != NULL && is_selinux_enabled() > 0)
                    744:        SET(details->flags, CD_RBAC_ENABLED);
                    745: #endif
1.1.1.2 ! misho     746:     debug_return;
        !           747: }
        !           748: 
        !           749: static void
        !           750: sudo_check_suid(const char *path)
        !           751: {
        !           752:     struct stat sb;
        !           753:     debug_decl(sudo_check_suid, SUDO_DEBUG_PCOMM)
        !           754: 
        !           755:     if (geteuid() != 0) {
        !           756:        if (strchr(path, '/') != NULL && stat(path, &sb) == 0) {
        !           757:            /* Try to determine why sudo was not running as root. */
        !           758:            if (sb.st_uid != ROOT_UID || !ISSET(sb.st_mode, S_ISUID)) {
        !           759:                errorx(1,
        !           760:                    _("%s must be owned by uid %d and have the setuid bit set"),
        !           761:                    path, ROOT_UID);
        !           762:            } else {
        !           763:                errorx(1, _("effective uid is not %d, is %s on a file system "
        !           764:                    "with the 'nosuid' option set or an NFS file system without"
        !           765:                    " root privileges?"), ROOT_UID, path);
        !           766:            }
        !           767:        } else {
        !           768:            errorx(1,
        !           769:                _("effective uid is not %d, is sudo installed setuid root?"),
        !           770:                ROOT_UID);
        !           771:        }
        !           772:     }
        !           773:     debug_return;
1.1       misho     774: }
                    775: 
                    776: /*
                    777:  * Disable core dumps to avoid dropping a core with user password in it.
                    778:  * We will reset this limit before executing the command.
                    779:  * Not all operating systems disable core dumps for setuid processes.
                    780:  */
                    781: static void
                    782: disable_coredumps(void)
                    783: {
1.1.1.2 ! misho     784: #if defined(__linux__) || defined(RLIMIT_CORE)
1.1       misho     785:     struct rlimit rl;
                    786: #endif
1.1.1.2 ! misho     787:     debug_decl(disable_coredumps, SUDO_DEBUG_UTIL)
1.1       misho     788: 
                    789: #if defined(__linux__)
                    790:     /*
                    791:      * Unlimit the number of processes since Linux's setuid() will
                    792:      * apply resource limits when changing uid and return EAGAIN if
                    793:      * nproc would be violated by the uid switch.
                    794:      */
                    795:     (void) getrlimit(RLIMIT_NPROC, &nproclimit);
                    796:     rl.rlim_cur = rl.rlim_max = RLIM_INFINITY;
                    797:     if (setrlimit(RLIMIT_NPROC, &rl)) {
                    798:        memcpy(&rl, &nproclimit, sizeof(struct rlimit));
                    799:        rl.rlim_cur = rl.rlim_max;
                    800:        (void)setrlimit(RLIMIT_NPROC, &rl);
                    801:     }
                    802: #endif /* __linux__ */
1.1.1.2 ! misho     803: #ifdef RLIMIT_CORE
1.1       misho     804:     /*
1.1.1.2 ! misho     805:      * Turn off core dumps?
1.1       misho     806:      */
1.1.1.2 ! misho     807:     if (sudo_conf_disable_coredump()) {
        !           808:        (void) getrlimit(RLIMIT_CORE, &corelimit);
        !           809:        memcpy(&rl, &corelimit, sizeof(struct rlimit));
        !           810:        rl.rlim_cur = 0;
        !           811:        (void) setrlimit(RLIMIT_CORE, &rl);
        !           812:     }
        !           813: #endif /* RLIMIT_CORE */
        !           814:     debug_return;
1.1       misho     815: }
                    816: 
                    817: #ifdef HAVE_PROJECT_H
                    818: static void
                    819: set_project(struct passwd *pw)
                    820: {
                    821:     struct project proj;
                    822:     char buf[PROJECT_BUFSZ];
                    823:     int errval;
1.1.1.2 ! misho     824:     debug_decl(set_project, SUDO_DEBUG_UTIL)
1.1       misho     825: 
                    826:     /*
                    827:      * Collect the default project for the user and settaskid
                    828:      */
                    829:     setprojent();
                    830:     if (getdefaultproj(pw->pw_name, &proj, buf, sizeof(buf)) != NULL) {
                    831:        errval = setproject(proj.pj_name, pw->pw_name, TASK_NORMAL);
                    832:        switch(errval) {
                    833:        case 0:
                    834:            break;
                    835:        case SETPROJ_ERR_TASK:
                    836:            switch (errno) {
                    837:            case EAGAIN:
                    838:                warningx(_("resource control limit has been reached"));
                    839:                break;
                    840:            case ESRCH:
                    841:                warningx(_("user \"%s\" is not a member of project \"%s\""),
                    842:                    pw->pw_name, proj.pj_name);
                    843:                break;
                    844:            case EACCES:
                    845:                warningx(_("the invoking task is final"));
                    846:                break;
                    847:            default:
                    848:                warningx(_("could not join project \"%s\""), proj.pj_name);
                    849:            }
                    850:        case SETPROJ_ERR_POOL:
                    851:            switch (errno) {
                    852:            case EACCES:
                    853:                warningx(_("no resource pool accepting default bindings "
                    854:                    "exists for project \"%s\""), proj.pj_name);
                    855:                break;
                    856:            case ESRCH:
                    857:                warningx(_("specified resource pool does not exist for "
                    858:                    "project \"%s\""), proj.pj_name);
                    859:                break;
                    860:            default:
                    861:                warningx(_("could not bind to default resource pool for "
                    862:                    "project \"%s\""), proj.pj_name);
                    863:            }
                    864:            break;
                    865:        default:
                    866:            if (errval <= 0) {
                    867:                warningx(_("setproject failed for project \"%s\""), proj.pj_name);
                    868:            } else {
                    869:                warningx(_("warning, resource control assignment failed for "
                    870:                    "project \"%s\""), proj.pj_name);
                    871:            }
                    872:        }
                    873:     } else {
                    874:        warning("getdefaultproj");
                    875:     }
                    876:     endprojent();
1.1.1.2 ! misho     877:     debug_return;
1.1       misho     878: }
                    879: #endif /* HAVE_PROJECT_H */
                    880: 
                    881: /*
                    882:  * Setup the execution environment immediately prior to the call to execve()
1.1.1.2 ! misho     883:  * Returns true on success and false on failure.
1.1       misho     884:  */
1.1.1.2 ! misho     885: bool
1.1       misho     886: exec_setup(struct command_details *details, const char *ptyname, int ptyfd)
                    887: {
1.1.1.2 ! misho     888:     bool rval = false;
        !           889:     debug_decl(exec_setup, SUDO_DEBUG_EXEC)
1.1       misho     890: 
                    891: #ifdef HAVE_SELINUX
                    892:     if (ISSET(details->flags, CD_RBAC_ENABLED)) {
                    893:        if (selinux_setup(details->selinux_role, details->selinux_type,
                    894:            ptyname ? ptyname : user_details.tty, ptyfd) == -1)
                    895:            goto done;
                    896:     }
                    897: #endif
                    898: 
1.1.1.2 ! misho     899:     if (details->pw != NULL) {
1.1       misho     900: #ifdef HAVE_PROJECT_H
1.1.1.2 ! misho     901:        set_project(details->pw);
1.1       misho     902: #endif
                    903: #ifdef HAVE_GETUSERATTR
1.1.1.2 ! misho     904:        aix_prep_user(details->pw->pw_name, ptyname ? ptyname : user_details.tty);
1.1       misho     905: #endif
                    906: #ifdef HAVE_LOGIN_CAP_H
                    907:        if (details->login_class) {
                    908:            int flags;
                    909:            login_cap_t *lc;
                    910: 
                    911:            /*
1.1.1.2 ! misho     912:             * We only use setusercontext() to set the nice value and rlimits
        !           913:             * unless this is a login shell (sudo -i).
1.1       misho     914:             */
                    915:            lc = login_getclass((char *)details->login_class);
                    916:            if (!lc) {
                    917:                warningx(_("unknown login class %s"), details->login_class);
                    918:                errno = ENOENT;
                    919:                goto done;
                    920:            }
1.1.1.2 ! misho     921:            if (ISSET(sudo_mode, MODE_LOGIN_SHELL)) {
        !           922:                /* Set everything except user, group and login name. */
        !           923:                flags = LOGIN_SETALL;
        !           924:                CLR(flags, LOGIN_SETGROUP|LOGIN_SETLOGIN|LOGIN_SETUSER|LOGIN_SETENV|LOGIN_SETPATH);
        !           925:                CLR(details->flags, CD_SET_UMASK); /* LOGIN_UMASK instead */
        !           926:            } else {
        !           927:                flags = LOGIN_SETRESOURCES|LOGIN_SETPRIORITY;
        !           928:            }
        !           929:            if (setusercontext(lc, details->pw, details->pw->pw_uid, flags)) {
        !           930:                if (details->pw->pw_uid != ROOT_UID) {
1.1       misho     931:                    warning(_("unable to set user context"));
                    932:                    goto done;
                    933:                } else
                    934:                    warning(_("unable to set user context"));
                    935:            }
                    936:        }
                    937: #endif /* HAVE_LOGIN_CAP_H */
                    938:     }
                    939: 
                    940:     /*
                    941:      * Set groups, including supplementary group vector.
                    942:      */
1.1.1.2 ! misho     943:     if (!ISSET(details->flags, CD_PRESERVE_GROUPS)) {
        !           944:        if (details->ngroups >= 0) {
        !           945:            if (sudo_setgroups(details->ngroups, details->groups) < 0) {
        !           946:                warning(_("unable to set supplementary group IDs"));
        !           947:                goto done;
        !           948:            }
        !           949:        }
        !           950:     }
1.1       misho     951: #ifdef HAVE_SETEUID
                    952:     if (ISSET(details->flags, CD_SET_EGID) && setegid(details->egid)) {
                    953:        warning(_("unable to set effective gid to runas gid %u"),
                    954:            (unsigned int)details->egid);
                    955:        goto done;
                    956:     }
                    957: #endif
                    958:     if (ISSET(details->flags, CD_SET_GID) && setgid(details->gid)) {
                    959:        warning(_("unable to set gid to runas gid %u"),
                    960:            (unsigned int)details->gid);
                    961:        goto done;
                    962:     }
                    963: 
                    964:     if (ISSET(details->flags, CD_SET_PRIORITY)) {
                    965:        if (setpriority(PRIO_PROCESS, 0, details->priority) != 0) {
                    966:            warning(_("unable to set process priority"));
                    967:            goto done;
                    968:        }
                    969:     }
                    970:     if (ISSET(details->flags, CD_SET_UMASK))
                    971:        (void) umask(details->umask);
                    972:     if (details->chroot) {
                    973:        if (chroot(details->chroot) != 0 || chdir("/") != 0) {
                    974:            warning(_("unable to change root to %s"), details->chroot);
                    975:            goto done;
                    976:        }
                    977:     }
                    978: 
                    979: #ifdef HAVE_SETRESUID
                    980:     if (setresuid(details->uid, details->euid, details->euid) != 0) {
                    981:        warning(_("unable to change to runas uid (%u, %u)"), details->uid,
                    982:            details->euid);
                    983:        goto done;
                    984:     }
                    985: #elif HAVE_SETREUID
                    986:     if (setreuid(details->uid, details->euid) != 0) {
                    987:        warning(_("unable to change to runas uid (%u, %u)"),
                    988:            (unsigned int)details->uid, (unsigned int)details->euid);
                    989:        goto done;
                    990:     }
                    991: #else
                    992:     if (seteuid(details->euid) != 0 || setuid(details->euid) != 0) {
                    993:        warning(_("unable to change to runas uid (%u, %u)"), details->uid,
                    994:            details->euid);
                    995:        goto done;
                    996:     }
                    997: #endif /* !HAVE_SETRESUID && !HAVE_SETREUID */
                    998: 
                    999:     /*
                   1000:      * Only change cwd if we have chroot()ed or the policy modules
                   1001:      * specifies a different cwd.  Must be done after uid change.
                   1002:      */
                   1003:     if (details->cwd) {
                   1004:        if (details->chroot || strcmp(details->cwd, user_details.cwd) != 0) {
                   1005:            /* Note: cwd is relative to the new root, if any. */
                   1006:            if (chdir(details->cwd) != 0) {
                   1007:                warning(_("unable to change directory to %s"), details->cwd);
                   1008:                goto done;
                   1009:            }
                   1010:        }
                   1011:     }
                   1012: 
                   1013:     /*
                   1014:      * Restore nproc resource limit if pam_limits didn't do it for us.
                   1015:      * We must do this *after* the uid change to avoid potential EAGAIN
                   1016:      * from setuid().
                   1017:      */
                   1018: #if defined(__linux__)
                   1019:     {
                   1020:        struct rlimit rl;
                   1021:        if (getrlimit(RLIMIT_NPROC, &rl) == 0) {
                   1022:            if (rl.rlim_cur == RLIM_INFINITY && rl.rlim_max == RLIM_INFINITY)
                   1023:                (void) setrlimit(RLIMIT_NPROC, &nproclimit);
                   1024:        }
                   1025:     }
                   1026: #endif
                   1027: 
1.1.1.2 ! misho    1028:     rval = true;
1.1       misho    1029: 
                   1030: done:
1.1.1.2 ! misho    1031:     debug_return_bool(rval);
1.1       misho    1032: }
                   1033: 
                   1034: /*
                   1035:  * Run the command and wait for it to complete.
                   1036:  */
                   1037: int
                   1038: run_command(struct command_details *details)
                   1039: {
                   1040:     struct plugin_container *plugin;
                   1041:     struct command_status cstat;
                   1042:     int exitcode = 1;
1.1.1.2 ! misho    1043:     debug_decl(run_command, SUDO_DEBUG_EXEC)
1.1       misho    1044: 
                   1045:     cstat.type = CMD_INVALID;
                   1046:     cstat.val = 0;
                   1047: 
1.1.1.2 ! misho    1048:     sudo_execute(details, &cstat);
1.1       misho    1049: 
                   1050:     switch (cstat.type) {
                   1051:     case CMD_ERRNO:
                   1052:        /* exec_setup() or execve() returned an error. */
1.1.1.2 ! misho    1053:        sudo_debug_printf(SUDO_DEBUG_DEBUG,
        !          1054:            "calling policy close with errno %d", cstat.val);
1.1       misho    1055:        policy_close(&policy_plugin, 0, cstat.val);
                   1056:        tq_foreach_fwd(&io_plugins, plugin) {
1.1.1.2 ! misho    1057:            sudo_debug_printf(SUDO_DEBUG_DEBUG,
        !          1058:                "calling I/O close with errno %d", cstat.val);
1.1       misho    1059:            iolog_close(plugin, 0, cstat.val);
                   1060:        }
                   1061:        exitcode = 1;
                   1062:        break;
                   1063:     case CMD_WSTATUS:
                   1064:        /* Command ran, exited or was killed. */
1.1.1.2 ! misho    1065:        sudo_debug_printf(SUDO_DEBUG_DEBUG,
        !          1066:            "calling policy close with wait status %d", cstat.val);
1.1       misho    1067:        policy_close(&policy_plugin, cstat.val, 0);
                   1068:        tq_foreach_fwd(&io_plugins, plugin) {
1.1.1.2 ! misho    1069:            sudo_debug_printf(SUDO_DEBUG_DEBUG,
        !          1070:                "calling I/O close with wait status %d", cstat.val);
1.1       misho    1071:            iolog_close(plugin, cstat.val, 0);
                   1072:        }
                   1073:        if (WIFEXITED(cstat.val))
                   1074:            exitcode = WEXITSTATUS(cstat.val);
                   1075:        else if (WIFSIGNALED(cstat.val))
                   1076:            exitcode = WTERMSIG(cstat.val) | 128;
                   1077:        break;
                   1078:     default:
                   1079:        warningx(_("unexpected child termination condition: %d"), cstat.type);
                   1080:        break;
                   1081:     }
1.1.1.2 ! misho    1082:     debug_return_int(exitcode);
1.1       misho    1083: }
                   1084: 
                   1085: static int
                   1086: policy_open(struct plugin_container *plugin, char * const settings[],
                   1087:     char * const user_info[], char * const user_env[])
                   1088: {
1.1.1.2 ! misho    1089:     int rval;
        !          1090:     debug_decl(policy_open, SUDO_DEBUG_PCOMM)
        !          1091: 
        !          1092:     /*
        !          1093:      * Backwards compatibility for older API versions
        !          1094:      */
        !          1095:     switch (plugin->u.generic->version) {
        !          1096:     case SUDO_API_MKVERSION(1, 0):
        !          1097:     case SUDO_API_MKVERSION(1, 1):
        !          1098:        rval = plugin->u.policy_1_0->open(plugin->u.io_1_0->version,
        !          1099:            sudo_conversation, _sudo_printf, settings, user_info, user_env);
        !          1100:        break;
        !          1101:     default:
        !          1102:        rval = plugin->u.policy->open(SUDO_API_VERSION, sudo_conversation,
        !          1103:            _sudo_printf, settings, user_info, user_env, plugin->options);
        !          1104:     }
        !          1105: 
        !          1106:     debug_return_bool(rval);
1.1       misho    1107: }
                   1108: 
                   1109: static void
                   1110: policy_close(struct plugin_container *plugin, int exit_status, int error)
                   1111: {
1.1.1.2 ! misho    1112:     debug_decl(policy_close, SUDO_DEBUG_PCOMM)
1.1       misho    1113:     plugin->u.policy->close(exit_status, error);
1.1.1.2 ! misho    1114:     debug_return;
1.1       misho    1115: }
                   1116: 
                   1117: static int
                   1118: policy_show_version(struct plugin_container *plugin, int verbose)
                   1119: {
1.1.1.2 ! misho    1120:     debug_decl(policy_show_version, SUDO_DEBUG_PCOMM)
        !          1121:     debug_return_bool(plugin->u.policy->show_version(verbose));
1.1       misho    1122: }
                   1123: 
                   1124: static int
                   1125: policy_check(struct plugin_container *plugin, int argc, char * const argv[],
                   1126:     char *env_add[], char **command_info[], char **argv_out[],
                   1127:     char **user_env_out[])
                   1128: {
1.1.1.2 ! misho    1129:     debug_decl(policy_check, SUDO_DEBUG_PCOMM)
        !          1130:     debug_return_bool(plugin->u.policy->check_policy(argc, argv, env_add,
        !          1131:        command_info, argv_out, user_env_out));
1.1       misho    1132: }
                   1133: 
                   1134: static int
                   1135: policy_list(struct plugin_container *plugin, int argc, char * const argv[],
                   1136:     int verbose, const char *list_user)
                   1137: {
1.1.1.2 ! misho    1138:     debug_decl(policy_list, SUDO_DEBUG_PCOMM)
1.1       misho    1139:     if (plugin->u.policy->list == NULL) {
                   1140:        warningx(_("policy plugin %s does not support listing privileges"),
                   1141:            plugin->name);
1.1.1.2 ! misho    1142:        debug_return_bool(false);
1.1       misho    1143:     }
1.1.1.2 ! misho    1144:     debug_return_bool(plugin->u.policy->list(argc, argv, verbose, list_user));
1.1       misho    1145: }
                   1146: 
                   1147: static int
                   1148: policy_validate(struct plugin_container *plugin)
                   1149: {
1.1.1.2 ! misho    1150:     debug_decl(policy_validate, SUDO_DEBUG_PCOMM)
1.1       misho    1151:     if (plugin->u.policy->validate == NULL) {
                   1152:        warningx(_("policy plugin %s does not support the -v option"),
                   1153:            plugin->name);
1.1.1.2 ! misho    1154:        debug_return_bool(false);
1.1       misho    1155:     }
1.1.1.2 ! misho    1156:     debug_return_bool(plugin->u.policy->validate());
1.1       misho    1157: }
                   1158: 
                   1159: static void
                   1160: policy_invalidate(struct plugin_container *plugin, int remove)
                   1161: {
1.1.1.2 ! misho    1162:     debug_decl(policy_invalidate, SUDO_DEBUG_PCOMM)
1.1       misho    1163:     if (plugin->u.policy->invalidate == NULL) {
                   1164:        errorx(1, _("policy plugin %s does not support the -k/-K options"),
                   1165:            plugin->name);
                   1166:     }
                   1167:     plugin->u.policy->invalidate(remove);
1.1.1.2 ! misho    1168:     debug_return;
1.1       misho    1169: }
                   1170: 
1.1.1.2 ! misho    1171: int
        !          1172: policy_init_session(struct command_details *details)
1.1       misho    1173: {
1.1.1.2 ! misho    1174:     int rval = true;
        !          1175:     debug_decl(policy_init_session, SUDO_DEBUG_PCOMM)
        !          1176: 
        !          1177:     if (policy_plugin.u.policy->init_session) {
        !          1178:        /*
        !          1179:         * Backwards compatibility for older API versions
        !          1180:         */
        !          1181:        switch (policy_plugin.u.generic->version) {
        !          1182:        case SUDO_API_MKVERSION(1, 0):
        !          1183:        case SUDO_API_MKVERSION(1, 1):
        !          1184:            rval = policy_plugin.u.policy_1_0->init_session(details->pw);
        !          1185:            break;
        !          1186:        default:
        !          1187:            rval = policy_plugin.u.policy->init_session(details->pw,
        !          1188:                &details->envp);
        !          1189:        }
        !          1190:     }
        !          1191:     debug_return_bool(rval);
1.1       misho    1192: }
                   1193: 
                   1194: static int
                   1195: iolog_open(struct plugin_container *plugin, char * const settings[],
                   1196:     char * const user_info[], char * const command_info[],
                   1197:     int argc, char * const argv[], char * const user_env[])
                   1198: {
                   1199:     int rval;
1.1.1.2 ! misho    1200:     debug_decl(iolog_open, SUDO_DEBUG_PCOMM)
1.1       misho    1201: 
                   1202:     /*
1.1.1.2 ! misho    1203:      * Backwards compatibility for older API versions
1.1       misho    1204:      */
                   1205:     switch (plugin->u.generic->version) {
                   1206:     case SUDO_API_MKVERSION(1, 0):
                   1207:        rval = plugin->u.io_1_0->open(plugin->u.io_1_0->version,
                   1208:            sudo_conversation, _sudo_printf, settings, user_info, argc, argv,
                   1209:            user_env);
                   1210:        break;
1.1.1.2 ! misho    1211:     case SUDO_API_MKVERSION(1, 1):
        !          1212:        rval = plugin->u.io_1_1->open(plugin->u.io_1_1->version,
        !          1213:            sudo_conversation, _sudo_printf, settings, user_info,
        !          1214:            command_info, argc, argv, user_env);
        !          1215:        break;
1.1       misho    1216:     default:
                   1217:        rval = plugin->u.io->open(SUDO_API_VERSION, sudo_conversation,
1.1.1.2 ! misho    1218:            _sudo_printf, settings, user_info, command_info,
        !          1219:            argc, argv, user_env, plugin->options);
1.1       misho    1220:     }
1.1.1.2 ! misho    1221:     debug_return_bool(rval);
1.1       misho    1222: }
                   1223: 
                   1224: static void
                   1225: iolog_close(struct plugin_container *plugin, int exit_status, int error)
                   1226: {
1.1.1.2 ! misho    1227:     debug_decl(iolog_close, SUDO_DEBUG_PCOMM)
1.1       misho    1228:     plugin->u.io->close(exit_status, error);
1.1.1.2 ! misho    1229:     debug_return;
1.1       misho    1230: }
                   1231: 
                   1232: static int
                   1233: iolog_show_version(struct plugin_container *plugin, int verbose)
                   1234: {
1.1.1.2 ! misho    1235:     debug_decl(iolog_show_version, SUDO_DEBUG_PCOMM)
        !          1236:     debug_return_bool(plugin->u.io->show_version(verbose));
1.1       misho    1237: }
                   1238: 
                   1239: /*
1.1.1.2 ! misho    1240:  * Remove the specified I/O logging plugin from the io_plugins list.
        !          1241:  * Deregisters any hooks before unlinking, then frees the container.
1.1       misho    1242:  */
1.1.1.2 ! misho    1243: static void
        !          1244: iolog_unlink(struct plugin_container *plugin)
1.1       misho    1245: {
1.1.1.2 ! misho    1246:     debug_decl(iolog_unlink, SUDO_DEBUG_PCOMM)
1.1       misho    1247: 
1.1.1.2 ! misho    1248:     /* Deregister hooks, if any. */
        !          1249:     if (plugin->u.io->version >= SUDO_API_MKVERSION(1, 2)) {
        !          1250:        if (plugin->u.io->deregister_hooks != NULL)
        !          1251:            plugin->u.io->deregister_hooks(SUDO_HOOK_VERSION,
        !          1252:                deregister_hook);
        !          1253:     }
        !          1254:     /* Remove from io_plugins list and free. */
        !          1255:     tq_remove(&io_plugins, plugin);
        !          1256:     efree(plugin);
1.1       misho    1257: 
1.1.1.2 ! misho    1258:     debug_return;
1.1       misho    1259: }

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