Annotation of embedaddon/sudo/src/sudo.c, revision 1.1
1.1 ! misho 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>