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