File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / sudo / src / sudo.c
Revision 1.1.1.2 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue May 29 12:26:49 2012 UTC (12 years, 2 months ago) by misho
Branches: sudo, MAIN
CVS tags: v1_8_5p1, HEAD
sudo 1.8.5p1

    1: /*
    2:  * Copyright (c) 2009-2012 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: #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>
   66: # ifndef LOGIN_SETENV
   67: #  define LOGIN_SETENV	0
   68: # endif
   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: #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>
   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 */
  108: static int sudo_mode;
  109: 
  110: /*
  111:  * Local functions
  112:  */
  113: static void fix_fds(void);
  114: static void disable_coredumps(void);
  115: static void sudo_check_suid(const char *path);
  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);
  141: static void iolog_unlink(struct plugin_container *plugin);
  142: 
  143: #ifdef RLIMIT_CORE
  144: static struct rlimit corelimit;
  145: #endif /* RLIMIT_CORE */
  146: #if defined(__linux__)
  147: static struct rlimit nproclimit;
  148: #endif
  149: 
  150: int
  151: main(int argc, char *argv[], char *envp[])
  152: {
  153:     int nargc, ok, exitcode = 0;
  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;
  159:     debug_decl(main, SUDO_DEBUG_MAIN)
  160: 
  161: #if defined(SUDO_DEVEL) && defined(__OpenBSD__)
  162:     {
  163: 	extern char *malloc_options;
  164: 	malloc_options = "AFGJPR";
  165:     }
  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: 
  187:     /* Make sure we are setuid root. */
  188:     sudo_check_suid(argv[0]);
  189: 
  190:     /* Reset signal mask and make sure fds 0-2 are open. */
  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: 
  199:     /* Read sudo.conf. */
  200:     sudo_conf_read();
  201: 
  202:     /* Disable core dumps if not enabled in sudo.conf. */
  203:     disable_coredumps();
  204: 
  205:     /* Parse command line arguments. */
  206:     sudo_mode = parse_args(argc, argv, &nargc, &nargv, &settings, &env_add);
  207:     sudo_debug_printf(SUDO_DEBUG_DEBUG, "sudo_mode %d", sudo_mode);
  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: 
  216:     /* Load plugins. */
  217:     if (!sudo_load_plugins(&policy_plugin, &io_plugins))
  218: 	errorx(1, _("fatal error, unable to load plugins"));
  219: 
  220:     /* Open policy plugin. */
  221:     ok = policy_open(&policy_plugin, settings, user_info, envp);
  222:     if (ok != 1) {
  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);
  235: 		if (ok == 1)
  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);
  242: 	    exit(ok != 1);
  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);
  254: 	    exit(ok != 1);
  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);
  259: 	    sudo_debug_printf(SUDO_DEBUG_INFO, "policy plugin returns %d", ok);
  260: 	    if (ok != 1) {
  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) {
  271: 		case 1:
  272: 		    break;
  273: 		case 0:
  274: 		    /* I/O plugin asked to be disabled, remove and free. */
  275: 		    iolog_unlink(plugin);
  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: 	    }
  285: 	    /* Setup command details and run command/edit. */
  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);
  291: 	    /* Become full root (not just setuid) so user cannot kill us. */
  292: 	    (void) setuid(ROOT_UID);
  293: 	    /* Restore coredumpsize resource limit before running. */
  294: #ifdef RLIMIT_CORE
  295: 	    if (sudo_conf_disable_coredump())
  296: 		(void) setrlimit(RLIMIT_CORE, &corelimit);
  297: #endif /* RLIMIT_CORE */
  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:     }
  308:     sudo_debug_exit_int(__func__, __FILE__, __LINE__, sudo_debug_subsys, exitcode);                
  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;
  320:     debug_decl(fix_fds, SUDO_DEBUG_UTIL)
  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:     }
  341:     debug_return;
  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;
  352:     debug_decl(fill_group_list, SUDO_DEBUG_UTIL)
  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:     }
  373:     debug_return_int(rval);
  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;
  382:     debug_decl(get_user_groups, SUDO_DEBUG_UTIL)
  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:     }
  416:     debug_return_str(gid_list);
  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: {
  426:     char *cp, **user_info, cwd[PATH_MAX], host[MAXHOSTNAMELEN];
  427:     struct passwd *pw;
  428:     int fd, i = 0;
  429:     debug_decl(get_user_info, SUDO_DEBUG_UTIL)
  430: 
  431:     /* XXX - bound check number of entries */
  432:     user_info = emalloc2(32, sizeof(char *));
  433: 
  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: 
  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: 
  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: 
  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: 
  486:     if ((cp = get_process_ttyname()) != NULL) {
  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;
  491: 	efree(cp);
  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: 
  509:     debug_return_ptr(user_info);
  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;
  522:     debug_decl(command_info_to_details, SUDO_DEBUG_PCOMM)
  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: 
  533:     sudo_debug_printf(SUDO_DEBUG_INFO, "command info from plugin:");
  534:     for (i = 0; info[i] != NULL; i++) {
  535: 	sudo_debug_printf(SUDO_DEBUG_INFO, "    %d: %s", i, info[i]);
  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) {
  577: 		    if (atobool(info[i] + sizeof("noexec=") - 1) == true)
  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) {
  584: 		    if (atobool(info[i] + sizeof("preserve_groups=") - 1) == true)
  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) {
  678: 		    if (atobool(info[i] + sizeof("set_utmp=") - 1) == true)
  679: 			SET(details->flags, CD_SET_UTMP);
  680: 		    break;
  681: 		}
  682: 		if (strncmp("sudoedit=", info[i], sizeof("sudoedit=") - 1) == 0) {
  683: 		    if (atobool(info[i] + sizeof("sudoedit=") - 1) == true)
  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) {
  720: 		    if (atobool(info[i] + sizeof("use_pty=") - 1) == true)
  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: 
  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: 
  742: #ifdef HAVE_SELINUX
  743:     if (details->selinux_role != NULL && is_selinux_enabled() > 0)
  744: 	SET(details->flags, CD_RBAC_ENABLED);
  745: #endif
  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;
  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: {
  784: #if defined(__linux__) || defined(RLIMIT_CORE)
  785:     struct rlimit rl;
  786: #endif
  787:     debug_decl(disable_coredumps, SUDO_DEBUG_UTIL)
  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__ */
  803: #ifdef RLIMIT_CORE
  804:     /*
  805:      * Turn off core dumps?
  806:      */
  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;
  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;
  824:     debug_decl(set_project, SUDO_DEBUG_UTIL)
  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();
  877:     debug_return;
  878: }
  879: #endif /* HAVE_PROJECT_H */
  880: 
  881: /*
  882:  * Setup the execution environment immediately prior to the call to execve()
  883:  * Returns true on success and false on failure.
  884:  */
  885: bool
  886: exec_setup(struct command_details *details, const char *ptyname, int ptyfd)
  887: {
  888:     bool rval = false;
  889:     debug_decl(exec_setup, SUDO_DEBUG_EXEC)
  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: 
  899:     if (details->pw != NULL) {
  900: #ifdef HAVE_PROJECT_H
  901: 	set_project(details->pw);
  902: #endif
  903: #ifdef HAVE_GETUSERATTR
  904: 	aix_prep_user(details->pw->pw_name, ptyname ? ptyname : user_details.tty);
  905: #endif
  906: #ifdef HAVE_LOGIN_CAP_H
  907: 	if (details->login_class) {
  908: 	    int flags;
  909: 	    login_cap_t *lc;
  910: 
  911: 	    /*
  912: 	     * We only use setusercontext() to set the nice value and rlimits
  913: 	     * unless this is a login shell (sudo -i).
  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: 	    }
  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) {
  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:      */
  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:     }
  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: 
 1028:     rval = true;
 1029: 
 1030: done:
 1031:     debug_return_bool(rval);
 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;
 1043:     debug_decl(run_command, SUDO_DEBUG_EXEC)
 1044: 
 1045:     cstat.type = CMD_INVALID;
 1046:     cstat.val = 0;
 1047: 
 1048:     sudo_execute(details, &cstat);
 1049: 
 1050:     switch (cstat.type) {
 1051:     case CMD_ERRNO:
 1052: 	/* exec_setup() or execve() returned an error. */
 1053: 	sudo_debug_printf(SUDO_DEBUG_DEBUG,
 1054: 	    "calling policy close with errno %d", cstat.val);
 1055: 	policy_close(&policy_plugin, 0, cstat.val);
 1056: 	tq_foreach_fwd(&io_plugins, plugin) {
 1057: 	    sudo_debug_printf(SUDO_DEBUG_DEBUG,
 1058: 		"calling I/O close with errno %d", cstat.val);
 1059: 	    iolog_close(plugin, 0, cstat.val);
 1060: 	}
 1061: 	exitcode = 1;
 1062: 	break;
 1063:     case CMD_WSTATUS:
 1064: 	/* Command ran, exited or was killed. */
 1065: 	sudo_debug_printf(SUDO_DEBUG_DEBUG,
 1066: 	    "calling policy close with wait status %d", cstat.val);
 1067: 	policy_close(&policy_plugin, cstat.val, 0);
 1068: 	tq_foreach_fwd(&io_plugins, plugin) {
 1069: 	    sudo_debug_printf(SUDO_DEBUG_DEBUG,
 1070: 		"calling I/O close with wait status %d", cstat.val);
 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:     }
 1082:     debug_return_int(exitcode);
 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: {
 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);
 1107: }
 1108: 
 1109: static void
 1110: policy_close(struct plugin_container *plugin, int exit_status, int error)
 1111: {
 1112:     debug_decl(policy_close, SUDO_DEBUG_PCOMM)
 1113:     plugin->u.policy->close(exit_status, error);
 1114:     debug_return;
 1115: }
 1116: 
 1117: static int
 1118: policy_show_version(struct plugin_container *plugin, int verbose)
 1119: {
 1120:     debug_decl(policy_show_version, SUDO_DEBUG_PCOMM)
 1121:     debug_return_bool(plugin->u.policy->show_version(verbose));
 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: {
 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));
 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: {
 1138:     debug_decl(policy_list, SUDO_DEBUG_PCOMM)
 1139:     if (plugin->u.policy->list == NULL) {
 1140: 	warningx(_("policy plugin %s does not support listing privileges"),
 1141: 	    plugin->name);
 1142: 	debug_return_bool(false);
 1143:     }
 1144:     debug_return_bool(plugin->u.policy->list(argc, argv, verbose, list_user));
 1145: }
 1146: 
 1147: static int
 1148: policy_validate(struct plugin_container *plugin)
 1149: {
 1150:     debug_decl(policy_validate, SUDO_DEBUG_PCOMM)
 1151:     if (plugin->u.policy->validate == NULL) {
 1152: 	warningx(_("policy plugin %s does not support the -v option"),
 1153: 	    plugin->name);
 1154: 	debug_return_bool(false);
 1155:     }
 1156:     debug_return_bool(plugin->u.policy->validate());
 1157: }
 1158: 
 1159: static void
 1160: policy_invalidate(struct plugin_container *plugin, int remove)
 1161: {
 1162:     debug_decl(policy_invalidate, SUDO_DEBUG_PCOMM)
 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);
 1168:     debug_return;
 1169: }
 1170: 
 1171: int
 1172: policy_init_session(struct command_details *details)
 1173: {
 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);
 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;
 1200:     debug_decl(iolog_open, SUDO_DEBUG_PCOMM)
 1201: 
 1202:     /*
 1203:      * Backwards compatibility for older API versions
 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;
 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;
 1216:     default:
 1217: 	rval = plugin->u.io->open(SUDO_API_VERSION, sudo_conversation,
 1218: 	    _sudo_printf, settings, user_info, command_info,
 1219: 	    argc, argv, user_env, plugin->options);
 1220:     }
 1221:     debug_return_bool(rval);
 1222: }
 1223: 
 1224: static void
 1225: iolog_close(struct plugin_container *plugin, int exit_status, int error)
 1226: {
 1227:     debug_decl(iolog_close, SUDO_DEBUG_PCOMM)
 1228:     plugin->u.io->close(exit_status, error);
 1229:     debug_return;
 1230: }
 1231: 
 1232: static int
 1233: iolog_show_version(struct plugin_container *plugin, int verbose)
 1234: {
 1235:     debug_decl(iolog_show_version, SUDO_DEBUG_PCOMM)
 1236:     debug_return_bool(plugin->u.io->show_version(verbose));
 1237: }
 1238: 
 1239: /*
 1240:  * Remove the specified I/O logging plugin from the io_plugins list.
 1241:  * Deregisters any hooks before unlinking, then frees the container.
 1242:  */
 1243: static void
 1244: iolog_unlink(struct plugin_container *plugin)
 1245: {
 1246:     debug_decl(iolog_unlink, SUDO_DEBUG_PCOMM)
 1247: 
 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);
 1257: 
 1258:     debug_return;
 1259: }

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