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