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