Annotation of embedaddon/sudo/src/sudo.c, revision 1.1.1.4
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:
86: #include "sudo.h"
87: #include "sudo_plugin.h"
88: #include "sudo_plugin_int.h"
1.1.1.4 ! misho 89: #include "sudo_usage.h"
1.1 misho 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;
97: const char *list_user, *runas_user, *runas_group; /* 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.2 misho 136: #endif /* RLIMIT_CORE */
1.1 misho 137: #if defined(__linux__)
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();
! 357: if (ud->ngroups != -1) {
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.4 ! misho 470: fatalx(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.4 ! misho 496: fatalx(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.4 ! misho 503: fatalx(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.4 ! misho 514: fatalx(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;
533: long lval;
534: unsigned long ulval;
535: char *cp, *ep;
1.1.1.2 misho 536: debug_decl(command_info_to_details, SUDO_DEBUG_PCOMM)
1.1 misho 537:
538: memset(details, 0, sizeof(*details));
539: details->closefrom = -1;
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) {
556: cp = info[i] + sizeof("closefrom=") - 1;
557: if (*cp == '\0')
558: break;
559: errno = 0;
560: lval = strtol(cp, &ep, 0);
561: if (*cp != '\0' && *ep == '\0' &&
562: !(errno == ERANGE &&
563: (lval == LONG_MAX || lval == LONG_MIN)) &&
564: lval < INT_MAX && lval > INT_MIN) {
565: details->closefrom = (int)lval;
566: }
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: /* XXX - bounds check -NZERO to NZERO (inclusive). */
582: if (strncmp("nice=", info[i], sizeof("nice=") - 1) == 0) {
583: cp = info[i] + sizeof("nice=") - 1;
584: if (*cp == '\0')
585: break;
586: errno = 0;
587: lval = strtol(cp, &ep, 0);
588: if (*cp != '\0' && *ep == '\0' &&
589: !(errno == ERANGE &&
590: (lval == LONG_MAX || lval == LONG_MIN)) &&
591: lval < INT_MAX && lval > INT_MIN) {
592: details->priority = (int)lval;
593: SET(details->flags, CD_SET_PRIORITY);
594: }
595: break;
596: }
597: if (strncmp("noexec=", info[i], sizeof("noexec=") - 1) == 0) {
1.1.1.2 misho 598: if (atobool(info[i] + sizeof("noexec=") - 1) == true)
1.1 misho 599: SET(details->flags, CD_NOEXEC);
600: break;
601: }
602: break;
603: case 'p':
604: if (strncmp("preserve_groups=", info[i], sizeof("preserve_groups=") - 1) == 0) {
1.1.1.2 misho 605: if (atobool(info[i] + sizeof("preserve_groups=") - 1) == true)
1.1 misho 606: SET(details->flags, CD_PRESERVE_GROUPS);
607: break;
608: }
609: break;
610: case 'r':
611: if (strncmp("runas_egid=", info[i], sizeof("runas_egid=") - 1) == 0) {
612: cp = info[i] + sizeof("runas_egid=") - 1;
613: if (*cp == '\0')
614: break;
615: errno = 0;
616: ulval = strtoul(cp, &ep, 0);
617: if (*cp != '\0' && *ep == '\0' &&
618: (errno != ERANGE || ulval != ULONG_MAX)) {
619: details->egid = (gid_t)ulval;
620: SET(details->flags, CD_SET_EGID);
621: }
622: break;
623: }
624: if (strncmp("runas_euid=", info[i], sizeof("runas_euid=") - 1) == 0) {
625: cp = info[i] + sizeof("runas_euid=") - 1;
626: if (*cp == '\0')
627: break;
628: errno = 0;
629: ulval = strtoul(cp, &ep, 0);
630: if (*cp != '\0' && *ep == '\0' &&
631: (errno != ERANGE || ulval != ULONG_MAX)) {
632: details->euid = (uid_t)ulval;
633: SET(details->flags, CD_SET_EUID);
634: }
635: break;
636: }
637: if (strncmp("runas_gid=", info[i], sizeof("runas_gid=") - 1) == 0) {
638: cp = info[i] + sizeof("runas_gid=") - 1;
639: if (*cp == '\0')
640: break;
641: errno = 0;
642: ulval = strtoul(cp, &ep, 0);
643: if (*cp != '\0' && *ep == '\0' &&
644: (errno != ERANGE || ulval != ULONG_MAX)) {
645: details->gid = (gid_t)ulval;
646: SET(details->flags, CD_SET_GID);
647: }
648: break;
649: }
650: if (strncmp("runas_groups=", info[i], sizeof("runas_groups=") - 1) == 0) {
651: int j;
652:
653: /* count groups, alloc and fill in */
654: cp = info[i] + sizeof("runas_groups=") - 1;
655: if (*cp == '\0')
656: break;
657: for (;;) {
658: details->ngroups++;
659: if ((cp = strchr(cp, ',')) == NULL)
660: break;
661: cp++;
662: }
663: if (details->ngroups != 0) {
664: details->groups =
665: emalloc2(details->ngroups, sizeof(GETGROUPS_T));
666: cp = info[i] + sizeof("runas_groups=") - 1;
667: for (j = 0; j < details->ngroups;) {
668: errno = 0;
669: ulval = strtoul(cp, &ep, 0);
670: if (*cp == '\0' || (*ep != ',' && *ep != '\0') ||
671: (ulval == ULONG_MAX && errno == ERANGE)) {
672: break;
673: }
674: details->groups[j++] = (gid_t)ulval;
675: cp = ep + 1;
676: }
677: details->ngroups = j;
678: }
679: break;
680: }
681: if (strncmp("runas_uid=", info[i], sizeof("runas_uid=") - 1) == 0) {
682: cp = info[i] + sizeof("runas_uid=") - 1;
683: if (*cp == '\0')
684: break;
685: errno = 0;
686: ulval = strtoul(cp, &ep, 0);
687: if (*cp != '\0' && *ep == '\0' &&
688: (errno != ERANGE || ulval != ULONG_MAX)) {
689: details->uid = (uid_t)ulval;
690: SET(details->flags, CD_SET_UID);
691: }
692: break;
693: }
1.1.1.3 misho 694: #ifdef HAVE_PRIV_SET
695: if (strncmp("runas_privs=", info[i], sizeof("runas_privs=") - 1) == 0) {
696: const char *endp;
697: cp = info[i] + sizeof("runas_privs=") - 1;
698: if (*cp == '\0')
699: break;
700: errno = 0;
701: details->privs = priv_str_to_set(cp, ",", &endp);
702: if (details->privs == NULL)
703: warning("invalid runas_privs %s", endp);
704: }
705: if (strncmp("runas_limitprivs=", info[i], sizeof("runas_limitprivs=") - 1) == 0) {
706: const char *endp;
707: cp = info[i] + sizeof("runas_limitprivs=") - 1;
708: if (*cp == '\0')
709: break;
710: errno = 0;
711: details->limitprivs = priv_str_to_set(cp, ",", &endp);
712: if (details->limitprivs == NULL)
713: warning("invalid runas_limitprivs %s", endp);
714: }
715: #endif /* HAVE_PRIV_SET */
1.1 misho 716: break;
717: case 's':
718: SET_STRING("selinux_role=", selinux_role)
719: SET_STRING("selinux_type=", selinux_type)
720: if (strncmp("set_utmp=", info[i], sizeof("set_utmp=") - 1) == 0) {
1.1.1.2 misho 721: if (atobool(info[i] + sizeof("set_utmp=") - 1) == true)
1.1 misho 722: SET(details->flags, CD_SET_UTMP);
723: break;
724: }
725: if (strncmp("sudoedit=", info[i], sizeof("sudoedit=") - 1) == 0) {
1.1.1.2 misho 726: if (atobool(info[i] + sizeof("sudoedit=") - 1) == true)
1.1 misho 727: SET(details->flags, CD_SUDOEDIT);
728: break;
729: }
730: break;
731: case 't':
732: if (strncmp("timeout=", info[i], sizeof("timeout=") - 1) == 0) {
733: cp = info[i] + sizeof("timeout=") - 1;
734: if (*cp == '\0')
735: break;
736: errno = 0;
737: lval = strtol(cp, &ep, 0);
738: if (*cp != '\0' && *ep == '\0' &&
739: !(errno == ERANGE &&
740: (lval == LONG_MAX || lval == LONG_MIN)) &&
741: lval <= INT_MAX && lval >= 0) {
742: details->timeout = (int)lval;
743: SET(details->flags, CD_SET_TIMEOUT);
744: }
745: break;
746: }
747: break;
748: case 'u':
749: if (strncmp("umask=", info[i], sizeof("umask=") - 1) == 0) {
750: cp = info[i] + sizeof("umask=") - 1;
751: if (*cp == '\0')
752: break;
753: errno = 0;
754: ulval = strtoul(cp, &ep, 8);
755: if (*cp != '\0' && *ep == '\0' &&
756: (errno != ERANGE || ulval != ULONG_MAX)) {
757: details->umask = (uid_t)ulval;
758: SET(details->flags, CD_SET_UMASK);
759: }
760: break;
761: }
762: if (strncmp("use_pty=", info[i], sizeof("use_pty=") - 1) == 0) {
1.1.1.2 misho 763: if (atobool(info[i] + sizeof("use_pty=") - 1) == true)
1.1 misho 764: SET(details->flags, CD_USE_PTY);
765: break;
766: }
767: SET_STRING("utmp_user=", utmp_user)
768: break;
769: }
770: }
771:
772: if (!ISSET(details->flags, CD_SET_EUID))
773: details->euid = details->uid;
774:
1.1.1.2 misho 775: #ifdef HAVE_SETAUTHDB
776: aix_setauthdb(IDtouser(details->euid));
777: #endif
778: details->pw = getpwuid(details->euid);
779: if (details->pw != NULL && (details->pw = pw_dup(details->pw)) == NULL)
1.1.1.4 ! misho 780: fatalx(NULL);
1.1.1.2 misho 781: #ifdef HAVE_SETAUTHDB
782: aix_restoreauthdb();
783: #endif
784:
1.1 misho 785: #ifdef HAVE_SELINUX
786: if (details->selinux_role != NULL && is_selinux_enabled() > 0)
787: SET(details->flags, CD_RBAC_ENABLED);
788: #endif
1.1.1.2 misho 789: debug_return;
790: }
791:
792: static void
793: sudo_check_suid(const char *path)
794: {
795: struct stat sb;
796: debug_decl(sudo_check_suid, SUDO_DEBUG_PCOMM)
797:
798: if (geteuid() != 0) {
799: if (strchr(path, '/') != NULL && stat(path, &sb) == 0) {
800: /* Try to determine why sudo was not running as root. */
801: if (sb.st_uid != ROOT_UID || !ISSET(sb.st_mode, S_ISUID)) {
1.1.1.4 ! misho 802: fatalx(
1.1.1.2 misho 803: _("%s must be owned by uid %d and have the setuid bit set"),
804: path, ROOT_UID);
805: } else {
1.1.1.4 ! misho 806: fatalx(_("effective uid is not %d, is %s on a file system "
1.1.1.2 misho 807: "with the 'nosuid' option set or an NFS file system without"
808: " root privileges?"), ROOT_UID, path);
809: }
810: } else {
1.1.1.4 ! misho 811: fatalx(
1.1.1.2 misho 812: _("effective uid is not %d, is sudo installed setuid root?"),
813: ROOT_UID);
814: }
815: }
816: debug_return;
1.1 misho 817: }
818:
819: /*
820: * Disable core dumps to avoid dropping a core with user password in it.
821: * We will reset this limit before executing the command.
822: * Not all operating systems disable core dumps for setuid processes.
823: */
824: static void
825: disable_coredumps(void)
826: {
1.1.1.2 misho 827: #if defined(__linux__) || defined(RLIMIT_CORE)
1.1 misho 828: struct rlimit rl;
829: #endif
1.1.1.2 misho 830: debug_decl(disable_coredumps, SUDO_DEBUG_UTIL)
1.1 misho 831:
832: #if defined(__linux__)
833: /*
834: * Unlimit the number of processes since Linux's setuid() will
835: * apply resource limits when changing uid and return EAGAIN if
836: * nproc would be violated by the uid switch.
837: */
838: (void) getrlimit(RLIMIT_NPROC, &nproclimit);
839: rl.rlim_cur = rl.rlim_max = RLIM_INFINITY;
840: if (setrlimit(RLIMIT_NPROC, &rl)) {
841: memcpy(&rl, &nproclimit, sizeof(struct rlimit));
842: rl.rlim_cur = rl.rlim_max;
843: (void)setrlimit(RLIMIT_NPROC, &rl);
844: }
845: #endif /* __linux__ */
1.1.1.2 misho 846: #ifdef RLIMIT_CORE
1.1 misho 847: /*
1.1.1.2 misho 848: * Turn off core dumps?
1.1 misho 849: */
1.1.1.2 misho 850: if (sudo_conf_disable_coredump()) {
851: (void) getrlimit(RLIMIT_CORE, &corelimit);
852: memcpy(&rl, &corelimit, sizeof(struct rlimit));
853: rl.rlim_cur = 0;
854: (void) setrlimit(RLIMIT_CORE, &rl);
855: }
856: #endif /* RLIMIT_CORE */
857: debug_return;
1.1 misho 858: }
859:
860: /*
861: * Setup the execution environment immediately prior to the call to execve()
1.1.1.2 misho 862: * Returns true on success and false on failure.
1.1 misho 863: */
1.1.1.2 misho 864: bool
1.1 misho 865: exec_setup(struct command_details *details, const char *ptyname, int ptyfd)
866: {
1.1.1.2 misho 867: bool rval = false;
868: debug_decl(exec_setup, SUDO_DEBUG_EXEC)
1.1 misho 869:
870: #ifdef HAVE_SELINUX
871: if (ISSET(details->flags, CD_RBAC_ENABLED)) {
872: if (selinux_setup(details->selinux_role, details->selinux_type,
873: ptyname ? ptyname : user_details.tty, ptyfd) == -1)
874: goto done;
875: }
876: #endif
877:
1.1.1.2 misho 878: if (details->pw != NULL) {
1.1 misho 879: #ifdef HAVE_PROJECT_H
1.1.1.2 misho 880: set_project(details->pw);
1.1 misho 881: #endif
1.1.1.3 misho 882: #ifdef HAVE_PRIV_SET
1.1.1.4 ! misho 883: if (details->privs != NULL) {
! 884: if (setppriv(PRIV_SET, PRIV_INHERITABLE, details->privs) != 0) {
! 885: warning("unable to set privileges");
! 886: goto done;
! 887: }
1.1.1.3 misho 888: }
1.1.1.4 ! misho 889: if (details->limitprivs != NULL) {
! 890: if (setppriv(PRIV_SET, PRIV_LIMIT, details->limitprivs) != 0) {
! 891: warning("unable to set limit privileges");
! 892: goto done;
! 893: }
! 894: } else if (details->privs != NULL) {
! 895: if (setppriv(PRIV_SET, PRIV_LIMIT, details->privs) != 0) {
! 896: warning("unable to set limit privileges");
! 897: goto done;
! 898: }
1.1.1.3 misho 899: }
900: #endif /* HAVE_PRIV_SET */
901:
1.1 misho 902: #ifdef HAVE_GETUSERATTR
1.1.1.2 misho 903: aix_prep_user(details->pw->pw_name, ptyname ? ptyname : user_details.tty);
1.1 misho 904: #endif
905: #ifdef HAVE_LOGIN_CAP_H
906: if (details->login_class) {
907: int flags;
908: login_cap_t *lc;
909:
910: /*
1.1.1.2 misho 911: * We only use setusercontext() to set the nice value and rlimits
912: * unless this is a login shell (sudo -i).
1.1 misho 913: */
914: lc = login_getclass((char *)details->login_class);
915: if (!lc) {
916: warningx(_("unknown login class %s"), details->login_class);
917: errno = ENOENT;
918: goto done;
919: }
1.1.1.2 misho 920: if (ISSET(sudo_mode, MODE_LOGIN_SHELL)) {
921: /* Set everything except user, group and login name. */
922: flags = LOGIN_SETALL;
923: CLR(flags, LOGIN_SETGROUP|LOGIN_SETLOGIN|LOGIN_SETUSER|LOGIN_SETENV|LOGIN_SETPATH);
924: CLR(details->flags, CD_SET_UMASK); /* LOGIN_UMASK instead */
925: } else {
926: flags = LOGIN_SETRESOURCES|LOGIN_SETPRIORITY;
927: }
928: if (setusercontext(lc, details->pw, details->pw->pw_uid, flags)) {
929: if (details->pw->pw_uid != ROOT_UID) {
1.1 misho 930: warning(_("unable to set user context"));
931: goto done;
932: } else
933: warning(_("unable to set user context"));
934: }
935: }
936: #endif /* HAVE_LOGIN_CAP_H */
937: }
938:
939: /*
940: * Set groups, including supplementary group vector.
941: */
1.1.1.2 misho 942: if (!ISSET(details->flags, CD_PRESERVE_GROUPS)) {
943: if (details->ngroups >= 0) {
944: if (sudo_setgroups(details->ngroups, details->groups) < 0) {
945: warning(_("unable to set supplementary group IDs"));
946: goto done;
947: }
948: }
949: }
1.1 misho 950: #ifdef HAVE_SETEUID
951: if (ISSET(details->flags, CD_SET_EGID) && setegid(details->egid)) {
952: warning(_("unable to set effective gid to runas gid %u"),
953: (unsigned int)details->egid);
954: goto done;
955: }
956: #endif
957: if (ISSET(details->flags, CD_SET_GID) && setgid(details->gid)) {
958: warning(_("unable to set gid to runas gid %u"),
959: (unsigned int)details->gid);
960: goto done;
961: }
962:
963: if (ISSET(details->flags, CD_SET_PRIORITY)) {
964: if (setpriority(PRIO_PROCESS, 0, details->priority) != 0) {
965: warning(_("unable to set process priority"));
966: goto done;
967: }
968: }
969: if (ISSET(details->flags, CD_SET_UMASK))
970: (void) umask(details->umask);
971: if (details->chroot) {
972: if (chroot(details->chroot) != 0 || chdir("/") != 0) {
973: warning(_("unable to change root to %s"), details->chroot);
974: goto done;
975: }
976: }
977:
978: #ifdef HAVE_SETRESUID
979: if (setresuid(details->uid, details->euid, details->euid) != 0) {
980: warning(_("unable to change to runas uid (%u, %u)"), details->uid,
981: details->euid);
982: goto done;
983: }
984: #elif HAVE_SETREUID
985: if (setreuid(details->uid, details->euid) != 0) {
986: warning(_("unable to change to runas uid (%u, %u)"),
987: (unsigned int)details->uid, (unsigned int)details->euid);
988: goto done;
989: }
990: #else
991: if (seteuid(details->euid) != 0 || setuid(details->euid) != 0) {
992: warning(_("unable to change to runas uid (%u, %u)"), details->uid,
993: details->euid);
994: goto done;
995: }
996: #endif /* !HAVE_SETRESUID && !HAVE_SETREUID */
997:
998: /*
999: * Only change cwd if we have chroot()ed or the policy modules
1000: * specifies a different cwd. Must be done after uid change.
1001: */
1002: if (details->cwd) {
1003: if (details->chroot || strcmp(details->cwd, user_details.cwd) != 0) {
1004: /* Note: cwd is relative to the new root, if any. */
1005: if (chdir(details->cwd) != 0) {
1006: warning(_("unable to change directory to %s"), details->cwd);
1007: goto done;
1008: }
1009: }
1010: }
1011:
1012: /*
1.1.1.3 misho 1013: * SuSE Enterprise Linux uses RLIMIT_NPROC and _SC_CHILD_MAX
1014: * interchangably. This causes problems when setting RLIMIT_NPROC
1015: * to RLIM_INFINITY due to a bug in bash where bash tries to honor
1016: * the value of _SC_CHILD_MAX but treats a value of -1 as an error,
1017: * and uses a default value of 32 instead.
1018: *
1019: * To work around this problem, we restore the nproc resource limit
1020: * if sysconf(_SC_CHILD_MAX) is negative. In most cases, pam_limits
1021: * will set RLIMIT_NPROC for us.
1022: *
1.1 misho 1023: * We must do this *after* the uid change to avoid potential EAGAIN
1024: * from setuid().
1025: */
1.1.1.3 misho 1026: #if defined(__linux__) && defined(_SC_CHILD_MAX)
1.1 misho 1027: {
1028: struct rlimit rl;
1.1.1.3 misho 1029: long l;
1030: errno = 0;
1031: l = sysconf(_SC_CHILD_MAX);
1032: if (l == -1 && errno == 0 && getrlimit(RLIMIT_NPROC, &rl) == 0) {
1.1 misho 1033: if (rl.rlim_cur == RLIM_INFINITY && rl.rlim_max == RLIM_INFINITY)
1034: (void) setrlimit(RLIMIT_NPROC, &nproclimit);
1035: }
1036: }
1037: #endif
1038:
1.1.1.2 misho 1039: rval = true;
1.1 misho 1040:
1041: done:
1.1.1.2 misho 1042: debug_return_bool(rval);
1.1 misho 1043: }
1044:
1045: /*
1046: * Run the command and wait for it to complete.
1047: */
1048: int
1049: run_command(struct command_details *details)
1050: {
1051: struct plugin_container *plugin;
1052: struct command_status cstat;
1053: int exitcode = 1;
1.1.1.2 misho 1054: debug_decl(run_command, SUDO_DEBUG_EXEC)
1.1 misho 1055:
1056: cstat.type = CMD_INVALID;
1057: cstat.val = 0;
1058:
1.1.1.2 misho 1059: sudo_execute(details, &cstat);
1.1 misho 1060:
1061: switch (cstat.type) {
1062: case CMD_ERRNO:
1063: /* exec_setup() or execve() returned an error. */
1.1.1.2 misho 1064: sudo_debug_printf(SUDO_DEBUG_DEBUG,
1065: "calling policy close with errno %d", cstat.val);
1.1 misho 1066: policy_close(&policy_plugin, 0, cstat.val);
1067: tq_foreach_fwd(&io_plugins, plugin) {
1.1.1.2 misho 1068: sudo_debug_printf(SUDO_DEBUG_DEBUG,
1069: "calling I/O close with errno %d", cstat.val);
1.1 misho 1070: iolog_close(plugin, 0, cstat.val);
1071: }
1072: exitcode = 1;
1073: break;
1074: case CMD_WSTATUS:
1075: /* Command ran, exited or was killed. */
1.1.1.2 misho 1076: sudo_debug_printf(SUDO_DEBUG_DEBUG,
1077: "calling policy close with wait status %d", cstat.val);
1.1 misho 1078: policy_close(&policy_plugin, cstat.val, 0);
1079: tq_foreach_fwd(&io_plugins, plugin) {
1.1.1.2 misho 1080: sudo_debug_printf(SUDO_DEBUG_DEBUG,
1081: "calling I/O close with wait status %d", cstat.val);
1.1 misho 1082: iolog_close(plugin, cstat.val, 0);
1083: }
1084: if (WIFEXITED(cstat.val))
1085: exitcode = WEXITSTATUS(cstat.val);
1086: else if (WIFSIGNALED(cstat.val))
1087: exitcode = WTERMSIG(cstat.val) | 128;
1088: break;
1089: default:
1090: warningx(_("unexpected child termination condition: %d"), cstat.type);
1091: break;
1092: }
1.1.1.2 misho 1093: debug_return_int(exitcode);
1.1 misho 1094: }
1095:
1096: static int
1097: policy_open(struct plugin_container *plugin, char * const settings[],
1098: char * const user_info[], char * const user_env[])
1099: {
1.1.1.2 misho 1100: int rval;
1101: debug_decl(policy_open, SUDO_DEBUG_PCOMM)
1102:
1103: /*
1104: * Backwards compatibility for older API versions
1105: */
1106: switch (plugin->u.generic->version) {
1107: case SUDO_API_MKVERSION(1, 0):
1108: case SUDO_API_MKVERSION(1, 1):
1109: rval = plugin->u.policy_1_0->open(plugin->u.io_1_0->version,
1110: sudo_conversation, _sudo_printf, settings, user_info, user_env);
1111: break;
1112: default:
1113: rval = plugin->u.policy->open(SUDO_API_VERSION, sudo_conversation,
1114: _sudo_printf, settings, user_info, user_env, plugin->options);
1115: }
1116:
1117: debug_return_bool(rval);
1.1 misho 1118: }
1119:
1120: static void
1121: policy_close(struct plugin_container *plugin, int exit_status, int error)
1122: {
1.1.1.2 misho 1123: debug_decl(policy_close, SUDO_DEBUG_PCOMM)
1.1.1.4 ! misho 1124: if (plugin->u.policy->close != NULL)
! 1125: plugin->u.policy->close(exit_status, error);
! 1126: else
! 1127: warning(_("unable to execute %s"), command_details.command);
1.1.1.2 misho 1128: debug_return;
1.1 misho 1129: }
1130:
1131: static int
1132: policy_show_version(struct plugin_container *plugin, int verbose)
1133: {
1.1.1.2 misho 1134: debug_decl(policy_show_version, SUDO_DEBUG_PCOMM)
1.1.1.4 ! misho 1135: if (plugin->u.policy->show_version == NULL)
! 1136: debug_return_bool(true);
1.1.1.2 misho 1137: debug_return_bool(plugin->u.policy->show_version(verbose));
1.1 misho 1138: }
1139:
1140: static int
1141: policy_check(struct plugin_container *plugin, int argc, char * const argv[],
1142: char *env_add[], char **command_info[], char **argv_out[],
1143: char **user_env_out[])
1144: {
1.1.1.2 misho 1145: debug_decl(policy_check, SUDO_DEBUG_PCOMM)
1.1.1.4 ! misho 1146: if (plugin->u.policy->check_policy == NULL) {
! 1147: fatalx(_("policy plugin %s is missing the `check_policy' method"),
! 1148: plugin->name);
! 1149: }
1.1.1.2 misho 1150: debug_return_bool(plugin->u.policy->check_policy(argc, argv, env_add,
1151: command_info, argv_out, user_env_out));
1.1 misho 1152: }
1153:
1154: static int
1155: policy_list(struct plugin_container *plugin, int argc, char * const argv[],
1156: int verbose, const char *list_user)
1157: {
1.1.1.2 misho 1158: debug_decl(policy_list, SUDO_DEBUG_PCOMM)
1.1 misho 1159: if (plugin->u.policy->list == NULL) {
1160: warningx(_("policy plugin %s does not support listing privileges"),
1161: plugin->name);
1.1.1.2 misho 1162: debug_return_bool(false);
1.1 misho 1163: }
1.1.1.2 misho 1164: debug_return_bool(plugin->u.policy->list(argc, argv, verbose, list_user));
1.1 misho 1165: }
1166:
1167: static int
1168: policy_validate(struct plugin_container *plugin)
1169: {
1.1.1.2 misho 1170: debug_decl(policy_validate, SUDO_DEBUG_PCOMM)
1.1 misho 1171: if (plugin->u.policy->validate == NULL) {
1172: warningx(_("policy plugin %s does not support the -v option"),
1173: plugin->name);
1.1.1.2 misho 1174: debug_return_bool(false);
1.1 misho 1175: }
1.1.1.2 misho 1176: debug_return_bool(plugin->u.policy->validate());
1.1 misho 1177: }
1178:
1179: static void
1180: policy_invalidate(struct plugin_container *plugin, int remove)
1181: {
1.1.1.2 misho 1182: debug_decl(policy_invalidate, SUDO_DEBUG_PCOMM)
1.1 misho 1183: if (plugin->u.policy->invalidate == NULL) {
1.1.1.4 ! misho 1184: fatalx(_("policy plugin %s does not support the -k/-K options"),
1.1 misho 1185: plugin->name);
1186: }
1187: plugin->u.policy->invalidate(remove);
1.1.1.2 misho 1188: debug_return;
1.1 misho 1189: }
1190:
1.1.1.2 misho 1191: int
1192: policy_init_session(struct command_details *details)
1.1 misho 1193: {
1.1.1.2 misho 1194: int rval = true;
1195: debug_decl(policy_init_session, SUDO_DEBUG_PCOMM)
1196:
1197: if (policy_plugin.u.policy->init_session) {
1198: /*
1199: * Backwards compatibility for older API versions
1200: */
1201: switch (policy_plugin.u.generic->version) {
1202: case SUDO_API_MKVERSION(1, 0):
1203: case SUDO_API_MKVERSION(1, 1):
1204: rval = policy_plugin.u.policy_1_0->init_session(details->pw);
1205: break;
1206: default:
1207: rval = policy_plugin.u.policy->init_session(details->pw,
1208: &details->envp);
1209: }
1210: }
1211: debug_return_bool(rval);
1.1 misho 1212: }
1213:
1214: static int
1215: iolog_open(struct plugin_container *plugin, char * const settings[],
1216: char * const user_info[], char * const command_info[],
1217: int argc, char * const argv[], char * const user_env[])
1218: {
1219: int rval;
1.1.1.2 misho 1220: debug_decl(iolog_open, SUDO_DEBUG_PCOMM)
1.1 misho 1221:
1222: /*
1.1.1.2 misho 1223: * Backwards compatibility for older API versions
1.1 misho 1224: */
1225: switch (plugin->u.generic->version) {
1226: case SUDO_API_MKVERSION(1, 0):
1227: rval = plugin->u.io_1_0->open(plugin->u.io_1_0->version,
1228: sudo_conversation, _sudo_printf, settings, user_info, argc, argv,
1229: user_env);
1230: break;
1.1.1.2 misho 1231: case SUDO_API_MKVERSION(1, 1):
1232: rval = plugin->u.io_1_1->open(plugin->u.io_1_1->version,
1233: sudo_conversation, _sudo_printf, settings, user_info,
1234: command_info, argc, argv, user_env);
1235: break;
1.1 misho 1236: default:
1237: rval = plugin->u.io->open(SUDO_API_VERSION, sudo_conversation,
1.1.1.2 misho 1238: _sudo_printf, settings, user_info, command_info,
1239: argc, argv, user_env, plugin->options);
1.1 misho 1240: }
1.1.1.2 misho 1241: debug_return_bool(rval);
1.1 misho 1242: }
1243:
1244: static void
1245: iolog_close(struct plugin_container *plugin, int exit_status, int error)
1246: {
1.1.1.2 misho 1247: debug_decl(iolog_close, SUDO_DEBUG_PCOMM)
1.1.1.4 ! misho 1248: if (plugin->u.io->close != NULL)
! 1249: plugin->u.io->close(exit_status, error);
1.1.1.2 misho 1250: debug_return;
1.1 misho 1251: }
1252:
1253: static int
1254: iolog_show_version(struct plugin_container *plugin, int verbose)
1255: {
1.1.1.2 misho 1256: debug_decl(iolog_show_version, SUDO_DEBUG_PCOMM)
1.1.1.4 ! misho 1257: if (plugin->u.io->show_version == NULL)
! 1258: debug_return_bool(true);
1.1.1.2 misho 1259: debug_return_bool(plugin->u.io->show_version(verbose));
1.1 misho 1260: }
1261:
1262: /*
1.1.1.2 misho 1263: * Remove the specified I/O logging plugin from the io_plugins list.
1264: * Deregisters any hooks before unlinking, then frees the container.
1.1 misho 1265: */
1.1.1.2 misho 1266: static void
1267: iolog_unlink(struct plugin_container *plugin)
1.1 misho 1268: {
1.1.1.2 misho 1269: debug_decl(iolog_unlink, SUDO_DEBUG_PCOMM)
1.1 misho 1270:
1.1.1.2 misho 1271: /* Deregister hooks, if any. */
1272: if (plugin->u.io->version >= SUDO_API_MKVERSION(1, 2)) {
1273: if (plugin->u.io->deregister_hooks != NULL)
1274: plugin->u.io->deregister_hooks(SUDO_HOOK_VERSION,
1275: deregister_hook);
1276: }
1277: /* Remove from io_plugins list and free. */
1278: tq_remove(&io_plugins, plugin);
1279: efree(plugin);
1.1 misho 1280:
1.1.1.2 misho 1281: debug_return;
1.1 misho 1282: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>