d678fa1fbc1601c9129e3b0104bdfc7f2806f252
[debian/sudo] / plugins / sudoers / env.c
1 /*
2  * Copyright (c) 2000-2005, 2007-2011
3  *      Todd C. Miller <Todd.Miller@courtesan.com>
4  *
5  * Permission to use, copy, modify, and distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  *
17  * Sponsored in part by the Defense Advanced Research Projects
18  * Agency (DARPA) and Air Force Research Laboratory, Air Force
19  * Materiel Command, USAF, under agreement number F39502-99-1-0512.
20  */
21
22 #include <config.h>
23
24 #include <sys/types.h>
25 #include <sys/param.h>
26 #include <sys/stat.h>
27 #include <stdio.h>
28 #ifdef STDC_HEADERS
29 # include <stdlib.h>
30 # include <stddef.h>
31 #else
32 # ifdef HAVE_STDLIB_H
33 #  include <stdlib.h>
34 # endif
35 #endif /* STDC_HEADERS */
36 #ifdef HAVE_STRING_H
37 # include <string.h>
38 #endif /* HAVE_STRING_H */
39 #ifdef HAVE_STRINGS_H
40 # include <strings.h>
41 #endif /* HAVE_STRINGS_H */
42 #ifdef HAVE_UNISTD_H
43 # include <unistd.h>
44 #endif /* HAVE_UNISTD_H */
45 #ifdef HAVE_INTTYPES_H
46 # include <inttypes.h>
47 #endif
48 #ifdef HAVE_LOGIN_CAP_H
49 # include <login_cap.h>
50 # ifndef LOGIN_SETENV
51 #  define LOGIN_SETENV  0
52 # endif
53 #endif /* HAVE_LOGIN_CAP_H */
54 #include <ctype.h>
55 #include <errno.h>
56 #include <limits.h>
57 #include <pwd.h>
58
59 #include "sudoers.h"
60
61 /*
62  * If there is no SIZE_MAX or SIZE_T_MAX we have to assume that size_t
63  * could be signed (as it is on SunOS 4.x).  This just means that
64  * emalloc2() and erealloc3() cannot allocate huge amounts on such a
65  * platform but that is OK since sudo doesn't need to do so anyway.
66  */
67 #ifndef SIZE_MAX
68 # ifdef SIZE_T_MAX
69 #  define SIZE_MAX      SIZE_T_MAX
70 # else
71 #  define SIZE_MAX      INT_MAX
72 # endif /* SIZE_T_MAX */
73 #endif /* SIZE_MAX */
74         
75 /*
76  * Flags used in rebuild_env()
77  */
78 #undef DID_TERM
79 #define DID_TERM        0x0001
80 #undef DID_PATH
81 #define DID_PATH        0x0002
82 #undef DID_HOME
83 #define DID_HOME        0x0004
84 #undef DID_SHELL
85 #define DID_SHELL       0x0008
86 #undef DID_LOGNAME
87 #define DID_LOGNAME     0x0010
88 #undef DID_USER
89 #define DID_USER        0x0020
90 #undef DID_USERNAME
91 #define DID_USERNAME    0x0040
92 #undef DID_MAIL
93 #define DID_MAIL        0x0080
94 #undef DID_MAX
95 #define DID_MAX         0x00ff
96
97 #undef KEPT_TERM
98 #define KEPT_TERM       0x0100
99 #undef KEPT_PATH
100 #define KEPT_PATH       0x0200
101 #undef KEPT_HOME
102 #define KEPT_HOME       0x0400
103 #undef KEPT_SHELL
104 #define KEPT_SHELL      0x0800
105 #undef KEPT_LOGNAME
106 #define KEPT_LOGNAME    0x1000
107 #undef KEPT_USER
108 #define KEPT_USER       0x2000
109 #undef KEPT_USERNAME
110 #define KEPT_USERNAME   0x4000
111 #undef KEPT_MAIL
112 #define KEPT_MAIL       0x8000
113 #undef KEPT_MAX
114 #define KEPT_MAX        0xff00
115
116 struct environment {
117     char * const *old_envp;     /* pointer the environment we passed back */
118     char **envp;                /* pointer to the new environment */
119     size_t env_size;            /* size of new_environ in char **'s */
120     size_t env_len;             /* number of slots used, not counting NULL */
121 };
122
123 /*
124  * Copy of the sudo-managed environment.
125  */
126 static struct environment env;
127
128 /*
129  * Default table of "bad" variables to remove from the environment.
130  * XXX - how to omit TERMCAP if it starts with '/'?
131  */
132 static const char *initial_badenv_table[] = {
133     "IFS",
134     "CDPATH",
135     "LOCALDOMAIN",
136     "RES_OPTIONS",
137     "HOSTALIASES",
138     "NLSPATH",
139     "PATH_LOCALE",
140     "LD_*",
141     "_RLD*",
142 #ifdef __hpux
143     "SHLIB_PATH",
144 #endif /* __hpux */
145 #ifdef _AIX
146     "LDR_*",
147     "LIBPATH",
148     "AUTHSTATE",
149 #endif
150 #ifdef __APPLE__
151     "DYLD_*",
152 #endif
153 #ifdef HAVE_KERB5
154     "KRB5_CONFIG*",
155     "KRB5_KTNAME",
156 #endif /* HAVE_KERB5 */
157 #ifdef HAVE_SECURID
158     "VAR_ACE",
159     "USR_ACE",
160     "DLC_ACE",
161 #endif /* HAVE_SECURID */
162     "TERMINFO",                 /* terminfo, exclusive path to terminfo files */
163     "TERMINFO_DIRS",            /* terminfo, path(s) to terminfo files */
164     "TERMPATH",                 /* termcap, path(s) to termcap files */
165     "TERMCAP",                  /* XXX - only if it starts with '/' */
166     "ENV",                      /* ksh, file to source before script runs */
167     "BASH_ENV",                 /* bash, file to source before script runs */
168     "PS4",                      /* bash, prefix for lines in xtrace mode */
169     "GLOBIGNORE",               /* bash, globbing patterns to ignore */
170     "SHELLOPTS",                /* bash, extra command line options */
171     "JAVA_TOOL_OPTIONS",        /* java, extra command line options */
172     "PERLIO_DEBUG ",            /* perl, debugging output file */
173     "PERLLIB",                  /* perl, search path for modules/includes */
174     "PERL5LIB",                 /* perl 5, search path for modules/includes */
175     "PERL5OPT",                 /* perl 5, extra command line options */
176     "PERL5DB",                  /* perl 5, command used to load debugger */
177     "FPATH",                    /* ksh, search path for functions */
178     "NULLCMD",                  /* zsh, command for null file redirection */
179     "READNULLCMD",              /* zsh, command for null file redirection */
180     "ZDOTDIR",                  /* zsh, search path for dot files */
181     "TMPPREFIX",                /* zsh, prefix for temporary files */
182     "PYTHONHOME",               /* python, module search path */
183     "PYTHONPATH",               /* python, search path */
184     "PYTHONINSPECT",            /* python, allow inspection */
185     "PYTHONUSERBASE",           /* python, per user site-packages directory */
186     "RUBYLIB",                  /* ruby, library load path */
187     "RUBYOPT",                  /* ruby, extra command line options */
188     NULL
189 };
190
191 /*
192  * Default table of variables to check for '%' and '/' characters.
193  */
194 static const char *initial_checkenv_table[] = {
195     "COLORTERM",
196     "LANG",
197     "LANGUAGE",
198     "LC_*",
199     "LINGUAS",
200     "TERM",
201     NULL
202 };
203
204 /*
205  * Default table of variables to preserve in the environment.
206  */
207 static const char *initial_keepenv_table[] = {
208     "COLORS",
209     "DISPLAY",
210     "HOSTNAME",
211     "KRB5CCNAME",
212     "LS_COLORS",
213     "PATH",
214     "PS1",
215     "PS2",
216     "TZ",
217     "XAUTHORITY",
218     "XAUTHORIZATION",
219     NULL
220 };
221
222 /*
223  * Initialize env based on envp.
224  */
225 void
226 env_init(char * const envp[])
227 {
228     char * const *ep;
229     size_t len;
230     debug_decl(env_init, SUDO_DEBUG_ENV)
231
232     if (envp == NULL) {
233         /* Reset to initial state but keep a pointer to what we allocated. */
234         envp = env.envp;
235         memset(&env, 0, sizeof(env));
236         env.old_envp = envp;
237     } else {
238         /* Make private copy of envp. */
239         for (ep = envp; *ep != NULL; ep++)
240             continue;
241         len = (size_t)(ep - envp);
242
243         env.env_len = len;
244         env.env_size = len + 1 + 128;
245         env.envp = emalloc2(env.env_size, sizeof(char *));
246 #ifdef ENV_DEBUG
247         memset(env.envp, 0, env.env_size * sizeof(char *));
248 #endif
249         memcpy(env.envp, envp, len * sizeof(char *));
250         env.envp[len] = NULL;
251
252         /* Free the old envp we allocated, if any. */
253         if (env.old_envp != NULL)
254             efree((void *)env.old_envp);
255     }
256
257     debug_return;
258 }
259
260 /*
261  * Getter for private copy of the environment.
262  */
263 char **
264 env_get(void)
265 {
266     return env.envp;
267 }
268
269 /*
270  * Similar to putenv(3) but operates on sudo's private copy of the
271  * environment (not environ) and it always overwrites.  The dupcheck param
272  * determines whether we need to verify that the variable is not already set.
273  * Will only overwrite an existing variable if overwrite is set.
274  * Does not include warnings or debugging to avoid recursive calls.
275  */
276 static int
277 sudo_putenv_nodebug(char *str, bool dupcheck, bool overwrite)
278 {
279     char **ep;
280     size_t len;
281     bool found = false;
282
283     /* Make sure there is room for the new entry plus a NULL. */
284     if (env.env_size > 2 && env.env_len > env.env_size - 2) {
285         char **nenvp;
286         size_t nsize;
287
288         if (env.env_size > SIZE_MAX - 128) {
289             errorx2(1, _("internal error, %s overflow"),
290                 "sudo_putenv_nodebug()");
291         }
292         nsize = env.env_size + 128;
293         if (nsize > SIZE_MAX / sizeof(char *)) {
294             errorx2(1, _("internal error, %s overflow"),
295                 "sudo_putenv_nodebug()");
296         }
297         nenvp = realloc(env.envp, nsize * sizeof(char *));
298         if (nenvp == NULL) {
299             errno = ENOMEM;
300             return -1;
301         }
302         env.envp = nenvp;
303         env.env_size = nsize;
304 #ifdef ENV_DEBUG
305         memset(env.envp + env.env_len, 0,
306             (env.env_size - env.env_len) * sizeof(char *));
307 #endif
308     }
309
310 #ifdef ENV_DEBUG
311     if (env.envp[env.env_len] != NULL) {
312         errno = EINVAL;
313         return -1;
314     }
315 #endif
316
317     if (dupcheck) {
318         len = (strchr(str, '=') - str) + 1;
319         for (ep = env.envp; *ep != NULL; ep++) {
320             if (strncmp(str, *ep, len) == 0) {
321                 if (overwrite)
322                     *ep = str;
323                 found = true;
324                 break;
325             }
326         }
327         /* Prune out extra instances of the variable we just overwrote. */
328         if (found && overwrite) {
329             while (*++ep != NULL) {
330                 if (strncmp(str, *ep, len) == 0) {
331                     char **cur = ep;
332                     while ((*cur = *(cur + 1)) != NULL)
333                         cur++;
334                     ep--;
335                 }
336             }
337             env.env_len = ep - env.envp;
338         }
339     }
340
341     if (!found) {
342         ep = env.envp + env.env_len;
343         env.env_len++;
344         *ep++ = str;
345         *ep = NULL;
346     }
347     return 0;
348 }
349
350 /*
351  * Similar to putenv(3) but operates on sudo's private copy of the
352  * environment (not environ) and it always overwrites.  The dupcheck param
353  * determines whether we need to verify that the variable is not already set.
354  * Will only overwrite an existing variable if overwrite is set.
355  */
356 static int
357 sudo_putenv(char *str, bool dupcheck, bool overwrite)
358 {
359     int rval;
360     debug_decl(sudo_putenv, SUDO_DEBUG_ENV)
361
362     sudo_debug_printf(SUDO_DEBUG_INFO, "sudo_putenv: %s", str);
363
364     rval = sudo_putenv_nodebug(str, dupcheck, overwrite);
365     if (rval == -1) {
366 #ifdef ENV_DEBUG
367         if (env.envp[env.env_len] != NULL)
368             errorx(1, _("sudo_putenv: corrupted envp, length mismatch"));
369 #endif
370         errorx(1, _("unable to allocate memory"));
371     }
372     debug_return_int(rval);
373 }
374
375 /*
376  * Similar to setenv(3) but operates on a private copy of the environment.
377  * The dupcheck param determines whether we need to verify that the variable
378  * is not already set.
379  */
380 static int
381 sudo_setenv2(const char *var, const char *val, bool dupcheck, bool overwrite)
382 {
383     char *estring;
384     size_t esize;
385     int rval;
386     debug_decl(sudo_setenv2, SUDO_DEBUG_ENV)
387
388     esize = strlen(var) + 1 + strlen(val) + 1;
389     estring = emalloc(esize);
390
391     /* Build environment string and insert it. */
392     if (strlcpy(estring, var, esize) >= esize ||
393         strlcat(estring, "=", esize) >= esize ||
394         strlcat(estring, val, esize) >= esize) {
395
396         errorx(1, _("internal error, %s overflow"), "sudo_setenv2()");
397     }
398     rval = sudo_putenv(estring, dupcheck, overwrite);
399     if (rval == -1)
400         efree(estring);
401     debug_return_int(rval);
402 }
403
404 /*
405  * Similar to setenv(3) but operates on a private copy of the environment.
406  * Does not include warnings or debugging to avoid recursive calls.
407  */
408 static int
409 sudo_setenv_nodebug(const char *var, const char *val, int overwrite)
410 {
411     char *estring;
412     size_t esize;
413     int rval = -1;
414
415     esize = strlen(var) + 1 + strlen(val) + 1;
416     if ((estring = malloc(esize)) == NULL) {
417         errno = ENOMEM;
418         goto done;
419     }
420
421     /* Build environment string and insert it. */
422     if (strlcpy(estring, var, esize) >= esize ||
423         strlcat(estring, "=", esize) >= esize ||
424         strlcat(estring, val, esize) >= esize) {
425
426         errno = EINVAL;
427         goto done;
428     }
429     rval = sudo_putenv_nodebug(estring, true, overwrite);
430 done:
431     if (rval == -1)
432         efree(estring);
433     return rval;
434 }
435
436 /*
437  * Similar to setenv(3) but operates on a private copy of the environment.
438  */
439 int
440 sudo_setenv(const char *var, const char *val, int overwrite)
441 {
442     int rval;
443     debug_decl(sudo_setenv, SUDO_DEBUG_ENV)
444
445     rval = sudo_setenv_nodebug(var, val, overwrite);
446     if (rval == -1) {
447         if (errno == EINVAL)
448             errorx(1, _("internal error, %s overflow"), "sudo_setenv()");
449         errorx(1, _("unable to allocate memory"));
450     }
451     debug_return_int(rval);
452 }
453
454 /*
455  * Similar to unsetenv(3) but operates on a private copy of the environment.
456  * Does not include warnings or debugging to avoid recursive calls.
457  */
458 static int
459 sudo_unsetenv_nodebug(const char *var)
460 {
461     char **ep = env.envp;
462     size_t len;
463
464     if (ep == NULL || var == NULL || *var == '\0' || strchr(var, '=') != NULL) {
465         errno = EINVAL;
466         return -1;
467     }
468
469     len = strlen(var);
470     while (*ep != NULL) {
471         if (strncmp(var, *ep, len) == 0 && (*ep)[len] == '=') {
472             /* Found it; shift remainder + NULL over by one. */
473             char **cur = ep;
474             while ((*cur = *(cur + 1)) != NULL)
475                 cur++;
476             /* Keep going, could be multiple instances of the var. */
477         } else {
478             ep++;
479         }
480     }
481     return 0;
482 }
483
484 /*
485  * Similar to unsetenv(3) but operates on a private copy of the environment.
486  */
487 int
488 sudo_unsetenv(const char *name)
489 {
490     int rval;
491     debug_decl(sudo_unsetenv, SUDO_DEBUG_ENV)
492
493     sudo_debug_printf(SUDO_DEBUG_INFO, "sudo_unsetenv: %s", name);
494
495     rval = sudo_unsetenv_nodebug(name);
496
497     debug_return_int(rval);
498 }
499
500 /*
501  * Similar to getenv(3) but operates on a private copy of the environment.
502  * Does not include warnings or debugging to avoid recursive calls.
503  */
504 static char *
505 sudo_getenv_nodebug(const char *name)
506 {
507     char **ep, *val = NULL;
508     size_t namelen = 0;
509
510     if (env.env_len != 0) {
511         /* For BSD compatibility, treat '=' in name like end of string. */
512         while (name[namelen] != '\0' && name[namelen] != '=')
513             namelen++;
514         for (ep = env.envp; *ep != NULL; ep++) {
515             if (strncmp(*ep, name, namelen) == 0 && (*ep)[namelen] == '=') {
516                 val = *ep + namelen + 1;
517                 break;
518             }
519         }
520     }
521     return val;
522 }
523
524 /*
525  * Similar to getenv(3) but operates on a private copy of the environment.
526  */
527 char *
528 sudo_getenv(const char *name)
529 {
530     char *val;
531     debug_decl(sudo_getenv, SUDO_DEBUG_ENV)
532
533     sudo_debug_printf(SUDO_DEBUG_INFO, "sudo_getenv: %s", name);
534
535     val = sudo_getenv_nodebug(name);
536
537     debug_return_str(val);
538 }
539
540 /*
541  * Merge another environment with our private copy.
542  */
543 void
544 env_merge(char * const envp[], bool overwrite)
545 {
546     char * const *ep;
547     debug_decl(env_merge, SUDO_DEBUG_ENV)
548
549     for (ep = envp; *ep != NULL; ep++)
550         sudo_putenv(*ep, true, overwrite);
551
552     debug_return;
553 }
554
555 /*
556  * Check the env_delete blacklist.
557  * Returns true if the variable was found, else false.
558  */
559 static bool
560 matches_env_delete(const char *var)
561 {
562     struct list_member *cur;
563     size_t len;
564     bool iswild;
565     bool match = false;
566     debug_decl(matches_env_delete, SUDO_DEBUG_ENV)
567
568     /* Skip anything listed in env_delete. */
569     for (cur = def_env_delete; cur; cur = cur->next) {
570         len = strlen(cur->value);
571         /* Deal with '*' wildcard */
572         if (cur->value[len - 1] == '*') {
573             len--;
574             iswild = true;
575         } else
576             iswild = false;
577         if (strncmp(cur->value, var, len) == 0 &&
578             (iswild || var[len] == '=')) {
579             match = true;
580             break;
581         }
582     }
583     debug_return_bool(match);
584 }
585
586 /*
587  * Apply the env_check list.
588  * Returns true if the variable is allowed, false if denied
589  * or -1 if no match.
590  */
591 static int
592 matches_env_check(const char *var)
593 {
594     struct list_member *cur;
595     size_t len;
596     bool iswild;
597     int keepit = -1;
598     debug_decl(matches_env_check, SUDO_DEBUG_ENV)
599
600     for (cur = def_env_check; cur; cur = cur->next) {
601         len = strlen(cur->value);
602         /* Deal with '*' wildcard */
603         if (cur->value[len - 1] == '*') {
604             len--;
605             iswild = true;
606         } else
607             iswild = false;
608         if (strncmp(cur->value, var, len) == 0 &&
609             (iswild || var[len] == '=')) {
610             keepit = !strpbrk(var, "/%");
611             break;
612         }
613     }
614     debug_return_bool(keepit);
615 }
616
617 /*
618  * Check the env_keep list.
619  * Returns true if the variable is allowed else false.
620  */
621 static bool
622 matches_env_keep(const char *var)
623 {
624     struct list_member *cur;
625     size_t len;
626     bool iswild, keepit = false;
627     debug_decl(matches_env_keep, SUDO_DEBUG_ENV)
628
629     /* Preserve SHELL variable for "sudo -s". */
630     if (ISSET(sudo_mode, MODE_SHELL) && strncmp(var, "SHELL=", 6) == 0) {
631         keepit = true;
632         goto done;
633     }
634
635     for (cur = def_env_keep; cur; cur = cur->next) {
636         len = strlen(cur->value);
637         /* Deal with '*' wildcard */
638         if (cur->value[len - 1] == '*') {
639             len--;
640             iswild = true;
641         } else
642             iswild = false;
643         if (strncmp(cur->value, var, len) == 0 &&
644             (iswild || var[len] == '=')) {
645             keepit = true;
646             break;
647         }
648     }
649 done:
650     debug_return_bool(keepit);
651 }
652
653 /*
654  * Look up var in the env_delete and env_check.
655  * Returns true if we should delete the variable, else false.
656  */
657 static bool
658 env_should_delete(const char *var)
659 {
660     int delete_it;
661     debug_decl(env_should_delete, SUDO_DEBUG_ENV);
662
663     delete_it = matches_env_delete(var);
664     if (!delete_it)
665         delete_it = matches_env_check(var) == false;
666
667     sudo_debug_printf(SUDO_DEBUG_INFO, "delete %s: %s",
668         var, delete_it ? "YES" : "NO");
669     debug_return_bool(delete_it);
670 }
671
672 /*
673  * Lookup var in the env_check and env_keep lists.
674  * Returns true if the variable is allowed else false.
675  */
676 static bool
677 env_should_keep(const char *var)
678 {
679     int keepit;
680     debug_decl(env_should_keep, SUDO_DEBUG_ENV)
681
682     keepit = matches_env_check(var);
683     if (keepit == -1)
684         keepit = matches_env_keep(var);
685
686     sudo_debug_printf(SUDO_DEBUG_INFO, "keep %s: %s",
687         var, keepit ? "YES" : "NO");
688     debug_return_bool(keepit == true);
689 }
690
691 static void
692 env_update_didvar(const char *ep, unsigned int *didvar)
693 {
694     switch (*ep) {
695         case 'H':
696             if (strncmp(ep, "HOME=", 5) == 0)
697                 SET(*didvar, DID_HOME);
698             break;
699         case 'L':
700             if (strncmp(ep, "LOGNAME=", 8) == 0)
701                 SET(*didvar, DID_LOGNAME);
702             break;
703         case 'M':
704             if (strncmp(ep, "MAIL=", 5) == 0)
705                 SET(*didvar, DID_MAIL);
706             break;
707         case 'P':
708             if (strncmp(ep, "PATH=", 5) == 0)
709                 SET(*didvar, DID_PATH);
710             break;
711         case 'S':
712             if (strncmp(ep, "SHELL=", 6) == 0)
713                 SET(*didvar, DID_SHELL);
714             break;
715         case 'T':
716             if (strncmp(ep, "TERM=", 5) == 0)
717                 SET(*didvar, DID_TERM);
718             break;
719         case 'U':
720             if (strncmp(ep, "USER=", 5) == 0)
721                 SET(*didvar, DID_USER);
722             if (strncmp(ep, "USERNAME=", 5) == 0)
723                 SET(*didvar, DID_USERNAME);
724             break;
725     }
726 }
727
728 /*
729  * Build a new environment and ether clear potentially dangerous
730  * variables from the old one or start with a clean slate.
731  * Also adds sudo-specific variables (SUDO_*).
732  */
733 void
734 rebuild_env(void)
735 {
736     char **old_envp, **ep, *cp, *ps1;
737     char idbuf[MAX_UID_T_LEN + 1];
738     unsigned int didvar;
739     bool reset_home = false;
740
741     /*
742      * Either clean out the environment or reset to a safe default.
743      */
744     ps1 = NULL;
745     didvar = 0;
746     env.env_len = 0;
747     env.env_size = 128;
748     old_envp = env.envp;
749     env.envp = emalloc2(env.env_size, sizeof(char *));
750 #ifdef ENV_DEBUG
751     memset(env.envp, 0, env.env_size * sizeof(char *));
752 #else
753     env.envp[0] = NULL;
754 #endif
755
756     /* Reset HOME based on target user if configured to. */
757     if (ISSET(sudo_mode, MODE_RUN)) {
758         if (def_always_set_home ||
759             ISSET(sudo_mode, MODE_RESET_HOME | MODE_LOGIN_SHELL) || 
760             (ISSET(sudo_mode, MODE_SHELL) && def_set_home))
761             reset_home = true;
762     }
763
764     if (def_env_reset || ISSET(sudo_mode, MODE_LOGIN_SHELL)) {
765         /*
766          * If starting with a fresh environment, initialize it based on
767          * /etc/environment or login.conf.  For "sudo -i" we want those
768          * variables to override the invoking user's environment, so we
769          * defer reading them until later.
770          */
771         if (!ISSET(sudo_mode, MODE_LOGIN_SHELL)) {
772 #ifdef HAVE_LOGIN_CAP_H
773             /* Insert login class environment variables. */
774             if (login_class) {
775                 login_cap_t *lc = login_getclass(login_class);
776                 if (lc != NULL) {
777                     setusercontext(lc, runas_pw, runas_pw->pw_uid,
778                         LOGIN_SETPATH|LOGIN_SETENV);
779                     login_close(lc);
780                 }
781             }
782 #endif /* HAVE_LOGIN_CAP_H */
783 #if defined(_AIX) || (defined(__linux__) && !defined(HAVE_PAM))
784             /* Insert system-wide environment variables. */
785             read_env_file(_PATH_ENVIRONMENT, true);
786 #endif
787             for (ep = env.envp; *ep; ep++)
788                 env_update_didvar(*ep, &didvar);
789         }
790
791         /* Pull in vars we want to keep from the old environment. */
792         for (ep = old_envp; *ep; ep++) {
793             bool keepit;
794
795             /* Skip variables with values beginning with () (bash functions) */
796             if ((cp = strchr(*ep, '=')) != NULL) {
797                 if (strncmp(cp, "=() ", 3) == 0)
798                     continue;
799             }
800
801             /*
802              * Look up the variable in the env_check and env_keep lists.
803              */
804             keepit = env_should_keep(*ep);
805
806             /*
807              * Do SUDO_PS1 -> PS1 conversion.
808              * This must happen *after* env_should_keep() is called.
809              */
810             if (strncmp(*ep, "SUDO_PS1=", 8) == 0)
811                 ps1 = *ep + 5;
812
813             if (keepit) {
814                 /* Preserve variable. */
815                 sudo_putenv(*ep, false, false);
816                 env_update_didvar(*ep, &didvar);
817             }
818         }
819         didvar |= didvar << 8;          /* convert DID_* to KEPT_* */
820
821         /*
822          * Add in defaults.  In -i mode these come from the runas user,
823          * otherwise they may be from the user's environment (depends
824          * on sudoers options).
825          */
826         if (ISSET(sudo_mode, MODE_LOGIN_SHELL)) {
827             sudo_setenv2("SHELL", runas_pw->pw_shell,
828                 ISSET(didvar, DID_SHELL), true);
829             sudo_setenv2("LOGNAME", runas_pw->pw_name,
830                 ISSET(didvar, DID_LOGNAME), true);
831             sudo_setenv2("USER", runas_pw->pw_name,
832                 ISSET(didvar, DID_USER), true);
833             sudo_setenv2("USERNAME", runas_pw->pw_name,
834                 ISSET(didvar, DID_USERNAME), true);
835         } else {
836             if (!ISSET(didvar, DID_SHELL))
837                 sudo_setenv2("SHELL", sudo_user.pw->pw_shell, false, true);
838             /* We will set LOGNAME later in the !def_set_logname case. */
839             if (!def_set_logname) {
840                 if (!ISSET(didvar, DID_LOGNAME))
841                     sudo_setenv2("LOGNAME", user_name, false, true);
842                 if (!ISSET(didvar, DID_USER))
843                     sudo_setenv2("USER", user_name, false, true);
844                 if (!ISSET(didvar, DID_USERNAME))
845                     sudo_setenv2("USERNAME", user_name, false, true);
846             }
847         }
848
849         /* If we didn't keep HOME, reset it based on target user. */
850         if (!ISSET(didvar, KEPT_HOME))
851             reset_home = true;
852
853         /*
854          * Set MAIL to target user in -i mode or if MAIL is not preserved
855          * from user's environment.
856          */
857         if (ISSET(sudo_mode, MODE_LOGIN_SHELL) || !ISSET(didvar, KEPT_MAIL)) {
858             cp = _PATH_MAILDIR;
859             if (cp[sizeof(_PATH_MAILDIR) - 2] == '/')
860                 easprintf(&cp, "MAIL=%s%s", _PATH_MAILDIR, runas_pw->pw_name);
861             else
862                 easprintf(&cp, "MAIL=%s/%s", _PATH_MAILDIR, runas_pw->pw_name);
863             sudo_putenv(cp, ISSET(didvar, DID_MAIL), true);
864         }
865     } else {
866         /*
867          * Copy environ entries as long as they don't match env_delete or
868          * env_check.
869          */
870         for (ep = old_envp; *ep; ep++) {
871             /* Skip variables with values beginning with () (bash functions) */
872             if ((cp = strchr(*ep, '=')) != NULL) {
873                 if (strncmp(cp, "=() ", 3) == 0)
874                     continue;
875             }
876
877             /* Add variable unless it matches a black list. */
878             if (!env_should_delete(*ep)) {
879                 if (strncmp(*ep, "SUDO_PS1=", 9) == 0)
880                     ps1 = *ep + 5;
881                 else if (strncmp(*ep, "PATH=", 5) == 0)
882                     SET(didvar, DID_PATH);
883                 else if (strncmp(*ep, "TERM=", 5) == 0)
884                     SET(didvar, DID_TERM);
885                 sudo_putenv(*ep, false, false);
886             }
887         }
888     }
889     /* Replace the PATH envariable with a secure one? */
890     if (def_secure_path && !user_is_exempt()) {
891         sudo_setenv2("PATH", def_secure_path, true, true);
892         SET(didvar, DID_PATH);
893     }
894
895     /*
896      * Set $USER, $LOGNAME and $USERNAME to target if "set_logname" is not
897      * disabled.  We skip this if we are running a login shell (because
898      * they have already been set) or sudoedit (because we want the editor
899      * to find the invoking user's startup files).
900      */
901     if (def_set_logname && !ISSET(sudo_mode, MODE_LOGIN_SHELL|MODE_EDIT)) {
902         if (!ISSET(didvar, KEPT_LOGNAME))
903             sudo_setenv2("LOGNAME", runas_pw->pw_name, true, true);
904         if (!ISSET(didvar, KEPT_USER))
905             sudo_setenv2("USER", runas_pw->pw_name, true, true);
906         if (!ISSET(didvar, KEPT_USERNAME))
907             sudo_setenv2("USERNAME", runas_pw->pw_name, true, true);
908     }
909
910     /* Set $HOME to target user if not preserving user's value. */
911     if (reset_home)
912         sudo_setenv2("HOME", runas_pw->pw_dir, true, true);
913
914     /* Provide default values for $TERM and $PATH if they are not set. */
915     if (!ISSET(didvar, DID_TERM))
916         sudo_putenv("TERM=unknown", false, false);
917     if (!ISSET(didvar, DID_PATH))
918         sudo_setenv2("PATH", _PATH_STDPATH, false, true);
919
920     /* Set PS1 if SUDO_PS1 is set. */
921     if (ps1 != NULL)
922         sudo_putenv(ps1, true, true);
923
924     /* Add the SUDO_COMMAND envariable (cmnd + args). */
925     if (user_args) {
926         easprintf(&cp, "%s %s", user_cmnd, user_args);
927         sudo_setenv2("SUDO_COMMAND", cp, true, true);
928         efree(cp);
929     } else {
930         sudo_setenv2("SUDO_COMMAND", user_cmnd, true, true);
931     }
932
933     /* Add the SUDO_USER, SUDO_UID, SUDO_GID environment variables. */
934     sudo_setenv2("SUDO_USER", user_name, true, true);
935     snprintf(idbuf, sizeof(idbuf), "%u", (unsigned int) user_uid);
936     sudo_setenv2("SUDO_UID", idbuf, true, true);
937     snprintf(idbuf, sizeof(idbuf), "%u", (unsigned int) user_gid);
938     sudo_setenv2("SUDO_GID", idbuf, true, true);
939
940     /* Free old environment. */
941     efree(old_envp);
942 }
943
944 void
945 insert_env_vars(char * const envp[])
946 {
947     char * const *ep;
948
949     if (envp == NULL)
950         return;
951
952     /* Add user-specified environment variables. */
953     for (ep = envp; *ep != NULL; ep++)
954         sudo_putenv(*ep, true, true);
955 }
956
957 /*
958  * Validate the list of environment variables passed in on the command
959  * line against env_delete, env_check, and env_keep.
960  * Calls log_fatal() if any specified variables are not allowed.
961  */
962 void
963 validate_env_vars(char * const env_vars[])
964 {
965     char * const *ep;
966     char *eq, *bad = NULL;
967     size_t len, blen = 0, bsize = 0;
968     bool okvar;
969
970     if (env_vars == NULL)
971         return;
972
973     /* Add user-specified environment variables. */
974     for (ep = env_vars; *ep != NULL; ep++) {
975         if (def_secure_path && !user_is_exempt() &&
976             strncmp(*ep, "PATH=", 5) == 0) {
977             okvar = false;
978         } else if (def_env_reset) {
979             okvar = env_should_keep(*ep);
980         } else {
981             okvar = !env_should_delete(*ep);
982         }
983         if (okvar == false) {
984             /* Not allowed, add to error string, allocating as needed. */
985             if ((eq = strchr(*ep, '=')) != NULL)
986                 *eq = '\0';
987             len = strlen(*ep) + 2;
988             if (blen + len >= bsize) {
989                 do {
990                     bsize += 1024;
991                 } while (blen + len >= bsize);
992                 bad = erealloc(bad, bsize);
993                 bad[blen] = '\0';
994             }
995             strlcat(bad, *ep, bsize);
996             strlcat(bad, ", ", bsize);
997             blen += len;
998             if (eq != NULL)
999                 *eq = '=';
1000         }
1001     }
1002     if (bad != NULL) {
1003         bad[blen - 2] = '\0';           /* remove trailing ", " */
1004         log_fatal(NO_MAIL,
1005             _("sorry, you are not allowed to set the following environment variables: %s"), bad);
1006         /* NOTREACHED */
1007         efree(bad);
1008     }
1009 }
1010
1011 /*
1012  * Read in /etc/environment ala AIX and Linux.
1013  * Lines may be in either of three formats:
1014  *  NAME=VALUE
1015  *  NAME="VALUE"
1016  *  NAME='VALUE'
1017  * with an optional "export" prefix so the shell can source the file.
1018  * Invalid lines, blank lines, or lines consisting solely of a comment
1019  * character are skipped.
1020  */
1021 void
1022 read_env_file(const char *path, int overwrite)
1023 {
1024     FILE *fp;
1025     char *cp, *var, *val;
1026     size_t var_len, val_len;
1027
1028     if ((fp = fopen(path, "r")) == NULL)
1029         return;
1030
1031     while ((var = sudo_parseln(fp)) != NULL) {
1032         /* Skip blank or comment lines */
1033         if (*var == '\0')
1034             continue;
1035
1036         /* Skip optional "export " */
1037         if (strncmp(var, "export", 6) == 0 && isspace((unsigned char) var[6])) {
1038             var += 7;
1039             while (isspace((unsigned char) *var)) {
1040                 var++;
1041             }
1042         }
1043
1044         /* Must be of the form name=["']value['"] */
1045         for (val = var; *val != '\0' && *val != '='; val++)
1046             ;
1047         if (var == val || *val != '=')
1048             continue;
1049         var_len = (size_t)(val - var);
1050         val_len = strlen(++val);
1051
1052         /* Strip leading and trailing single/double quotes */
1053         if ((val[0] == '\'' || val[0] == '\"') && val[0] == val[val_len - 1]) {
1054             val[val_len - 1] = '\0';
1055             val++;
1056             val_len -= 2;
1057         }
1058
1059         cp = emalloc(var_len + 1 + val_len + 1);
1060         memcpy(cp, var, var_len + 1); /* includes '=' */
1061         memcpy(cp + var_len + 1, val, val_len + 1); /* includes NUL */
1062
1063         sudo_putenv(cp, true, overwrite);
1064     }
1065     fclose(fp);
1066 }
1067
1068 void
1069 init_envtables(void)
1070 {
1071     struct list_member *cur;
1072     const char **p;
1073
1074     /* Fill in the "env_delete" list. */
1075     for (p = initial_badenv_table; *p; p++) {
1076         cur = ecalloc(1, sizeof(struct list_member));
1077         cur->value = estrdup(*p);
1078         cur->next = def_env_delete;
1079         def_env_delete = cur;
1080     }
1081
1082     /* Fill in the "env_check" list. */
1083     for (p = initial_checkenv_table; *p; p++) {
1084         cur = ecalloc(1, sizeof(struct list_member));
1085         cur->value = estrdup(*p);
1086         cur->next = def_env_check;
1087         def_env_check = cur;
1088     }
1089
1090     /* Fill in the "env_keep" list. */
1091     for (p = initial_keepenv_table; *p; p++) {
1092         cur = ecalloc(1, sizeof(struct list_member));
1093         cur->value = estrdup(*p);
1094         cur->next = def_env_keep;
1095         def_env_keep = cur;
1096     }
1097 }
1098
1099 int
1100 sudoers_hook_getenv(const char *name, char **value, void *closure)
1101 {
1102     static bool in_progress = false; /* avoid recursion */
1103
1104     if (in_progress || env.envp == NULL)
1105         return SUDO_HOOK_RET_NEXT;
1106
1107     in_progress = true;
1108     *value = sudo_getenv_nodebug(name);
1109     in_progress = false;
1110     return SUDO_HOOK_RET_STOP;
1111 }
1112
1113 int
1114 sudoers_hook_putenv(char *string, void *closure)
1115 {
1116     static bool in_progress = false; /* avoid recursion */
1117
1118     if (in_progress || env.envp == NULL)
1119         return SUDO_HOOK_RET_NEXT;
1120
1121     in_progress = true;
1122     sudo_putenv_nodebug(string, true, true);
1123     in_progress = false;
1124     return SUDO_HOOK_RET_STOP;
1125 }
1126
1127 int
1128 sudoers_hook_setenv(const char *name, const char *value, int overwrite, void *closure)
1129 {
1130     static bool in_progress = false; /* avoid recursion */
1131
1132     if (in_progress || env.envp == NULL)
1133         return SUDO_HOOK_RET_NEXT;
1134
1135     in_progress = true;
1136     sudo_setenv_nodebug(name, value, overwrite);
1137     in_progress = false;
1138     return SUDO_HOOK_RET_STOP;
1139 }
1140
1141 int
1142 sudoers_hook_unsetenv(const char *name, void *closure)
1143 {
1144     static bool in_progress = false; /* avoid recursion */
1145
1146     if (in_progress || env.envp == NULL)
1147         return SUDO_HOOK_RET_NEXT;
1148
1149     in_progress = true;
1150     sudo_unsetenv_nodebug(name);
1151     in_progress = false;
1152     return SUDO_HOOK_RET_STOP;
1153 }