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