Imported Upstream version 1.8.3p2
[debian/sudo] / src / sudo.c
1 /*
2  * Copyright (c) 2009-2011 Todd C. Miller <Todd.Miller@courtesan.com>
3  *
4  * Permission to use, copy, modify, and distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15  */
16
17 #ifdef __TANDEM
18 # include <floss.h>
19 #endif
20
21 #include <config.h>
22
23 #include <sys/types.h>
24 #include <sys/param.h>
25 #include <sys/stat.h>
26 #include <sys/wait.h>
27 #include <sys/socket.h>
28 #ifdef HAVE_SYS_SELECT_H
29 # include <sys/select.h>
30 #endif /* HAVE_SYS_SELECT_H */
31 #include <sys/time.h>
32 #include <sys/resource.h>
33 #include <stdio.h>
34 #ifdef STDC_HEADERS
35 # include <stdlib.h>
36 # include <stddef.h>
37 #else
38 # ifdef HAVE_STDLIB_H
39 #  include <stdlib.h>
40 # endif
41 #endif /* STDC_HEADERS */
42 #ifdef HAVE_STRING_H
43 # if defined(HAVE_MEMORY_H) && !defined(STDC_HEADERS)
44 #  include <memory.h>
45 # endif
46 # include <string.h>
47 #endif /* HAVE_STRING_H */
48 #ifdef HAVE_STRINGS_H
49 # include <strings.h>
50 #endif /* HAVE_STRINGS_H */
51 #ifdef HAVE_UNISTD_H
52 # include <unistd.h>
53 #endif /* HAVE_UNISTD_H */
54 #include <ctype.h>
55 #include <errno.h>
56 #include <fcntl.h>
57 #include <limits.h>
58 #include <signal.h>
59 #include <grp.h>
60 #include <pwd.h>
61 #if TIME_WITH_SYS_TIME
62 # include <time.h>
63 #endif
64 #ifdef HAVE_SETLOCALE
65 # include <locale.h>
66 #endif
67 #ifdef HAVE_LOGIN_CAP_H
68 # include <login_cap.h>
69 #endif
70 #ifdef HAVE_PROJECT_H
71 # include <project.h>
72 # include <sys/task.h>
73 #endif
74 #ifdef HAVE_SELINUX
75 # include <selinux/selinux.h>
76 #endif
77 #ifdef HAVE_SETAUTHDB
78 # include <usersec.h>
79 #endif /* HAVE_SETAUTHDB */
80 #if defined(HAVE_GETPRPWNAM) && defined(HAVE_SET_AUTH_PARAMETERS)
81 # ifdef __hpux
82 #  undef MAXINT
83 #  include <hpsecurity.h>
84 # else
85 #  include <sys/security.h>
86 # endif /* __hpux */
87 # include <prot.h>
88 #endif /* HAVE_GETPRPWNAM && HAVE_SET_AUTH_PARAMETERS */
89 #ifdef HAVE_PRIV_SET
90 # include <priv.h>
91 #endif
92
93 #include "sudo.h"
94 #include "sudo_plugin.h"
95 #include "sudo_plugin_int.h"
96 #include <sudo_usage.h>
97
98 /*
99  * Local variables
100  */
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 */
105 int debug_level;
106
107 /*
108  * Local functions
109  */
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,
118     int error);
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,
123     int error);
124
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,
129     int error);
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,
139     struct passwd *pwd);
140
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,
146     int error);
147 static int iolog_show_version(struct plugin_container *plugin, int verbose);
148
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;
154 #endif
155
156 int
157 main(int argc, char *argv[], char *envp[])
158 {
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;
164     sigset_t mask;
165     int ok;
166 #if defined(SUDO_DEVEL) && defined(__OpenBSD__)
167     extern char *malloc_options;
168     malloc_options = "AFGJPR";
169 #endif
170
171 #if !defined(HAVE_GETPROGNAME) && !defined(HAVE___PROGNAME)
172     if (argc > 0)
173         setprogname(argv[0]);
174 #endif
175
176 #ifdef HAVE_SETLOCALE
177     setlocale(LC_ALL, "");
178 #endif
179     bindtextdomain(PACKAGE_NAME, LOCALEDIR);
180     textdomain(PACKAGE_NAME);
181
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
186     initprivs();
187 # endif
188 #endif /* HAVE_GETPRPWNAM && HAVE_SET_AUTH_PARAMETERS */
189
190     if (geteuid() != 0)
191         errorx(1, _("must be setuid root"));
192
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);
196     disable_coredumps();
197     fix_fds();
198
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);
202
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);
206
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);
212     }
213
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"));
217
218     /* Open policy plugin. */
219     ok = policy_open(&policy_plugin, settings, user_info, envp);
220     if (ok != TRUE) {
221         if (ok == -2)
222             usage(1);
223         else
224             errorx(1, _("unable to initialize policy plugin"));
225     }
226
227     switch (sudo_mode & MODE_MASK) {
228         case MODE_VERSION:
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,
232                     nargc, nargv, envp);
233                 if (ok == TRUE)
234                     iolog_show_version(plugin, !user_details.uid);
235             }
236             break;
237         case MODE_VALIDATE:
238         case MODE_VALIDATE|MODE_INVALIDATE:
239             ok = policy_validate(&policy_plugin);
240             exit(ok != TRUE);
241         case MODE_KILL:
242         case MODE_INVALIDATE:
243             policy_invalidate(&policy_plugin, sudo_mode == MODE_KILL);
244             exit(0);
245             break;
246         case MODE_CHECK:
247         case MODE_CHECK|MODE_INVALIDATE:
248         case MODE_LIST:
249         case MODE_LIST|MODE_INVALIDATE:
250             ok = policy_list(&policy_plugin, nargc, nargv,
251                 ISSET(sudo_mode, MODE_LONG_LIST), list_user);
252             exit(ok != TRUE);
253         case MODE_EDIT:
254         case MODE_RUN:
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);
258             if (ok != TRUE) {
259                 if (ok == -2)
260                     usage(1);
261                 exit(1); /* plugin printed error message */
262             }
263             /* Open I/O plugins once policy plugin succeeds. */
264             for (plugin = io_plugins.first; plugin != NULL; plugin = next) {
265                 next = plugin->next;
266                 ok = iolog_open(plugin, settings, user_info,
267                     command_info, nargc, nargv, envp);
268                 switch (ok) {
269                 case TRUE:
270                     break;
271                 case FALSE:
272                     /* I/O plugin asked to be disabled, remove from list. */
273                     tq_remove(&io_plugins, plugin);
274                     break;
275                 case -2:
276                     usage(1);
277                     break;
278                 default:
279                     errorx(1, _("error initializing I/O plugin %s"),
280                         plugin->name);
281                 }
282             }
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);
294             } else {
295                 exitcode = run_command(&command_details);
296             }
297             /* The close method was called by sudo_edit/run_command. */
298             break;
299         default:
300             errorx(1, _("unexpected sudo mode 0x%x"), sudo_mode);
301     }
302     exit(exitcode);
303 }
304
305 /*
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.
308  */
309 static void
310 fix_fds(void)
311 {
312     int miss[3], devnull = -1;
313
314     /*
315      * stdin, stdout and stderr must be open; set them to /dev/null
316      * if they are closed.
317      */
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)
325             error(1, "dup2");
326         if (miss[STDOUT_FILENO] && dup2(devnull, STDOUT_FILENO) == -1)
327             error(1, "dup2");
328         if (miss[STDERR_FILENO] && dup2(devnull, STDERR_FILENO) == -1)
329             error(1, "dup2");
330         if (devnull > STDERR_FILENO)
331             close(devnull);
332     }
333 }
334
335 /*
336  * Allocate space for groups and fill in using getgrouplist()
337  * for when we cannot use getgroups().
338  */
339 static int
340 fill_group_list(struct user_details *ud)
341 {
342     int maxgroups, tries, rval = -1;
343
344 #if defined(HAVE_SYSCONF) && defined(_SC_NGROUPS_MAX)
345     maxgroups = (int)sysconf(_SC_NGROUPS_MAX);
346     if (maxgroups < 0)
347 #endif
348         maxgroups = NGROUPS_MAX;
349
350     /*
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.
354      */
355     ud->groups = NULL;
356     ud->ngroups = maxgroups;
357     for (tries = 0; tries < 10 && rval == -1; tries++) {
358         ud->ngroups *= 2;
359         efree(ud->groups);
360         ud->groups = emalloc2(ud->ngroups, sizeof(GETGROUPS_T));
361         rval = getgrouplist(ud->username, ud->gid, ud->groups, &ud->ngroups);
362     }
363     return rval;
364 }
365
366 static char *
367 get_user_groups(struct user_details *ud)
368 {
369     char *cp, *gid_list = NULL;
370     size_t glsize;
371     int i, len;
372
373     /*
374      * Systems with mbr_check_membership() support more than NGROUPS_MAX
375      * groups so we cannot use getgroups().
376      */
377     ud->groups = NULL;
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) {
382             efree(ud->groups);
383             ud->groups = NULL;
384         }
385     }
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"));
390     }
391
392     /*
393      * Format group list as a comma-separated string of gids.
394      */
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]);
403         cp += len;
404     }
405     return gid_list;
406 }
407
408 /*
409  * Return user information as an array of name=value pairs.
410  * and fill in struct user_details (which shares the same strings).
411  */
412 static char **
413 get_user_info(struct user_details *ud)
414 {
415     char cwd[PATH_MAX];
416     char host[MAXHOSTNAMELEN];
417     char **user_info, *cp;
418     struct passwd *pw;
419     int i = 0;
420
421     /* XXX - bound check number of entries */
422     user_info = emalloc2(32, sizeof(char *));
423
424     ud->uid = getuid();
425     ud->euid = geteuid();
426     ud->gid = getgid();
427     ud->egid = getegid();
428
429     pw = getpwuid(ud->uid);
430     if (pw == NULL)
431         errorx(1, _("unknown uid %u: who are you?"), (unsigned int)ud->uid);
432
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;
437
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;
441     }
442     ud->shell = estrdup(ud->shell);
443
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);
448
449     if ((cp = get_user_groups(ud)) != NULL)
450         user_info[++i] = cp;
451
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;
457     }
458
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;
465     }
466
467     if (gethostname(host, sizeof(host)) == 0)
468         host[sizeof(host) - 1] = '\0';
469     else
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;
475
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);
479
480     user_info[++i] = NULL;
481
482     return user_info;
483 }
484
485 /*
486  * Convert a command_info array into a command_details structure.
487  */
488 static void
489 command_info_to_details(char * const info[], struct command_details *details)
490 {
491     int i;
492     long lval;
493     unsigned long ulval;
494     char *cp, *ep;
495
496     memset(details, 0, sizeof(*details));
497     details->closefrom = -1;
498
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; \
502         break; \
503     }
504
505     for (i = 0; info[i] != NULL; i++) {
506         sudo_debug(9, "command info: %s", info[i]);
507         switch (info[i][0]) {
508             case 'c':
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;
514                     if (*cp == '\0')
515                         break;
516                     errno = 0;
517                     lval = strtol(cp, &ep, 0);
518                     if (*cp != '\0' && *ep == '\0' &&
519                         !(errno == ERANGE &&
520                         (lval == LONG_MAX || lval == LONG_MIN)) &&
521                         lval < INT_MAX && lval > INT_MIN) {
522                         details->closefrom = (int)lval;
523                     }
524                     break;
525                 }
526                 break;
527             case 'l':
528                 SET_STRING("login_class=", login_class)
529                 break;
530             case 'n':
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;
534                     if (*cp == '\0')
535                         break;
536                     errno = 0;
537                     lval = strtol(cp, &ep, 0);
538                     if (*cp != '\0' && *ep == '\0' &&
539                         !(errno == ERANGE &&
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);
544                     }
545                     break;
546                 }
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);
550                     break;
551                 }
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;
556                     break;
557                 }
558 #endif /* _PATH_SUDO_NOEXEC */
559                 break;
560             case 'p':
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);
564                     break;
565                 }
566                 break;
567             case 'r':
568                 if (strncmp("runas_egid=", info[i], sizeof("runas_egid=") - 1) == 0) {
569                     cp = info[i] + sizeof("runas_egid=") - 1;
570                     if (*cp == '\0')
571                         break;
572                     errno = 0;
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);
578                     }
579                     break;
580                 }
581                 if (strncmp("runas_euid=", info[i], sizeof("runas_euid=") - 1) == 0) {
582                     cp = info[i] + sizeof("runas_euid=") - 1;
583                     if (*cp == '\0')
584                         break;
585                     errno = 0;
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);
591                     }
592                     break;
593                 }
594                 if (strncmp("runas_gid=", info[i], sizeof("runas_gid=") - 1) == 0) {
595                     cp = info[i] + sizeof("runas_gid=") - 1;
596                     if (*cp == '\0')
597                         break;
598                     errno = 0;
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);
604                     }
605                     break;
606                 }
607                 if (strncmp("runas_groups=", info[i], sizeof("runas_groups=") - 1) == 0) {
608                     int j;
609
610                     /* count groups, alloc and fill in */
611                     cp = info[i] + sizeof("runas_groups=") - 1;
612                     if (*cp == '\0')
613                         break;
614                     for (;;) {
615                         details->ngroups++;
616                         if ((cp = strchr(cp, ',')) == NULL)
617                             break;
618                         cp++;
619                     }
620                     if (details->ngroups != 0) {
621                         details->groups =
622                             emalloc2(details->ngroups, sizeof(GETGROUPS_T));
623                         cp = info[i] + sizeof("runas_groups=") - 1;
624                         for (j = 0; j < details->ngroups;) {
625                             errno = 0;
626                             ulval = strtoul(cp, &ep, 0);
627                             if (*cp == '\0' || (*ep != ',' && *ep != '\0') ||
628                                 (ulval == ULONG_MAX && errno == ERANGE)) {
629                                 break;
630                             }
631                             details->groups[j++] = (gid_t)ulval;
632                             cp = ep + 1;
633                         }
634                         details->ngroups = j;
635                     }
636                     break;
637                 }
638                 if (strncmp("runas_uid=", info[i], sizeof("runas_uid=") - 1) == 0) {
639                     cp = info[i] + sizeof("runas_uid=") - 1;
640                     if (*cp == '\0')
641                         break;
642                     errno = 0;
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);
648                     }
649                     break;
650                 }
651                 break;
652             case 's':
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);
658                     break;
659                 }
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);
663                     break;
664                 }
665                 break;
666             case 't':
667                 if (strncmp("timeout=", info[i], sizeof("timeout=") - 1) == 0) {
668                     cp = info[i] + sizeof("timeout=") - 1;
669                     if (*cp == '\0')
670                         break;
671                     errno = 0;
672                     lval = strtol(cp, &ep, 0);
673                     if (*cp != '\0' && *ep == '\0' &&
674                         !(errno == ERANGE &&
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);
679                     }
680                     break;
681                 }
682                 break;
683             case 'u':
684                 if (strncmp("umask=", info[i], sizeof("umask=") - 1) == 0) {
685                     cp = info[i] + sizeof("umask=") - 1;
686                     if (*cp == '\0')
687                         break;
688                     errno = 0;
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);
694                     }
695                     break;
696                 }
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);
700                     break;
701                 }
702                 SET_STRING("utmp_user=", utmp_user)
703                 break;
704         }
705     }
706
707     if (!ISSET(details->flags, CD_SET_EUID))
708         details->euid = details->uid;
709
710 #ifdef HAVE_SELINUX
711     if (details->selinux_role != NULL && is_selinux_enabled() > 0)
712         SET(details->flags, CD_RBAC_ENABLED);
713 #endif
714 }
715
716 /*
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.
720  */
721 static void
722 disable_coredumps(void)
723 {
724 #if defined(__linux__) || (defined(RLIMIT_CORE) && !defined(SUDO_DEVEL))
725     struct rlimit rl;
726 #endif
727
728 #if defined(__linux__)
729     /*
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.
733      */
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);
740     }
741 #endif /* __linux__ */
742 #if defined(RLIMIT_CORE) && !defined(SUDO_DEVEL)
743     /*
744      * Turn off core dumps.
745      */
746     (void) getrlimit(RLIMIT_CORE, &corelimit);
747     memcpy(&rl, &corelimit, sizeof(struct rlimit));
748     rl.rlim_cur = 0;
749     (void) setrlimit(RLIMIT_CORE, &rl);
750 #endif /* RLIMIT_CORE && !SUDO_DEVEL */
751 }
752
753 #ifdef HAVE_PROJECT_H
754 static void
755 set_project(struct passwd *pw)
756 {
757     struct project proj;
758     char buf[PROJECT_BUFSZ];
759     int errval;
760
761     /*
762      * Collect the default project for the user and settaskid
763      */
764     setprojent();
765     if (getdefaultproj(pw->pw_name, &proj, buf, sizeof(buf)) != NULL) {
766         errval = setproject(proj.pj_name, pw->pw_name, TASK_NORMAL);
767         switch(errval) {
768         case 0:
769             break;
770         case SETPROJ_ERR_TASK:
771             switch (errno) {
772             case EAGAIN:
773                 warningx(_("resource control limit has been reached"));
774                 break;
775             case ESRCH:
776                 warningx(_("user \"%s\" is not a member of project \"%s\""),
777                     pw->pw_name, proj.pj_name);
778                 break;
779             case EACCES:
780                 warningx(_("the invoking task is final"));
781                 break;
782             default:
783                 warningx(_("could not join project \"%s\""), proj.pj_name);
784             }
785         case SETPROJ_ERR_POOL:
786             switch (errno) {
787             case EACCES:
788                 warningx(_("no resource pool accepting default bindings "
789                     "exists for project \"%s\""), proj.pj_name);
790                 break;
791             case ESRCH:
792                 warningx(_("specified resource pool does not exist for "
793                     "project \"%s\""), proj.pj_name);
794                 break;
795             default:
796                 warningx(_("could not bind to default resource pool for "
797                     "project \"%s\""), proj.pj_name);
798             }
799             break;
800         default:
801             if (errval <= 0) {
802                 warningx(_("setproject failed for project \"%s\""), proj.pj_name);
803             } else {
804                 warningx(_("warning, resource control assignment failed for "
805                     "project \"%s\""), proj.pj_name);
806             }
807         }
808     } else {
809         warning("getdefaultproj");
810     }
811     endprojent();
812 }
813 #endif /* HAVE_PROJECT_H */
814
815 /*
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.
819  */
820 static void
821 disable_execute(struct command_details *details)
822 {
823 #ifdef _PATH_SUDO_NOEXEC
824     char *cp, **ev, **nenvp;
825     int env_len = 0, env_size = 128;
826 #endif /* _PATH_SUDO_NOEXEC */
827
828 #ifdef HAVE_PRIV_SET
829     /* Solaris privileges, remove PRIV_PROC_EXEC post-execve. */
830     if (priv_set(PRIV_OFF, PRIV_LIMIT, "PRIV_PROC_EXEC", NULL) == 0)
831         return;
832     warning(_("unable to remove PRIV_PROC_EXEC from PRIV_LIMIT"));
833 #endif /* HAVE_PRIV_SET */
834
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) {
839             env_size += 128;
840             nenvp = erealloc3(nenvp, env_size, sizeof(char *));
841         }
842         /*
843          * Prune out existing preloaded libraries.
844          * XXX - should save and append instead of replacing.
845          */
846 # if defined(__darwin__) || defined(__APPLE__)
847         if (strncmp(*ev, "DYLD_INSERT_LIBRARIES=", sizeof("DYLD_INSERT_LIBRARIES=") - 1) == 0)
848             continue;
849         if (strncmp(*ev, "DYLD_FORCE_FLAT_NAMESPACE=", sizeof("DYLD_INSERT_LIBRARIES=") - 1) == 0)
850             continue;
851 # elif defined(__osf__) || defined(__sgi)
852         if (strncmp(*ev, "_RLD_LIST=", sizeof("_RLD_LIST=") - 1) == 0)
853             continue;
854 # elif defined(_AIX)
855         if (strncmp(*ev, "LDR_PRELOAD=", sizeof("LDR_PRELOAD=") - 1) == 0)
856             continue;
857 # else
858         if (strncmp(*ev, "LD_PRELOAD=", sizeof("LD_PRELOAD=") - 1) == 0)
859             continue;
860 # endif
861         nenvp[env_len++] = *ev;
862     }
863
864     /*
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
868      */
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);
874 # elif defined(_AIX)
875     cp = fmt_string("LDR_PRELOAD", noexec_path);
876 # else
877     cp = fmt_string("LD_PRELOAD", noexec_path);
878 # endif
879     if (cp == NULL)
880         error(1, NULL);
881     nenvp[env_len++] = cp;
882     nenvp[env_len] = NULL;
883
884     details->envp = nenvp;
885 #endif /* _PATH_SUDO_NOEXEC */
886 }
887
888 /*
889  * Setup the execution environment immediately prior to the call to execve()
890  * Returns TRUE on success and FALSE on failure.
891  */
892 int
893 exec_setup(struct command_details *details, const char *ptyname, int ptyfd)
894 {
895     int rval = FALSE;
896     struct passwd *pw;
897
898 #ifdef HAVE_SETAUTHDB
899     aix_setauthdb(IDtouser(details->euid));
900 #endif
901     pw = getpwuid(details->euid);
902 #ifdef HAVE_SETAUTHDB
903     aix_restoreauthdb();
904 #endif
905
906     /*
907      * Call policy plugin's session init before other setup occurs.
908      * The session init code is expected to print an error as needed.
909      */
910     if (policy_init_session(&policy_plugin, pw) != TRUE)
911         goto done;
912
913 #ifdef HAVE_SELINUX
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)
917             goto done;
918     }
919 #endif
920
921     if (pw != NULL) {
922 #ifdef HAVE_PROJECT_H
923         set_project(pw);
924 #endif
925 #ifdef HAVE_GETUSERATTR
926         aix_prep_user(pw->pw_name, ptyname ? ptyname : user_details.tty);
927 #endif
928 #ifdef HAVE_LOGIN_CAP_H
929         if (details->login_class) {
930             int flags;
931             login_cap_t *lc;
932
933             /*
934              * We only use setusercontext() to set the nice value and rlimits.
935              */
936             lc = login_getclass((char *)details->login_class);
937             if (!lc) {
938                 warningx(_("unknown login class %s"), details->login_class);
939                 errno = ENOENT;
940                 goto done;
941             }
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"));
946                     goto done;
947                 } else
948                     warning(_("unable to set user context"));
949             }
950         }
951 #endif /* HAVE_LOGIN_CAP_H */
952     }
953
954     /*
955      * Set groups, including supplementary group vector.
956      */
957 #ifdef HAVE_SETEUID
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);
961         goto done;
962     }
963 #endif
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);
967         goto done;
968     }
969
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"));
974                 goto done;
975             }
976         }
977     }
978
979     if (ISSET(details->flags, CD_SET_PRIORITY)) {
980         if (setpriority(PRIO_PROCESS, 0, details->priority) != 0) {
981             warning(_("unable to set process priority"));
982             goto done;
983         }
984     }
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);
990             goto done;
991         }
992     }
993
994     if (ISSET(details->flags, CD_NOEXEC))
995         disable_execute(details);
996
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,
1000             details->euid);
1001         goto done;
1002     }
1003 #elif HAVE_SETREUID
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);
1007         goto done;
1008     }
1009 #else
1010     if (seteuid(details->euid) != 0 || setuid(details->euid) != 0) {
1011         warning(_("unable to change to runas uid (%u, %u)"), details->uid,
1012             details->euid);
1013         goto done;
1014     }
1015 #endif /* !HAVE_SETRESUID && !HAVE_SETREUID */
1016
1017     /*
1018      * Only change cwd if we have chroot()ed or the policy modules
1019      * specifies a different cwd.  Must be done after uid change.
1020      */
1021     if (details->cwd) {
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);
1026                 goto done;
1027             }
1028         }
1029     }
1030
1031     /*
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
1034      * from setuid().
1035      */
1036 #if defined(__linux__)
1037     {
1038         struct rlimit rl;
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);
1042         }
1043     }
1044 #endif
1045
1046     rval = TRUE;
1047
1048 done:
1049     return rval;
1050 }
1051
1052 /*
1053  * Run the command and wait for it to complete.
1054  */
1055 int
1056 run_command(struct command_details *details)
1057 {
1058     struct plugin_container *plugin;
1059     struct command_status cstat;
1060     int exitcode = 1;
1061
1062     cstat.type = CMD_INVALID;
1063     cstat.val = 0;
1064
1065     sudo_execve(details, &cstat);
1066
1067     switch (cstat.type) {
1068     case CMD_ERRNO:
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);
1075         }
1076         exitcode = 1;
1077         break;
1078     case CMD_WSTATUS:
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);
1085         }
1086         if (WIFEXITED(cstat.val))
1087             exitcode = WEXITSTATUS(cstat.val);
1088         else if (WIFSIGNALED(cstat.val))
1089             exitcode = WTERMSIG(cstat.val) | 128;
1090         break;
1091     default:
1092         warningx(_("unexpected child termination condition: %d"), cstat.type);
1093         break;
1094     }
1095     return exitcode;
1096 }
1097
1098 static int
1099 policy_open(struct plugin_container *plugin, char * const settings[],
1100     char * const user_info[], char * const user_env[])
1101 {
1102     return plugin->u.policy->open(SUDO_API_VERSION, sudo_conversation,
1103         _sudo_printf, settings, user_info, user_env);
1104 }
1105
1106 static void
1107 policy_close(struct plugin_container *plugin, int exit_status, int error)
1108 {
1109     plugin->u.policy->close(exit_status, error);
1110 }
1111
1112 static int
1113 policy_show_version(struct plugin_container *plugin, int verbose)
1114 {
1115     return plugin->u.policy->show_version(verbose);
1116 }
1117
1118 static int
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[])
1122 {
1123     return plugin->u.policy->check_policy(argc, argv, env_add, command_info,
1124         argv_out, user_env_out);
1125 }
1126
1127 static int
1128 policy_list(struct plugin_container *plugin, int argc, char * const argv[],
1129     int verbose, const char *list_user)
1130 {
1131     if (plugin->u.policy->list == NULL) {
1132         warningx(_("policy plugin %s does not support listing privileges"),
1133             plugin->name);
1134         return FALSE;
1135     }
1136     return plugin->u.policy->list(argc, argv, verbose, list_user);
1137 }
1138
1139 static int
1140 policy_validate(struct plugin_container *plugin)
1141 {
1142     if (plugin->u.policy->validate == NULL) {
1143         warningx(_("policy plugin %s does not support the -v option"),
1144             plugin->name);
1145         return FALSE;
1146     }
1147     return plugin->u.policy->validate();
1148 }
1149
1150 static void
1151 policy_invalidate(struct plugin_container *plugin, int remove)
1152 {
1153     if (plugin->u.policy->invalidate == NULL) {
1154         errorx(1, _("policy plugin %s does not support the -k/-K options"),
1155             plugin->name);
1156     }
1157     plugin->u.policy->invalidate(remove);
1158 }
1159
1160 static int
1161 policy_init_session(struct plugin_container *plugin, struct passwd *pwd)
1162 {
1163     if (plugin->u.policy->init_session)
1164         return plugin->u.policy->init_session(pwd);
1165     return TRUE;
1166 }
1167
1168 static int
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[])
1172 {
1173     int rval;
1174
1175     /*
1176      * Backwards compatibility for API major 1, minor 0
1177      */
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,
1182             user_env);
1183         break;
1184     default:
1185         rval = plugin->u.io->open(SUDO_API_VERSION, sudo_conversation,
1186             _sudo_printf, settings, user_info, command_info, argc, argv,
1187             user_env);
1188     }
1189     return rval;
1190 }
1191
1192 static void
1193 iolog_close(struct plugin_container *plugin, int exit_status, int error)
1194 {
1195     plugin->u.io->close(exit_status, error);
1196 }
1197
1198 static int
1199 iolog_show_version(struct plugin_container *plugin, int verbose)
1200 {
1201     return plugin->u.io->show_version(verbose);
1202 }
1203
1204 /*
1205  * Simple debugging/logging.
1206  */
1207 void
1208 sudo_debug(int level, const char *fmt, ...)
1209 {
1210     va_list ap;
1211     char *buf;
1212
1213     if (level > debug_level)
1214         return;
1215
1216     /* Bracket fmt with program name and a newline to make it a single write */
1217     va_start(ap, fmt);
1218     evasprintf(&buf, fmt, ap);
1219     va_end(ap);
1220     fprintf(stderr, "%s: %s\n", getprogname(), buf);
1221     efree(buf);
1222 }