Merge commit 'upstream/1.8.1p2'
[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 static char *escape_cmnd(const char *src);
125
126 /* Policy plugin convenience functions. */
127 static int policy_open(struct plugin_container *plugin, char * const settings[],
128     char * const user_info[], char * const user_env[]);
129 static void policy_close(struct plugin_container *plugin, int exit_status,
130     int error);
131 static int policy_show_version(struct plugin_container *plugin, int verbose);
132 static int policy_check(struct plugin_container *plugin, int argc,
133     char * const argv[], char *env_add[], char **command_info[],
134     char **argv_out[], char **user_env_out[]);
135 static int policy_list(struct plugin_container *plugin, int argc,
136     char * const argv[], int verbose, const char *list_user);
137 static int policy_validate(struct plugin_container *plugin);
138 static void policy_invalidate(struct plugin_container *plugin, int remove);
139 static int policy_init_session(struct plugin_container *plugin,
140     struct passwd *pwd);
141
142 /* I/O log plugin convenience functions. */
143 static int iolog_open(struct plugin_container *plugin, char * const settings[],
144     char * const user_info[], char * const command_details[],
145     int argc, char * const argv[], char * const user_env[]);
146 static void iolog_close(struct plugin_container *plugin, int exit_status,
147     int error);
148 static int iolog_show_version(struct plugin_container *plugin, int verbose);
149
150 #if defined(RLIMIT_CORE) && !defined(SUDO_DEVEL)
151 static struct rlimit corelimit;
152 #endif /* RLIMIT_CORE && !SUDO_DEVEL */
153 #if defined(__linux__)
154 static struct rlimit nproclimit;
155 #endif
156
157 int
158 main(int argc, char *argv[], char *envp[])
159 {
160     int nargc, sudo_mode, exitcode = 0;
161     char **nargv, **settings, **env_add;
162     char **user_info, **command_info, **argv_out, **user_env_out;
163     struct plugin_container *plugin, *next;
164     struct command_details command_details;
165     sigset_t mask;
166     int ok;
167 #if defined(SUDO_DEVEL) && defined(__OpenBSD__)
168     extern char *malloc_options;
169     malloc_options = "AFGJPR";
170 #endif
171
172 #ifdef HAVE_SETLOCALE
173     setlocale(LC_ALL, "");
174 #endif
175
176 #if !defined(HAVE_GETPROGNAME) && !defined(HAVE___PROGNAME)
177     if (argc > 0)
178         setprogname(argv[0]);
179 #endif
180
181     /* Must be done before we do any password lookups */
182 #if defined(HAVE_GETPRPWNAM) && defined(HAVE_SET_AUTH_PARAMETERS)
183     (void) set_auth_parameters(argc, argv);
184 # ifdef HAVE_INITPRIVS
185     initprivs();
186 # endif
187 #endif /* HAVE_GETPRPWNAM && HAVE_SET_AUTH_PARAMETERS */
188
189     if (geteuid() != 0)
190         errorx(1, "must be setuid root");
191
192     /* Reset signal mask, disable core dumps and make sure fds 0-2 are open. */
193     (void) sigemptyset(&mask);
194     (void) sigprocmask(SIG_SETMASK, &mask, NULL);
195     disable_coredumps();
196     fix_fds();
197
198     /* Fill in user_info with user name, uid, cwd, etc. */
199     memset(&user_details, 0, sizeof(user_details));
200     user_info = get_user_info(&user_details);
201
202     /* Parse command line arguments. */
203     sudo_mode = parse_args(argc, argv, &nargc, &nargv, &settings, &env_add);
204     sudo_debug(9, "sudo_mode %d", sudo_mode);
205
206     /* Print sudo version early, in case of plugin init failure. */
207     if (ISSET(sudo_mode, MODE_VERSION)) {
208         printf("Sudo version %s\n", PACKAGE_VERSION);
209         if (user_details.uid == ROOT_UID)
210             (void) printf("Configure args: %s\n", CONFIGURE_ARGS);
211     }
212
213     /* Read sudo.conf and load plugins. */
214     if (!sudo_load_plugins(_PATH_SUDO_CONF, &policy_plugin, &io_plugins))
215         errorx(1, "fatal error, unable to load plugins");
216
217     /* Open policy plugin. */
218     ok = policy_open(&policy_plugin, settings, user_info, envp);
219     if (ok != TRUE) {
220         if (ok == -2)
221             usage(1);
222         else
223             errorx(1, "unable to initialize policy plugin");
224     }
225
226     switch (sudo_mode & MODE_MASK) {
227         case MODE_VERSION:
228             policy_show_version(&policy_plugin, !user_details.uid);
229             tq_foreach_fwd(&io_plugins, plugin) {
230                 ok = iolog_open(plugin, settings, user_info, NULL,
231                     nargc, nargv, envp);
232                 if (ok == TRUE)
233                     iolog_show_version(plugin, !user_details.uid);
234             }
235             break;
236         case MODE_VALIDATE:
237         case MODE_VALIDATE|MODE_INVALIDATE:
238             ok = policy_validate(&policy_plugin);
239             exit(ok != TRUE);
240         case MODE_KILL:
241         case MODE_INVALIDATE:
242             policy_invalidate(&policy_plugin, sudo_mode == MODE_KILL);
243             exit(0);
244             break;
245         case MODE_CHECK:
246         case MODE_CHECK|MODE_INVALIDATE:
247         case MODE_LIST:
248         case MODE_LIST|MODE_INVALIDATE:
249             ok = policy_list(&policy_plugin, nargc, nargv,
250                 ISSET(sudo_mode, MODE_LONG_LIST), list_user);
251             exit(ok != TRUE);
252         case MODE_EDIT:
253         case MODE_RUN:
254             ok = policy_check(&policy_plugin, nargc, nargv, env_add,
255                 &command_info, &argv_out, &user_env_out);
256             sudo_debug(8, "policy plugin returns %d", ok);
257             if (ok != TRUE) {
258                 if (ok == -2)
259                     usage(1);
260                 exit(1); /* plugin printed error message */
261             }
262             /* Open I/O plugins once policy plugin succeeds. */
263             for (plugin = io_plugins.first; plugin != NULL; plugin = next) {
264                 next = plugin->next;
265                 ok = iolog_open(plugin, settings, user_info,
266                     command_info, nargc, nargv, envp);
267                 switch (ok) {
268                 case TRUE:
269                     break;
270                 case FALSE:
271                     /* I/O plugin asked to be disabled, remove from list. */
272                     tq_remove(&io_plugins, plugin);
273                     break;
274                 case -2:
275                     usage(1);
276                     break;
277                 default:
278                     errorx(1, "error initializing I/O plugin %s", plugin->name);
279                 }
280             }
281             command_info_to_details(command_info, &command_details);
282             command_details.argv = argv_out;
283             command_details.envp = user_env_out;
284             if (ISSET(sudo_mode, MODE_BACKGROUND))
285                 SET(command_details.flags, CD_BACKGROUND);
286             /* Restore coredumpsize resource limit before running. */
287 #if defined(RLIMIT_CORE) && !defined(SUDO_DEVEL)
288             (void) setrlimit(RLIMIT_CORE, &corelimit);
289 #endif /* RLIMIT_CORE && !SUDO_DEVEL */
290             if (ISSET(command_details.flags, CD_SUDOEDIT)) {
291                 exitcode = sudo_edit(&command_details);
292             } else {
293                 if (ISSET(sudo_mode, MODE_SHELL)) {
294                     /* Escape meta chars if running a shell with args. */
295                     if (argv_out[1] != NULL && strcmp(argv_out[1], "-c") == 0 &&
296                         argv_out[2] != NULL && argv_out[3] == NULL)
297                         argv_out[2] = escape_cmnd(argv_out[2]);
298                 }
299                 exitcode = run_command(&command_details);
300             }
301             /* The close method was called by sudo_edit/run_command. */
302             break;
303         default:
304             errorx(1, "unexpected sudo mode 0x%x", sudo_mode);
305     }
306     exit(exitcode);
307 }
308
309 /*
310  * Ensure that stdin, stdout and stderr are open; set to /dev/null if not.
311  * Some operating systems do this automatically in the kernel or libc.
312  */
313 static void
314 fix_fds(void)
315 {
316     int miss[3], devnull = -1;
317
318     /*
319      * stdin, stdout and stderr must be open; set them to /dev/null
320      * if they are closed.
321      */
322     miss[STDIN_FILENO] = fcntl(STDIN_FILENO, F_GETFL, 0) == -1;
323     miss[STDOUT_FILENO] = fcntl(STDOUT_FILENO, F_GETFL, 0) == -1;
324     miss[STDERR_FILENO] = fcntl(STDERR_FILENO, F_GETFL, 0) == -1;
325     if (miss[STDIN_FILENO] || miss[STDOUT_FILENO] || miss[STDERR_FILENO]) {
326         if ((devnull = open(_PATH_DEVNULL, O_RDWR, 0644)) == -1)
327             error(1, "unable to open %s", _PATH_DEVNULL);
328         if (miss[STDIN_FILENO] && dup2(devnull, STDIN_FILENO) == -1)
329             error(1, "dup2");
330         if (miss[STDOUT_FILENO] && dup2(devnull, STDOUT_FILENO) == -1)
331             error(1, "dup2");
332         if (miss[STDERR_FILENO] && dup2(devnull, STDERR_FILENO) == -1)
333             error(1, "dup2");
334         if (devnull > STDERR_FILENO)
335             close(devnull);
336     }
337 }
338
339 static char *
340 get_user_groups(struct user_details *ud)
341 {
342     char *gid_list = NULL;
343 #ifdef HAVE_GETGROUPS
344     size_t glsize;
345     char *cp;
346     int i, len;
347
348     if ((ud->ngroups = getgroups(0, NULL)) <= 0)
349         return NULL;
350
351     ud->groups = emalloc2(ud->ngroups, sizeof(GETGROUPS_T));
352     if (getgroups(ud->ngroups, ud->groups) < 0)
353         error(1, "can't get group vector");
354     glsize = sizeof("groups=") - 1 + (ud->ngroups * (MAX_UID_T_LEN + 1));
355     gid_list = emalloc(glsize);
356     memcpy(gid_list, "groups=", sizeof("groups=") - 1);
357     cp = gid_list + sizeof("groups=") - 1;
358     for (i = 0; i < ud->ngroups; i++) {
359         /* XXX - check rval */
360         len = snprintf(cp, glsize - (cp - gid_list), "%s%u",
361             i ? "," : "", (unsigned int)ud->groups[i]);
362         cp += len;
363     }
364 #endif
365     return gid_list;
366 }
367
368 /*
369  * Return user information as an array of name=value pairs.
370  * and fill in struct user_details (which shares the same strings).
371  */
372 static char **
373 get_user_info(struct user_details *ud)
374 {
375     char cwd[PATH_MAX];
376     char host[MAXHOSTNAMELEN];
377     char **user_info, *cp;
378     struct passwd *pw;
379     int i = 0;
380
381     /* XXX - bound check number of entries */
382     user_info = emalloc2(32, sizeof(char *));
383
384     ud->uid = getuid();
385     ud->euid = geteuid();
386     ud->gid = getgid();
387     ud->egid = getegid();
388
389     pw = getpwuid(ud->uid);
390     if (pw == NULL)
391         errorx(1, "unknown uid %u: who are you?", (unsigned int)ud->uid);
392
393     user_info[i] = fmt_string("user", pw->pw_name);
394     if (user_info[i] == NULL)
395         errorx(1, "unable to allocate memory");
396     ud->username = user_info[i] + sizeof("user=") - 1;
397
398     /* Stash user's shell for use with the -s flag; don't pass to plugin. */
399     if ((ud->shell = getenv("SHELL")) == NULL || ud->shell[0] == '\0') {
400         ud->shell = pw->pw_shell[0] ? pw->pw_shell : _PATH_BSHELL;
401     }
402     ud->shell = estrdup(ud->shell);
403
404     easprintf(&user_info[++i], "uid=%u", (unsigned int)ud->uid);
405     easprintf(&user_info[++i], "euid=%u", (unsigned int)ud->euid);
406     easprintf(&user_info[++i], "gid=%u", (unsigned int)ud->gid);
407     easprintf(&user_info[++i], "egid=%u", (unsigned int)ud->egid);
408
409     if ((cp = get_user_groups(ud)) != NULL)
410         user_info[++i] = cp;
411
412     if (getcwd(cwd, sizeof(cwd)) != NULL) {
413         user_info[++i] = fmt_string("cwd", cwd);
414         if (user_info[i] == NULL)
415             errorx(1, "unable to allocate memory");
416         ud->cwd = user_info[i] + sizeof("cwd=") - 1;
417     }
418
419     if ((cp = ttyname(STDIN_FILENO)) || (cp = ttyname(STDOUT_FILENO)) ||
420         (cp = ttyname(STDERR_FILENO))) {
421         user_info[++i] = fmt_string("tty", cp);
422         if (user_info[i] == NULL)
423             errorx(1, "unable to allocate memory");
424         ud->tty = user_info[i] + sizeof("tty=") - 1;
425     }
426
427     if (gethostname(host, sizeof(host)) == 0)
428         host[sizeof(host) - 1] = '\0';
429     else
430         strlcpy(host, "localhost", sizeof(host));
431     user_info[++i] = fmt_string("host", host);
432     if (user_info[i] == NULL)
433         errorx(1, "unable to allocate memory");
434     ud->host = user_info[i] + sizeof("host=") - 1;
435
436     get_ttysize(&ud->ts_lines, &ud->ts_cols);
437     easprintf(&user_info[++i], "lines=%d", ud->ts_lines);
438     easprintf(&user_info[++i], "cols=%d", ud->ts_cols);
439
440     user_info[++i] = NULL;
441
442     return user_info;
443 }
444
445 /*
446  * Convert a command_info array into a command_details structure.
447  */
448 static void
449 command_info_to_details(char * const info[], struct command_details *details)
450 {
451     int i;
452     long lval;
453     unsigned long ulval;
454     char *cp, *ep;
455
456     memset(details, 0, sizeof(*details));
457     details->closefrom = -1;
458
459 #define SET_STRING(s, n) \
460     if (strncmp(s, info[i], sizeof(s) - 1) == 0 && info[i][sizeof(s) - 1]) { \
461         details->n = info[i] + sizeof(s) - 1; \
462         break; \
463     }
464
465     for (i = 0; info[i] != NULL; i++) {
466         sudo_debug(9, "command info: %s", info[i]);
467         switch (info[i][0]) {
468             case 'c':
469                 SET_STRING("chroot=", chroot)
470                 SET_STRING("command=", command)
471                 SET_STRING("cwd=", cwd)
472                 if (strncmp("closefrom=", info[i], sizeof("closefrom=") - 1) == 0) {
473                     cp = info[i] + sizeof("closefrom=") - 1;
474                     if (*cp == '\0')
475                         break;
476                     errno = 0;
477                     lval = strtol(cp, &ep, 0);
478                     if (*cp != '\0' && *ep == '\0' &&
479                         !(errno == ERANGE &&
480                         (lval == LONG_MAX || lval == LONG_MIN)) &&
481                         lval < INT_MAX && lval > INT_MIN) {
482                         details->closefrom = (int)lval;
483                     }
484                     break;
485                 }
486                 break;
487             case 'l':
488                 SET_STRING("login_class=", login_class)
489                 break;
490             case 'n':
491                 /* XXX - bounds check  -NZERO to NZERO (inclusive). */
492                 if (strncmp("nice=", info[i], sizeof("nice=") - 1) == 0) {
493                     cp = info[i] + sizeof("nice=") - 1;
494                     if (*cp == '\0')
495                         break;
496                     errno = 0;
497                     lval = strtol(cp, &ep, 0);
498                     if (*cp != '\0' && *ep == '\0' &&
499                         !(errno == ERANGE &&
500                         (lval == LONG_MAX || lval == LONG_MIN)) &&
501                         lval < INT_MAX && lval > INT_MIN) {
502                         details->priority = (int)lval;
503                         SET(details->flags, CD_SET_PRIORITY);
504                     }
505                     break;
506                 }
507                 if (strncmp("noexec=", info[i], sizeof("noexec=") - 1) == 0) {
508                     if (atobool(info[i] + sizeof("noexec=") - 1) == TRUE)
509                         SET(details->flags, CD_NOEXEC);
510                     break;
511                 }
512                 /* XXX - deprecated */
513                 if (strncmp("noexec_file=", info[i], sizeof("noexec_file=") - 1) == 0) {
514                     noexec_path = info[i] + sizeof("noexec_file=") - 1;
515                     break;
516                 }
517                 break;
518             case 'p':
519                 if (strncmp("preserve_groups=", info[i], sizeof("preserve_groups=") - 1) == 0) {
520                     if (atobool(info[i] + sizeof("preserve_groups=") - 1) == TRUE)
521                         SET(details->flags, CD_PRESERVE_GROUPS);
522                     break;
523                 }
524                 break;
525             case 'r':
526                 if (strncmp("runas_egid=", info[i], sizeof("runas_egid=") - 1) == 0) {
527                     cp = info[i] + sizeof("runas_egid=") - 1;
528                     if (*cp == '\0')
529                         break;
530                     errno = 0;
531                     ulval = strtoul(cp, &ep, 0);
532                     if (*cp != '\0' && *ep == '\0' &&
533                         (errno != ERANGE || ulval != ULONG_MAX)) {
534                         details->egid = (gid_t)ulval;
535                         SET(details->flags, CD_SET_EGID);
536                     }
537                     break;
538                 }
539                 if (strncmp("runas_euid=", info[i], sizeof("runas_euid=") - 1) == 0) {
540                     cp = info[i] + sizeof("runas_euid=") - 1;
541                     if (*cp == '\0')
542                         break;
543                     errno = 0;
544                     ulval = strtoul(cp, &ep, 0);
545                     if (*cp != '\0' && *ep == '\0' &&
546                         (errno != ERANGE || ulval != ULONG_MAX)) {
547                         details->euid = (uid_t)ulval;
548                         SET(details->flags, CD_SET_EUID);
549                     }
550                     break;
551                 }
552                 if (strncmp("runas_gid=", info[i], sizeof("runas_gid=") - 1) == 0) {
553                     cp = info[i] + sizeof("runas_gid=") - 1;
554                     if (*cp == '\0')
555                         break;
556                     errno = 0;
557                     ulval = strtoul(cp, &ep, 0);
558                     if (*cp != '\0' && *ep == '\0' &&
559                         (errno != ERANGE || ulval != ULONG_MAX)) {
560                         details->gid = (gid_t)ulval;
561                         SET(details->flags, CD_SET_GID);
562                     }
563                     break;
564                 }
565                 if (strncmp("runas_groups=", info[i], sizeof("runas_groups=") - 1) == 0) {
566                     int j;
567
568                     /* count groups, alloc and fill in */
569                     cp = info[i] + sizeof("runas_groups=") - 1;
570                     if (*cp == '\0')
571                         break;
572                     for (;;) {
573                         details->ngroups++;
574                         if ((cp = strchr(cp, ',')) == NULL)
575                             break;
576                         cp++;
577                     }
578                     if (details->ngroups != 0) {
579                         details->groups =
580                             emalloc2(details->ngroups, sizeof(GETGROUPS_T));
581                         cp = info[i] + sizeof("runas_groups=") - 1;
582                         for (j = 0; j < details->ngroups;) {
583                             errno = 0;
584                             ulval = strtoul(cp, &ep, 0);
585                             if (*cp == '\0' || (*ep != ',' && *ep != '\0') ||
586                                 (ulval == ULONG_MAX && errno == ERANGE)) {
587                                 break;
588                             }
589                             details->groups[j++] = (gid_t)ulval;
590                             cp = ep + 1;
591                         }
592                         details->ngroups = j;
593                     }
594                     break;
595                 }
596                 if (strncmp("runas_uid=", info[i], sizeof("runas_uid=") - 1) == 0) {
597                     cp = info[i] + sizeof("runas_uid=") - 1;
598                     if (*cp == '\0')
599                         break;
600                     errno = 0;
601                     ulval = strtoul(cp, &ep, 0);
602                     if (*cp != '\0' && *ep == '\0' &&
603                         (errno != ERANGE || ulval != ULONG_MAX)) {
604                         details->uid = (uid_t)ulval;
605                         SET(details->flags, CD_SET_UID);
606                     }
607                     break;
608                 }
609                 break;
610             case 's':
611                 SET_STRING("selinux_role=", selinux_role)
612                 SET_STRING("selinux_type=", selinux_type)
613                 if (strncmp("set_utmp=", info[i], sizeof("set_utmp=") - 1) == 0) {
614                     if (atobool(info[i] + sizeof("set_utmp=") - 1) == TRUE)
615                         SET(details->flags, CD_SET_UTMP);
616                     break;
617                 }
618                 if (strncmp("sudoedit=", info[i], sizeof("sudoedit=") - 1) == 0) {
619                     if (atobool(info[i] + sizeof("sudoedit=") - 1) == TRUE)
620                         SET(details->flags, CD_SUDOEDIT);
621                     break;
622                 }
623                 break;
624             case 't':
625                 if (strncmp("timeout=", info[i], sizeof("timeout=") - 1) == 0) {
626                     cp = info[i] + sizeof("timeout=") - 1;
627                     if (*cp == '\0')
628                         break;
629                     errno = 0;
630                     lval = strtol(cp, &ep, 0);
631                     if (*cp != '\0' && *ep == '\0' &&
632                         !(errno == ERANGE &&
633                         (lval == LONG_MAX || lval == LONG_MIN)) &&
634                         lval <= INT_MAX && lval >= 0) {
635                         details->timeout = (int)lval;
636                         SET(details->flags, CD_SET_TIMEOUT);
637                     }
638                     break;
639                 }
640                 break;
641             case 'u':
642                 if (strncmp("umask=", info[i], sizeof("umask=") - 1) == 0) {
643                     cp = info[i] + sizeof("umask=") - 1;
644                     if (*cp == '\0')
645                         break;
646                     errno = 0;
647                     ulval = strtoul(cp, &ep, 8);
648                     if (*cp != '\0' && *ep == '\0' &&
649                         (errno != ERANGE || ulval != ULONG_MAX)) {
650                         details->umask = (uid_t)ulval;
651                         SET(details->flags, CD_SET_UMASK);
652                     }
653                     break;
654                 }
655                 if (strncmp("use_pty=", info[i], sizeof("use_pty=") - 1) == 0) {
656                     if (atobool(info[i] + sizeof("use_pty=") - 1) == TRUE)
657                         SET(details->flags, CD_USE_PTY);
658                     break;
659                 }
660                 SET_STRING("utmp_user=", utmp_user)
661                 break;
662         }
663     }
664
665     if (!ISSET(details->flags, CD_SET_EUID))
666         details->euid = details->uid;
667
668 #ifdef HAVE_SELINUX
669     if (details->selinux_role != NULL && is_selinux_enabled() > 0)
670         SET(details->flags, CD_RBAC_ENABLED);
671 #endif
672 }
673
674 /*
675  * Disable core dumps to avoid dropping a core with user password in it.
676  * We will reset this limit before executing the command.
677  * Not all operating systems disable core dumps for setuid processes.
678  */
679 static void
680 disable_coredumps(void)
681 {
682 #if defined(__linux__) || (defined(RLIMIT_CORE) && !defined(SUDO_DEVEL))
683     struct rlimit rl;
684 #endif
685
686 #if defined(__linux__)
687     /*
688      * Unlimit the number of processes since Linux's setuid() will
689      * apply resource limits when changing uid and return EAGAIN if
690      * nproc would be violated by the uid switch.
691      */
692     (void) getrlimit(RLIMIT_NPROC, &nproclimit);
693     rl.rlim_cur = rl.rlim_max = RLIM_INFINITY;
694     if (setrlimit(RLIMIT_NPROC, &rl)) {
695         memcpy(&rl, &nproclimit, sizeof(struct rlimit));
696         rl.rlim_cur = rl.rlim_max;
697         (void)setrlimit(RLIMIT_NPROC, &rl);
698     }
699 #endif /* __linux__ */
700 #if defined(RLIMIT_CORE) && !defined(SUDO_DEVEL)
701     /*
702      * Turn off core dumps.
703      */
704     (void) getrlimit(RLIMIT_CORE, &corelimit);
705     memcpy(&rl, &corelimit, sizeof(struct rlimit));
706     rl.rlim_cur = 0;
707     (void) setrlimit(RLIMIT_CORE, &rl);
708 #endif /* RLIMIT_CORE && !SUDO_DEVEL */
709 }
710
711 #ifdef HAVE_PROJECT_H
712 static void
713 set_project(struct passwd *pw)
714 {
715     struct project proj;
716     char buf[PROJECT_BUFSZ];
717     int errval;
718
719     /*
720      * Collect the default project for the user and settaskid
721      */
722     setprojent();
723     if (getdefaultproj(pw->pw_name, &proj, buf, sizeof(buf)) != NULL) {
724         errval = setproject(proj.pj_name, pw->pw_name, TASK_NORMAL);
725         switch(errval) {
726         case 0:
727             break;
728         case SETPROJ_ERR_TASK:
729             switch (errno) {
730             case EAGAIN:
731                 warningx("resource control limit has been reached");
732                 break;
733             case ESRCH:
734                 warningx("user \"%s\" is not a member of project \"%s\"",
735                     pw->pw_name, proj.pj_name);
736                 break;
737             case EACCES:
738                 warningx("the invoking task is final");
739                 break;
740             default:
741                 warningx("could not join project \"%s\"", proj.pj_name);
742             }
743         case SETPROJ_ERR_POOL:
744             switch (errno) {
745             case EACCES:
746                 warningx("no resource pool accepting default bindings "
747                     "exists for project \"%s\"", proj.pj_name);
748                 break;
749             case ESRCH:
750                 warningx("specified resource pool does not exist for "
751                     "project \"%s\"", proj.pj_name);
752                 break;
753             default:
754                 warningx("could not bind to default resource pool for "
755                     "project \"%s\"", proj.pj_name);
756             }
757             break;
758         default:
759             if (errval <= 0) {
760                 warningx("setproject failed for project \"%s\"", proj.pj_name);
761             } else {
762                 warningx("warning, resource control assignment failed for "
763                     "project \"%s\"", proj.pj_name);
764             }
765         }
766     } else {
767         warning("getdefaultproj");
768     }
769     endprojent();
770 }
771 #endif /* HAVE_PROJECT_H */
772
773 /*
774  * Disable execution of child processes in the command we are about
775  * to run.  On systems with privilege sets, we can remove the exec
776  * privilege.  On other systems we use LD_PRELOAD and the like.
777  */
778 static void
779 disable_execute(struct command_details *details)
780 {
781     char *cp, **ev, **nenvp;
782     int env_len = 0, env_size = 128;
783
784 #ifdef HAVE_PRIV_SET
785     /* Solaris privileges, remove PRIV_PROC_EXEC post-execve. */
786     if (priv_set(PRIV_OFF, PRIV_LIMIT, "PRIV_PROC_EXEC", NULL) == 0)
787         return;
788     warning("unable to remove PRIV_PROC_EXEC from PRIV_LIMIT");
789 #endif /* HAVE_PRIV_SET */
790
791     nenvp = emalloc2(env_size, sizeof(char *));
792     for (ev = details->envp; *ev != NULL; ev++) {
793         if (env_len + 2 > env_size) {
794             env_size += 128;
795             nenvp = erealloc3(nenvp, env_size, sizeof(char *));
796         }
797         /*
798          * Prune out existing preloaded libraries.
799          * XXX - should save and append instead of replacing.
800          */
801 #if defined(__darwin__) || defined(__APPLE__)
802         if (strncmp(*ev, "DYLD_INSERT_LIBRARIES=", sizeof("DYLD_INSERT_LIBRARIES=") - 1) == 0)
803             continue;
804         if (strncmp(*ev, "DYLD_FORCE_FLAT_NAMESPACE=", sizeof("DYLD_INSERT_LIBRARIES=") - 1) == 0)
805             continue;
806 #elif defined(__osf__) || defined(__sgi)
807         if (strncmp(*ev, "_RLD_LIST=", sizeof("_RLD_LIST=") - 1) == 0)
808             continue;
809 #elif defined(_AIX)
810         if (strncmp(*ev, "LDR_PRELOAD=", sizeof("LDR_PRELOAD=") - 1) == 0)
811             continue;
812 #else
813         if (strncmp(*ev, "LD_PRELOAD=", sizeof("LD_PRELOAD=") - 1) == 0)
814             continue;
815 #endif
816         nenvp[env_len++] = *ev;
817     }
818
819     /*
820      * Preload a noexec file?  For a list of LD_PRELOAD-alikes, see
821      * http://www.fortran-2000.com/ArnaudRecipes/sharedlib.html
822      * XXX - need to support 32-bit and 64-bit variants
823      */
824 #if defined(__darwin__) || defined(__APPLE__)
825     nenvp[env_len++] = "DYLD_FORCE_FLAT_NAMESPACE=";
826     cp = fmt_string("DYLD_INSERT_LIBRARIES", noexec_path);
827 #elif defined(__osf__) || defined(__sgi)
828     easprintf(&cp, "_RLD_LIST=%s:DEFAULT", noexec_path);
829 #elif defined(_AIX)
830     cp = fmt_string("LDR_PRELOAD", noexec_path);
831 #else
832     cp = fmt_string("LD_PRELOAD", noexec_path);
833 #endif
834     if (cp == NULL)
835         error(1, NULL);
836     nenvp[env_len++] = cp;
837     nenvp[env_len] = NULL;
838
839     details->envp = nenvp;
840 }
841
842 /*
843  * Setup the execution environment immediately prior to the call to execve()
844  * Returns TRUE on success and FALSE on failure.
845  */
846 int
847 exec_setup(struct command_details *details, const char *ptyname, int ptyfd)
848 {
849     int rval = FALSE;
850     struct passwd *pw;
851
852 #ifdef HAVE_SETAUTHDB
853     aix_setauthdb(IDtouser(details->euid));
854 #endif
855     pw = getpwuid(details->euid);
856 #ifdef HAVE_SETAUTHDB
857     aix_restoreauthdb();
858 #endif
859
860     /*
861      * Call policy plugin's session init before other setup occurs.
862      * The session init code is expected to print an error as needed.
863      */
864     if (policy_init_session(&policy_plugin, pw) != TRUE)
865         goto done;
866
867 #ifdef HAVE_SELINUX
868     if (ISSET(details->flags, CD_RBAC_ENABLED)) {
869         if (selinux_setup(details->selinux_role, details->selinux_type,
870             ptyname ? ptyname : user_details.tty, ptyfd) == -1)
871             goto done;
872     }
873 #endif
874
875     if (pw != NULL) {
876 #ifdef HAVE_PROJECT_H
877         set_project(pw);
878 #endif
879 #ifdef HAVE_GETUSERATTR
880         aix_prep_user(pw->pw_name, ptyname ? ptyname : user_details.tty);
881 #endif
882 #ifdef HAVE_LOGIN_CAP_H
883         if (details->login_class) {
884             int flags;
885             login_cap_t *lc;
886
887             /*
888              * We only use setusercontext() to set the nice value and rlimits.
889              */
890             lc = login_getclass((char *)details->login_class);
891             if (!lc) {
892                 warningx("unknown login class %s", details->login_class);
893                 errno = ENOENT;
894                 goto done;
895             }
896             flags = LOGIN_SETRESOURCES|LOGIN_SETPRIORITY;
897             if (setusercontext(lc, pw, pw->pw_uid, flags)) {
898                 if (pw->pw_uid != ROOT_UID) {
899                     warning("unable to set user context");
900                     goto done;
901                 } else
902                     warning("unable to set user context");
903             }
904         }
905 #endif /* HAVE_LOGIN_CAP_H */
906     }
907
908     /*
909      * Set groups, including supplementary group vector.
910      */
911 #ifdef HAVE_SETEUID
912     if (ISSET(details->flags, CD_SET_EGID) && setegid(details->egid)) {
913         warning("unable to set egid to runas gid %u", details->egid);
914         goto done;
915     }
916 #endif
917     if (ISSET(details->flags, CD_SET_GID) && setgid(details->gid)) {
918         warning("unable to set gid to runas gid %u", details->gid);
919         goto done;
920     }
921
922     if (!ISSET(details->flags, CD_PRESERVE_GROUPS)) {
923 #ifdef HAVE_GETGROUPS
924         if (details->ngroups >= 0) {
925             if (setgroups(details->ngroups, details->groups) < 0) {
926                 warning("unable to set supplementary group IDs");
927                 goto done;
928             }
929         }
930 #else
931         if (pw && initgroups(pw->pw_name, pw->pw_gid) < 0) {
932             warning("unable to set supplementary group IDs");
933             goto done;
934         }
935 #endif
936     }
937
938     if (ISSET(details->flags, CD_SET_PRIORITY)) {
939         if (setpriority(PRIO_PROCESS, 0, details->priority) != 0) {
940             warning("unable to set process priority");
941             goto done;
942         }
943     }
944     if (ISSET(details->flags, CD_SET_UMASK))
945         (void) umask(details->umask);
946     if (details->chroot) {
947         if (chroot(details->chroot) != 0 || chdir("/") != 0) {
948             warning("unable to change root to %s", details->chroot);
949             goto done;
950         }
951     }
952
953     if (ISSET(details->flags, CD_NOEXEC))
954         disable_execute(details);
955
956 #ifdef HAVE_SETRESUID
957     if (setresuid(details->uid, details->euid, details->euid) != 0) {
958         warning("unable to change to runas uid (%u, %u)", details->uid,
959             details->euid);
960         goto done;
961     }
962 #elif HAVE_SETREUID
963     if (setreuid(details->uid, details->euid) != 0) {
964         warning("unable to change to runas uid (%u, %u)", details->uid,
965             details->euid);
966         goto done;
967     }
968 #else
969     if (seteuid(details->euid) != 0 || setuid(details->euid) != 0) {
970         warning("unable to change to runas uid (%u, %u)", details->uid,
971             details->euid);
972         goto done;
973     }
974 #endif /* !HAVE_SETRESUID && !HAVE_SETREUID */
975
976     /*
977      * Only change cwd if we have chroot()ed or the policy modules
978      * specifies a different cwd.  Must be done after uid change.
979      */
980     if (details->cwd) {
981         if (details->chroot || strcmp(details->cwd, user_details.cwd) != 0) {
982             /* Note: cwd is relative to the new root, if any. */
983             if (chdir(details->cwd) != 0) {
984                 warning("unable to change directory to %s", details->cwd);
985                 goto done;
986             }
987         }
988     }
989
990     /*
991      * Restore nproc resource limit if pam_limits didn't do it for us.
992      * We must do this *after* the uid change to avoid potential EAGAIN
993      * from setuid().
994      */
995 #if defined(__linux__)
996     {
997         struct rlimit rl;
998         if (getrlimit(RLIMIT_NPROC, &rl) == 0) {
999             if (rl.rlim_cur == RLIM_INFINITY && rl.rlim_max == RLIM_INFINITY)
1000                 (void) setrlimit(RLIMIT_NPROC, &nproclimit);
1001         }
1002     }
1003 #endif
1004
1005     rval = TRUE;
1006
1007 done:
1008     return rval;
1009 }
1010
1011 /*
1012  * Escape any non-alpha numeric or blank characters to make sure
1013  * they are not interpreted specially by the shell.
1014  */
1015 static char *
1016 escape_cmnd(const char *src)
1017 {
1018     char *cmnd, *dst;
1019
1020     /* Worst case scenario, we have to escape everything. */
1021     cmnd = dst = emalloc((2 * strlen(src)) + 1);
1022     while (*src != '\0') {
1023         if (!isalnum((unsigned char)*src) && !isspace((unsigned char)*src) &&
1024             *src != '_' && *src != '-') {
1025             /* quote potential meta character */
1026             *dst++ = '\\';
1027         }
1028         *dst++ = *src++;
1029     }
1030     *dst++ = '\0';
1031
1032     return cmnd;
1033 }
1034
1035 /*
1036  * Run the command and wait for it to complete.
1037  */
1038 int
1039 run_command(struct command_details *details)
1040 {
1041     struct plugin_container *plugin;
1042     struct command_status cstat;
1043     int exitcode = 1;
1044
1045     cstat.type = CMD_INVALID;
1046     cstat.val = 0;
1047
1048     sudo_execve(details, &cstat);
1049
1050     switch (cstat.type) {
1051     case CMD_ERRNO:
1052         /* exec_setup() or execve() returned an error. */
1053         sudo_debug(9, "calling policy close with errno");
1054         policy_close(&policy_plugin, 0, cstat.val);
1055         tq_foreach_fwd(&io_plugins, plugin) {
1056             sudo_debug(9, "calling I/O close with errno");
1057             iolog_close(plugin, 0, cstat.val);
1058         }
1059         exitcode = 1;
1060         break;
1061     case CMD_WSTATUS:
1062         /* Command ran, exited or was killed. */
1063         sudo_debug(9, "calling policy close with wait status");
1064         policy_close(&policy_plugin, cstat.val, 0);
1065         tq_foreach_fwd(&io_plugins, plugin) {
1066             sudo_debug(9, "calling I/O close with wait status");
1067             iolog_close(plugin, cstat.val, 0);
1068         }
1069         if (WIFEXITED(cstat.val))
1070             exitcode = WEXITSTATUS(cstat.val);
1071         else if (WIFSIGNALED(cstat.val))
1072             exitcode = WTERMSIG(cstat.val) | 128;
1073         break;
1074     default:
1075         warningx("unexpected child termination condition: %d", cstat.type);
1076         break;
1077     }
1078     return exitcode;
1079 }
1080
1081 static int
1082 policy_open(struct plugin_container *plugin, char * const settings[],
1083     char * const user_info[], char * const user_env[])
1084 {
1085     return plugin->u.policy->open(SUDO_API_VERSION, sudo_conversation,
1086         _sudo_printf, settings, user_info, user_env);
1087 }
1088
1089 static void
1090 policy_close(struct plugin_container *plugin, int exit_status, int error)
1091 {
1092     plugin->u.policy->close(exit_status, error);
1093 }
1094
1095 static int
1096 policy_show_version(struct plugin_container *plugin, int verbose)
1097 {
1098     return plugin->u.policy->show_version(verbose);
1099 }
1100
1101 static int
1102 policy_check(struct plugin_container *plugin, int argc, char * const argv[],
1103     char *env_add[], char **command_info[], char **argv_out[],
1104     char **user_env_out[])
1105 {
1106     return plugin->u.policy->check_policy(argc, argv, env_add, command_info,
1107         argv_out, user_env_out);
1108 }
1109
1110 static int
1111 policy_list(struct plugin_container *plugin, int argc, char * const argv[],
1112     int verbose, const char *list_user)
1113 {
1114     if (plugin->u.policy->list == NULL) {
1115         warningx("policy plugin %s does not support listing privileges",
1116             plugin->name);
1117         return FALSE;
1118     }
1119     return plugin->u.policy->list(argc, argv, verbose, list_user);
1120 }
1121
1122 static int
1123 policy_validate(struct plugin_container *plugin)
1124 {
1125     if (plugin->u.policy->validate == NULL) {
1126         warningx("policy plugin %s does not support the -v flag",
1127             plugin->name);
1128         return FALSE;
1129     }
1130     return plugin->u.policy->validate();
1131 }
1132
1133 static void
1134 policy_invalidate(struct plugin_container *plugin, int remove)
1135 {
1136     if (plugin->u.policy->invalidate == NULL) {
1137         errorx(1, "policy plugin %s does not support the -k/-K flags",
1138             plugin->name);
1139     }
1140     plugin->u.policy->invalidate(remove);
1141 }
1142
1143 static int
1144 policy_init_session(struct plugin_container *plugin, struct passwd *pwd)
1145 {
1146     if (plugin->u.policy->init_session)
1147         return plugin->u.policy->init_session(pwd);
1148     return TRUE;
1149 }
1150
1151 static int
1152 iolog_open(struct plugin_container *plugin, char * const settings[],
1153     char * const user_info[], char * const command_info[],
1154     int argc, char * const argv[], char * const user_env[])
1155 {
1156     int rval;
1157
1158     /*
1159      * Backwards compatibility for API major 1, minor 0
1160      */
1161     switch (plugin->u.generic->version) {
1162     case SUDO_API_MKVERSION(1, 0):
1163         rval = plugin->u.io_1_0->open(plugin->u.io_1_0->version,
1164             sudo_conversation, _sudo_printf, settings, user_info, argc, argv,
1165             user_env);
1166         break;
1167     default:
1168         rval = plugin->u.io->open(SUDO_API_VERSION, sudo_conversation,
1169             _sudo_printf, settings, user_info, command_info, argc, argv,
1170             user_env);
1171     }
1172     return rval;
1173 }
1174
1175 static void
1176 iolog_close(struct plugin_container *plugin, int exit_status, int error)
1177 {
1178     plugin->u.io->close(exit_status, error);
1179 }
1180
1181 static int
1182 iolog_show_version(struct plugin_container *plugin, int verbose)
1183 {
1184     return plugin->u.io->show_version(verbose);
1185 }
1186
1187 /*
1188  * Simple debugging/logging.
1189  */
1190 void
1191 sudo_debug(int level, const char *fmt, ...)
1192 {
1193     va_list ap;
1194     char *fmt2;
1195
1196     if (level > debug_level)
1197         return;
1198
1199     /* Backet fmt with program name and a newline to make it a single write */
1200     easprintf(&fmt2, "%s: %s\n", getprogname(), fmt);
1201     va_start(ap, fmt);
1202     vfprintf(stderr, fmt2, ap);
1203     va_end(ap);
1204     efree(fmt2);
1205 }