2 * Copyright (c) 2009-2011 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>
28 #ifdef HAVE_SYS_SELECT_H
29 # include <sys/select.h>
30 #endif /* HAVE_SYS_SELECT_H */
32 #include <sys/resource.h>
41 #endif /* STDC_HEADERS */
43 # if defined(HAVE_MEMORY_H) && !defined(STDC_HEADERS)
47 #endif /* HAVE_STRING_H */
50 #endif /* HAVE_STRINGS_H */
53 #endif /* HAVE_UNISTD_H */
61 #if TIME_WITH_SYS_TIME
67 #ifdef HAVE_LOGIN_CAP_H
68 # include <login_cap.h>
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 */
94 #include "sudo_plugin.h"
95 #include "sudo_plugin_int.h"
96 #include <sudo_usage.h>
101 struct plugin_container policy_plugin;
102 struct plugin_container_list io_plugins;
103 struct user_details user_details;
104 const char *list_user, *runas_user, *runas_group; /* extern for parse_args.c */
110 static void fix_fds(void);
111 static void disable_coredumps(void);
112 static char **get_user_info(struct user_details *);
113 static void command_info_to_details(char * const info[],
114 struct command_details *details);
115 static int policy_open(struct plugin_container *plugin, char * const settings[],
116 char * const user_info[], char * const user_env[]);
117 static void policy_close(struct plugin_container *plugin, int exit_status,
119 static int iolog_open(struct plugin_container *plugin, char * const settings[],
120 char * const user_info[], char * const command_details[],
121 int argc, char * const argv[], char * const user_env[]);
122 static void iolog_close(struct plugin_container *plugin, int exit_status,
125 /* Policy plugin convenience functions. */
126 static int policy_open(struct plugin_container *plugin, char * const settings[],
127 char * const user_info[], char * const user_env[]);
128 static void policy_close(struct plugin_container *plugin, int exit_status,
130 static int policy_show_version(struct plugin_container *plugin, int verbose);
131 static int policy_check(struct plugin_container *plugin, int argc,
132 char * const argv[], char *env_add[], char **command_info[],
133 char **argv_out[], char **user_env_out[]);
134 static int policy_list(struct plugin_container *plugin, int argc,
135 char * const argv[], int verbose, const char *list_user);
136 static int policy_validate(struct plugin_container *plugin);
137 static void policy_invalidate(struct plugin_container *plugin, int remove);
138 static int policy_init_session(struct plugin_container *plugin,
141 /* I/O log plugin convenience functions. */
142 static int iolog_open(struct plugin_container *plugin, char * const settings[],
143 char * const user_info[], char * const command_details[],
144 int argc, char * const argv[], char * const user_env[]);
145 static void iolog_close(struct plugin_container *plugin, int exit_status,
147 static int iolog_show_version(struct plugin_container *plugin, int verbose);
149 #if defined(RLIMIT_CORE) && !defined(SUDO_DEVEL)
150 static struct rlimit corelimit;
151 #endif /* RLIMIT_CORE && !SUDO_DEVEL */
152 #if defined(__linux__)
153 static struct rlimit nproclimit;
157 main(int argc, char *argv[], char *envp[])
159 int nargc, sudo_mode, exitcode = 0;
160 char **nargv, **settings, **env_add;
161 char **user_info, **command_info, **argv_out, **user_env_out;
162 struct plugin_container *plugin, *next;
163 struct command_details command_details;
166 #if defined(SUDO_DEVEL) && defined(__OpenBSD__)
167 extern char *malloc_options;
168 malloc_options = "AFGJPR";
171 #if !defined(HAVE_GETPROGNAME) && !defined(HAVE___PROGNAME)
173 setprogname(argv[0]);
176 #ifdef HAVE_SETLOCALE
177 setlocale(LC_ALL, "");
179 bindtextdomain(PACKAGE_NAME, LOCALEDIR);
180 textdomain(PACKAGE_NAME);
182 /* Must be done before we do any password lookups */
183 #if defined(HAVE_GETPRPWNAM) && defined(HAVE_SET_AUTH_PARAMETERS)
184 (void) set_auth_parameters(argc, argv);
185 # ifdef HAVE_INITPRIVS
188 #endif /* HAVE_GETPRPWNAM && HAVE_SET_AUTH_PARAMETERS */
191 errorx(1, _("must be setuid root"));
193 /* Reset signal mask, disable core dumps and make sure fds 0-2 are open. */
194 (void) sigemptyset(&mask);
195 (void) sigprocmask(SIG_SETMASK, &mask, NULL);
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 /* Parse command line arguments. */
204 sudo_mode = parse_args(argc, argv, &nargc, &nargv, &settings, &env_add);
205 sudo_debug(9, "sudo_mode %d", sudo_mode);
207 /* Print sudo version early, in case of plugin init failure. */
208 if (ISSET(sudo_mode, MODE_VERSION)) {
209 printf(_("Sudo version %s\n"), PACKAGE_VERSION);
210 if (user_details.uid == ROOT_UID)
211 (void) printf(_("Configure options: %s\n"), CONFIGURE_ARGS);
214 /* Read sudo.conf and load plugins. */
215 if (!sudo_load_plugins(_PATH_SUDO_CONF, &policy_plugin, &io_plugins))
216 errorx(1, _("fatal error, unable to load plugins"));
218 /* Open policy plugin. */
219 ok = policy_open(&policy_plugin, settings, user_info, envp);
224 errorx(1, _("unable to initialize policy plugin"));
227 switch (sudo_mode & MODE_MASK) {
229 policy_show_version(&policy_plugin, !user_details.uid);
230 tq_foreach_fwd(&io_plugins, plugin) {
231 ok = iolog_open(plugin, settings, user_info, NULL,
234 iolog_show_version(plugin, !user_details.uid);
238 case MODE_VALIDATE|MODE_INVALIDATE:
239 ok = policy_validate(&policy_plugin);
242 case MODE_INVALIDATE:
243 policy_invalidate(&policy_plugin, sudo_mode == MODE_KILL);
247 case MODE_CHECK|MODE_INVALIDATE:
249 case MODE_LIST|MODE_INVALIDATE:
250 ok = policy_list(&policy_plugin, nargc, nargv,
251 ISSET(sudo_mode, MODE_LONG_LIST), list_user);
255 ok = policy_check(&policy_plugin, nargc, nargv, env_add,
256 &command_info, &argv_out, &user_env_out);
257 sudo_debug(8, "policy plugin returns %d", ok);
261 exit(1); /* plugin printed error message */
263 /* Open I/O plugins once policy plugin succeeds. */
264 for (plugin = io_plugins.first; plugin != NULL; plugin = next) {
266 ok = iolog_open(plugin, settings, user_info,
267 command_info, nargc, nargv, envp);
272 /* I/O plugin asked to be disabled, remove from list. */
273 tq_remove(&io_plugins, plugin);
279 errorx(1, _("error initializing I/O plugin %s"),
283 command_info_to_details(command_info, &command_details);
284 command_details.argv = argv_out;
285 command_details.envp = user_env_out;
286 if (ISSET(sudo_mode, MODE_BACKGROUND))
287 SET(command_details.flags, CD_BACKGROUND);
288 /* Restore coredumpsize resource limit before running. */
289 #if defined(RLIMIT_CORE) && !defined(SUDO_DEVEL)
290 (void) setrlimit(RLIMIT_CORE, &corelimit);
291 #endif /* RLIMIT_CORE && !SUDO_DEVEL */
292 if (ISSET(command_details.flags, CD_SUDOEDIT)) {
293 exitcode = sudo_edit(&command_details);
295 exitcode = run_command(&command_details);
297 /* The close method was called by sudo_edit/run_command. */
300 errorx(1, _("unexpected sudo mode 0x%x"), sudo_mode);
306 * Ensure that stdin, stdout and stderr are open; set to /dev/null if not.
307 * Some operating systems do this automatically in the kernel or libc.
312 int miss[3], devnull = -1;
315 * stdin, stdout and stderr must be open; set them to /dev/null
316 * if they are closed.
318 miss[STDIN_FILENO] = fcntl(STDIN_FILENO, F_GETFL, 0) == -1;
319 miss[STDOUT_FILENO] = fcntl(STDOUT_FILENO, F_GETFL, 0) == -1;
320 miss[STDERR_FILENO] = fcntl(STDERR_FILENO, F_GETFL, 0) == -1;
321 if (miss[STDIN_FILENO] || miss[STDOUT_FILENO] || miss[STDERR_FILENO]) {
322 if ((devnull = open(_PATH_DEVNULL, O_RDWR, 0644)) == -1)
323 error(1, _("unable to open %s"), _PATH_DEVNULL);
324 if (miss[STDIN_FILENO] && dup2(devnull, STDIN_FILENO) == -1)
326 if (miss[STDOUT_FILENO] && dup2(devnull, STDOUT_FILENO) == -1)
328 if (miss[STDERR_FILENO] && dup2(devnull, STDERR_FILENO) == -1)
330 if (devnull > STDERR_FILENO)
336 * Allocate space for groups and fill in using getgrouplist()
337 * for when we cannot use getgroups().
340 fill_group_list(struct user_details *ud)
342 int maxgroups, tries, rval = -1;
344 #if defined(HAVE_SYSCONF) && defined(_SC_NGROUPS_MAX)
345 maxgroups = (int)sysconf(_SC_NGROUPS_MAX);
348 maxgroups = NGROUPS_MAX;
351 * It is possible to belong to more groups in the group database
352 * than NGROUPS_MAX. We start off with NGROUPS_MAX * 2 entries
353 * and double this as needed.
356 ud->ngroups = maxgroups;
357 for (tries = 0; tries < 10 && rval == -1; tries++) {
360 ud->groups = emalloc2(ud->ngroups, sizeof(GETGROUPS_T));
361 rval = getgrouplist(ud->username, ud->gid, ud->groups, &ud->ngroups);
367 get_user_groups(struct user_details *ud)
369 char *cp, *gid_list = NULL;
374 * Systems with mbr_check_membership() support more than NGROUPS_MAX
375 * groups so we cannot use getgroups().
378 #ifndef HAVE_MBR_CHECK_MEMBERSHIP
379 if ((ud->ngroups = getgroups(0, NULL)) > 0) {
380 ud->groups = emalloc2(ud->ngroups, sizeof(GETGROUPS_T));
381 if (getgroups(ud->ngroups, ud->groups) < 0) {
386 #endif /* HAVE_MBR_CHECK_MEMBERSHIP */
387 if (ud->groups == NULL) {
388 if (fill_group_list(ud) == -1)
389 error(1, _("unable to get group vector"));
393 * Format group list as a comma-separated string of gids.
395 glsize = sizeof("groups=") - 1 + (ud->ngroups * (MAX_UID_T_LEN + 1));
396 gid_list = emalloc(glsize);
397 memcpy(gid_list, "groups=", sizeof("groups=") - 1);
398 cp = gid_list + sizeof("groups=") - 1;
399 for (i = 0; i < ud->ngroups; i++) {
400 /* XXX - check rval */
401 len = snprintf(cp, glsize - (cp - gid_list), "%s%u",
402 i ? "," : "", (unsigned int)ud->groups[i]);
409 * Return user information as an array of name=value pairs.
410 * and fill in struct user_details (which shares the same strings).
413 get_user_info(struct user_details *ud)
416 char host[MAXHOSTNAMELEN];
417 char **user_info, *cp;
421 /* XXX - bound check number of entries */
422 user_info = emalloc2(32, sizeof(char *));
425 ud->euid = geteuid();
427 ud->egid = getegid();
429 pw = getpwuid(ud->uid);
431 errorx(1, _("unknown uid %u: who are you?"), (unsigned int)ud->uid);
433 user_info[i] = fmt_string("user", pw->pw_name);
434 if (user_info[i] == NULL)
435 errorx(1, _("unable to allocate memory"));
436 ud->username = user_info[i] + sizeof("user=") - 1;
438 /* Stash user's shell for use with the -s flag; don't pass to plugin. */
439 if ((ud->shell = getenv("SHELL")) == NULL || ud->shell[0] == '\0') {
440 ud->shell = pw->pw_shell[0] ? pw->pw_shell : _PATH_BSHELL;
442 ud->shell = estrdup(ud->shell);
444 easprintf(&user_info[++i], "uid=%u", (unsigned int)ud->uid);
445 easprintf(&user_info[++i], "euid=%u", (unsigned int)ud->euid);
446 easprintf(&user_info[++i], "gid=%u", (unsigned int)ud->gid);
447 easprintf(&user_info[++i], "egid=%u", (unsigned int)ud->egid);
449 if ((cp = get_user_groups(ud)) != NULL)
452 if (getcwd(cwd, sizeof(cwd)) != NULL) {
453 user_info[++i] = fmt_string("cwd", cwd);
454 if (user_info[i] == NULL)
455 errorx(1, _("unable to allocate memory"));
456 ud->cwd = user_info[i] + sizeof("cwd=") - 1;
459 if ((cp = ttyname(STDIN_FILENO)) || (cp = ttyname(STDOUT_FILENO)) ||
460 (cp = ttyname(STDERR_FILENO))) {
461 user_info[++i] = fmt_string("tty", cp);
462 if (user_info[i] == NULL)
463 errorx(1, _("unable to allocate memory"));
464 ud->tty = user_info[i] + sizeof("tty=") - 1;
467 if (gethostname(host, sizeof(host)) == 0)
468 host[sizeof(host) - 1] = '\0';
470 strlcpy(host, "localhost", sizeof(host));
471 user_info[++i] = fmt_string("host", host);
472 if (user_info[i] == NULL)
473 errorx(1, _("unable to allocate memory"));
474 ud->host = user_info[i] + sizeof("host=") - 1;
476 get_ttysize(&ud->ts_lines, &ud->ts_cols);
477 easprintf(&user_info[++i], "lines=%d", ud->ts_lines);
478 easprintf(&user_info[++i], "cols=%d", ud->ts_cols);
480 user_info[++i] = NULL;
486 * Convert a command_info array into a command_details structure.
489 command_info_to_details(char * const info[], struct command_details *details)
496 memset(details, 0, sizeof(*details));
497 details->closefrom = -1;
499 #define SET_STRING(s, n) \
500 if (strncmp(s, info[i], sizeof(s) - 1) == 0 && info[i][sizeof(s) - 1]) { \
501 details->n = info[i] + sizeof(s) - 1; \
505 for (i = 0; info[i] != NULL; i++) {
506 sudo_debug(9, "command info: %s", info[i]);
507 switch (info[i][0]) {
509 SET_STRING("chroot=", chroot)
510 SET_STRING("command=", command)
511 SET_STRING("cwd=", cwd)
512 if (strncmp("closefrom=", info[i], sizeof("closefrom=") - 1) == 0) {
513 cp = info[i] + sizeof("closefrom=") - 1;
517 lval = strtol(cp, &ep, 0);
518 if (*cp != '\0' && *ep == '\0' &&
520 (lval == LONG_MAX || lval == LONG_MIN)) &&
521 lval < INT_MAX && lval > INT_MIN) {
522 details->closefrom = (int)lval;
528 SET_STRING("login_class=", login_class)
531 /* XXX - bounds check -NZERO to NZERO (inclusive). */
532 if (strncmp("nice=", info[i], sizeof("nice=") - 1) == 0) {
533 cp = info[i] + sizeof("nice=") - 1;
537 lval = strtol(cp, &ep, 0);
538 if (*cp != '\0' && *ep == '\0' &&
540 (lval == LONG_MAX || lval == LONG_MIN)) &&
541 lval < INT_MAX && lval > INT_MIN) {
542 details->priority = (int)lval;
543 SET(details->flags, CD_SET_PRIORITY);
547 if (strncmp("noexec=", info[i], sizeof("noexec=") - 1) == 0) {
548 if (atobool(info[i] + sizeof("noexec=") - 1) == TRUE)
549 SET(details->flags, CD_NOEXEC);
552 #ifdef _PATH_SUDO_NOEXEC
553 /* XXX - deprecated */
554 if (strncmp("noexec_file=", info[i], sizeof("noexec_file=") - 1) == 0) {
555 noexec_path = info[i] + sizeof("noexec_file=") - 1;
558 #endif /* _PATH_SUDO_NOEXEC */
561 if (strncmp("preserve_groups=", info[i], sizeof("preserve_groups=") - 1) == 0) {
562 if (atobool(info[i] + sizeof("preserve_groups=") - 1) == TRUE)
563 SET(details->flags, CD_PRESERVE_GROUPS);
568 if (strncmp("runas_egid=", info[i], sizeof("runas_egid=") - 1) == 0) {
569 cp = info[i] + sizeof("runas_egid=") - 1;
573 ulval = strtoul(cp, &ep, 0);
574 if (*cp != '\0' && *ep == '\0' &&
575 (errno != ERANGE || ulval != ULONG_MAX)) {
576 details->egid = (gid_t)ulval;
577 SET(details->flags, CD_SET_EGID);
581 if (strncmp("runas_euid=", info[i], sizeof("runas_euid=") - 1) == 0) {
582 cp = info[i] + sizeof("runas_euid=") - 1;
586 ulval = strtoul(cp, &ep, 0);
587 if (*cp != '\0' && *ep == '\0' &&
588 (errno != ERANGE || ulval != ULONG_MAX)) {
589 details->euid = (uid_t)ulval;
590 SET(details->flags, CD_SET_EUID);
594 if (strncmp("runas_gid=", info[i], sizeof("runas_gid=") - 1) == 0) {
595 cp = info[i] + sizeof("runas_gid=") - 1;
599 ulval = strtoul(cp, &ep, 0);
600 if (*cp != '\0' && *ep == '\0' &&
601 (errno != ERANGE || ulval != ULONG_MAX)) {
602 details->gid = (gid_t)ulval;
603 SET(details->flags, CD_SET_GID);
607 if (strncmp("runas_groups=", info[i], sizeof("runas_groups=") - 1) == 0) {
610 /* count groups, alloc and fill in */
611 cp = info[i] + sizeof("runas_groups=") - 1;
616 if ((cp = strchr(cp, ',')) == NULL)
620 if (details->ngroups != 0) {
622 emalloc2(details->ngroups, sizeof(GETGROUPS_T));
623 cp = info[i] + sizeof("runas_groups=") - 1;
624 for (j = 0; j < details->ngroups;) {
626 ulval = strtoul(cp, &ep, 0);
627 if (*cp == '\0' || (*ep != ',' && *ep != '\0') ||
628 (ulval == ULONG_MAX && errno == ERANGE)) {
631 details->groups[j++] = (gid_t)ulval;
634 details->ngroups = j;
638 if (strncmp("runas_uid=", info[i], sizeof("runas_uid=") - 1) == 0) {
639 cp = info[i] + sizeof("runas_uid=") - 1;
643 ulval = strtoul(cp, &ep, 0);
644 if (*cp != '\0' && *ep == '\0' &&
645 (errno != ERANGE || ulval != ULONG_MAX)) {
646 details->uid = (uid_t)ulval;
647 SET(details->flags, CD_SET_UID);
653 SET_STRING("selinux_role=", selinux_role)
654 SET_STRING("selinux_type=", selinux_type)
655 if (strncmp("set_utmp=", info[i], sizeof("set_utmp=") - 1) == 0) {
656 if (atobool(info[i] + sizeof("set_utmp=") - 1) == TRUE)
657 SET(details->flags, CD_SET_UTMP);
660 if (strncmp("sudoedit=", info[i], sizeof("sudoedit=") - 1) == 0) {
661 if (atobool(info[i] + sizeof("sudoedit=") - 1) == TRUE)
662 SET(details->flags, CD_SUDOEDIT);
667 if (strncmp("timeout=", info[i], sizeof("timeout=") - 1) == 0) {
668 cp = info[i] + sizeof("timeout=") - 1;
672 lval = strtol(cp, &ep, 0);
673 if (*cp != '\0' && *ep == '\0' &&
675 (lval == LONG_MAX || lval == LONG_MIN)) &&
676 lval <= INT_MAX && lval >= 0) {
677 details->timeout = (int)lval;
678 SET(details->flags, CD_SET_TIMEOUT);
684 if (strncmp("umask=", info[i], sizeof("umask=") - 1) == 0) {
685 cp = info[i] + sizeof("umask=") - 1;
689 ulval = strtoul(cp, &ep, 8);
690 if (*cp != '\0' && *ep == '\0' &&
691 (errno != ERANGE || ulval != ULONG_MAX)) {
692 details->umask = (uid_t)ulval;
693 SET(details->flags, CD_SET_UMASK);
697 if (strncmp("use_pty=", info[i], sizeof("use_pty=") - 1) == 0) {
698 if (atobool(info[i] + sizeof("use_pty=") - 1) == TRUE)
699 SET(details->flags, CD_USE_PTY);
702 SET_STRING("utmp_user=", utmp_user)
707 if (!ISSET(details->flags, CD_SET_EUID))
708 details->euid = details->uid;
711 if (details->selinux_role != NULL && is_selinux_enabled() > 0)
712 SET(details->flags, CD_RBAC_ENABLED);
717 * Disable core dumps to avoid dropping a core with user password in it.
718 * We will reset this limit before executing the command.
719 * Not all operating systems disable core dumps for setuid processes.
722 disable_coredumps(void)
724 #if defined(__linux__) || (defined(RLIMIT_CORE) && !defined(SUDO_DEVEL))
728 #if defined(__linux__)
730 * Unlimit the number of processes since Linux's setuid() will
731 * apply resource limits when changing uid and return EAGAIN if
732 * nproc would be violated by the uid switch.
734 (void) getrlimit(RLIMIT_NPROC, &nproclimit);
735 rl.rlim_cur = rl.rlim_max = RLIM_INFINITY;
736 if (setrlimit(RLIMIT_NPROC, &rl)) {
737 memcpy(&rl, &nproclimit, sizeof(struct rlimit));
738 rl.rlim_cur = rl.rlim_max;
739 (void)setrlimit(RLIMIT_NPROC, &rl);
741 #endif /* __linux__ */
742 #if defined(RLIMIT_CORE) && !defined(SUDO_DEVEL)
744 * Turn off core dumps.
746 (void) getrlimit(RLIMIT_CORE, &corelimit);
747 memcpy(&rl, &corelimit, sizeof(struct rlimit));
749 (void) setrlimit(RLIMIT_CORE, &rl);
750 #endif /* RLIMIT_CORE && !SUDO_DEVEL */
753 #ifdef HAVE_PROJECT_H
755 set_project(struct passwd *pw)
758 char buf[PROJECT_BUFSZ];
762 * Collect the default project for the user and settaskid
765 if (getdefaultproj(pw->pw_name, &proj, buf, sizeof(buf)) != NULL) {
766 errval = setproject(proj.pj_name, pw->pw_name, TASK_NORMAL);
770 case SETPROJ_ERR_TASK:
773 warningx(_("resource control limit has been reached"));
776 warningx(_("user \"%s\" is not a member of project \"%s\""),
777 pw->pw_name, proj.pj_name);
780 warningx(_("the invoking task is final"));
783 warningx(_("could not join project \"%s\""), proj.pj_name);
785 case SETPROJ_ERR_POOL:
788 warningx(_("no resource pool accepting default bindings "
789 "exists for project \"%s\""), proj.pj_name);
792 warningx(_("specified resource pool does not exist for "
793 "project \"%s\""), proj.pj_name);
796 warningx(_("could not bind to default resource pool for "
797 "project \"%s\""), proj.pj_name);
802 warningx(_("setproject failed for project \"%s\""), proj.pj_name);
804 warningx(_("warning, resource control assignment failed for "
805 "project \"%s\""), proj.pj_name);
809 warning("getdefaultproj");
813 #endif /* HAVE_PROJECT_H */
816 * Disable execution of child processes in the command we are about
817 * to run. On systems with privilege sets, we can remove the exec
818 * privilege. On other systems we use LD_PRELOAD and the like.
821 disable_execute(struct command_details *details)
823 #ifdef _PATH_SUDO_NOEXEC
824 char *cp, **ev, **nenvp;
825 int env_len = 0, env_size = 128;
826 #endif /* _PATH_SUDO_NOEXEC */
829 /* Solaris privileges, remove PRIV_PROC_EXEC post-execve. */
830 if (priv_set(PRIV_OFF, PRIV_LIMIT, "PRIV_PROC_EXEC", NULL) == 0)
832 warning(_("unable to remove PRIV_PROC_EXEC from PRIV_LIMIT"));
833 #endif /* HAVE_PRIV_SET */
835 #ifdef _PATH_SUDO_NOEXEC
836 nenvp = emalloc2(env_size, sizeof(char *));
837 for (ev = details->envp; *ev != NULL; ev++) {
838 if (env_len + 2 > env_size) {
840 nenvp = erealloc3(nenvp, env_size, sizeof(char *));
843 * Prune out existing preloaded libraries.
844 * XXX - should save and append instead of replacing.
846 # if defined(__darwin__) || defined(__APPLE__)
847 if (strncmp(*ev, "DYLD_INSERT_LIBRARIES=", sizeof("DYLD_INSERT_LIBRARIES=") - 1) == 0)
849 if (strncmp(*ev, "DYLD_FORCE_FLAT_NAMESPACE=", sizeof("DYLD_INSERT_LIBRARIES=") - 1) == 0)
851 # elif defined(__osf__) || defined(__sgi)
852 if (strncmp(*ev, "_RLD_LIST=", sizeof("_RLD_LIST=") - 1) == 0)
855 if (strncmp(*ev, "LDR_PRELOAD=", sizeof("LDR_PRELOAD=") - 1) == 0)
858 if (strncmp(*ev, "LD_PRELOAD=", sizeof("LD_PRELOAD=") - 1) == 0)
861 nenvp[env_len++] = *ev;
865 * Preload a noexec file? For a list of LD_PRELOAD-alikes, see
866 * http://www.fortran-2000.com/ArnaudRecipes/sharedlib.html
867 * XXX - need to support 32-bit and 64-bit variants
869 # if defined(__darwin__) || defined(__APPLE__)
870 nenvp[env_len++] = "DYLD_FORCE_FLAT_NAMESPACE=";
871 cp = fmt_string("DYLD_INSERT_LIBRARIES", noexec_path);
872 # elif defined(__osf__) || defined(__sgi)
873 easprintf(&cp, "_RLD_LIST=%s:DEFAULT", noexec_path);
875 cp = fmt_string("LDR_PRELOAD", noexec_path);
877 cp = fmt_string("LD_PRELOAD", noexec_path);
881 nenvp[env_len++] = cp;
882 nenvp[env_len] = NULL;
884 details->envp = nenvp;
885 #endif /* _PATH_SUDO_NOEXEC */
889 * Setup the execution environment immediately prior to the call to execve()
890 * Returns TRUE on success and FALSE on failure.
893 exec_setup(struct command_details *details, const char *ptyname, int ptyfd)
898 #ifdef HAVE_SETAUTHDB
899 aix_setauthdb(IDtouser(details->euid));
901 pw = getpwuid(details->euid);
902 #ifdef HAVE_SETAUTHDB
907 * Call policy plugin's session init before other setup occurs.
908 * The session init code is expected to print an error as needed.
910 if (policy_init_session(&policy_plugin, pw) != TRUE)
914 if (ISSET(details->flags, CD_RBAC_ENABLED)) {
915 if (selinux_setup(details->selinux_role, details->selinux_type,
916 ptyname ? ptyname : user_details.tty, ptyfd) == -1)
922 #ifdef HAVE_PROJECT_H
925 #ifdef HAVE_GETUSERATTR
926 aix_prep_user(pw->pw_name, ptyname ? ptyname : user_details.tty);
928 #ifdef HAVE_LOGIN_CAP_H
929 if (details->login_class) {
934 * We only use setusercontext() to set the nice value and rlimits.
936 lc = login_getclass((char *)details->login_class);
938 warningx(_("unknown login class %s"), details->login_class);
942 flags = LOGIN_SETRESOURCES|LOGIN_SETPRIORITY;
943 if (setusercontext(lc, pw, pw->pw_uid, flags)) {
944 if (pw->pw_uid != ROOT_UID) {
945 warning(_("unable to set user context"));
948 warning(_("unable to set user context"));
951 #endif /* HAVE_LOGIN_CAP_H */
955 * Set groups, including supplementary group vector.
958 if (ISSET(details->flags, CD_SET_EGID) && setegid(details->egid)) {
959 warning(_("unable to set effective gid to runas gid %u"),
960 (unsigned int)details->egid);
964 if (ISSET(details->flags, CD_SET_GID) && setgid(details->gid)) {
965 warning(_("unable to set gid to runas gid %u"),
966 (unsigned int)details->gid);
970 if (!ISSET(details->flags, CD_PRESERVE_GROUPS)) {
971 if (details->ngroups >= 0) {
972 if (sudo_setgroups(details->ngroups, details->groups) < 0) {
973 warning(_("unable to set supplementary group IDs"));
979 if (ISSET(details->flags, CD_SET_PRIORITY)) {
980 if (setpriority(PRIO_PROCESS, 0, details->priority) != 0) {
981 warning(_("unable to set process priority"));
985 if (ISSET(details->flags, CD_SET_UMASK))
986 (void) umask(details->umask);
987 if (details->chroot) {
988 if (chroot(details->chroot) != 0 || chdir("/") != 0) {
989 warning(_("unable to change root to %s"), details->chroot);
994 if (ISSET(details->flags, CD_NOEXEC))
995 disable_execute(details);
997 #ifdef HAVE_SETRESUID
998 if (setresuid(details->uid, details->euid, details->euid) != 0) {
999 warning(_("unable to change to runas uid (%u, %u)"), details->uid,
1004 if (setreuid(details->uid, details->euid) != 0) {
1005 warning(_("unable to change to runas uid (%u, %u)"),
1006 (unsigned int)details->uid, (unsigned int)details->euid);
1010 if (seteuid(details->euid) != 0 || setuid(details->euid) != 0) {
1011 warning(_("unable to change to runas uid (%u, %u)"), details->uid,
1015 #endif /* !HAVE_SETRESUID && !HAVE_SETREUID */
1018 * Only change cwd if we have chroot()ed or the policy modules
1019 * specifies a different cwd. Must be done after uid change.
1022 if (details->chroot || strcmp(details->cwd, user_details.cwd) != 0) {
1023 /* Note: cwd is relative to the new root, if any. */
1024 if (chdir(details->cwd) != 0) {
1025 warning(_("unable to change directory to %s"), details->cwd);
1032 * Restore nproc resource limit if pam_limits didn't do it for us.
1033 * We must do this *after* the uid change to avoid potential EAGAIN
1036 #if defined(__linux__)
1039 if (getrlimit(RLIMIT_NPROC, &rl) == 0) {
1040 if (rl.rlim_cur == RLIM_INFINITY && rl.rlim_max == RLIM_INFINITY)
1041 (void) setrlimit(RLIMIT_NPROC, &nproclimit);
1053 * Run the command and wait for it to complete.
1056 run_command(struct command_details *details)
1058 struct plugin_container *plugin;
1059 struct command_status cstat;
1062 cstat.type = CMD_INVALID;
1065 sudo_execve(details, &cstat);
1067 switch (cstat.type) {
1069 /* exec_setup() or execve() returned an error. */
1070 sudo_debug(9, "calling policy close with errno");
1071 policy_close(&policy_plugin, 0, cstat.val);
1072 tq_foreach_fwd(&io_plugins, plugin) {
1073 sudo_debug(9, "calling I/O close with errno");
1074 iolog_close(plugin, 0, cstat.val);
1079 /* Command ran, exited or was killed. */
1080 sudo_debug(9, "calling policy close with wait status");
1081 policy_close(&policy_plugin, cstat.val, 0);
1082 tq_foreach_fwd(&io_plugins, plugin) {
1083 sudo_debug(9, "calling I/O close with wait status");
1084 iolog_close(plugin, cstat.val, 0);
1086 if (WIFEXITED(cstat.val))
1087 exitcode = WEXITSTATUS(cstat.val);
1088 else if (WIFSIGNALED(cstat.val))
1089 exitcode = WTERMSIG(cstat.val) | 128;
1092 warningx(_("unexpected child termination condition: %d"), cstat.type);
1099 policy_open(struct plugin_container *plugin, char * const settings[],
1100 char * const user_info[], char * const user_env[])
1102 return plugin->u.policy->open(SUDO_API_VERSION, sudo_conversation,
1103 _sudo_printf, settings, user_info, user_env);
1107 policy_close(struct plugin_container *plugin, int exit_status, int error)
1109 plugin->u.policy->close(exit_status, error);
1113 policy_show_version(struct plugin_container *plugin, int verbose)
1115 return plugin->u.policy->show_version(verbose);
1119 policy_check(struct plugin_container *plugin, int argc, char * const argv[],
1120 char *env_add[], char **command_info[], char **argv_out[],
1121 char **user_env_out[])
1123 return plugin->u.policy->check_policy(argc, argv, env_add, command_info,
1124 argv_out, user_env_out);
1128 policy_list(struct plugin_container *plugin, int argc, char * const argv[],
1129 int verbose, const char *list_user)
1131 if (plugin->u.policy->list == NULL) {
1132 warningx(_("policy plugin %s does not support listing privileges"),
1136 return plugin->u.policy->list(argc, argv, verbose, list_user);
1140 policy_validate(struct plugin_container *plugin)
1142 if (plugin->u.policy->validate == NULL) {
1143 warningx(_("policy plugin %s does not support the -v option"),
1147 return plugin->u.policy->validate();
1151 policy_invalidate(struct plugin_container *plugin, int remove)
1153 if (plugin->u.policy->invalidate == NULL) {
1154 errorx(1, _("policy plugin %s does not support the -k/-K options"),
1157 plugin->u.policy->invalidate(remove);
1161 policy_init_session(struct plugin_container *plugin, struct passwd *pwd)
1163 if (plugin->u.policy->init_session)
1164 return plugin->u.policy->init_session(pwd);
1169 iolog_open(struct plugin_container *plugin, char * const settings[],
1170 char * const user_info[], char * const command_info[],
1171 int argc, char * const argv[], char * const user_env[])
1176 * Backwards compatibility for API major 1, minor 0
1178 switch (plugin->u.generic->version) {
1179 case SUDO_API_MKVERSION(1, 0):
1180 rval = plugin->u.io_1_0->open(plugin->u.io_1_0->version,
1181 sudo_conversation, _sudo_printf, settings, user_info, argc, argv,
1185 rval = plugin->u.io->open(SUDO_API_VERSION, sudo_conversation,
1186 _sudo_printf, settings, user_info, command_info, argc, argv,
1193 iolog_close(struct plugin_container *plugin, int exit_status, int error)
1195 plugin->u.io->close(exit_status, error);
1199 iolog_show_version(struct plugin_container *plugin, int verbose)
1201 return plugin->u.io->show_version(verbose);
1205 * Simple debugging/logging.
1208 sudo_debug(int level, const char *fmt, ...)
1213 if (level > debug_level)
1216 /* Backet fmt with program name and a newline to make it a single write */
1217 easprintf(&fmt2, "%s: %s\n", getprogname(), fmt);
1219 vfprintf(stderr, fmt2, ap);