2 * Copyright (c) 2009-2012 Todd C. Miller <Todd.Miller@courtesan.com>
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.
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.
23 #include <sys/types.h>
24 #include <sys/param.h>
27 #include <sys/socket.h>
29 #include <sys/resource.h>
38 #endif /* STDC_HEADERS */
40 # if defined(HAVE_MEMORY_H) && !defined(STDC_HEADERS)
44 #endif /* HAVE_STRING_H */
47 #endif /* HAVE_STRINGS_H */
50 #endif /* HAVE_UNISTD_H */
58 #if TIME_WITH_SYS_TIME
64 #ifdef HAVE_LOGIN_CAP_H
65 # include <login_cap.h>
67 # define LOGIN_SETENV 0
72 # include <sys/task.h>
75 # include <selinux/selinux.h>
79 #endif /* HAVE_SETAUTHDB */
80 #if defined(HAVE_GETPRPWNAM) && defined(HAVE_SET_AUTH_PARAMETERS)
83 # include <hpsecurity.h>
85 # include <sys/security.h>
88 #endif /* HAVE_GETPRPWNAM && HAVE_SET_AUTH_PARAMETERS */
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>
97 #include "sudo_plugin.h"
98 #include "sudo_plugin_int.h"
99 #include <sudo_usage.h>
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 */
108 static int sudo_mode;
113 static void fix_fds(void);
114 static void disable_coredumps(void);
115 static void sudo_check_suid(const char *path);
116 static char **get_user_info(struct user_details *);
117 static void command_info_to_details(char * const info[],
118 struct command_details *details);
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,
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);
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,
140 static int iolog_show_version(struct plugin_container *plugin, int verbose);
141 static void iolog_unlink(struct plugin_container *plugin);
144 static struct rlimit corelimit;
145 #endif /* RLIMIT_CORE */
146 #if defined(__linux__)
147 static struct rlimit nproclimit;
151 main(int argc, char *argv[], char *envp[])
153 int nargc, ok, exitcode = 0;
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;
159 debug_decl(main, SUDO_DEBUG_MAIN)
161 #if defined(SUDO_DEVEL) && defined(__OpenBSD__)
163 extern char *malloc_options;
164 malloc_options = "AFGJPR";
168 #if !defined(HAVE_GETPROGNAME) && !defined(HAVE___PROGNAME)
170 setprogname(argv[0]);
173 #ifdef HAVE_SETLOCALE
174 setlocale(LC_ALL, "");
176 bindtextdomain(PACKAGE_NAME, LOCALEDIR);
177 textdomain(PACKAGE_NAME);
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
185 #endif /* HAVE_GETPRPWNAM && HAVE_SET_AUTH_PARAMETERS */
187 /* Make sure we are setuid root. */
188 sudo_check_suid(argv[0]);
190 /* Reset signal mask, save signal state and make sure fds 0-2 are open. */
191 (void) sigemptyset(&mask);
192 (void) sigprocmask(SIG_SETMASK, &mask, NULL);
196 /* Read sudo.conf. */
199 /* Fill in user_info with user name, uid, cwd, etc. */
200 memset(&user_details, 0, sizeof(user_details));
201 user_info = get_user_info(&user_details);
203 /* Disable core dumps if not enabled in sudo.conf. */
206 /* Parse command line arguments. */
207 sudo_mode = parse_args(argc, argv, &nargc, &nargv, &settings, &env_add);
208 sudo_debug_printf(SUDO_DEBUG_DEBUG, "sudo_mode %d", sudo_mode);
210 /* Print sudo version early, in case of plugin init failure. */
211 if (ISSET(sudo_mode, MODE_VERSION)) {
212 printf(_("Sudo version %s\n"), PACKAGE_VERSION);
213 if (user_details.uid == ROOT_UID)
214 (void) printf(_("Configure options: %s\n"), CONFIGURE_ARGS);
218 if (!sudo_load_plugins(&policy_plugin, &io_plugins))
219 errorx(1, _("fatal error, unable to load plugins"));
221 /* Open policy plugin. */
222 ok = policy_open(&policy_plugin, settings, user_info, envp);
227 errorx(1, _("unable to initialize policy plugin"));
230 switch (sudo_mode & MODE_MASK) {
232 policy_show_version(&policy_plugin, !user_details.uid);
233 tq_foreach_fwd(&io_plugins, plugin) {
234 ok = iolog_open(plugin, settings, user_info, NULL,
237 iolog_show_version(plugin, !user_details.uid);
241 case MODE_VALIDATE|MODE_INVALIDATE:
242 ok = policy_validate(&policy_plugin);
245 case MODE_INVALIDATE:
246 policy_invalidate(&policy_plugin, sudo_mode == MODE_KILL);
250 case MODE_CHECK|MODE_INVALIDATE:
252 case MODE_LIST|MODE_INVALIDATE:
253 ok = policy_list(&policy_plugin, nargc, nargv,
254 ISSET(sudo_mode, MODE_LONG_LIST), list_user);
258 ok = policy_check(&policy_plugin, nargc, nargv, env_add,
259 &command_info, &argv_out, &user_env_out);
260 sudo_debug_printf(SUDO_DEBUG_INFO, "policy plugin returns %d", ok);
264 exit(1); /* plugin printed error message */
266 /* Open I/O plugins once policy plugin succeeds. */
267 for (plugin = io_plugins.first; plugin != NULL; plugin = next) {
269 ok = iolog_open(plugin, settings, user_info,
270 command_info, nargc, nargv, envp);
275 /* I/O plugin asked to be disabled, remove and free. */
276 iolog_unlink(plugin);
282 errorx(1, _("error initializing I/O plugin %s"),
286 /* Setup command details and run command/edit. */
287 command_info_to_details(command_info, &command_details);
288 command_details.argv = argv_out;
289 command_details.envp = user_env_out;
290 if (ISSET(sudo_mode, MODE_BACKGROUND))
291 SET(command_details.flags, CD_BACKGROUND);
292 /* Become full root (not just setuid) so user cannot kill us. */
293 (void) setuid(ROOT_UID);
294 /* Restore coredumpsize resource limit before running. */
296 if (sudo_conf_disable_coredump())
297 (void) setrlimit(RLIMIT_CORE, &corelimit);
298 #endif /* RLIMIT_CORE */
299 if (ISSET(command_details.flags, CD_SUDOEDIT)) {
300 exitcode = sudo_edit(&command_details);
302 exitcode = run_command(&command_details);
304 /* The close method was called by sudo_edit/run_command. */
307 errorx(1, _("unexpected sudo mode 0x%x"), sudo_mode);
309 sudo_debug_exit_int(__func__, __FILE__, __LINE__, sudo_debug_subsys, exitcode);
314 * Ensure that stdin, stdout and stderr are open; set to /dev/null if not.
315 * Some operating systems do this automatically in the kernel or libc.
320 int miss[3], devnull = -1;
321 debug_decl(fix_fds, SUDO_DEBUG_UTIL)
324 * stdin, stdout and stderr must be open; set them to /dev/null
325 * if they are closed.
327 miss[STDIN_FILENO] = fcntl(STDIN_FILENO, F_GETFL, 0) == -1;
328 miss[STDOUT_FILENO] = fcntl(STDOUT_FILENO, F_GETFL, 0) == -1;
329 miss[STDERR_FILENO] = fcntl(STDERR_FILENO, F_GETFL, 0) == -1;
330 if (miss[STDIN_FILENO] || miss[STDOUT_FILENO] || miss[STDERR_FILENO]) {
331 if ((devnull = open(_PATH_DEVNULL, O_RDWR, 0644)) == -1)
332 error(1, _("unable to open %s"), _PATH_DEVNULL);
333 if (miss[STDIN_FILENO] && dup2(devnull, STDIN_FILENO) == -1)
335 if (miss[STDOUT_FILENO] && dup2(devnull, STDOUT_FILENO) == -1)
337 if (miss[STDERR_FILENO] && dup2(devnull, STDERR_FILENO) == -1)
339 if (devnull > STDERR_FILENO)
346 * Allocate space for groups and fill in using getgrouplist()
347 * for when we cannot use getgroups().
350 fill_group_list(struct user_details *ud)
352 int maxgroups, tries, rval = -1;
353 debug_decl(fill_group_list, SUDO_DEBUG_UTIL)
355 #if defined(HAVE_SYSCONF) && defined(_SC_NGROUPS_MAX)
356 maxgroups = (int)sysconf(_SC_NGROUPS_MAX);
359 maxgroups = NGROUPS_MAX;
362 * It is possible to belong to more groups in the group database
363 * than NGROUPS_MAX. We start off with NGROUPS_MAX * 2 entries
364 * and double this as needed.
367 ud->ngroups = maxgroups;
368 for (tries = 0; tries < 10 && rval == -1; tries++) {
371 ud->groups = emalloc2(ud->ngroups, sizeof(GETGROUPS_T));
372 rval = getgrouplist(ud->username, ud->gid, ud->groups, &ud->ngroups);
374 debug_return_int(rval);
378 get_user_groups(struct user_details *ud)
380 char *cp, *gid_list = NULL;
383 debug_decl(get_user_groups, SUDO_DEBUG_UTIL)
386 * Systems with mbr_check_membership() support more than NGROUPS_MAX
387 * groups so we cannot use getgroups().
390 #ifndef HAVE_MBR_CHECK_MEMBERSHIP
391 if ((ud->ngroups = getgroups(0, NULL)) > 0) {
392 ud->groups = emalloc2(ud->ngroups, sizeof(GETGROUPS_T));
393 if (getgroups(ud->ngroups, ud->groups) < 0) {
398 #endif /* HAVE_MBR_CHECK_MEMBERSHIP */
399 if (ud->groups == NULL) {
400 if (fill_group_list(ud) == -1)
401 error(1, _("unable to get group vector"));
405 * Format group list as a comma-separated string of gids.
407 glsize = sizeof("groups=") - 1 + (ud->ngroups * (MAX_UID_T_LEN + 1));
408 gid_list = emalloc(glsize);
409 memcpy(gid_list, "groups=", sizeof("groups=") - 1);
410 cp = gid_list + sizeof("groups=") - 1;
411 for (i = 0; i < ud->ngroups; i++) {
412 /* XXX - check rval */
413 len = snprintf(cp, glsize - (cp - gid_list), "%s%u",
414 i ? "," : "", (unsigned int)ud->groups[i]);
417 debug_return_str(gid_list);
421 * Return user information as an array of name=value pairs.
422 * and fill in struct user_details (which shares the same strings).
425 get_user_info(struct user_details *ud)
427 char *cp, **user_info, cwd[PATH_MAX], host[MAXHOSTNAMELEN];
430 debug_decl(get_user_info, SUDO_DEBUG_UTIL)
432 /* XXX - bound check number of entries */
433 user_info = emalloc2(32, sizeof(char *));
436 ud->ppid = getppid();
437 ud->pgid = getpgid(0);
438 ud->tcpgid = (pid_t)-1;
439 fd = open(_PATH_TTY, O_RDWR|O_NOCTTY|O_NONBLOCK, 0);
441 ud->tcpgid = tcgetpgrp(fd);
447 ud->euid = geteuid();
449 ud->egid = getegid();
451 pw = getpwuid(ud->uid);
453 errorx(1, _("unknown uid %u: who are you?"), (unsigned int)ud->uid);
455 user_info[i] = fmt_string("user", pw->pw_name);
456 if (user_info[i] == NULL)
457 errorx(1, _("unable to allocate memory"));
458 ud->username = user_info[i] + sizeof("user=") - 1;
460 /* Stash user's shell for use with the -s flag; don't pass to plugin. */
461 if ((ud->shell = getenv("SHELL")) == NULL || ud->shell[0] == '\0') {
462 ud->shell = pw->pw_shell[0] ? pw->pw_shell : _PATH_BSHELL;
464 ud->shell = estrdup(ud->shell);
466 easprintf(&user_info[++i], "pid=%d", (int)ud->pid);
467 easprintf(&user_info[++i], "ppid=%d", (int)ud->ppid);
468 easprintf(&user_info[++i], "pgid=%d", (int)ud->pgid);
469 easprintf(&user_info[++i], "tcpgid=%d", (int)ud->tcpgid);
470 easprintf(&user_info[++i], "sid=%d", (int)ud->sid);
472 easprintf(&user_info[++i], "uid=%u", (unsigned int)ud->uid);
473 easprintf(&user_info[++i], "euid=%u", (unsigned int)ud->euid);
474 easprintf(&user_info[++i], "gid=%u", (unsigned int)ud->gid);
475 easprintf(&user_info[++i], "egid=%u", (unsigned int)ud->egid);
477 if ((cp = get_user_groups(ud)) != NULL)
480 if (getcwd(cwd, sizeof(cwd)) != NULL) {
481 user_info[++i] = fmt_string("cwd", cwd);
482 if (user_info[i] == NULL)
483 errorx(1, _("unable to allocate memory"));
484 ud->cwd = user_info[i] + sizeof("cwd=") - 1;
487 if ((cp = get_process_ttyname()) != NULL) {
488 user_info[++i] = fmt_string("tty", cp);
489 if (user_info[i] == NULL)
490 errorx(1, _("unable to allocate memory"));
491 ud->tty = user_info[i] + sizeof("tty=") - 1;
495 if (gethostname(host, sizeof(host)) == 0)
496 host[sizeof(host) - 1] = '\0';
498 strlcpy(host, "localhost", sizeof(host));
499 user_info[++i] = fmt_string("host", host);
500 if (user_info[i] == NULL)
501 errorx(1, _("unable to allocate memory"));
502 ud->host = user_info[i] + sizeof("host=") - 1;
504 get_ttysize(&ud->ts_lines, &ud->ts_cols);
505 easprintf(&user_info[++i], "lines=%d", ud->ts_lines);
506 easprintf(&user_info[++i], "cols=%d", ud->ts_cols);
508 user_info[++i] = NULL;
510 debug_return_ptr(user_info);
514 * Convert a command_info array into a command_details structure.
517 command_info_to_details(char * const info[], struct command_details *details)
523 debug_decl(command_info_to_details, SUDO_DEBUG_PCOMM)
525 memset(details, 0, sizeof(*details));
526 details->closefrom = -1;
528 #define SET_STRING(s, n) \
529 if (strncmp(s, info[i], sizeof(s) - 1) == 0 && info[i][sizeof(s) - 1]) { \
530 details->n = info[i] + sizeof(s) - 1; \
534 sudo_debug_printf(SUDO_DEBUG_INFO, "command info from plugin:");
535 for (i = 0; info[i] != NULL; i++) {
536 sudo_debug_printf(SUDO_DEBUG_INFO, " %d: %s", i, info[i]);
537 switch (info[i][0]) {
539 SET_STRING("chroot=", chroot)
540 SET_STRING("command=", command)
541 SET_STRING("cwd=", cwd)
542 if (strncmp("closefrom=", info[i], sizeof("closefrom=") - 1) == 0) {
543 cp = info[i] + sizeof("closefrom=") - 1;
547 lval = strtol(cp, &ep, 0);
548 if (*cp != '\0' && *ep == '\0' &&
550 (lval == LONG_MAX || lval == LONG_MIN)) &&
551 lval < INT_MAX && lval > INT_MIN) {
552 details->closefrom = (int)lval;
558 SET_STRING("login_class=", login_class)
561 /* XXX - bounds check -NZERO to NZERO (inclusive). */
562 if (strncmp("nice=", info[i], sizeof("nice=") - 1) == 0) {
563 cp = info[i] + sizeof("nice=") - 1;
567 lval = strtol(cp, &ep, 0);
568 if (*cp != '\0' && *ep == '\0' &&
570 (lval == LONG_MAX || lval == LONG_MIN)) &&
571 lval < INT_MAX && lval > INT_MIN) {
572 details->priority = (int)lval;
573 SET(details->flags, CD_SET_PRIORITY);
577 if (strncmp("noexec=", info[i], sizeof("noexec=") - 1) == 0) {
578 if (atobool(info[i] + sizeof("noexec=") - 1) == true)
579 SET(details->flags, CD_NOEXEC);
584 if (strncmp("preserve_groups=", info[i], sizeof("preserve_groups=") - 1) == 0) {
585 if (atobool(info[i] + sizeof("preserve_groups=") - 1) == true)
586 SET(details->flags, CD_PRESERVE_GROUPS);
591 if (strncmp("runas_egid=", info[i], sizeof("runas_egid=") - 1) == 0) {
592 cp = info[i] + sizeof("runas_egid=") - 1;
596 ulval = strtoul(cp, &ep, 0);
597 if (*cp != '\0' && *ep == '\0' &&
598 (errno != ERANGE || ulval != ULONG_MAX)) {
599 details->egid = (gid_t)ulval;
600 SET(details->flags, CD_SET_EGID);
604 if (strncmp("runas_euid=", info[i], sizeof("runas_euid=") - 1) == 0) {
605 cp = info[i] + sizeof("runas_euid=") - 1;
609 ulval = strtoul(cp, &ep, 0);
610 if (*cp != '\0' && *ep == '\0' &&
611 (errno != ERANGE || ulval != ULONG_MAX)) {
612 details->euid = (uid_t)ulval;
613 SET(details->flags, CD_SET_EUID);
617 if (strncmp("runas_gid=", info[i], sizeof("runas_gid=") - 1) == 0) {
618 cp = info[i] + sizeof("runas_gid=") - 1;
622 ulval = strtoul(cp, &ep, 0);
623 if (*cp != '\0' && *ep == '\0' &&
624 (errno != ERANGE || ulval != ULONG_MAX)) {
625 details->gid = (gid_t)ulval;
626 SET(details->flags, CD_SET_GID);
630 if (strncmp("runas_groups=", info[i], sizeof("runas_groups=") - 1) == 0) {
633 /* count groups, alloc and fill in */
634 cp = info[i] + sizeof("runas_groups=") - 1;
639 if ((cp = strchr(cp, ',')) == NULL)
643 if (details->ngroups != 0) {
645 emalloc2(details->ngroups, sizeof(GETGROUPS_T));
646 cp = info[i] + sizeof("runas_groups=") - 1;
647 for (j = 0; j < details->ngroups;) {
649 ulval = strtoul(cp, &ep, 0);
650 if (*cp == '\0' || (*ep != ',' && *ep != '\0') ||
651 (ulval == ULONG_MAX && errno == ERANGE)) {
654 details->groups[j++] = (gid_t)ulval;
657 details->ngroups = j;
661 if (strncmp("runas_uid=", info[i], sizeof("runas_uid=") - 1) == 0) {
662 cp = info[i] + sizeof("runas_uid=") - 1;
666 ulval = strtoul(cp, &ep, 0);
667 if (*cp != '\0' && *ep == '\0' &&
668 (errno != ERANGE || ulval != ULONG_MAX)) {
669 details->uid = (uid_t)ulval;
670 SET(details->flags, CD_SET_UID);
675 if (strncmp("runas_privs=", info[i], sizeof("runas_privs=") - 1) == 0) {
677 cp = info[i] + sizeof("runas_privs=") - 1;
681 details->privs = priv_str_to_set(cp, ",", &endp);
682 if (details->privs == NULL)
683 warning("invalid runas_privs %s", endp);
685 if (strncmp("runas_limitprivs=", info[i], sizeof("runas_limitprivs=") - 1) == 0) {
687 cp = info[i] + sizeof("runas_limitprivs=") - 1;
691 details->limitprivs = priv_str_to_set(cp, ",", &endp);
692 if (details->limitprivs == NULL)
693 warning("invalid runas_limitprivs %s", endp);
695 #endif /* HAVE_PRIV_SET */
698 SET_STRING("selinux_role=", selinux_role)
699 SET_STRING("selinux_type=", selinux_type)
700 if (strncmp("set_utmp=", info[i], sizeof("set_utmp=") - 1) == 0) {
701 if (atobool(info[i] + sizeof("set_utmp=") - 1) == true)
702 SET(details->flags, CD_SET_UTMP);
705 if (strncmp("sudoedit=", info[i], sizeof("sudoedit=") - 1) == 0) {
706 if (atobool(info[i] + sizeof("sudoedit=") - 1) == true)
707 SET(details->flags, CD_SUDOEDIT);
712 if (strncmp("timeout=", info[i], sizeof("timeout=") - 1) == 0) {
713 cp = info[i] + sizeof("timeout=") - 1;
717 lval = strtol(cp, &ep, 0);
718 if (*cp != '\0' && *ep == '\0' &&
720 (lval == LONG_MAX || lval == LONG_MIN)) &&
721 lval <= INT_MAX && lval >= 0) {
722 details->timeout = (int)lval;
723 SET(details->flags, CD_SET_TIMEOUT);
729 if (strncmp("umask=", info[i], sizeof("umask=") - 1) == 0) {
730 cp = info[i] + sizeof("umask=") - 1;
734 ulval = strtoul(cp, &ep, 8);
735 if (*cp != '\0' && *ep == '\0' &&
736 (errno != ERANGE || ulval != ULONG_MAX)) {
737 details->umask = (uid_t)ulval;
738 SET(details->flags, CD_SET_UMASK);
742 if (strncmp("use_pty=", info[i], sizeof("use_pty=") - 1) == 0) {
743 if (atobool(info[i] + sizeof("use_pty=") - 1) == true)
744 SET(details->flags, CD_USE_PTY);
747 SET_STRING("utmp_user=", utmp_user)
752 if (!ISSET(details->flags, CD_SET_EUID))
753 details->euid = details->uid;
755 #ifdef HAVE_SETAUTHDB
756 aix_setauthdb(IDtouser(details->euid));
758 details->pw = getpwuid(details->euid);
759 if (details->pw != NULL && (details->pw = pw_dup(details->pw)) == NULL)
760 errorx(1, _("unable to allocate memory"));
761 #ifdef HAVE_SETAUTHDB
766 if (details->selinux_role != NULL && is_selinux_enabled() > 0)
767 SET(details->flags, CD_RBAC_ENABLED);
773 sudo_check_suid(const char *path)
776 debug_decl(sudo_check_suid, SUDO_DEBUG_PCOMM)
778 if (geteuid() != 0) {
779 if (strchr(path, '/') != NULL && stat(path, &sb) == 0) {
780 /* Try to determine why sudo was not running as root. */
781 if (sb.st_uid != ROOT_UID || !ISSET(sb.st_mode, S_ISUID)) {
783 _("%s must be owned by uid %d and have the setuid bit set"),
786 errorx(1, _("effective uid is not %d, is %s on a file system "
787 "with the 'nosuid' option set or an NFS file system without"
788 " root privileges?"), ROOT_UID, path);
792 _("effective uid is not %d, is sudo installed setuid root?"),
800 * Disable core dumps to avoid dropping a core with user password in it.
801 * We will reset this limit before executing the command.
802 * Not all operating systems disable core dumps for setuid processes.
805 disable_coredumps(void)
807 #if defined(__linux__) || defined(RLIMIT_CORE)
810 debug_decl(disable_coredumps, SUDO_DEBUG_UTIL)
812 #if defined(__linux__)
814 * Unlimit the number of processes since Linux's setuid() will
815 * apply resource limits when changing uid and return EAGAIN if
816 * nproc would be violated by the uid switch.
818 (void) getrlimit(RLIMIT_NPROC, &nproclimit);
819 rl.rlim_cur = rl.rlim_max = RLIM_INFINITY;
820 if (setrlimit(RLIMIT_NPROC, &rl)) {
821 memcpy(&rl, &nproclimit, sizeof(struct rlimit));
822 rl.rlim_cur = rl.rlim_max;
823 (void)setrlimit(RLIMIT_NPROC, &rl);
825 #endif /* __linux__ */
828 * Turn off core dumps?
830 if (sudo_conf_disable_coredump()) {
831 (void) getrlimit(RLIMIT_CORE, &corelimit);
832 memcpy(&rl, &corelimit, sizeof(struct rlimit));
834 (void) setrlimit(RLIMIT_CORE, &rl);
836 #endif /* RLIMIT_CORE */
840 #ifdef HAVE_PROJECT_H
842 set_project(struct passwd *pw)
845 char buf[PROJECT_BUFSZ];
847 debug_decl(set_project, SUDO_DEBUG_UTIL)
850 * Collect the default project for the user and settaskid
853 if (getdefaultproj(pw->pw_name, &proj, buf, sizeof(buf)) != NULL) {
854 errval = setproject(proj.pj_name, pw->pw_name, TASK_NORMAL);
858 case SETPROJ_ERR_TASK:
861 warningx(_("resource control limit has been reached"));
864 warningx(_("user \"%s\" is not a member of project \"%s\""),
865 pw->pw_name, proj.pj_name);
868 warningx(_("the invoking task is final"));
871 warningx(_("could not join project \"%s\""), proj.pj_name);
873 case SETPROJ_ERR_POOL:
876 warningx(_("no resource pool accepting default bindings "
877 "exists for project \"%s\""), proj.pj_name);
880 warningx(_("specified resource pool does not exist for "
881 "project \"%s\""), proj.pj_name);
884 warningx(_("could not bind to default resource pool for "
885 "project \"%s\""), proj.pj_name);
890 warningx(_("setproject failed for project \"%s\""), proj.pj_name);
892 warningx(_("warning, resource control assignment failed for "
893 "project \"%s\""), proj.pj_name);
897 warning("getdefaultproj");
902 #endif /* HAVE_PROJECT_H */
905 * Setup the execution environment immediately prior to the call to execve()
906 * Returns true on success and false on failure.
909 exec_setup(struct command_details *details, const char *ptyname, int ptyfd)
912 debug_decl(exec_setup, SUDO_DEBUG_EXEC)
915 if (ISSET(details->flags, CD_RBAC_ENABLED)) {
916 if (selinux_setup(details->selinux_role, details->selinux_type,
917 ptyname ? ptyname : user_details.tty, ptyfd) == -1)
922 if (details->pw != NULL) {
923 #ifdef HAVE_PROJECT_H
924 set_project(details->pw);
927 if (details->privs != NULL) {
928 if (setppriv(PRIV_SET, PRIV_INHERITABLE, details->privs) != 0) {
929 warning("unable to set privileges");
933 if (details->limitprivs != NULL) {
934 if (setppriv(PRIV_SET, PRIV_LIMIT, details->limitprivs) != 0) {
935 warning("unable to set limit privileges");
938 } else if (details->privs != NULL) {
939 if (setppriv(PRIV_SET, PRIV_LIMIT, details->privs) != 0) {
940 warning("unable to set limit privileges");
944 #endif /* HAVE_PRIV_SET */
946 #ifdef HAVE_GETUSERATTR
947 aix_prep_user(details->pw->pw_name, ptyname ? ptyname : user_details.tty);
949 #ifdef HAVE_LOGIN_CAP_H
950 if (details->login_class) {
955 * We only use setusercontext() to set the nice value and rlimits
956 * unless this is a login shell (sudo -i).
958 lc = login_getclass((char *)details->login_class);
960 warningx(_("unknown login class %s"), details->login_class);
964 if (ISSET(sudo_mode, MODE_LOGIN_SHELL)) {
965 /* Set everything except user, group and login name. */
966 flags = LOGIN_SETALL;
967 CLR(flags, LOGIN_SETGROUP|LOGIN_SETLOGIN|LOGIN_SETUSER|LOGIN_SETENV|LOGIN_SETPATH);
968 CLR(details->flags, CD_SET_UMASK); /* LOGIN_UMASK instead */
970 flags = LOGIN_SETRESOURCES|LOGIN_SETPRIORITY;
972 if (setusercontext(lc, details->pw, details->pw->pw_uid, flags)) {
973 if (details->pw->pw_uid != ROOT_UID) {
974 warning(_("unable to set user context"));
977 warning(_("unable to set user context"));
980 #endif /* HAVE_LOGIN_CAP_H */
984 * Set groups, including supplementary group vector.
986 if (!ISSET(details->flags, CD_PRESERVE_GROUPS)) {
987 if (details->ngroups >= 0) {
988 if (sudo_setgroups(details->ngroups, details->groups) < 0) {
989 warning(_("unable to set supplementary group IDs"));
995 if (ISSET(details->flags, CD_SET_EGID) && setegid(details->egid)) {
996 warning(_("unable to set effective gid to runas gid %u"),
997 (unsigned int)details->egid);
1001 if (ISSET(details->flags, CD_SET_GID) && setgid(details->gid)) {
1002 warning(_("unable to set gid to runas gid %u"),
1003 (unsigned int)details->gid);
1007 if (ISSET(details->flags, CD_SET_PRIORITY)) {
1008 if (setpriority(PRIO_PROCESS, 0, details->priority) != 0) {
1009 warning(_("unable to set process priority"));
1013 if (ISSET(details->flags, CD_SET_UMASK))
1014 (void) umask(details->umask);
1015 if (details->chroot) {
1016 if (chroot(details->chroot) != 0 || chdir("/") != 0) {
1017 warning(_("unable to change root to %s"), details->chroot);
1022 #ifdef HAVE_SETRESUID
1023 if (setresuid(details->uid, details->euid, details->euid) != 0) {
1024 warning(_("unable to change to runas uid (%u, %u)"), details->uid,
1029 if (setreuid(details->uid, details->euid) != 0) {
1030 warning(_("unable to change to runas uid (%u, %u)"),
1031 (unsigned int)details->uid, (unsigned int)details->euid);
1035 if (seteuid(details->euid) != 0 || setuid(details->euid) != 0) {
1036 warning(_("unable to change to runas uid (%u, %u)"), details->uid,
1040 #endif /* !HAVE_SETRESUID && !HAVE_SETREUID */
1043 * Only change cwd if we have chroot()ed or the policy modules
1044 * specifies a different cwd. Must be done after uid change.
1047 if (details->chroot || strcmp(details->cwd, user_details.cwd) != 0) {
1048 /* Note: cwd is relative to the new root, if any. */
1049 if (chdir(details->cwd) != 0) {
1050 warning(_("unable to change directory to %s"), details->cwd);
1057 * SuSE Enterprise Linux uses RLIMIT_NPROC and _SC_CHILD_MAX
1058 * interchangably. This causes problems when setting RLIMIT_NPROC
1059 * to RLIM_INFINITY due to a bug in bash where bash tries to honor
1060 * the value of _SC_CHILD_MAX but treats a value of -1 as an error,
1061 * and uses a default value of 32 instead.
1063 * To work around this problem, we restore the nproc resource limit
1064 * if sysconf(_SC_CHILD_MAX) is negative. In most cases, pam_limits
1065 * will set RLIMIT_NPROC for us.
1067 * We must do this *after* the uid change to avoid potential EAGAIN
1070 #if defined(__linux__) && defined(_SC_CHILD_MAX)
1075 l = sysconf(_SC_CHILD_MAX);
1076 if (l == -1 && errno == 0 && getrlimit(RLIMIT_NPROC, &rl) == 0) {
1077 if (rl.rlim_cur == RLIM_INFINITY && rl.rlim_max == RLIM_INFINITY)
1078 (void) setrlimit(RLIMIT_NPROC, &nproclimit);
1086 debug_return_bool(rval);
1090 * Run the command and wait for it to complete.
1093 run_command(struct command_details *details)
1095 struct plugin_container *plugin;
1096 struct command_status cstat;
1098 debug_decl(run_command, SUDO_DEBUG_EXEC)
1100 cstat.type = CMD_INVALID;
1103 sudo_execute(details, &cstat);
1105 switch (cstat.type) {
1107 /* exec_setup() or execve() returned an error. */
1108 sudo_debug_printf(SUDO_DEBUG_DEBUG,
1109 "calling policy close with errno %d", cstat.val);
1110 policy_close(&policy_plugin, 0, cstat.val);
1111 tq_foreach_fwd(&io_plugins, plugin) {
1112 sudo_debug_printf(SUDO_DEBUG_DEBUG,
1113 "calling I/O close with errno %d", cstat.val);
1114 iolog_close(plugin, 0, cstat.val);
1119 /* Command ran, exited or was killed. */
1120 sudo_debug_printf(SUDO_DEBUG_DEBUG,
1121 "calling policy close with wait status %d", cstat.val);
1122 policy_close(&policy_plugin, cstat.val, 0);
1123 tq_foreach_fwd(&io_plugins, plugin) {
1124 sudo_debug_printf(SUDO_DEBUG_DEBUG,
1125 "calling I/O close with wait status %d", cstat.val);
1126 iolog_close(plugin, cstat.val, 0);
1128 if (WIFEXITED(cstat.val))
1129 exitcode = WEXITSTATUS(cstat.val);
1130 else if (WIFSIGNALED(cstat.val))
1131 exitcode = WTERMSIG(cstat.val) | 128;
1134 warningx(_("unexpected child termination condition: %d"), cstat.type);
1137 debug_return_int(exitcode);
1141 policy_open(struct plugin_container *plugin, char * const settings[],
1142 char * const user_info[], char * const user_env[])
1145 debug_decl(policy_open, SUDO_DEBUG_PCOMM)
1148 * Backwards compatibility for older API versions
1150 switch (plugin->u.generic->version) {
1151 case SUDO_API_MKVERSION(1, 0):
1152 case SUDO_API_MKVERSION(1, 1):
1153 rval = plugin->u.policy_1_0->open(plugin->u.io_1_0->version,
1154 sudo_conversation, _sudo_printf, settings, user_info, user_env);
1157 rval = plugin->u.policy->open(SUDO_API_VERSION, sudo_conversation,
1158 _sudo_printf, settings, user_info, user_env, plugin->options);
1161 debug_return_bool(rval);
1165 policy_close(struct plugin_container *plugin, int exit_status, int error)
1167 debug_decl(policy_close, SUDO_DEBUG_PCOMM)
1168 plugin->u.policy->close(exit_status, error);
1173 policy_show_version(struct plugin_container *plugin, int verbose)
1175 debug_decl(policy_show_version, SUDO_DEBUG_PCOMM)
1176 debug_return_bool(plugin->u.policy->show_version(verbose));
1180 policy_check(struct plugin_container *plugin, int argc, char * const argv[],
1181 char *env_add[], char **command_info[], char **argv_out[],
1182 char **user_env_out[])
1184 debug_decl(policy_check, SUDO_DEBUG_PCOMM)
1185 debug_return_bool(plugin->u.policy->check_policy(argc, argv, env_add,
1186 command_info, argv_out, user_env_out));
1190 policy_list(struct plugin_container *plugin, int argc, char * const argv[],
1191 int verbose, const char *list_user)
1193 debug_decl(policy_list, SUDO_DEBUG_PCOMM)
1194 if (plugin->u.policy->list == NULL) {
1195 warningx(_("policy plugin %s does not support listing privileges"),
1197 debug_return_bool(false);
1199 debug_return_bool(plugin->u.policy->list(argc, argv, verbose, list_user));
1203 policy_validate(struct plugin_container *plugin)
1205 debug_decl(policy_validate, SUDO_DEBUG_PCOMM)
1206 if (plugin->u.policy->validate == NULL) {
1207 warningx(_("policy plugin %s does not support the -v option"),
1209 debug_return_bool(false);
1211 debug_return_bool(plugin->u.policy->validate());
1215 policy_invalidate(struct plugin_container *plugin, int remove)
1217 debug_decl(policy_invalidate, SUDO_DEBUG_PCOMM)
1218 if (plugin->u.policy->invalidate == NULL) {
1219 errorx(1, _("policy plugin %s does not support the -k/-K options"),
1222 plugin->u.policy->invalidate(remove);
1227 policy_init_session(struct command_details *details)
1230 debug_decl(policy_init_session, SUDO_DEBUG_PCOMM)
1232 if (policy_plugin.u.policy->init_session) {
1234 * Backwards compatibility for older API versions
1236 switch (policy_plugin.u.generic->version) {
1237 case SUDO_API_MKVERSION(1, 0):
1238 case SUDO_API_MKVERSION(1, 1):
1239 rval = policy_plugin.u.policy_1_0->init_session(details->pw);
1242 rval = policy_plugin.u.policy->init_session(details->pw,
1246 debug_return_bool(rval);
1250 iolog_open(struct plugin_container *plugin, char * const settings[],
1251 char * const user_info[], char * const command_info[],
1252 int argc, char * const argv[], char * const user_env[])
1255 debug_decl(iolog_open, SUDO_DEBUG_PCOMM)
1258 * Backwards compatibility for older API versions
1260 switch (plugin->u.generic->version) {
1261 case SUDO_API_MKVERSION(1, 0):
1262 rval = plugin->u.io_1_0->open(plugin->u.io_1_0->version,
1263 sudo_conversation, _sudo_printf, settings, user_info, argc, argv,
1266 case SUDO_API_MKVERSION(1, 1):
1267 rval = plugin->u.io_1_1->open(plugin->u.io_1_1->version,
1268 sudo_conversation, _sudo_printf, settings, user_info,
1269 command_info, argc, argv, user_env);
1272 rval = plugin->u.io->open(SUDO_API_VERSION, sudo_conversation,
1273 _sudo_printf, settings, user_info, command_info,
1274 argc, argv, user_env, plugin->options);
1276 debug_return_bool(rval);
1280 iolog_close(struct plugin_container *plugin, int exit_status, int error)
1282 debug_decl(iolog_close, SUDO_DEBUG_PCOMM)
1283 plugin->u.io->close(exit_status, error);
1288 iolog_show_version(struct plugin_container *plugin, int verbose)
1290 debug_decl(iolog_show_version, SUDO_DEBUG_PCOMM)
1291 debug_return_bool(plugin->u.io->show_version(verbose));
1295 * Remove the specified I/O logging plugin from the io_plugins list.
1296 * Deregisters any hooks before unlinking, then frees the container.
1299 iolog_unlink(struct plugin_container *plugin)
1301 debug_decl(iolog_unlink, SUDO_DEBUG_PCOMM)
1303 /* Deregister hooks, if any. */
1304 if (plugin->u.io->version >= SUDO_API_MKVERSION(1, 2)) {
1305 if (plugin->u.io->deregister_hooks != NULL)
1306 plugin->u.io->deregister_hooks(SUDO_HOOK_VERSION,
1309 /* Remove from io_plugins list and free. */
1310 tq_remove(&io_plugins, plugin);