1 /*
2 * SPDX-License-Identifier: ISC
3 *
4 * Copyright (c) 2009-2021 Todd C. Miller <Todd.Miller@sudo.ws>
5 *
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18
19 /*
20 * This is an open source non-commercial project. Dear PVS-Studio, please check it.
21 * PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
22 */
23
24 #ifdef __TANDEM
25 # include <floss.h>
26 #endif
27
28 #include <config.h>
29
30 #include <sys/types.h>
31 #include <sys/stat.h>
32 #include <sys/wait.h>
33 #include <sys/resource.h>
34 #include <sys/socket.h>
35 #include <stddef.h>
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <unistd.h>
40 #include <ctype.h>
41 #include <errno.h>
42 #include <fcntl.h>
43 #include <limits.h>
44 #include <signal.h>
45 #include <grp.h>
46 #include <pwd.h>
47 #include <time.h>
48 #ifdef HAVE_SELINUX
49 # include <selinux/selinux.h> /* for is_selinux_enabled() */
50 #endif
51 #ifdef HAVE_SETAUTHDB
52 # include <usersec.h>
53 #endif /* HAVE_SETAUTHDB */
54 #if defined(HAVE_GETPRPWNAM) && defined(HAVE_SET_AUTH_PARAMETERS)
55 # ifdef __hpux
56 # undef MAXINT
57 # include <hpsecurity.h>
58 # else
59 # include <sys/security.h>
60 # endif /* __hpux */
61 # include <prot.h>
62 #endif /* HAVE_GETPRPWNAM && HAVE_SET_AUTH_PARAMETERS */
63
64 #include <sudo_usage.h>
65 #include "sudo.h"
66 #include "sudo_plugin.h"
67 #include "sudo_plugin_int.h"
68
69 /*
70 * Local variables
71 */
72 struct plugin_container policy_plugin;
73 struct plugin_container_list io_plugins = TAILQ_HEAD_INITIALIZER(io_plugins);
74 struct plugin_container_list audit_plugins = TAILQ_HEAD_INITIALIZER(audit_plugins);
75 struct plugin_container_list approval_plugins = TAILQ_HEAD_INITIALIZER(approval_plugins);
76 struct user_details user_details;
77 const char *list_user; /* extern for parse_args.c */
78 int sudo_debug_instance = SUDO_DEBUG_INSTANCE_INITIALIZER;
79 static struct command_details command_details;
80 static int sudo_mode;
81 static struct sudo_event_base *sudo_event_base;
82
83 struct sudo_gc_entry {
84 SLIST_ENTRY(sudo_gc_entry) entries;
85 enum sudo_gc_types type;
86 union {
87 char **vec;
88 void *ptr;
89 } u;
90 };
91 SLIST_HEAD(sudo_gc_list, sudo_gc_entry);
92 #ifdef NO_LEAKS
93 static struct sudo_gc_list sudo_gc_list = SLIST_HEAD_INITIALIZER(sudo_gc_list);
94 #endif
95
96 /*
97 * Local functions
98 */
99 static void fix_fds(void);
100 static void sudo_check_suid(const char *path);
101 static char **get_user_info(struct user_details *);
102 static void command_info_to_details(char * const info[],
103 struct command_details *details);
104 static void gc_init(void);
105
106 /* Policy plugin convenience functions. */
107 static void policy_open(void);
108 static void policy_close(int exit_status, int error);
109 static int policy_show_version(int verbose);
110 static bool policy_check(int argc, char * const argv[], char *env_add[],
111 char **command_info[], char **run_argv[], char **run_envp[]);
112 static void policy_list(int argc, char * const argv[],
113 int verbose, const char *user);
114 static void policy_validate(char * const argv[]);
115 static void policy_invalidate(int unlinkit);
116
117 /* I/O log plugin convenience functions. */
118 static bool iolog_open(char * const command_info[], int run_argc,
119 char * const run_argv[], char * const run_envp[]);
120 static void iolog_close(int exit_status, int error);
121 static void iolog_show_version(int verbose, int argc, char * const argv[],
122 char * const envp[]);
123 static void unlink_plugin(struct plugin_container_list *plugin_list, struct plugin_container *plugin);
124 static void free_plugin_container(struct plugin_container *plugin, bool ioplugin);
125
126 /* Audit plugin convenience functions (some are public). */
127 static void audit_open(void);
128 static void audit_close(int exit_status, int error);
129 static void audit_show_version(int verbose);
130
131 /* Approval plugin convenience functions (some are public). */
132 static void approval_show_version(int verbose);
133
134 sudo_dso_public int main(int argc, char *argv[], char *envp[]);
135
136 static struct sudo_settings *sudo_settings;
137 static char * const *user_info, * const *submit_argv, * const *submit_envp;
138 static int submit_optind;
139
140 int
main(int argc,char * argv[],char * envp[])141 main(int argc, char *argv[], char *envp[])
142 {
143 int nargc, status = 0;
144 char **nargv, **env_add;
145 char **command_info = NULL, **argv_out = NULL, **run_envp = NULL;
146 const char * const allowed_prognames[] = { "sudo", "sudoedit", NULL };
147 sigset_t mask;
148 debug_decl_vars(main, SUDO_DEBUG_MAIN);
149
150 /* Only allow "sudo" or "sudoedit" as the program name. */
151 initprogname2(argc > 0 ? argv[0] : "sudo", allowed_prognames);
152
153 /* Crank resource limits to unlimited. */
154 unlimit_sudo();
155
156 /* Make sure fds 0-2 are open and do OS-specific initialization. */
157 fix_fds();
158 os_init(argc, argv, envp);
159
160 setlocale(LC_ALL, "");
161 bindtextdomain(PACKAGE_NAME, LOCALEDIR);
162 textdomain(PACKAGE_NAME);
163
164 (void) tzset();
165
166 /* Must be done before we do any password lookups */
167 #if defined(HAVE_GETPRPWNAM) && defined(HAVE_SET_AUTH_PARAMETERS)
168 (void) set_auth_parameters(argc, argv);
169 # ifdef HAVE_INITPRIVS
170 initprivs();
171 # endif
172 #endif /* HAVE_GETPRPWNAM && HAVE_SET_AUTH_PARAMETERS */
173
174 /* Initialize the debug subsystem. */
175 if (sudo_conf_read(NULL, SUDO_CONF_DEBUG) == -1)
176 exit(EXIT_FAILURE);
177 sudo_debug_instance = sudo_debug_register(getprogname(),
178 NULL, NULL, sudo_conf_debug_files(getprogname()), -1);
179 if (sudo_debug_instance == SUDO_DEBUG_INSTANCE_ERROR)
180 exit(EXIT_FAILURE);
181
182 /* Make sure we are setuid root. */
183 sudo_check_suid(argc > 0 ? argv[0] : "sudo");
184
185 /* Save original signal state and setup default signal handlers. */
186 save_signals();
187 init_signals();
188
189 /* Reset signal mask to the default value (unblock). */
190 (void) sigemptyset(&mask);
191 (void) sigprocmask(SIG_SETMASK, &mask, NULL);
192
193 /* Parse the rest of sudo.conf. */
194 sudo_conf_read(NULL, SUDO_CONF_ALL & ~SUDO_CONF_DEBUG);
195
196 /* Fill in user_info with user name, uid, cwd, etc. */
197 if ((user_info = get_user_info(&user_details)) == NULL)
198 exit(EXIT_FAILURE); /* get_user_info printed error message */
199
200 /* Disable core dumps if not enabled in sudo.conf. */
201 if (sudo_conf_disable_coredump())
202 disable_coredump();
203
204 /* Parse command line arguments, preserving the original argv/envp. */
205 submit_argv = argv;
206 submit_envp = envp;
207 sudo_mode = parse_args(argc, argv, &submit_optind, &nargc, &nargv,
208 &sudo_settings, &env_add);
209 sudo_debug_printf(SUDO_DEBUG_DEBUG, "sudo_mode %d", sudo_mode);
210
211 /* Print sudo version early, in case of plugin init failure. */
212 if (ISSET(sudo_mode, MODE_VERSION)) {
213 printf(_("Sudo version %s\n"), PACKAGE_VERSION);
214 if (user_details.cred.uid == ROOT_UID)
215 (void) printf(_("Configure options: %s\n"), CONFIGURE_ARGS);
216 }
217
218 /* Use conversation function for sudo_(warn|fatal)x? for plugins. */
219 sudo_warn_set_conversation(sudo_conversation);
220
221 /* Load plugins. */
222 if (!sudo_load_plugins())
223 sudo_fatalx("%s", U_("fatal error, unable to load plugins"));
224
225 /* Allocate event base so plugin can use it. */
226 if ((sudo_event_base = sudo_ev_base_alloc()) == NULL)
227 sudo_fatalx("%s", U_("unable to allocate memory"));
228
229 /* Open policy and audit plugins. */
230 /* XXX - audit policy_open errors */
231 audit_open();
232 policy_open();
233
234 switch (sudo_mode & MODE_MASK) {
235 case MODE_VERSION:
236 policy_show_version(!user_details.cred.uid);
237 iolog_show_version(!user_details.cred.uid, nargc, nargv,
238 submit_envp);
239 approval_show_version(!user_details.cred.uid);
240 audit_show_version(!user_details.cred.uid);
241 break;
242 case MODE_VALIDATE:
243 case MODE_VALIDATE|MODE_INVALIDATE:
244 policy_validate(nargv);
245 break;
246 case MODE_KILL:
247 case MODE_INVALIDATE:
248 policy_invalidate(sudo_mode == MODE_KILL);
249 break;
250 case MODE_CHECK:
251 case MODE_CHECK|MODE_INVALIDATE:
252 case MODE_LIST:
253 case MODE_LIST|MODE_INVALIDATE:
254 policy_list(nargc, nargv, ISSET(sudo_mode, MODE_LONG_LIST),
255 list_user);
256 break;
257 case MODE_EDIT:
258 case MODE_RUN:
259 if (!policy_check(nargc, nargv, env_add, &command_info, &argv_out,
260 &run_envp))
261 goto access_denied;
262
263 /* Reset nargv/nargc based on argv_out. */
264 /* XXX - leaks old nargv in shell mode */
265 for (nargv = argv_out, nargc = 0; nargv[nargc] != NULL; nargc++)
266 continue;
267 if (nargc == 0)
268 sudo_fatalx("%s",
269 U_("plugin did not return a command to execute"));
270
271 /* Approval plugins run after policy plugin accepts the command. */
272 if (!approval_check(command_info, nargv, run_envp))
273 goto access_denied;
274
275 /* Open I/O plugin once policy and approval plugins succeed. */
276 if (!iolog_open(command_info, nargc, nargv, run_envp))
277 goto access_denied;
278
279 /* Audit the accept event on behalf of the sudo front-end. */
280 if (!audit_accept("sudo", SUDO_FRONT_END, command_info,
281 nargv, run_envp))
282 goto access_denied;
283
284 /* Setup command details and run command/edit. */
285 command_info_to_details(command_info, &command_details);
286 command_details.tty = user_details.tty;
287 command_details.argv = argv_out;
288 command_details.envp = run_envp;
289 command_details.evbase = sudo_event_base;
290 if (ISSET(sudo_mode, MODE_LOGIN_SHELL))
291 SET(command_details.flags, CD_LOGIN_SHELL);
292 if (ISSET(sudo_mode, MODE_BACKGROUND))
293 SET(command_details.flags, CD_BACKGROUND);
294 if (ISSET(command_details.flags, CD_SUDOEDIT)) {
295 status = sudo_edit(&command_details);
296 } else {
297 status = run_command(&command_details);
298 }
299 /* The close method was called by sudo_edit/run_command. */
300 break;
301 default:
302 sudo_fatalx(U_("unexpected sudo mode 0x%x"), sudo_mode);
303 }
304
305 /*
306 * If the command was terminated by a signal, sudo needs to terminated
307 * the same way. Otherwise, the shell may ignore a keyboard-generated
308 * signal. However, we want to avoid having sudo dump core itself.
309 */
310 if (WIFSIGNALED(status)) {
311 struct sigaction sa;
312
313 if (WCOREDUMP(status))
314 disable_coredump();
315
316 memset(&sa, 0, sizeof(sa));
317 sigemptyset(&sa.sa_mask);
318 sa.sa_handler = SIG_DFL;
319 sigaction(WTERMSIG(status), &sa, NULL);
320 sudo_debug_exit_int(__func__, __FILE__, __LINE__, sudo_debug_subsys,
321 WTERMSIG(status) | 128);
322 kill(getpid(), WTERMSIG(status));
323 }
324 sudo_debug_exit_int(__func__, __FILE__, __LINE__, sudo_debug_subsys,
325 WEXITSTATUS(status));
326 exit(WEXITSTATUS(status));
327
328 access_denied:
329 /* Policy/approval failure, close policy and audit plugins before exit. */
330 if (policy_plugin.u.policy->version >= SUDO_API_MKVERSION(1, 15))
331 policy_close(0, EACCES);
332 audit_close(SUDO_PLUGIN_NO_STATUS, 0);
333 sudo_debug_exit_int(__func__, __FILE__, __LINE__, sudo_debug_subsys,
334 EXIT_FAILURE);
335 exit(EXIT_FAILURE);
336 }
337
338 int
os_init_common(int argc,char * argv[],char * envp[])339 os_init_common(int argc, char *argv[], char *envp[])
340 {
341 #ifdef STATIC_SUDOERS_PLUGIN
342 preload_static_symbols();
343 #endif
344 gc_init();
345 return 0;
346 }
347
348 /*
349 * Ensure that stdin, stdout and stderr are open; set to /dev/null if not.
350 * Some operating systems do this automatically in the kernel or libc.
351 */
352 static void
fix_fds(void)353 fix_fds(void)
354 {
355 int miss[3], devnull = -1;
356 debug_decl(fix_fds, SUDO_DEBUG_UTIL);
357
358 /*
359 * stdin, stdout and stderr must be open; set them to /dev/null
360 * if they are closed.
361 */
362 miss[STDIN_FILENO] = fcntl(STDIN_FILENO, F_GETFL, 0) == -1;
363 miss[STDOUT_FILENO] = fcntl(STDOUT_FILENO, F_GETFL, 0) == -1;
364 miss[STDERR_FILENO] = fcntl(STDERR_FILENO, F_GETFL, 0) == -1;
365 if (miss[STDIN_FILENO] || miss[STDOUT_FILENO] || miss[STDERR_FILENO]) {
366 devnull = open(_PATH_DEVNULL, O_RDWR, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
367 if (devnull == -1)
368 sudo_fatal(U_("unable to open %s"), _PATH_DEVNULL);
369 if (miss[STDIN_FILENO] && dup2(devnull, STDIN_FILENO) == -1)
370 sudo_fatal("dup2");
371 if (miss[STDOUT_FILENO] && dup2(devnull, STDOUT_FILENO) == -1)
372 sudo_fatal("dup2");
373 if (miss[STDERR_FILENO] && dup2(devnull, STDERR_FILENO) == -1)
374 sudo_fatal("dup2");
375 if (devnull > STDERR_FILENO)
376 close(devnull);
377 }
378 debug_return;
379 }
380
381 /*
382 * Allocate space for groups and fill in using sudo_getgrouplist2()
383 * for when we cannot (or don't want to) use getgroups().
384 * Returns 0 on success and -1 on failure.
385 */
386 static int
fill_group_list(const char * user,struct sudo_cred * cred)387 fill_group_list(const char *user, struct sudo_cred *cred)
388 {
389 int ret = -1;
390 debug_decl(fill_group_list, SUDO_DEBUG_UTIL);
391
392 /*
393 * If user specified a max number of groups, use it, otherwise let
394 * sudo_getgrouplist2() allocate the group vector.
395 */
396 cred->ngroups = sudo_conf_max_groups();
397 if (cred->ngroups > 0) {
398 cred->groups = reallocarray(NULL, cred->ngroups, sizeof(GETGROUPS_T));
399 if (cred->groups != NULL) {
400 /* Clamp to max_groups if insufficient space for all groups. */
401 if (sudo_getgrouplist2(user, cred->gid, &cred->groups,
402 &cred->ngroups) == -1) {
403 cred->ngroups = sudo_conf_max_groups();
404 }
405 ret = 0;
406 }
407 } else {
408 cred->groups = NULL;
409 ret = sudo_getgrouplist2(user, cred->gid, &cred->groups,
410 &cred->ngroups);
411 }
412 if (ret == -1) {
413 sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_ERRNO,
414 "%s: %s: unable to get groups via sudo_getgrouplist2()",
415 __func__, user);
416 } else {
417 sudo_debug_printf(SUDO_DEBUG_INFO,
418 "%s: %s: got %d groups via sudo_getgrouplist2()",
419 __func__, user, cred->ngroups);
420 }
421 debug_return_int(ret);
422 }
423
424 static char *
get_user_groups(const char * user,struct sudo_cred * cred)425 get_user_groups(const char *user, struct sudo_cred *cred)
426 {
427 char *cp, *gid_list = NULL;
428 size_t glsize;
429 int i, len, group_source;
430 debug_decl(get_user_groups, SUDO_DEBUG_UTIL);
431
432 cred->groups = NULL;
433 group_source = sudo_conf_group_source();
434 if (group_source != GROUP_SOURCE_DYNAMIC) {
435 int maxgroups = (int)sysconf(_SC_NGROUPS_MAX);
436 if (maxgroups < 0)
437 maxgroups = NGROUPS_MAX;
438
439 /* Note that macOS may return ngroups > NGROUPS_MAX. */
440 cred->ngroups = getgroups(0, NULL); // -V575
441 if (cred->ngroups > 0) {
442 /* Use groups from kernel if not at limit or source is static. */
443 if (cred->ngroups != maxgroups || group_source == GROUP_SOURCE_STATIC) {
444 cred->groups = reallocarray(NULL, cred->ngroups, sizeof(GETGROUPS_T));
445 if (cred->groups == NULL)
446 goto done;
447 cred->ngroups = getgroups(cred->ngroups, cred->groups);
448 if (cred->ngroups < 0) {
449 sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_ERRNO,
450 "%s: unable to get %d groups via getgroups()",
451 __func__, cred->ngroups);
452 free(cred->groups);
453 cred->groups = NULL;
454 } else {
455 sudo_debug_printf(SUDO_DEBUG_INFO,
456 "%s: got %d groups via getgroups()",
457 __func__, cred->ngroups);
458 }
459 }
460 }
461 }
462 if (cred->groups == NULL) {
463 /*
464 * Query group database if kernel list is too small or disabled.
465 * Typically, this is because NFS can only support up to 16 groups.
466 */
467 if (fill_group_list(user, cred) == -1)
468 goto done;
469 }
470
471 /*
472 * Format group list as a comma-separated string of gids.
473 */
474 glsize = sizeof("groups=") - 1 + (cred->ngroups * (MAX_UID_T_LEN + 1));
475 if ((gid_list = malloc(glsize)) == NULL)
476 goto done;
477 memcpy(gid_list, "groups=", sizeof("groups=") - 1);
478 cp = gid_list + sizeof("groups=") - 1;
479 for (i = 0; i < cred->ngroups; i++) {
480 len = snprintf(cp, glsize - (cp - gid_list), "%s%u",
481 i ? "," : "", (unsigned int)cred->groups[i]);
482 if (len < 0 || (size_t)len >= glsize - (cp - gid_list))
483 sudo_fatalx(U_("internal error, %s overflow"), __func__);
484 cp += len;
485 }
486 done:
487 debug_return_str(gid_list);
488 }
489
490 /*
491 * Return user information as an array of name=value pairs.
492 * and fill in struct user_details (which shares the same strings).
493 */
494 static char **
get_user_info(struct user_details * ud)495 get_user_info(struct user_details *ud)
496 {
497 char *cp, **info, path[PATH_MAX];
498 size_t info_max = 32 + RLIM_NLIMITS;
499 unsigned int i = 0;
500 mode_t mask;
501 struct passwd *pw;
502 int fd, n;
503 debug_decl(get_user_info, SUDO_DEBUG_UTIL);
504
505 /*
506 * On BSD systems you can set a hint to keep the password and
507 * group databases open instead of having to open and close
508 * them all the time. Since sudo does a lot of password and
509 * group lookups, keeping the file open can speed things up.
510 */
511 #ifdef HAVE_SETPASSENT
512 setpassent(1);
513 #endif /* HAVE_SETPASSENT */
514 #ifdef HAVE_SETGROUPENT
515 setgroupent(1);
516 #endif /* HAVE_SETGROUPENT */
517
518 memset(ud, 0, sizeof(*ud));
519
520 /* XXX - bound check number of entries */
521 info = reallocarray(NULL, info_max, sizeof(char *));
522 if (info == NULL)
523 goto oom;
524
525 ud->pid = getpid();
526 ud->ppid = getppid();
527 ud->pgid = getpgid(0);
528 fd = open(_PATH_TTY, O_RDWR);
529 if (fd != -1) {
530 if ((ud->tcpgid = tcgetpgrp(fd)) == -1)
531 ud->tcpgid = 0;
532 close(fd);
533 }
534 if ((ud->sid = getsid(0)) == -1)
535 ud->sid = 0;
536
537 ud->cred.uid = getuid();
538 ud->cred.euid = geteuid();
539 ud->cred.gid = getgid();
540 ud->cred.egid = getegid();
541
542 #ifdef HAVE_SETAUTHDB
543 aix_setauthdb(IDtouser(ud->cred.uid), NULL);
544 #endif
545 pw = getpwuid(ud->cred.uid);
546 #ifdef HAVE_SETAUTHDB
547 aix_restoreauthdb();
548 #endif
549 if (pw == NULL)
550 sudo_fatalx(U_("you do not exist in the %s database"), "passwd");
551
552 info[i] = sudo_new_key_val("user", pw->pw_name);
553 if (info[i] == NULL)
554 goto oom;
555 ud->username = info[i] + sizeof("user=") - 1;
556
557 /* Stash user's shell for use with the -s flag; don't pass to plugin. */
558 if ((ud->shell = getenv("SHELL")) == NULL || ud->shell[0] == '\0') {
559 ud->shell = pw->pw_shell[0] ? pw->pw_shell : _PATH_SUDO_BSHELL;
560 }
561 if ((ud->shell = strdup(ud->shell)) == NULL)
562 goto oom;
563
564 if (asprintf(&info[++i], "pid=%d", (int)ud->pid) == -1)
565 goto oom;
566 if (asprintf(&info[++i], "ppid=%d", (int)ud->ppid) == -1)
567 goto oom;
568 if (asprintf(&info[++i], "pgid=%d", (int)ud->pgid) == -1)
569 goto oom;
570 if (asprintf(&info[++i], "tcpgid=%d", (int)ud->tcpgid) == -1)
571 goto oom;
572 if (asprintf(&info[++i], "sid=%d", (int)ud->sid) == -1)
573 goto oom;
574 if (asprintf(&info[++i], "uid=%u", (unsigned int)ud->cred.uid) == -1)
575 goto oom;
576 if (asprintf(&info[++i], "euid=%u", (unsigned int)ud->cred.euid) == -1)
577 goto oom;
578 if (asprintf(&info[++i], "gid=%u", (unsigned int)ud->cred.gid) == -1)
579 goto oom;
580 if (asprintf(&info[++i], "egid=%u", (unsigned int)ud->cred.egid) == -1)
581 goto oom;
582
583 if ((cp = get_user_groups(ud->username, &ud->cred)) == NULL)
584 goto oom;
585 info[++i] = cp;
586
587 mask = umask(0);
588 umask(mask);
589 if (asprintf(&info[++i], "umask=0%o", (unsigned int)mask) == -1)
590 goto oom;
591
592 if (getcwd(path, sizeof(path)) != NULL) {
593 info[++i] = sudo_new_key_val("cwd", path);
594 if (info[i] == NULL)
595 goto oom;
596 ud->cwd = info[i] + sizeof("cwd=") - 1;
597 }
598
599 if (get_process_ttyname(path, sizeof(path)) != NULL) {
600 info[++i] = sudo_new_key_val("tty", path);
601 if (info[i] == NULL)
602 goto oom;
603 ud->tty = info[i] + sizeof("tty=") - 1;
604 } else {
605 /* tty may not always be present */
606 if (errno != ENOENT)
607 sudo_warn("%s", U_("unable to determine tty"));
608 }
609
610 cp = sudo_gethostname();
611 info[++i] = sudo_new_key_val("host", cp ? cp : "localhost");
612 free(cp);
613 if (info[i] == NULL)
614 goto oom;
615 ud->host = info[i] + sizeof("host=") - 1;
616
617 sudo_get_ttysize(&ud->ts_rows, &ud->ts_cols);
618 if (asprintf(&info[++i], "lines=%d", ud->ts_rows) == -1)
619 goto oom;
620 if (asprintf(&info[++i], "cols=%d", ud->ts_cols) == -1)
621 goto oom;
622
623 n = serialize_limits(&info[i + 1], info_max - (i + 1));
624 if (n == -1)
625 goto oom;
626 i += n;
627
628 info[++i] = NULL;
629
630 /* Add to list of vectors to be garbage collected at exit. */
631 if (!gc_add(GC_VECTOR, info))
632 goto bad;
633
634 debug_return_ptr(info);
635 oom:
636 sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
637 bad:
638 while (i--)
639 free(info[i]);
640 free(info);
641 debug_return_ptr(NULL);
642 }
643
644 /*
645 * Convert a command_info array into a command_details structure.
646 */
647 static void
command_info_to_details(char * const info[],struct command_details * details)648 command_info_to_details(char * const info[], struct command_details *details)
649 {
650 int i;
651 id_t id;
652 char *cp;
653 const char *errstr;
654 debug_decl(command_info_to_details, SUDO_DEBUG_PCOMM);
655
656 memset(details, 0, sizeof(*details));
657 details->info = info;
658 details->closefrom = -1;
659 details->execfd = -1;
660 details->flags = CD_SUDOEDIT_CHECKDIR | CD_SET_GROUPS;
661 TAILQ_INIT(&details->preserved_fds);
662
663 #define SET_STRING(s, n) \
664 if (strncmp(s, info[i], sizeof(s) - 1) == 0 && info[i][sizeof(s) - 1]) { \
665 details->n = info[i] + sizeof(s) - 1; \
666 break; \
667 }
668 #define SET_FLAG(s, n) \
669 if (strncmp(s, info[i], sizeof(s) - 1) == 0) { \
670 switch (sudo_strtobool(info[i] + sizeof(s) - 1)) { \
671 case true: \
672 SET(details->flags, n); \
673 break; \
674 case false: \
675 CLR(details->flags, n); \
676 break; \
677 default: \
678 sudo_debug_printf(SUDO_DEBUG_ERROR, \
679 "invalid boolean value for %s", info[i]); \
680 break; \
681 } \
682 break; \
683 }
684
685 sudo_debug_printf(SUDO_DEBUG_INFO, "command info from plugin:");
686 for (i = 0; info[i] != NULL; i++) {
687 sudo_debug_printf(SUDO_DEBUG_INFO, " %d: %s", i, info[i]);
688 switch (info[i][0]) {
689 case 'c':
690 SET_STRING("chroot=", chroot)
691 SET_STRING("command=", command)
692 SET_STRING("cwd=", cwd)
693 if (strncmp("cwd_optional=", info[i], sizeof("cwd_optional=") - 1) == 0) {
694 cp = info[i] + sizeof("cwd_optional=") - 1;
695 details->cwd_optional = sudo_strtobool(cp);
696 if (details->cwd_optional == -1) {
697 errno = EINVAL;
698 sudo_fatal("%s", info[i]);
699 }
700 break;
701 }
702 if (strncmp("closefrom=", info[i], sizeof("closefrom=") - 1) == 0) {
703 cp = info[i] + sizeof("closefrom=") - 1;
704 details->closefrom = sudo_strtonum(cp, 0, INT_MAX, &errstr);
705 if (errstr != NULL)
706 sudo_fatalx(U_("%s: %s"), info[i], U_(errstr));
707 break;
708 }
709 break;
710 case 'e':
711 SET_FLAG("exec_background=", CD_EXEC_BG)
712 if (strncmp("execfd=", info[i], sizeof("execfd=") - 1) == 0) {
713 cp = info[i] + sizeof("execfd=") - 1;
714 details->execfd = sudo_strtonum(cp, 0, INT_MAX, &errstr);
715 if (errstr != NULL)
716 sudo_fatalx(U_("%s: %s"), info[i], U_(errstr));
717 #ifdef HAVE_FEXECVE
718 /* Must keep fd open during exec. */
719 add_preserved_fd(&details->preserved_fds, details->execfd);
720 #else
721 /* Plugin thinks we support fexecve() but we don't. */
722 (void)fcntl(details->execfd, F_SETFD, FD_CLOEXEC);
723 details->execfd = -1;
724 #endif
725 break;
726 }
727 break;
728 case 'i':
729 SET_FLAG("intercept=", CD_INTERCEPT)
730 break;
731 case 'l':
732 SET_STRING("login_class=", login_class)
733 SET_FLAG("log_subcmds=", CD_LOG_SUBCMDS)
734 break;
735 case 'n':
736 if (strncmp("nice=", info[i], sizeof("nice=") - 1) == 0) {
737 cp = info[i] + sizeof("nice=") - 1;
738 details->priority = sudo_strtonum(cp, INT_MIN, INT_MAX,
739 &errstr);
740 if (errstr != NULL)
741 sudo_fatalx(U_("%s: %s"), info[i], U_(errstr));
742 SET(details->flags, CD_SET_PRIORITY);
743 break;
744 }
745 SET_FLAG("noexec=", CD_NOEXEC)
746 break;
747 case 'p':
748 SET_FLAG("preserve_groups=", CD_PRESERVE_GROUPS)
749 if (strncmp("preserve_fds=", info[i], sizeof("preserve_fds=") - 1) == 0) {
750 parse_preserved_fds(&details->preserved_fds,
751 info[i] + sizeof("preserve_fds=") - 1);
752 break;
753 }
754 break;
755 case 'r':
756 if (strncmp("runas_egid=", info[i], sizeof("runas_egid=") - 1) == 0) {
757 cp = info[i] + sizeof("runas_egid=") - 1;
758 id = sudo_strtoid(cp, &errstr);
759 if (errstr != NULL)
760 sudo_fatalx(U_("%s: %s"), info[i], U_(errstr));
761 details->cred.egid = (gid_t)id;
762 SET(details->flags, CD_SET_EGID);
763 break;
764 }
765 if (strncmp("runas_euid=", info[i], sizeof("runas_euid=") - 1) == 0) {
766 cp = info[i] + sizeof("runas_euid=") - 1;
767 id = sudo_strtoid(cp, &errstr);
768 if (errstr != NULL)
769 sudo_fatalx(U_("%s: %s"), info[i], U_(errstr));
770 details->cred.euid = (uid_t)id;
771 SET(details->flags, CD_SET_EUID);
772 break;
773 }
774 if (strncmp("runas_gid=", info[i], sizeof("runas_gid=") - 1) == 0) {
775 cp = info[i] + sizeof("runas_gid=") - 1;
776 id = sudo_strtoid(cp, &errstr);
777 if (errstr != NULL)
778 sudo_fatalx(U_("%s: %s"), info[i], U_(errstr));
779 details->cred.gid = (gid_t)id;
780 SET(details->flags, CD_SET_GID);
781 break;
782 }
783 if (strncmp("runas_groups=", info[i], sizeof("runas_groups=") - 1) == 0) {
784 cp = info[i] + sizeof("runas_groups=") - 1;
785 details->cred.ngroups = sudo_parse_gids(cp, NULL, &details->cred.groups);
786 /* sudo_parse_gids() will print a warning on error. */
787 if (details->cred.ngroups == -1)
788 exit(EXIT_FAILURE); /* XXX */
789 break;
790 }
791 if (strncmp("runas_uid=", info[i], sizeof("runas_uid=") - 1) == 0) {
792 cp = info[i] + sizeof("runas_uid=") - 1;
793 id = sudo_strtoid(cp, &errstr);
794 if (errstr != NULL)
795 sudo_fatalx(U_("%s: %s"), info[i], U_(errstr));
796 details->cred.uid = (uid_t)id;
797 SET(details->flags, CD_SET_UID);
798 break;
799 }
800 #ifdef HAVE_PRIV_SET
801 if (strncmp("runas_privs=", info[i], sizeof("runas_privs=") - 1) == 0) {
802 const char *endp;
803 cp = info[i] + sizeof("runas_privs=") - 1;
804 if (*cp != '\0') {
805 details->privs = priv_str_to_set(cp, ",", &endp);
806 if (details->privs == NULL)
807 sudo_warn("invalid runas_privs %s", endp);
808 }
809 break;
810 }
811 if (strncmp("runas_limitprivs=", info[i], sizeof("runas_limitprivs=") - 1) == 0) {
812 const char *endp;
813 cp = info[i] + sizeof("runas_limitprivs=") - 1;
814 if (*cp != '\0') {
815 details->limitprivs = priv_str_to_set(cp, ",", &endp);
816 if (details->limitprivs == NULL)
817 sudo_warn("invalid runas_limitprivs %s", endp);
818 }
819 break;
820 }
821 #endif /* HAVE_PRIV_SET */
822 SET_STRING("runas_user=", runas_user)
823 break;
824 case 's':
825 SET_STRING("selinux_role=", selinux_role)
826 SET_STRING("selinux_type=", selinux_type)
827 SET_FLAG("set_utmp=", CD_SET_UTMP)
828 SET_FLAG("sudoedit=", CD_SUDOEDIT)
829 SET_FLAG("sudoedit_checkdir=", CD_SUDOEDIT_CHECKDIR)
830 SET_FLAG("sudoedit_follow=", CD_SUDOEDIT_FOLLOW)
831 break;
832 case 't':
833 if (strncmp("timeout=", info[i], sizeof("timeout=") - 1) == 0) {
834 cp = info[i] + sizeof("timeout=") - 1;
835 details->timeout = sudo_strtonum(cp, 0, INT_MAX, &errstr);
836 if (errstr != NULL)
837 sudo_fatalx(U_("%s: %s"), info[i], U_(errstr));
838 SET(details->flags, CD_SET_TIMEOUT);
839 break;
840 }
841 break;
842 case 'u':
843 if (strncmp("umask=", info[i], sizeof("umask=") - 1) == 0) {
844 cp = info[i] + sizeof("umask=") - 1;
845 details->umask = sudo_strtomode(cp, &errstr);
846 if (errstr != NULL)
847 sudo_fatalx(U_("%s: %s"), info[i], U_(errstr));
848 SET(details->flags, CD_SET_UMASK);
849 break;
850 }
851 SET_FLAG("umask_override=", CD_OVERRIDE_UMASK)
852 SET_FLAG("use_pty=", CD_USE_PTY)
853 SET_STRING("utmp_user=", utmp_user)
854 break;
855 }
856 }
857
858 if (!ISSET(details->flags, CD_SET_EUID))
859 details->cred.euid = details->cred.uid;
860 if (!ISSET(details->flags, CD_SET_EGID))
861 details->cred.egid = details->cred.gid;
862 if (!ISSET(details->flags, CD_SET_UMASK))
863 CLR(details->flags, CD_OVERRIDE_UMASK);
864
865 #ifdef HAVE_SETAUTHDB
866 aix_setauthdb(IDtouser(details->cred.euid), NULL);
867 #endif
868 if (details->runas_user != NULL)
869 details->pw = getpwnam(details->runas_user);
870 if (details->pw == NULL)
871 details->pw = getpwuid(details->cred.euid);
872 #ifdef HAVE_SETAUTHDB
873 aix_restoreauthdb();
874 #endif
875 if (details->pw != NULL && (details->pw = pw_dup(details->pw)) == NULL)
876 sudo_fatalx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
877
878 #ifdef HAVE_SELINUX
879 if (details->selinux_role != NULL && is_selinux_enabled() > 0)
880 SET(details->flags, CD_RBAC_ENABLED);
881 #endif
882 debug_return;
883 }
884
885 static void
sudo_check_suid(const char * sudo)886 sudo_check_suid(const char *sudo)
887 {
888 char pathbuf[PATH_MAX];
889 struct stat sb;
890 bool qualified;
891 debug_decl(sudo_check_suid, SUDO_DEBUG_PCOMM);
892
893 if (geteuid() != ROOT_UID) {
894 /* Search for sudo binary in PATH if not fully qualified. */
895 qualified = strchr(sudo, '/') != NULL;
896 if (!qualified) {
897 char *path = getenv_unhooked("PATH");
898 if (path != NULL) {
899 const char *cp, *ep;
900 const char *pathend = path + strlen(path);
901
902 for (cp = sudo_strsplit(path, pathend, ":", &ep); cp != NULL;
903 cp = sudo_strsplit(NULL, pathend, ":", &ep)) {
904
905 int len = snprintf(pathbuf, sizeof(pathbuf), "%.*s/%s",
906 (int)(ep - cp), cp, sudo);
907 if (len < 0 || len >= ssizeof(pathbuf))
908 continue;
909 if (access(pathbuf, X_OK) == 0) {
910 sudo = pathbuf;
911 qualified = true;
912 break;
913 }
914 }
915 }
916 }
917
918 if (qualified && stat(sudo, &sb) == 0) {
919 /* Try to determine why sudo was not running as root. */
920 if (sb.st_uid != ROOT_UID || !ISSET(sb.st_mode, S_ISUID)) {
921 sudo_fatalx(
922 U_("%s must be owned by uid %d and have the setuid bit set"),
923 sudo, ROOT_UID);
924 } else {
925 sudo_fatalx(U_("effective uid is not %d, is %s on a file system "
926 "with the 'nosuid' option set or an NFS file system without"
927 " root privileges?"), ROOT_UID, sudo);
928 }
929 } else {
930 sudo_fatalx(
931 U_("effective uid is not %d, is sudo installed setuid root?"),
932 ROOT_UID);
933 }
934 }
935 debug_return;
936 }
937
938 bool
set_user_groups(struct command_details * details)939 set_user_groups(struct command_details *details)
940 {
941 bool ret = false;
942 debug_decl(set_user_groups, SUDO_DEBUG_EXEC);
943
944 if (!ISSET(details->flags, CD_PRESERVE_GROUPS)) {
945 if (details->cred.ngroups >= 0) {
946 if (sudo_setgroups(details->cred.ngroups, details->cred.groups) < 0) {
947 sudo_warn("%s", U_("unable to set supplementary group IDs"));
948 goto done;
949 }
950 }
951 }
952 #ifdef HAVE_SETEUID
953 if (ISSET(details->flags, CD_SET_EGID) && setegid(details->cred.egid)) {
954 sudo_warn(U_("unable to set effective gid to runas gid %u"),
955 (unsigned int)details->cred.egid);
956 goto done;
957 }
958 #endif
959 if (ISSET(details->flags, CD_SET_GID) && setgid(details->cred.gid)) {
960 sudo_warn(U_("unable to set gid to runas gid %u"),
961 (unsigned int)details->cred.gid);
962 goto done;
963 }
964 ret = true;
965
966 done:
967 CLR(details->flags, CD_SET_GROUPS);
968 debug_return_bool(ret);
969 }
970
971 /*
972 * Run the command and wait for it to complete.
973 * Returns wait status suitable for use with the wait(2) macros.
974 */
975 int
run_command(struct command_details * details)976 run_command(struct command_details *details)
977 {
978 struct command_status cstat;
979 int status = W_EXITCODE(1, 0);
980 debug_decl(run_command, SUDO_DEBUG_EXEC);
981
982 cstat.type = CMD_INVALID;
983 cstat.val = 0;
984
985 sudo_execute(details, &cstat);
986
987 switch (cstat.type) {
988 case CMD_ERRNO:
989 /* exec_setup() or execve() returned an error. */
990 iolog_close(0, cstat.val);
991 policy_close(0, cstat.val);
992 audit_close(SUDO_PLUGIN_EXEC_ERROR, cstat.val);
993 break;
994 case CMD_WSTATUS:
995 /* Command ran, exited or was killed. */
996 status = cstat.val;
997 iolog_close(status, 0);
998 policy_close(status, 0);
999 audit_close(SUDO_PLUGIN_WAIT_STATUS, cstat.val);
1000 break;
1001 default:
1002 /* TODO: handle front end error conditions. */
1003 sudo_warnx(U_("unexpected child termination condition: %d"), cstat.type);
1004 break;
1005 }
1006 debug_return_int(status);
1007 }
1008
1009 /*
1010 * Format struct sudo_settings as name=value pairs for the plugin
1011 * to consume. Returns a NULL-terminated plugin-style array of pairs.
1012 */
1013 static char **
format_plugin_settings(struct plugin_container * plugin)1014 format_plugin_settings(struct plugin_container *plugin)
1015 {
1016 size_t plugin_settings_size;
1017 struct sudo_debug_file *debug_file;
1018 struct sudo_settings *setting;
1019 char **plugin_settings;
1020 unsigned int i = 0;
1021 debug_decl(format_plugin_settings, SUDO_DEBUG_PCOMM);
1022
1023 /* Determine sudo_settings array size (including plugin_path and NULL) */
1024 plugin_settings_size = 2;
1025 for (setting = sudo_settings; setting->name != NULL; setting++)
1026 plugin_settings_size++;
1027 if (plugin->debug_files != NULL) {
1028 TAILQ_FOREACH(debug_file, plugin->debug_files, entries)
1029 plugin_settings_size++;
1030 }
1031
1032 /* Allocate and fill in. */
1033 plugin_settings = reallocarray(NULL, plugin_settings_size, sizeof(char *));
1034 if (plugin_settings == NULL)
1035 goto bad;
1036 plugin_settings[i] = sudo_new_key_val("plugin_path", plugin->path);
1037 if (plugin_settings[i] == NULL)
1038 goto bad;
1039 for (setting = sudo_settings; setting->name != NULL; setting++) {
1040 if (setting->value != NULL) {
1041 sudo_debug_printf(SUDO_DEBUG_INFO, "settings: %s=%s",
1042 setting->name, setting->value);
1043 plugin_settings[++i] =
1044 sudo_new_key_val(setting->name, setting->value);
1045 if (plugin_settings[i] == NULL)
1046 goto bad;
1047 }
1048 }
1049 if (plugin->debug_files != NULL) {
1050 TAILQ_FOREACH(debug_file, plugin->debug_files, entries) {
1051 /* XXX - quote filename? */
1052 if (asprintf(&plugin_settings[++i], "debug_flags=%s %s",
1053 debug_file->debug_file, debug_file->debug_flags) == -1)
1054 goto bad;
1055 }
1056 }
1057 plugin_settings[++i] = NULL;
1058
1059 /* Add to list of vectors to be garbage collected at exit. */
1060 if (!gc_add(GC_VECTOR, plugin_settings))
1061 sudo_fatalx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
1062
1063 debug_return_ptr(plugin_settings);
1064 bad:
1065 while (i--)
1066 free(plugin_settings[i]);
1067 free(plugin_settings);
1068 debug_return_ptr(NULL);
1069 }
1070
1071 static void
policy_open(void)1072 policy_open(void)
1073 {
1074 char **plugin_settings;
1075 const char *errstr = NULL;
1076 int ok;
1077 debug_decl(policy_open, SUDO_DEBUG_PCOMM);
1078
1079 /* Convert struct sudo_settings to plugin_settings[] */
1080 plugin_settings = format_plugin_settings(&policy_plugin);
1081 if (plugin_settings == NULL)
1082 sudo_fatalx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
1083
1084 /*
1085 * Backward compatibility for older API versions
1086 */
1087 sudo_debug_set_active_instance(SUDO_DEBUG_INSTANCE_INITIALIZER);
1088 switch (policy_plugin.u.generic->version) {
1089 case SUDO_API_MKVERSION(1, 0):
1090 case SUDO_API_MKVERSION(1, 1):
1091 ok = policy_plugin.u.policy_1_0->open(policy_plugin.u.io_1_0->version,
1092 sudo_conversation_1_7, sudo_conversation_printf, plugin_settings,
1093 user_info, submit_envp);
1094 break;
1095 default:
1096 ok = policy_plugin.u.policy->open(SUDO_API_VERSION, sudo_conversation,
1097 sudo_conversation_printf, plugin_settings, user_info, submit_envp,
1098 policy_plugin.options, &errstr);
1099 }
1100
1101 /* Stash plugin debug instance ID if set in open() function. */
1102 policy_plugin.debug_instance = sudo_debug_get_active_instance();
1103 sudo_debug_set_active_instance(sudo_debug_instance);
1104
1105 if (ok != 1) {
1106 if (ok == -2)
1107 usage();
1108 else {
1109 /* XXX - audit */
1110 sudo_fatalx("%s", U_("unable to initialize policy plugin"));
1111 }
1112 }
1113
1114 debug_return;
1115 }
1116
1117 static void
policy_close(int exit_status,int error_code)1118 policy_close(int exit_status, int error_code)
1119 {
1120 debug_decl(policy_close, SUDO_DEBUG_PCOMM);
1121
1122 if (error_code != 0) {
1123 sudo_debug_printf(SUDO_DEBUG_DEBUG,
1124 "%s: calling policy close with errno %d",
1125 policy_plugin.name, error_code);
1126 } else {
1127 sudo_debug_printf(SUDO_DEBUG_DEBUG,
1128 "%s: calling policy close with wait status %d",
1129 policy_plugin.name, exit_status);
1130 }
1131 if (policy_plugin.u.policy->close != NULL) {
1132 sudo_debug_set_active_instance(policy_plugin.debug_instance);
1133 policy_plugin.u.policy->close(exit_status, error_code);
1134 sudo_debug_set_active_instance(sudo_debug_instance);
1135 } else if (error_code != 0) {
1136 if (command_details.command != NULL) {
1137 errno = error_code;
1138 sudo_warn(U_("unable to execute %s"), command_details.command);
1139 }
1140 }
1141
1142 debug_return;
1143 }
1144
1145 static int
policy_show_version(int verbose)1146 policy_show_version(int verbose)
1147 {
1148 int ret = true;
1149 debug_decl(policy_show_version, SUDO_DEBUG_PCOMM);
1150
1151 sudo_debug_set_active_instance(policy_plugin.debug_instance);
1152 if (policy_plugin.u.policy->show_version != NULL)
1153 ret = policy_plugin.u.policy->show_version(verbose);
1154 if (policy_plugin.u.policy->version >= SUDO_API_MKVERSION(1, 15)) {
1155 if (policy_plugin.u.policy->close != NULL)
1156 policy_plugin.u.policy->close(0, 0);
1157 }
1158 sudo_debug_set_active_instance(sudo_debug_instance);
1159
1160 debug_return_int(ret);
1161 }
1162
1163 static bool
policy_check(int argc,char * const argv[],char * env_add[],char ** command_info[],char ** run_argv[],char ** run_envp[])1164 policy_check(int argc, char * const argv[], char *env_add[],
1165 char **command_info[], char **run_argv[], char **run_envp[])
1166 {
1167 const char *errstr = NULL;
1168 int ok;
1169 debug_decl(policy_check, SUDO_DEBUG_PCOMM);
1170
1171 if (policy_plugin.u.policy->check_policy == NULL) {
1172 sudo_fatalx(U_("policy plugin %s is missing the \"check_policy\" method"),
1173 policy_plugin.name);
1174 }
1175 sudo_debug_set_active_instance(policy_plugin.debug_instance);
1176 ok = policy_plugin.u.policy->check_policy(argc, argv, env_add,
1177 command_info, run_argv, run_envp, &errstr);
1178 sudo_debug_set_active_instance(sudo_debug_instance);
1179 sudo_debug_printf(SUDO_DEBUG_INFO, "policy plugin returns %d (%s)",
1180 ok, errstr ? errstr : "");
1181
1182 /* On success, the close method will be called by sudo_edit/run_command. */
1183 if (ok != 1) {
1184 switch (ok) {
1185 case 0:
1186 audit_reject(policy_plugin.name, SUDO_POLICY_PLUGIN,
1187 errstr ? errstr : _("command rejected by policy"),
1188 *command_info);
1189 break;
1190 case -1:
1191 audit_error(policy_plugin.name, SUDO_POLICY_PLUGIN,
1192 errstr ? errstr : _("policy plugin error"),
1193 *command_info);
1194 break;
1195 case -2:
1196 usage();
1197 break;
1198 }
1199 debug_return_bool(false);
1200 }
1201 debug_return_bool(audit_accept(policy_plugin.name, SUDO_POLICY_PLUGIN,
1202 *command_info, *run_argv, *run_envp));
1203 }
1204
1205 static void
policy_list(int argc,char * const argv[],int verbose,const char * user)1206 policy_list(int argc, char * const argv[], int verbose, const char *user)
1207 {
1208 const char *errstr = NULL;
1209 /* TODO: add list_user */
1210 char * const command_info[] = {
1211 "command=list",
1212 NULL
1213 };
1214 int ok;
1215 debug_decl(policy_list, SUDO_DEBUG_PCOMM);
1216
1217 if (policy_plugin.u.policy->list == NULL) {
1218 sudo_fatalx(U_("policy plugin %s does not support listing privileges"),
1219 policy_plugin.name);
1220 }
1221 sudo_debug_set_active_instance(policy_plugin.debug_instance);
1222 ok = policy_plugin.u.policy->list(argc, argv, verbose, user, &errstr);
1223 sudo_debug_set_active_instance(sudo_debug_instance);
1224
1225 switch (ok) {
1226 case 1:
1227 audit_accept(policy_plugin.name, SUDO_POLICY_PLUGIN,
1228 command_info, argv, submit_envp);
1229 break;
1230 case 0:
1231 audit_reject(policy_plugin.name, SUDO_POLICY_PLUGIN,
1232 errstr ? errstr : _("command rejected by policy"),
1233 command_info);
1234 break;
1235 default:
1236 audit_error(policy_plugin.name, SUDO_POLICY_PLUGIN,
1237 errstr ? errstr : _("policy plugin error"),
1238 command_info);
1239 break;
1240 }
1241
1242 /* Policy must be closed after auditing to avoid use after free. */
1243 if (policy_plugin.u.policy->version >= SUDO_API_MKVERSION(1, 15))
1244 policy_close(0, 0);
1245 audit_close(SUDO_PLUGIN_NO_STATUS, 0);
1246
1247 exit(ok != 1);
1248 }
1249
1250 static void
policy_validate(char * const argv[])1251 policy_validate(char * const argv[])
1252 {
1253 const char *errstr = NULL;
1254 char * const command_info[] = {
1255 "command=validate",
1256 NULL
1257 };
1258 int ok = 0;
1259 debug_decl(policy_validate, SUDO_DEBUG_PCOMM);
1260
1261 if (policy_plugin.u.policy->validate == NULL) {
1262 sudo_fatalx(U_("policy plugin %s does not support the -v option"),
1263 policy_plugin.name);
1264 }
1265 sudo_debug_set_active_instance(policy_plugin.debug_instance);
1266 ok = policy_plugin.u.policy->validate(&errstr);
1267 sudo_debug_set_active_instance(sudo_debug_instance);
1268
1269 switch (ok) {
1270 case 1:
1271 audit_accept(policy_plugin.name, SUDO_POLICY_PLUGIN, command_info,
1272 argv, submit_envp);
1273 break;
1274 case 0:
1275 audit_reject(policy_plugin.name, SUDO_POLICY_PLUGIN,
1276 errstr ? errstr : _("command rejected by policy"),
1277 command_info);
1278 break;
1279 default:
1280 audit_error(policy_plugin.name, SUDO_POLICY_PLUGIN,
1281 errstr ? errstr : _("policy plugin error"),
1282 command_info);
1283 break;
1284 }
1285
1286 /* Policy must be closed after auditing to avoid use after free. */
1287 if (policy_plugin.u.policy->version >= SUDO_API_MKVERSION(1, 15))
1288 policy_close(0, 0);
1289 audit_close(SUDO_PLUGIN_NO_STATUS, 0);
1290
1291 exit(ok != 1);
1292 }
1293
1294 static void
policy_invalidate(int unlinkit)1295 policy_invalidate(int unlinkit)
1296 {
1297 debug_decl(policy_invalidate, SUDO_DEBUG_PCOMM);
1298
1299 if (policy_plugin.u.policy->invalidate == NULL) {
1300 sudo_fatalx(U_("policy plugin %s does not support the -k/-K options"),
1301 policy_plugin.name);
1302 }
1303 sudo_debug_set_active_instance(policy_plugin.debug_instance);
1304 policy_plugin.u.policy->invalidate(unlinkit);
1305 if (policy_plugin.u.policy->version >= SUDO_API_MKVERSION(1, 15)) {
1306 if (policy_plugin.u.policy->close != NULL)
1307 policy_plugin.u.policy->close(0, 0);
1308 }
1309 sudo_debug_set_active_instance(sudo_debug_instance);
1310
1311 audit_close(SUDO_PLUGIN_NO_STATUS, 0);
1312
1313 exit(EXIT_SUCCESS);
1314 }
1315
1316 int
policy_init_session(struct command_details * details)1317 policy_init_session(struct command_details *details)
1318 {
1319 const char *errstr = NULL;
1320 int ret = true;
1321 debug_decl(policy_init_session, SUDO_DEBUG_PCOMM);
1322
1323 /*
1324 * We set groups, including supplementary group vector,
1325 * as part of the session setup. This allows for dynamic
1326 * groups to be set via pam_group(8) in pam_setcred(3).
1327 */
1328 if (ISSET(details->flags, CD_SET_GROUPS)) {
1329 /* set_user_groups() prints error message on failure. */
1330 if (!set_user_groups(details))
1331 goto done;
1332 }
1333
1334 /* Session setup may override sudoers umask so set it first. */
1335 if (ISSET(details->flags, CD_SET_UMASK))
1336 (void) umask(details->umask);
1337
1338 if (policy_plugin.u.policy->init_session) {
1339 /*
1340 * Backward compatibility for older API versions
1341 */
1342 sudo_debug_set_active_instance(policy_plugin.debug_instance);
1343 switch (policy_plugin.u.generic->version) {
1344 case SUDO_API_MKVERSION(1, 0):
1345 case SUDO_API_MKVERSION(1, 1):
1346 ret = policy_plugin.u.policy_1_0->init_session(details->pw);
1347 break;
1348 default:
1349 ret = policy_plugin.u.policy->init_session(details->pw,
1350 &details->envp, &errstr);
1351 }
1352 sudo_debug_set_active_instance(sudo_debug_instance);
1353 if (ret != 1) {
1354 audit_error(policy_plugin.name, SUDO_POLICY_PLUGIN,
1355 errstr ? errstr : _("policy plugin error"),
1356 details->info);
1357 }
1358 }
1359 done:
1360 debug_return_int(ret);
1361 }
1362
1363 static int
iolog_open_int(struct plugin_container * plugin,char * const command_info[],int argc,char * const argv[],char * const run_envp[],const char ** errstr)1364 iolog_open_int(struct plugin_container *plugin, char * const command_info[],
1365 int argc, char * const argv[], char * const run_envp[], const char **errstr)
1366 {
1367 char **plugin_settings;
1368 int ret;
1369 debug_decl(iolog_open_int, SUDO_DEBUG_PCOMM);
1370
1371 /* Convert struct sudo_settings to plugin_settings[] */
1372 plugin_settings = format_plugin_settings(plugin);
1373 if (plugin_settings == NULL) {
1374 sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
1375 debug_return_int(-1);
1376 }
1377
1378 /*
1379 * Backward compatibility for older API versions
1380 */
1381 sudo_debug_set_active_instance(plugin->debug_instance);
1382 switch (plugin->u.generic->version) {
1383 case SUDO_API_MKVERSION(1, 0):
1384 ret = plugin->u.io_1_0->open(plugin->u.io_1_0->version,
1385 sudo_conversation_1_7, sudo_conversation_printf, plugin_settings,
1386 user_info, argc, argv, run_envp);
1387 break;
1388 case SUDO_API_MKVERSION(1, 1):
1389 ret = plugin->u.io_1_1->open(plugin->u.io_1_1->version,
1390 sudo_conversation_1_7, sudo_conversation_printf, plugin_settings,
1391 user_info, command_info, argc, argv, run_envp);
1392 break;
1393 default:
1394 ret = plugin->u.io->open(SUDO_API_VERSION, sudo_conversation,
1395 sudo_conversation_printf, plugin_settings, user_info, command_info,
1396 argc, argv, run_envp, plugin->options, errstr);
1397 }
1398
1399 /* Stash plugin debug instance ID if set in open() function. */
1400 plugin->debug_instance = sudo_debug_get_active_instance();
1401 sudo_debug_set_active_instance(sudo_debug_instance);
1402
1403 debug_return_int(ret);
1404 }
1405
1406 static bool
iolog_open(char * const command_info[],int argc,char * const argv[],char * const run_envp[])1407 iolog_open(char * const command_info[], int argc, char * const argv[],
1408 char * const run_envp[])
1409 {
1410 struct plugin_container *plugin, *next;
1411 const char *errstr = NULL;
1412 debug_decl(iolog_open, SUDO_DEBUG_PCOMM);
1413
1414 TAILQ_FOREACH_SAFE(plugin, &io_plugins, entries, next) {
1415 int ok = iolog_open_int(plugin, command_info, argc, argv, run_envp,
1416 &errstr);
1417 switch (ok) {
1418 case 1:
1419 break;
1420 case 0:
1421 /* I/O plugin asked to be disabled, remove and free. */
1422 unlink_plugin(&io_plugins, plugin);
1423 break;
1424 case -2:
1425 usage();
1426 break;
1427 default:
1428 sudo_warnx(U_("error initializing I/O plugin %s"),
1429 plugin->name);
1430 audit_error(plugin->name, SUDO_IO_PLUGIN,
1431 errstr ? errstr : _("error initializing I/O plugin"),
1432 command_info);
1433 debug_return_bool(false);
1434 }
1435 }
1436
1437 debug_return_bool(true);
1438 }
1439
1440 static void
iolog_close(int exit_status,int error_code)1441 iolog_close(int exit_status, int error_code)
1442 {
1443 struct plugin_container *plugin;
1444 debug_decl(iolog_close, SUDO_DEBUG_PCOMM);
1445
1446 TAILQ_FOREACH(plugin, &io_plugins, entries) {
1447 if (plugin->u.io->close != NULL) {
1448 if (error_code != 0) {
1449 sudo_debug_printf(SUDO_DEBUG_DEBUG,
1450 "%s: calling I/O close with errno %d",
1451 plugin->name, error_code);
1452 } else {
1453 sudo_debug_printf(SUDO_DEBUG_DEBUG,
1454 "%s: calling I/O close with wait status %d",
1455 plugin->name, exit_status);
1456 }
1457 sudo_debug_set_active_instance(plugin->debug_instance);
1458 plugin->u.io->close(exit_status, error_code);
1459 sudo_debug_set_active_instance(sudo_debug_instance);
1460 }
1461 }
1462
1463 debug_return;
1464 }
1465
1466 static void
iolog_show_version(int verbose,int argc,char * const argv[],char * const envp[])1467 iolog_show_version(int verbose, int argc, char * const argv[],
1468 char * const envp[])
1469 {
1470 const char *errstr = NULL;
1471 struct plugin_container *plugin;
1472 debug_decl(iolog_show_version, SUDO_DEBUG_PCOMM);
1473
1474 TAILQ_FOREACH(plugin, &io_plugins, entries) {
1475 int ok = iolog_open_int(plugin, NULL, argc, argv, envp, &errstr);
1476 if (ok != -1) {
1477 sudo_debug_set_active_instance(plugin->debug_instance);
1478 if (plugin->u.io->show_version != NULL) {
1479 /* Return value of show_version currently ignored. */
1480 plugin->u.io->show_version(verbose);
1481 }
1482 if (plugin->u.io->version >= SUDO_API_MKVERSION(1, 15)) {
1483 if (plugin->u.io->close != NULL)
1484 plugin->u.io->close(0, 0);
1485 }
1486 sudo_debug_set_active_instance(sudo_debug_instance);
1487 }
1488 }
1489
1490 debug_return;
1491 }
1492
1493 /*
1494 * Remove the specified plugin from the plugins list.
1495 * Deregisters any hooks before unlinking, then frees the container.
1496 */
1497 static void
unlink_plugin(struct plugin_container_list * plugin_list,struct plugin_container * plugin)1498 unlink_plugin(struct plugin_container_list *plugin_list,
1499 struct plugin_container *plugin)
1500 {
1501 void (*deregister_hooks)(int , int (*)(struct sudo_hook *)) = NULL;
1502 debug_decl(unlink_plugin, SUDO_DEBUG_PCOMM);
1503
1504 /* Deregister hooks, if any. */
1505 if (plugin->u.generic->version >= SUDO_API_MKVERSION(1, 2)) {
1506 switch (plugin->u.generic->type) {
1507 case SUDO_IO_PLUGIN:
1508 deregister_hooks = plugin->u.io->deregister_hooks;
1509 break;
1510 case SUDO_AUDIT_PLUGIN:
1511 deregister_hooks = plugin->u.audit->deregister_hooks;
1512 break;
1513 default:
1514 sudo_debug_printf(SUDO_DEBUG_ERROR,
1515 "%s: unsupported plugin type %d", __func__,
1516 plugin->u.generic->type);
1517 break;
1518 }
1519 }
1520 if (deregister_hooks != NULL) {
1521 sudo_debug_set_active_instance(plugin->debug_instance);
1522 deregister_hooks(SUDO_HOOK_VERSION, deregister_hook);
1523 sudo_debug_set_active_instance(sudo_debug_instance);
1524 }
1525
1526 /* Remove from plugin list and free. */
1527 TAILQ_REMOVE(plugin_list, plugin, entries);
1528 free_plugin_container(plugin, true);
1529
1530 debug_return;
1531 }
1532
1533 static int
audit_open_int(struct plugin_container * plugin,const char ** errstr)1534 audit_open_int(struct plugin_container *plugin, const char **errstr)
1535 {
1536 char **plugin_settings;
1537 int ret;
1538 debug_decl(audit_open_int, SUDO_DEBUG_PCOMM);
1539
1540 /* Convert struct sudo_settings to plugin_settings[] */
1541 plugin_settings = format_plugin_settings(plugin);
1542 if (plugin_settings == NULL) {
1543 sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
1544 debug_return_int(-1);
1545 }
1546
1547 sudo_debug_set_active_instance(plugin->debug_instance);
1548 ret = plugin->u.audit->open(SUDO_API_VERSION, sudo_conversation,
1549 sudo_conversation_printf, plugin_settings, user_info,
1550 submit_optind, submit_argv, submit_envp, plugin->options, errstr);
1551
1552 /* Stash plugin debug instance ID if set in open() function. */
1553 plugin->debug_instance = sudo_debug_get_active_instance();
1554 sudo_debug_set_active_instance(sudo_debug_instance);
1555
1556 debug_return_int(ret);
1557 }
1558
1559 static void
audit_open(void)1560 audit_open(void)
1561 {
1562 struct plugin_container *plugin, *next;
1563 const char *errstr = NULL;
1564 debug_decl(audit_open, SUDO_DEBUG_PCOMM);
1565
1566 TAILQ_FOREACH_SAFE(plugin, &audit_plugins, entries, next) {
1567 int ok = audit_open_int(plugin, &errstr);
1568 switch (ok) {
1569 case 1:
1570 break;
1571 case 0:
1572 /* Audit plugin asked to be disabled, remove and free. */
1573 unlink_plugin(&audit_plugins, plugin);
1574 break;
1575 case -2:
1576 usage();
1577 break;
1578 default:
1579 /* TODO: pass error message to other audit plugins */
1580 sudo_fatalx(U_("error initializing audit plugin %s"),
1581 plugin->name);
1582 }
1583 }
1584
1585 debug_return;
1586 }
1587
1588 static void
audit_close(int status_type,int status)1589 audit_close(int status_type, int status)
1590 {
1591 struct plugin_container *plugin;
1592 debug_decl(audit_close, SUDO_DEBUG_PCOMM);
1593
1594 TAILQ_FOREACH(plugin, &audit_plugins, entries) {
1595 if (plugin->u.audit->close != NULL) {
1596 sudo_debug_set_active_instance(plugin->debug_instance);
1597 plugin->u.audit->close(status_type, status);
1598 sudo_debug_set_active_instance(sudo_debug_instance);
1599 }
1600 }
1601
1602 debug_return;
1603 }
1604
1605 static void
audit_show_version(int verbose)1606 audit_show_version(int verbose)
1607 {
1608 struct plugin_container *plugin;
1609 debug_decl(audit_show_version, SUDO_DEBUG_PCOMM);
1610
1611 TAILQ_FOREACH(plugin, &audit_plugins, entries) {
1612 sudo_debug_set_active_instance(plugin->debug_instance);
1613 if (plugin->u.audit->show_version != NULL) {
1614 /* Return value of show_version currently ignored. */
1615 plugin->u.audit->show_version(verbose);
1616 }
1617 if (plugin->u.audit->close != NULL)
1618 plugin->u.audit->close(SUDO_PLUGIN_NO_STATUS, 0);
1619 sudo_debug_set_active_instance(sudo_debug_instance);
1620 }
1621
1622 debug_return;
1623 }
1624
1625 /*
1626 * Error from plugin or front-end.
1627 * The error will not be sent to plugin source, if specified.
1628 */
1629 static bool
audit_error2(struct plugin_container * source,const char * plugin_name,unsigned int plugin_type,const char * audit_msg,char * const command_info[])1630 audit_error2(struct plugin_container *source, const char *plugin_name,
1631 unsigned int plugin_type, const char *audit_msg, char * const command_info[])
1632 {
1633 struct plugin_container *plugin;
1634 const char *errstr = NULL;
1635 bool ret = true;
1636 int ok;
1637 debug_decl(audit_error2, SUDO_DEBUG_PCOMM);
1638
1639 TAILQ_FOREACH(plugin, &audit_plugins, entries) {
1640 if (plugin->u.audit->error == NULL)
1641 continue;
1642
1643 /* Avoid a loop if the audit plugin itself has an error. */
1644 if (plugin == source)
1645 continue;
1646
1647 sudo_debug_set_active_instance(plugin->debug_instance);
1648 ok = plugin->u.audit->error(plugin_name, plugin_type,
1649 audit_msg, command_info, &errstr);
1650 sudo_debug_set_active_instance(sudo_debug_instance);
1651 if (ok != 1) {
1652 /*
1653 * Don't propagate the error to other audit plugins.
1654 * It is not worth the trouble to avoid potential loops.
1655 */
1656 sudo_debug_printf(SUDO_DEBUG_ERROR,
1657 "%s: plugin %s error failed, ret %d", __func__,
1658 plugin->name, ok);
1659 sudo_warnx(U_("%s: unable to log error event%s%s"),
1660 plugin->name, errstr ? ": " : "", errstr ? errstr : "");
1661 ret = false;
1662 }
1663 }
1664
1665 debug_return_bool(ret);
1666 }
1667
1668 /*
1669 * Command accepted by policy.
1670 * See command_info[] for additional info.
1671 * XXX - actual environment may be updated by policy_init_session().
1672 */
1673 bool
audit_accept(const char * plugin_name,unsigned int plugin_type,char * const command_info[],char * const run_argv[],char * const run_envp[])1674 audit_accept(const char *plugin_name, unsigned int plugin_type,
1675 char * const command_info[], char * const run_argv[],
1676 char * const run_envp[])
1677 {
1678 struct plugin_container *plugin;
1679 const char *errstr = NULL;
1680 int ok;
1681 debug_decl(audit_accept, SUDO_DEBUG_PCOMM);
1682
1683 TAILQ_FOREACH(plugin, &audit_plugins, entries) {
1684 if (plugin->u.audit->accept == NULL)
1685 continue;
1686
1687 sudo_debug_set_active_instance(plugin->debug_instance);
1688 ok = plugin->u.audit->accept(plugin_name, plugin_type,
1689 command_info, run_argv, run_envp, &errstr);
1690 sudo_debug_set_active_instance(sudo_debug_instance);
1691 if (ok != 1) {
1692 sudo_debug_printf(SUDO_DEBUG_ERROR,
1693 "%s: plugin %s accept failed, ret %d", __func__,
1694 plugin->name, ok);
1695 sudo_warnx(U_("%s: unable to log accept event%s%s"),
1696 plugin->name, errstr ? ": " : "", errstr ? errstr : "");
1697
1698 /* Notify other audit plugins and return. */
1699 audit_error2(plugin, plugin->name, SUDO_AUDIT_PLUGIN,
1700 errstr ? errstr : _("audit plugin error"), command_info);
1701 debug_return_bool(false);
1702 }
1703 }
1704
1705 debug_return_bool(true);
1706 }
1707
1708 /*
1709 * Command rejected by policy or I/O plugin.
1710 */
1711 bool
audit_reject(const char * plugin_name,unsigned int plugin_type,const char * audit_msg,char * const command_info[])1712 audit_reject(const char *plugin_name, unsigned int plugin_type,
1713 const char *audit_msg, char * const command_info[])
1714 {
1715 struct plugin_container *plugin;
1716 const char *errstr = NULL;
1717 bool ret = true;
1718 int ok;
1719 debug_decl(audit_reject, SUDO_DEBUG_PCOMM);
1720
1721 TAILQ_FOREACH(plugin, &audit_plugins, entries) {
1722 if (plugin->u.audit->reject == NULL)
1723 continue;
1724
1725 sudo_debug_set_active_instance(plugin->debug_instance);
1726 ok = plugin->u.audit->reject(plugin_name, plugin_type,
1727 audit_msg, command_info, &errstr);
1728 sudo_debug_set_active_instance(sudo_debug_instance);
1729 if (ok != 1) {
1730 sudo_debug_printf(SUDO_DEBUG_ERROR,
1731 "%s: plugin %s reject failed, ret %d", __func__,
1732 plugin->name, ok);
1733 sudo_warnx(U_("%s: unable to log reject event%s%s"),
1734 plugin->name, errstr ? ": " : "", errstr ? errstr : "");
1735
1736 /* Notify other audit plugins. */
1737 audit_error2(plugin, plugin->name, SUDO_AUDIT_PLUGIN,
1738 errstr ? errstr : _("audit plugin error"), command_info);
1739
1740 ret = false;
1741 break;
1742 }
1743 }
1744
1745 debug_return_bool(ret);
1746 }
1747
1748 /*
1749 * Error from plugin or front-end.
1750 */
1751 bool
audit_error(const char * plugin_name,unsigned int plugin_type,const char * audit_msg,char * const command_info[])1752 audit_error(const char *plugin_name, unsigned int plugin_type,
1753 const char *audit_msg, char * const command_info[])
1754 {
1755 return audit_error2(NULL, plugin_name, plugin_type, audit_msg,
1756 command_info);
1757 }
1758
1759 static int
approval_open_int(struct plugin_container * plugin)1760 approval_open_int(struct plugin_container *plugin)
1761 {
1762 char **plugin_settings;
1763 const char *errstr = NULL;
1764 int ret;
1765 debug_decl(approval_open_int, SUDO_DEBUG_PCOMM);
1766
1767 /* Convert struct sudo_settings to plugin_settings[] */
1768 plugin_settings = format_plugin_settings(plugin);
1769 if (plugin_settings == NULL)
1770 sudo_fatalx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
1771
1772 sudo_debug_set_active_instance(SUDO_DEBUG_INSTANCE_INITIALIZER);
1773 ret = plugin->u.approval->open(SUDO_API_VERSION, sudo_conversation,
1774 sudo_conversation_printf, plugin_settings, user_info, submit_optind,
1775 submit_argv, submit_envp, plugin->options, &errstr);
1776
1777 /* Stash plugin debug instance ID if set in open() function. */
1778 plugin->debug_instance = sudo_debug_get_active_instance();
1779 sudo_debug_set_active_instance(sudo_debug_instance);
1780
1781 switch (ret) {
1782 case 1:
1783 break;
1784 case 0:
1785 /* approval plugin asked to be disabled, remove and free. */
1786 unlink_plugin(&approval_plugins, plugin);
1787 break;
1788 case -2:
1789 usage();
1790 break;
1791 default:
1792 /* XXX - audit */
1793 sudo_fatalx(U_("error initializing approval plugin %s"),
1794 plugin->name);
1795 }
1796
1797 debug_return_int(ret);
1798 }
1799
1800 static void
approval_show_version(int verbose)1801 approval_show_version(int verbose)
1802 {
1803 struct plugin_container *plugin, *next;
1804 int ok;
1805 debug_decl(approval_show_version, SUDO_DEBUG_PCOMM);
1806
1807 /*
1808 * Approval plugin us only open for the life of the show_version() call.
1809 */
1810 TAILQ_FOREACH_SAFE(plugin, &approval_plugins, entries, next) {
1811 if (plugin->u.approval->show_version == NULL)
1812 continue;
1813
1814 ok = approval_open_int(plugin);
1815 if (ok == 1) {
1816 /* Return value of show_version currently ignored. */
1817 sudo_debug_set_active_instance(plugin->debug_instance);
1818 plugin->u.approval->show_version(verbose);
1819 if (plugin->u.approval->close != NULL)
1820 plugin->u.approval->close();
1821 sudo_debug_set_active_instance(sudo_debug_instance);
1822 }
1823 }
1824
1825 debug_return;
1826 }
1827
1828 /*
1829 * Run approval checks (there may be more than one).
1830 * This is a "one-shot" plugin that has no open/close and is only
1831 * called if the policy plugin accepts the command first.
1832 */
1833 bool
approval_check(char * const command_info[],char * const run_argv[],char * const run_envp[])1834 approval_check(char * const command_info[], char * const run_argv[],
1835 char * const run_envp[])
1836 {
1837 struct plugin_container *plugin, *next;
1838 const char *errstr = NULL;
1839 int ok;
1840 debug_decl(approval_check, SUDO_DEBUG_PCOMM);
1841
1842 /*
1843 * Approval plugin is only open for the life of the check() call.
1844 */
1845 TAILQ_FOREACH_SAFE(plugin, &approval_plugins, entries, next) {
1846 if (plugin->u.approval->check == NULL)
1847 continue;
1848
1849 ok = approval_open_int(plugin);
1850 if (ok != 1)
1851 continue;
1852
1853 sudo_debug_set_active_instance(plugin->debug_instance);
1854 ok = plugin->u.approval->check(command_info, run_argv, run_envp,
1855 &errstr);
1856 sudo_debug_set_active_instance(sudo_debug_instance);
1857 sudo_debug_printf(SUDO_DEBUG_INFO, "approval plugin %s returns %d (%s)",
1858 plugin->name, ok, errstr ? errstr : "");
1859
1860 switch (ok) {
1861 case 0:
1862 audit_reject(plugin->name, SUDO_APPROVAL_PLUGIN,
1863 errstr ? errstr : _("command rejected by approver"),
1864 command_info);
1865 break;
1866 case 1:
1867 if (!audit_accept(plugin->name, SUDO_APPROVAL_PLUGIN, command_info,
1868 run_argv, run_envp))
1869 ok = -1;
1870 break;
1871 case -1:
1872 audit_error(plugin->name, SUDO_APPROVAL_PLUGIN,
1873 errstr ? errstr : _("approval plugin error"),
1874 command_info);
1875 break;
1876 case -2:
1877 usage();
1878 break;
1879 }
1880
1881 /* Close approval plugin now that errstr has been consumed. */
1882 if (plugin->u.approval->close != NULL) {
1883 sudo_debug_set_active_instance(plugin->debug_instance);
1884 plugin->u.approval->close();
1885 sudo_debug_set_active_instance(sudo_debug_instance);
1886 }
1887
1888 if (ok != 1)
1889 debug_return_bool(false);
1890 }
1891
1892 debug_return_bool(true);
1893 }
1894
1895 static void
plugin_event_callback(int fd,int what,void * v)1896 plugin_event_callback(int fd, int what, void *v)
1897 {
1898 struct sudo_plugin_event_int *ev_int = v;
1899 int old_instance;
1900 debug_decl(plugin_event_callback, SUDO_DEBUG_PCOMM);
1901
1902 /* Run the real callback using the plugin's debug instance. */
1903 old_instance = sudo_debug_set_active_instance(ev_int->debug_instance);
1904 ev_int->callback(fd, what, ev_int->closure);
1905 sudo_debug_set_active_instance(old_instance);
1906
1907 debug_return;
1908 }
1909
1910 /*
1911 * Fill in a previously allocated struct sudo_plugin_event.
1912 */
1913 static int
plugin_event_set(struct sudo_plugin_event * pev,int fd,int events,sudo_ev_callback_t callback,void * closure)1914 plugin_event_set(struct sudo_plugin_event *pev, int fd, int events,
1915 sudo_ev_callback_t callback, void *closure)
1916 {
1917 struct sudo_plugin_event_int *ev_int;
1918 debug_decl(plugin_event_set, SUDO_DEBUG_PCOMM);
1919
1920 ev_int = __containerof(pev, struct sudo_plugin_event_int, public);
1921 if (sudo_ev_set(&ev_int->private, fd, events, plugin_event_callback, ev_int) == -1)
1922 debug_return_int(-1);
1923
1924 /* Stash active instance so we can restore it when callback runs. */
1925 ev_int->debug_instance = sudo_debug_get_active_instance();
1926
1927 /* Actual user-specified callback and closure. */
1928 ev_int->callback = callback;
1929 ev_int->closure = closure;
1930
1931 /* Plugin can only operate on the main event loop. */
1932 ev_int->private.base = sudo_event_base;
1933
1934 debug_return_int(1);
1935 }
1936
1937 /*
1938 * Add a struct sudo_plugin_event to the main event loop.
1939 */
1940 static int
plugin_event_add(struct sudo_plugin_event * pev,struct timespec * timo)1941 plugin_event_add(struct sudo_plugin_event *pev, struct timespec *timo)
1942 {
1943 struct sudo_plugin_event_int *ev_int;
1944 debug_decl(plugin_event_add, SUDO_DEBUG_PCOMM);
1945
1946 ev_int = __containerof(pev, struct sudo_plugin_event_int, public);
1947 if (sudo_ev_add(NULL, &ev_int->private, timo, 0) == -1)
1948 debug_return_int(-1);
1949 debug_return_int(1);
1950 }
1951
1952 /*
1953 * Delete a struct sudo_plugin_event from the main event loop.
1954 */
1955 static int
plugin_event_del(struct sudo_plugin_event * pev)1956 plugin_event_del(struct sudo_plugin_event *pev)
1957 {
1958 struct sudo_plugin_event_int *ev_int;
1959 debug_decl(plugin_event_del, SUDO_DEBUG_PCOMM);
1960
1961 ev_int = __containerof(pev, struct sudo_plugin_event_int, public);
1962 if (sudo_ev_del(NULL, &ev_int->private) == -1)
1963 debug_return_int(-1);
1964 debug_return_int(1);
1965 }
1966
1967 /*
1968 * Get the amount of time remaining in a timeout event.
1969 */
1970 static int
plugin_event_pending(struct sudo_plugin_event * pev,int events,struct timespec * ts)1971 plugin_event_pending(struct sudo_plugin_event *pev, int events,
1972 struct timespec *ts)
1973 {
1974 struct sudo_plugin_event_int *ev_int;
1975 debug_decl(plugin_event_pending, SUDO_DEBUG_PCOMM);
1976
1977 ev_int = __containerof(pev, struct sudo_plugin_event_int, public);
1978 debug_return_int(sudo_ev_pending(&ev_int->private, events, ts));
1979 }
1980
1981 /*
1982 * Get the file descriptor associated with an event.
1983 */
1984 static int
plugin_event_fd(struct sudo_plugin_event * pev)1985 plugin_event_fd(struct sudo_plugin_event *pev)
1986 {
1987 struct sudo_plugin_event_int *ev_int;
1988 debug_decl(plugin_event_fd, SUDO_DEBUG_PCOMM);
1989
1990 ev_int = __containerof(pev, struct sudo_plugin_event_int, public);
1991 debug_return_int(sudo_ev_get_fd(&ev_int->private));
1992 }
1993
1994 /*
1995 * Break out of the event loop, killing the command if it is running.
1996 */
1997 static void
plugin_event_loopbreak(struct sudo_plugin_event * pev)1998 plugin_event_loopbreak(struct sudo_plugin_event *pev)
1999 {
2000 struct sudo_plugin_event_int *ev_int;
2001 debug_decl(plugin_event_loopbreak, SUDO_DEBUG_PCOMM);
2002
2003 ev_int = __containerof(pev, struct sudo_plugin_event_int, public);
2004 sudo_ev_loopbreak(ev_int->private.base);
2005 debug_return;
2006 }
2007
2008 /*
2009 * Reset the event base of a struct sudo_plugin_event.
2010 * The event is removed from the old base (if any) first.
2011 * A NULL base can be used to set the default sudo event base.
2012 */
2013 static void
plugin_event_setbase(struct sudo_plugin_event * pev,void * base)2014 plugin_event_setbase(struct sudo_plugin_event *pev, void *base)
2015 {
2016 struct sudo_plugin_event_int *ev_int;
2017 debug_decl(plugin_event_setbase, SUDO_DEBUG_PCOMM);
2018
2019 ev_int = __containerof(pev, struct sudo_plugin_event_int, public);
2020 if (ev_int->private.base != NULL)
2021 sudo_ev_del(ev_int->private.base, &ev_int->private);
2022 ev_int->private.base = base ? base : sudo_event_base;
2023 debug_return;
2024 }
2025
2026 /*
2027 * Free a struct sudo_plugin_event allocated by plugin_event_alloc().
2028 */
2029 static void
plugin_event_free(struct sudo_plugin_event * pev)2030 plugin_event_free(struct sudo_plugin_event *pev)
2031 {
2032 struct sudo_plugin_event_int *ev_int;
2033 debug_decl(plugin_event_free, SUDO_DEBUG_PCOMM);
2034
2035 /* The private field is first so sudo_ev_free() can free the struct. */
2036 ev_int = __containerof(pev, struct sudo_plugin_event_int, public);
2037 sudo_ev_free(&ev_int->private);
2038
2039 debug_return;
2040 }
2041
2042 /*
2043 * Allocate a struct sudo_plugin_event and fill in the public fields.
2044 */
2045 struct sudo_plugin_event *
sudo_plugin_event_alloc(void)2046 sudo_plugin_event_alloc(void)
2047 {
2048 struct sudo_plugin_event_int *ev_int;
2049 debug_decl(plugin_event_alloc, SUDO_DEBUG_PCOMM);
2050
2051 if ((ev_int = malloc(sizeof(*ev_int))) == NULL)
2052 debug_return_ptr(NULL);
2053
2054 /* Init public fields. */
2055 ev_int->public.set = plugin_event_set;
2056 ev_int->public.add = plugin_event_add;
2057 ev_int->public.del = plugin_event_del;
2058 ev_int->public.fd = plugin_event_fd;
2059 ev_int->public.pending = plugin_event_pending;
2060 ev_int->public.setbase = plugin_event_setbase;
2061 ev_int->public.loopbreak = plugin_event_loopbreak;
2062 ev_int->public.free = plugin_event_free;
2063
2064 /* Debug instance to use with the callback. */
2065 ev_int->debug_instance = SUDO_DEBUG_INSTANCE_INITIALIZER;
2066
2067 /* Clear private portion in case caller tries to use us uninitialized. */
2068 memset(&ev_int->private, 0, sizeof(ev_int->private));
2069
2070 debug_return_ptr(&ev_int->public);
2071 }
2072
2073 static void
free_plugin_container(struct plugin_container * plugin,bool ioplugin)2074 free_plugin_container(struct plugin_container *plugin, bool ioplugin)
2075 {
2076 debug_decl(free_plugin_container, SUDO_DEBUG_PLUGIN);
2077
2078 free(plugin->path);
2079 free(plugin->name);
2080 if (plugin->options != NULL) {
2081 int i = 0;
2082 while (plugin->options[i] != NULL)
2083 free(plugin->options[i++]);
2084 free(plugin->options);
2085 }
2086 if (ioplugin)
2087 free(plugin);
2088
2089 debug_return;
2090 }
2091
2092 bool
gc_add(enum sudo_gc_types type,void * v)2093 gc_add(enum sudo_gc_types type, void *v)
2094 {
2095 #ifdef NO_LEAKS
2096 struct sudo_gc_entry *gc;
2097 debug_decl(gc_add, SUDO_DEBUG_MAIN);
2098
2099 if (v == NULL)
2100 debug_return_bool(false);
2101
2102 gc = calloc(1, sizeof(*gc));
2103 if (gc == NULL) {
2104 sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
2105 debug_return_bool(false);
2106 }
2107 switch (type) {
2108 case GC_PTR:
2109 gc->u.ptr = v;
2110 break;
2111 case GC_VECTOR:
2112 gc->u.vec = v;
2113 break;
2114 default:
2115 free(gc);
2116 sudo_warnx("unexpected garbage type %d", type);
2117 debug_return_bool(false);
2118 }
2119 gc->type = type;
2120 SLIST_INSERT_HEAD(&sudo_gc_list, gc, entries);
2121 debug_return_bool(true);
2122 #else
2123 return true;
2124 #endif /* NO_LEAKS */
2125 }
2126
2127 #ifdef NO_LEAKS
2128 static void
gc_run(void)2129 gc_run(void)
2130 {
2131 struct plugin_container *plugin;
2132 struct sudo_gc_entry *gc;
2133 char **cur;
2134 debug_decl(gc_run, SUDO_DEBUG_MAIN);
2135
2136 /* Collect garbage. */
2137 while ((gc = SLIST_FIRST(&sudo_gc_list))) {
2138 SLIST_REMOVE_HEAD(&sudo_gc_list, entries);
2139 switch (gc->type) {
2140 case GC_PTR:
2141 free(gc->u.ptr);
2142 free(gc);
2143 break;
2144 case GC_VECTOR:
2145 for (cur = gc->u.vec; *cur != NULL; cur++)
2146 free(*cur);
2147 free(gc->u.vec);
2148 free(gc);
2149 break;
2150 default:
2151 sudo_warnx("unexpected garbage type %d", gc->type);
2152 }
2153 }
2154
2155 /* Free plugin structs. */
2156 free_plugin_container(&policy_plugin, false);
2157 while ((plugin = TAILQ_FIRST(&io_plugins))) {
2158 TAILQ_REMOVE(&io_plugins, plugin, entries);
2159 free_plugin_container(plugin, true);
2160 }
2161
2162 debug_return;
2163 }
2164 #endif /* NO_LEAKS */
2165
2166 static void
gc_init(void)2167 gc_init(void)
2168 {
2169 #ifdef NO_LEAKS
2170 atexit(gc_run);
2171 #endif
2172 }
2173