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