File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / sudo / src / sudo.c
Revision 1.1: download - view: text, annotated - select for diffs - revision graph
Tue Feb 21 16:23:02 2012 UTC (12 years, 5 months ago) by misho
CVS tags: MAIN, HEAD
Initial revision

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

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