Imported Upstream version 1.7.6p1
[debian/sudo] / env.c
1 /*
2  * Copyright (c) 2000-2005, 2007-2010
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 #include <ctype.h>
46 #include <errno.h>
47 #include <pwd.h>
48
49 #include "sudo.h"
50
51 /*
52  * Flags used in rebuild_env()
53  */
54 #undef DID_TERM
55 #define DID_TERM        0x0001
56 #undef DID_PATH
57 #define DID_PATH        0x0002
58 #undef DID_HOME
59 #define DID_HOME        0x0004
60 #undef DID_SHELL
61 #define DID_SHELL       0x0008
62 #undef DID_LOGNAME
63 #define DID_LOGNAME     0x0010
64 #undef DID_USER
65 #define DID_USER        0x0020
66 #undef DID_USERNAME
67 #define DID_USERNAME    0x0040
68 #undef DID_MAIL
69 #define DID_MAIL        0x0080
70 #undef DID_MAX
71 #define DID_MAX         0x00ff
72
73 #undef KEPT_TERM
74 #define KEPT_TERM       0x0100
75 #undef KEPT_PATH
76 #define KEPT_PATH       0x0200
77 #undef KEPT_HOME
78 #define KEPT_HOME       0x0400
79 #undef KEPT_SHELL
80 #define KEPT_SHELL      0x0800
81 #undef KEPT_LOGNAME
82 #define KEPT_LOGNAME    0x1000
83 #undef KEPT_USER
84 #define KEPT_USER       0x2000
85 #undef KEPT_USERNAME
86 #define KEPT_USERNAME   0x4000
87 #undef KEPT_MAIL
88 #define KEPT_MAIL       0x8000
89 #undef KEPT_MAX
90 #define KEPT_MAX        0xff00
91
92 struct environment {
93     char **envp;                /* pointer to the new environment */
94     size_t env_size;            /* size of new_environ in char **'s */
95     size_t env_len;             /* number of slots used, not counting NULL */
96     int owned;                  /* do we own envp or is it the system's? */
97 };
98
99 /*
100  * Prototypes
101  */
102 static void sudo_setenv         __P((const char *, const char *, int));
103 static void sudo_putenv         __P((char *, int, int));
104
105 extern char **environ;          /* global environment */
106
107 /*
108  * Copy of the sudo-managed environment.
109  */
110 static struct environment env;
111
112 /*
113  * Default table of "bad" variables to remove from the environment.
114  * XXX - how to omit TERMCAP if it starts with '/'?
115  */
116 static const char *initial_badenv_table[] = {
117     "IFS",
118     "CDPATH",
119     "LOCALDOMAIN",
120     "RES_OPTIONS",
121     "HOSTALIASES",
122     "NLSPATH",
123     "PATH_LOCALE",
124     "LD_*",
125     "_RLD*",
126 #ifdef __hpux
127     "SHLIB_PATH",
128 #endif /* __hpux */
129 #ifdef _AIX
130     "LDR_*",
131     "LIBPATH",
132     "AUTHSTATE",
133 #endif
134 #ifdef __APPLE__
135     "DYLD_*",
136 #endif
137 #ifdef HAVE_KERB4
138     "KRB_CONF*",
139     "KRBCONFDIR",
140     "KRBTKFILE",
141 #endif /* HAVE_KERB4 */
142 #ifdef HAVE_KERB5
143     "KRB5_CONFIG*",
144     "KRB5_KTNAME",
145 #endif /* HAVE_KERB5 */
146 #ifdef HAVE_SECURID
147     "VAR_ACE",
148     "USR_ACE",
149     "DLC_ACE",
150 #endif /* HAVE_SECURID */
151     "TERMINFO",                 /* terminfo, exclusive path to terminfo files */
152     "TERMINFO_DIRS",            /* terminfo, path(s) to terminfo files */
153     "TERMPATH",                 /* termcap, path(s) to termcap files */
154     "TERMCAP",                  /* XXX - only if it starts with '/' */
155     "ENV",                      /* ksh, file to source before script runs */
156     "BASH_ENV",                 /* bash, file to source before script runs */
157     "PS4",                      /* bash, prefix for lines in xtrace mode */
158     "GLOBIGNORE",               /* bash, globbing patterns to ignore */
159     "SHELLOPTS",                /* bash, extra command line options */
160     "JAVA_TOOL_OPTIONS",        /* java, extra command line options */
161     "PERLIO_DEBUG ",            /* perl, debugging output file */
162     "PERLLIB",                  /* perl, search path for modules/includes */
163     "PERL5LIB",                 /* perl 5, search path for modules/includes */
164     "PERL5OPT",                 /* perl 5, extra command line options */
165     "PERL5DB",                  /* perl 5, command used to load debugger */
166     "FPATH",                    /* ksh, search path for functions */
167     "NULLCMD",                  /* zsh, command for null file redirection */
168     "READNULLCMD",              /* zsh, command for null file redirection */
169     "ZDOTDIR",                  /* zsh, search path for dot files */
170     "TMPPREFIX",                /* zsh, prefix for temporary files */
171     "PYTHONHOME",               /* python, module search path */
172     "PYTHONPATH",               /* python, search path */
173     "PYTHONINSPECT",            /* python, allow inspection */
174     "PYTHONUSERBASE",           /* python, per user site-packages directory */
175     "RUBYLIB",                  /* ruby, library load path */
176     "RUBYOPT",                  /* ruby, extra command line options */
177     NULL
178 };
179
180 /*
181  * Default table of variables to check for '%' and '/' characters.
182  */
183 static const char *initial_checkenv_table[] = {
184     "COLORTERM",
185     "LANG",
186     "LANGUAGE",
187     "LC_*",
188     "LINGUAS",
189     "TERM",
190     NULL
191 };
192
193 /*
194  * Default table of variables to preserve in the environment.
195  */
196 static const char *initial_keepenv_table[] = {
197     "COLORS",
198     "DISPLAY",
199     "HOSTNAME",
200     "KRB5CCNAME",
201     "LS_COLORS",
202     "PATH",
203     "PS1",
204     "PS2",
205     "TZ",
206     "XAUTHORITY",
207     "XAUTHORIZATION",
208 #ifdef _AIX
209     "ODMDIR",
210 #endif
211     NULL
212 };
213
214 /*
215  * Initialize env based on envp.
216  */
217 void
218 env_init(lazy)
219     int lazy;
220 {
221     char * const *ep;
222     size_t len;
223
224     for (ep = environ; *ep != NULL; ep++)
225         continue;
226     len = (size_t)(ep - environ);
227
228     if (lazy) {
229         /*
230          * If we are already initialized due to lazy init (usualy via getenv())
231          * we need to avoid calling malloc() as it may call getenv() itself.
232          */
233         env.envp = environ;
234         env.env_len = len;
235         env.env_size = len;
236     } else if (!env.owned) {
237         env.env_len = len;
238         env.env_size = len + 1 + 128;
239         env.envp = emalloc2(env.env_size, sizeof(char *));
240 #ifdef ENV_DEBUG
241         memset(env.envp, 0, env.env_size * sizeof(char *));
242 #endif
243         memcpy(env.envp, environ, len * sizeof(char *));
244         env.envp[len] = '\0';
245         env.owned = TRUE;
246     }
247 }
248
249 char **
250 env_get()
251 {
252     return env.envp;
253 }
254
255 /*
256  * Similar to setenv(3) but operates on sudo's private copy of the environment
257  * (not environ) and it always overwrites.  The dupcheck param determines
258  * whether we need to verify that the variable is not already set.
259  */
260 static void
261 sudo_setenv(var, val, dupcheck)
262     const char *var;
263     const char *val;
264     int dupcheck;
265 {
266     char *estring;
267     size_t esize;
268
269     esize = strlen(var) + 1 + strlen(val) + 1;
270     estring = emalloc(esize);
271
272     /* Build environment string and insert it. */
273     if (strlcpy(estring, var, esize) >= esize ||
274         strlcat(estring, "=", esize) >= esize ||
275         strlcat(estring, val, esize) >= esize) {
276
277         errorx(1, "internal error, sudo_setenv() overflow");
278     }
279     sudo_putenv(estring, dupcheck, TRUE);
280 }
281
282 /*
283  * Version of getenv(3) that uses our own environ pointer.
284  */
285 char *
286 getenv(var)
287     const char *var;
288 {
289     char *cp, **ev;
290     size_t vlen = strlen(var);
291
292     if (env.envp == NULL)
293         env_init(TRUE);
294
295     for (ev = env.envp; (cp = *ev) != NULL; ev++) {
296         if (strncmp(var, cp, vlen) == 0 && cp[vlen] == '=')
297             return cp + vlen + 1;
298     }
299     return NULL;
300 }
301
302 /*
303  * Version of setenv(3) that uses our own environ pointer.
304  */
305 int
306 setenv(var, val, overwrite)
307     const char *var;
308     const char *val;
309     int overwrite;
310 {
311     char *estring, *ep;
312     const char *cp;
313     size_t esize;
314
315     if (!var || *var == '\0') {
316         errno = EINVAL;
317         return -1;
318     }
319
320     if (env.envp == NULL)
321         env_init(TRUE);
322
323     /*
324      * POSIX says a var name with '=' is an error but BSD
325      * just ignores the '=' and anything after it.
326      */
327     for (cp = var; *cp && *cp != '='; cp++)
328         ;
329     esize = (size_t)(cp - var) + 2;
330     if (val) {
331         esize += strlen(val);   /* glibc treats a NULL val as "" */
332     }
333
334     /* Allocate and fill in estring. */
335     estring = ep = emalloc(esize);
336     for (cp = var; *cp && *cp != '='; cp++)
337         *ep++ = *cp;
338     *ep++ = '=';
339     if (val) {
340         for (cp = val; *cp; cp++)
341             *ep++ = *cp;
342     }
343     *ep = '\0';
344
345 #ifdef ENV_DEBUG
346     if (env.envp[env.env_len] != NULL)
347         errorx(1, "setenv: corrupted envp, len mismatch");
348 #endif
349     sudo_putenv(estring, TRUE, overwrite);
350     return 0;
351 }
352
353 /*
354  * Version of unsetenv(3) that uses our own environ pointer.
355  */
356 #ifdef UNSETENV_VOID
357 void
358 #else
359 int
360 #endif
361 unsetenv(var)
362     const char *var;
363 {
364     char **ep;
365     size_t len;
366
367     if (var == NULL || *var == '\0' || strchr(var, '=') != NULL) {
368         errno = EINVAL;
369 #ifdef UNSETENV_VOID
370         return;
371 #else
372         return -1;
373 #endif
374     }
375
376     if (env.envp == NULL)
377         env_init(TRUE);
378
379 #ifdef ENV_DEBUG
380     if (env.envp[env.env_len] != NULL)
381         errorx(1, "unsetenv: corrupted envp, len mismatch");
382 #endif
383
384     len = strlen(var);
385     for (ep = env.envp; *ep != NULL;) {
386         if (strncmp(var, *ep, len) == 0 && (*ep)[len] == '=') {
387             /* Found it; shift remainder + NULL over by one. */
388             char **cur = ep;
389             while ((*cur = *(cur + 1)) != NULL)
390                 cur++;
391             /* Keep going, could be multiple instances of the var. */
392         } else {
393             ep++;
394         }
395     }
396     env.env_len = ep - env.envp;
397 #ifndef UNSETENV_VOID
398     return 0;
399 #endif
400 }
401
402 /*
403  * Version of putenv(3) that uses our own environ pointer.
404  */
405 int
406 #ifdef PUTENV_CONST
407 putenv(const char *string)
408 #else
409 putenv(string)
410     char *string;
411 #endif
412 {
413     if (env.envp == NULL)
414         env_init(TRUE);
415
416     if (strchr(string, '=') == NULL) {
417         errno = EINVAL;
418         return -1;
419     }
420 #ifdef ENV_DEBUG
421     if (env.envp[env.env_len] != NULL)
422         errorx(1, "putenv: corrupted envp, len mismatch");
423 #endif
424     sudo_putenv((char *)string, TRUE, TRUE);
425     return 0;
426 }
427
428 /*
429  * Similar to putenv(3) but operates on sudo's private copy of the
430  * environment (not environ) and it always overwrites.  The dupcheck param
431  * determines whether we need to verify that the variable is not already set.
432  * Will only overwrite an existing variable if overwrite is set.
433  */
434 static void
435 sudo_putenv(str, dupcheck, overwrite)
436     char *str;
437     int dupcheck;
438     int overwrite;
439 {
440     char **ep;
441     size_t len;
442     int found = FALSE;
443
444     /* Make sure there is room for the new entry plus a NULL. */
445     if (env.env_len + 2 > env.env_size) {
446         env.env_size += 128;
447         if (env.owned) {
448             env.envp = erealloc3(env.envp, env.env_size, sizeof(char *));
449         } else {
450             /* We don't own env.envp, allocate a new one. */
451             ep = emalloc2(env.env_size, sizeof(char *));
452             memcpy(ep, env.envp, env.env_size * sizeof(char *));
453             env.envp = ep;
454             env.owned = TRUE;
455         }
456 #ifdef ENV_DEBUG
457         memset(env.envp + env.env_len, 0,
458             (env.env_size - env.env_len) * sizeof(char *));
459 #endif
460     }
461
462 #ifdef ENV_DEBUG
463     if (env.envp[env.env_len] != NULL)
464         errorx(1, "sudo_putenv: corrupted envp, len mismatch");
465 #endif
466
467     if (dupcheck) {
468         len = (strchr(str, '=') - str) + 1;
469         for (ep = env.envp; !found && *ep != NULL; ep++) {
470             if (strncmp(str, *ep, len) == 0) {
471                 if (overwrite)
472                     *ep = str;
473                 found = TRUE;
474             }
475         }
476         /* Prune out duplicate variables. */
477         if (found && overwrite) {
478             while (*ep != NULL) {
479                 if (strncmp(str, *ep, len) == 0) {
480                     char **cur = ep;
481                     while ((*cur = *(cur + 1)) != NULL)
482                         cur++;
483                 } else {
484                     ep++;
485                 }
486             }
487             env.env_len = ep - env.envp;
488         }
489     }
490
491     if (!found) {
492         ep = env.envp + env.env_len;
493         env.env_len++;
494         *ep++ = str;
495         *ep = NULL;
496     }
497 }
498
499 /*
500  * Check the env_delete blacklist.
501  * Returns TRUE if the variable was found, else false.
502  */
503 static int
504 matches_env_delete(var)
505     const char *var;
506 {
507     struct list_member *cur;
508     size_t len;
509     int iswild, match = FALSE;
510
511     /* Skip anything listed in env_delete. */
512     for (cur = def_env_delete; cur; cur = cur->next) {
513         len = strlen(cur->value);
514         /* Deal with '*' wildcard */
515         if (cur->value[len - 1] == '*') {
516             len--;
517             iswild = TRUE;
518         } else
519             iswild = FALSE;
520         if (strncmp(cur->value, var, len) == 0 &&
521             (iswild || var[len] == '=')) {
522             match = TRUE;
523             break;
524         }
525     }
526     return match;
527 }
528
529 /*
530  * Apply the env_check list.
531  * Returns TRUE if the variable is allowed, FALSE if denied
532  * or -1 if no match.
533  */
534 static int
535 matches_env_check(var)
536     const char *var;
537 {
538     struct list_member *cur;
539     size_t len;
540     int iswild, keepit = -1;
541
542     for (cur = def_env_check; cur; cur = cur->next) {
543         len = strlen(cur->value);
544         /* Deal with '*' wildcard */
545         if (cur->value[len - 1] == '*') {
546             len--;
547             iswild = TRUE;
548         } else
549             iswild = FALSE;
550         if (strncmp(cur->value, var, len) == 0 &&
551             (iswild || var[len] == '=')) {
552             keepit = !strpbrk(var, "/%");
553             break;
554         }
555     }
556     return keepit;
557 }
558
559 /*
560  * Check the env_keep list.
561  * Returns TRUE if the variable is allowed else FALSE.
562  */
563 static int
564 matches_env_keep(var)
565     const char *var;
566 {
567     struct list_member *cur;
568     size_t len;
569     int iswild, keepit = FALSE;
570
571     for (cur = def_env_keep; cur; cur = cur->next) {
572         len = strlen(cur->value);
573         /* Deal with '*' wildcard */
574         if (cur->value[len - 1] == '*') {
575             len--;
576             iswild = TRUE;
577         } else
578             iswild = FALSE;
579         if (strncmp(cur->value, var, len) == 0 &&
580             (iswild || var[len] == '=')) {
581             keepit = TRUE;
582             break;
583         }
584     }
585     return keepit;
586 }
587
588 /*
589  * Build a new environment and ether clear potentially dangerous
590  * variables from the old one or start with a clean slate.
591  * Also adds sudo-specific variables (SUDO_*).
592  */
593 void
594 rebuild_env(noexec)
595     int noexec;
596 {
597     char **old_envp, **ep, *cp, *ps1;
598     char idbuf[MAX_UID_T_LEN];
599     unsigned int didvar;
600     int reset_home = FALSE;
601
602     /*
603      * Either clean out the environment or reset to a safe default.
604      */
605     ps1 = NULL;
606     didvar = 0;
607     env.env_len = 0;
608     env.env_size = 128;
609     old_envp = env.envp;
610     env.envp = emalloc2(env.env_size, sizeof(char *));
611 #ifdef ENV_DEBUG
612     memset(env.envp, 0, env.env_size * sizeof(char *));
613 #endif
614
615     /* Reset HOME based on target user if configured to. */
616     if (ISSET(sudo_mode, MODE_RUN)) {
617         if (def_always_set_home ||
618             ISSET(sudo_mode, MODE_RESET_HOME | MODE_LOGIN_SHELL) || 
619             (ISSET(sudo_mode, MODE_SHELL) && def_set_home))
620             reset_home = TRUE;
621     }
622
623     if (def_env_reset || ISSET(sudo_mode, MODE_LOGIN_SHELL)) {
624         /* Pull in vars we want to keep from the old environment. */
625         for (ep = old_envp; *ep; ep++) {
626             int keepit;
627
628             /* Skip variables with values beginning with () (bash functions) */
629             if ((cp = strchr(*ep, '=')) != NULL) {
630                 if (strncmp(cp, "=() ", 3) == 0)
631                     continue;
632             }
633
634             /*
635              * First check certain variables for '%' and '/' characters.
636              * If no match there, check the keep list.
637              * If nothing matched, we remove it from the environment.
638              */
639             keepit = matches_env_check(*ep);
640             if (keepit == -1)
641                 keepit = matches_env_keep(*ep);
642
643             /* For SUDO_PS1 -> PS1 conversion. */
644             if (strncmp(*ep, "SUDO_PS1=", 8) == 0)
645                 ps1 = *ep + 5;
646
647             if (keepit) {
648                 /* Preserve variable. */
649                 switch (**ep) {
650                     case 'H':
651                         if (strncmp(*ep, "HOME=", 5) == 0)
652                             SET(didvar, DID_HOME);
653                         break;
654                     case 'L':
655                         if (strncmp(*ep, "LOGNAME=", 8) == 0)
656                             SET(didvar, DID_LOGNAME);
657                         break;
658                     case 'M':
659                         if (strncmp(*ep, "MAIL=", 5) == 0)
660                             SET(didvar, DID_MAIL);
661                         break;
662                     case 'P':
663                         if (strncmp(*ep, "PATH=", 5) == 0)
664                             SET(didvar, DID_PATH);
665                         break;
666                     case 'S':
667                         if (strncmp(*ep, "SHELL=", 6) == 0)
668                             SET(didvar, DID_SHELL);
669                         break;
670                     case 'T':
671                         if (strncmp(*ep, "TERM=", 5) == 0)
672                             SET(didvar, DID_TERM);
673                         break;
674                     case 'U':
675                         if (strncmp(*ep, "USER=", 5) == 0)
676                             SET(didvar, DID_USER);
677                         if (strncmp(*ep, "USERNAME=", 5) == 0)
678                             SET(didvar, DID_USERNAME);
679                         break;
680                 }
681                 sudo_putenv(*ep, FALSE, FALSE);
682             }
683         }
684         didvar |= didvar << 8;          /* convert DID_* to KEPT_* */
685
686         /*
687          * Add in defaults.  In -i mode these come from the runas user,
688          * otherwise they may be from the user's environment (depends
689          * on sudoers options).
690          */
691         if (ISSET(sudo_mode, MODE_LOGIN_SHELL)) {
692             sudo_setenv("SHELL", runas_pw->pw_shell, ISSET(didvar, DID_SHELL));
693             sudo_setenv("LOGNAME", runas_pw->pw_name,
694                 ISSET(didvar, DID_LOGNAME));
695             sudo_setenv("USER", runas_pw->pw_name, ISSET(didvar, DID_USER));
696             sudo_setenv("USERNAME", runas_pw->pw_name,
697                 ISSET(didvar, DID_USERNAME));
698         } else {
699             if (!ISSET(didvar, DID_SHELL))
700                 sudo_setenv("SHELL", sudo_user.pw->pw_shell, FALSE);
701             if (!ISSET(didvar, DID_LOGNAME))
702                 sudo_setenv("LOGNAME", user_name, FALSE);
703             if (!ISSET(didvar, DID_USER))
704                 sudo_setenv("USER", user_name, FALSE);
705             if (!ISSET(didvar, DID_USERNAME))
706                 sudo_setenv("USERNAME", user_name, FALSE);
707         }
708
709         /* If we didn't keep HOME, reset it based on target user. */
710         if (!ISSET(didvar, KEPT_HOME))
711             reset_home = TRUE;
712
713         /*
714          * Set MAIL to target user in -i mode or if MAIL is not preserved
715          * from user's environment.
716          */
717         if (ISSET(sudo_mode, MODE_LOGIN_SHELL) || !ISSET(didvar, KEPT_MAIL)) {
718             cp = _PATH_MAILDIR;
719             if (cp[sizeof(_PATH_MAILDIR) - 2] == '/')
720                 easprintf(&cp, "MAIL=%s%s", _PATH_MAILDIR, runas_pw->pw_name);
721             else
722                 easprintf(&cp, "MAIL=%s/%s", _PATH_MAILDIR, runas_pw->pw_name);
723             sudo_putenv(cp, ISSET(didvar, DID_MAIL), TRUE);
724         }
725     } else {
726         /*
727          * Copy environ entries as long as they don't match env_delete or
728          * env_check.
729          */
730         for (ep = old_envp; *ep; ep++) {
731             int okvar;
732
733             /* Skip variables with values beginning with () (bash functions) */
734             if ((cp = strchr(*ep, '=')) != NULL) {
735                 if (strncmp(cp, "=() ", 3) == 0)
736                     continue;
737             }
738
739             /*
740              * First check variables against the blacklist in env_delete.
741              * If no match there check for '%' and '/' characters.
742              */
743             okvar = matches_env_delete(*ep) != TRUE;
744             if (okvar)
745                 okvar = matches_env_check(*ep) != FALSE;
746
747             if (okvar) {
748                 if (strncmp(*ep, "SUDO_PS1=", 9) == 0)
749                     ps1 = *ep + 5;
750                 else if (strncmp(*ep, "PATH=", 5) == 0)
751                     SET(didvar, DID_PATH);
752                 else if (strncmp(*ep, "TERM=", 5) == 0)
753                     SET(didvar, DID_TERM);
754                 sudo_putenv(*ep, FALSE, FALSE);
755             }
756         }
757     }
758     /* Replace the PATH envariable with a secure one? */
759     if (def_secure_path && !user_is_exempt()) {
760         sudo_setenv("PATH", def_secure_path, TRUE);
761         SET(didvar, DID_PATH);
762     }
763
764     /* Set $USER, $LOGNAME and $USERNAME to target if "set_logname" is true. */
765     if (def_set_logname && !ISSET(sudo_mode, MODE_LOGIN_SHELL)) {
766         if (!ISSET(didvar, KEPT_LOGNAME))
767             sudo_setenv("LOGNAME", runas_pw->pw_name, TRUE);
768         if (!ISSET(didvar, KEPT_USER))
769             sudo_setenv("USER", runas_pw->pw_name, TRUE);
770         if (!ISSET(didvar, KEPT_USERNAME))
771             sudo_setenv("USERNAME", runas_pw->pw_name, TRUE);
772     }
773
774     /* Set $HOME to target user if not preserving user's value. */
775     if (reset_home)
776         sudo_setenv("HOME", runas_pw->pw_dir, TRUE);
777
778     /* Provide default values for $TERM and $PATH if they are not set. */
779     if (!ISSET(didvar, DID_TERM))
780         sudo_putenv("TERM=unknown", FALSE, FALSE);
781     if (!ISSET(didvar, DID_PATH))
782         sudo_setenv("PATH", _PATH_STDPATH, FALSE);
783
784     /*
785      * Preload a noexec file?  For a list of LD_PRELOAD-alikes, see
786      * http://www.fortran-2000.com/ArnaudRecipes/sharedlib.html
787      * XXX - should prepend to original value, if any
788      */
789     if (noexec && def_noexec_file != NULL) {
790 #if defined(__darwin__) || defined(__APPLE__)
791         sudo_setenv("DYLD_INSERT_LIBRARIES", def_noexec_file, TRUE);
792         sudo_setenv("DYLD_FORCE_FLAT_NAMESPACE", "", TRUE);
793 #else
794 # if defined(__osf__) || defined(__sgi)
795         easprintf(&cp, "%s:DEFAULT", def_noexec_file);
796         sudo_setenv("_RLD_LIST", cp, TRUE);
797         efree(cp);
798 # else
799 #  ifdef _AIX
800         sudo_setenv("LDR_PRELOAD", def_noexec_file, TRUE);
801 #  else
802         sudo_setenv("LD_PRELOAD", def_noexec_file, TRUE);
803 #  endif /* _AIX */
804 # endif /* __osf__ || __sgi */
805 #endif /* __darwin__ || __APPLE__ */
806     }
807
808     /* Set PS1 if SUDO_PS1 is set. */
809     if (ps1 != NULL)
810         sudo_putenv(ps1, TRUE, TRUE);
811
812     /* Add the SUDO_COMMAND envariable (cmnd + args). */
813     if (user_args) {
814         easprintf(&cp, "%s %s", user_cmnd, user_args);
815         sudo_setenv("SUDO_COMMAND", cp, TRUE);
816         efree(cp);
817     } else {
818         sudo_setenv("SUDO_COMMAND", user_cmnd, TRUE);
819     }
820
821     /* Add the SUDO_USER, SUDO_UID, SUDO_GID environment variables. */
822     sudo_setenv("SUDO_USER", user_name, TRUE);
823     snprintf(idbuf, sizeof(idbuf), "%u", (unsigned int) user_uid);
824     sudo_setenv("SUDO_UID", idbuf, TRUE);
825     snprintf(idbuf, sizeof(idbuf), "%u", (unsigned int) user_gid);
826     sudo_setenv("SUDO_GID", idbuf, TRUE);
827
828     /* Free old environment. */
829     efree(old_envp);
830 }
831
832 void
833 insert_env_vars(env_vars)
834     struct list_member *env_vars;
835 {
836     struct list_member *cur;
837
838     /* Add user-specified environment variables. */
839     for (cur = env_vars; cur != NULL; cur = cur->next)
840         putenv(cur->value);
841 }
842
843 /*
844  * Validate the list of environment variables passed in on the command
845  * line against env_delete, env_check, and env_keep.
846  * Calls log_error() if any specified variables are not allowed.
847  */
848 void
849 validate_env_vars(env_vars)
850     struct list_member *env_vars;
851 {
852     struct list_member *var;
853     char *eq, *bad = NULL;
854     size_t len, blen = 0, bsize = 0;
855     int okvar;
856
857     /* Add user-specified environment variables. */
858     for (var = env_vars; var != NULL; var = var->next) {
859         if (def_secure_path && !user_is_exempt() &&
860             strncmp(var->value, "PATH=", 5) == 0) {
861             okvar = FALSE;
862         } else if (def_env_reset) {
863             okvar = matches_env_check(var->value);
864             if (okvar == -1)
865                 okvar = matches_env_keep(var->value);
866         } else {
867             okvar = matches_env_delete(var->value) == FALSE;
868             if (okvar == FALSE)
869                 okvar = matches_env_check(var->value) != FALSE;
870         }
871         if (okvar == FALSE) {
872             /* Not allowed, add to error string, allocating as needed. */
873             if ((eq = strchr(var->value, '=')) != NULL)
874                 *eq = '\0';
875             len = strlen(var->value) + 2;
876             if (blen + len >= bsize) {
877                 do {
878                     bsize += 1024;
879                 } while (blen + len >= bsize);
880                 bad = erealloc(bad, bsize);
881                 bad[blen] = '\0';
882             }
883             strlcat(bad, var->value, bsize);
884             strlcat(bad, ", ", bsize);
885             blen += len;
886             if (eq != NULL)
887                 *eq = '=';
888         }
889     }
890     if (bad != NULL) {
891         bad[blen - 2] = '\0';           /* remove trailing ", " */
892         log_error(NO_MAIL,
893             "sorry, you are not allowed to set the following environment variables: %s", bad);
894         /* NOTREACHED */
895         efree(bad);
896     }
897 }
898
899 /*
900  * Read in /etc/environment ala AIX and Linux.
901  * Lines may be in either of three formats:
902  *  NAME=VALUE
903  *  NAME="VALUE"
904  *  NAME='VALUE'
905  * with an optional "export" prefix so the shell can source the file.
906  * Invalid lines, blank lines, or lines consisting solely of a comment
907  * character are skipped.
908  */
909 void
910 read_env_file(path, overwrite)
911     const char *path;
912     int overwrite;
913 {
914     FILE *fp;
915     char *cp, *var, *val;
916     size_t var_len, val_len;
917
918     if ((fp = fopen(path, "r")) == NULL)
919         return;
920
921     while ((var = sudo_parseln(fp)) != NULL) {
922         /* Skip blank or comment lines */
923         if (*var == '\0')
924             continue;
925
926         /* Skip optional "export " */
927         if (strncmp(var, "export", 6) == 0 && isspace((unsigned char) var[6])) {
928             var += 7;
929             while (isspace((unsigned char) *var)) {
930                 var++;
931             }
932         }
933
934         /* Must be of the form name=["']value['"] */
935         for (val = var; *val != '\0' && *val != '='; val++)
936             ;
937         if (var == val || *val != '=')
938             continue;
939         var_len = (size_t)(val - var);
940         val_len = strlen(++val);
941
942         /* Strip leading and trailing single/double quotes */
943         if ((val[0] == '\'' || val[0] == '\"') && val[0] == val[val_len - 1]) {
944             val[val_len - 1] = '\0';
945             val++;
946             val_len -= 2;
947         }
948
949         cp = emalloc(var_len + 1 + val_len + 1);
950         memcpy(cp, var, var_len + 1); /* includes '=' */
951         memcpy(cp + var_len + 1, val, val_len + 1); /* includes NUL */
952
953         sudo_putenv(cp, TRUE, overwrite);
954     }
955     fclose(fp);
956 }
957
958 void
959 init_envtables()
960 {
961     struct list_member *cur;
962     const char **p;
963
964     /* Fill in the "env_delete" list. */
965     for (p = initial_badenv_table; *p; p++) {
966         cur = emalloc(sizeof(struct list_member));
967         cur->value = estrdup(*p);
968         cur->next = def_env_delete;
969         def_env_delete = cur;
970     }
971
972     /* Fill in the "env_check" list. */
973     for (p = initial_checkenv_table; *p; p++) {
974         cur = emalloc(sizeof(struct list_member));
975         cur->value = estrdup(*p);
976         cur->next = def_env_check;
977         def_env_check = cur;
978     }
979
980     /* Fill in the "env_keep" list. */
981     for (p = initial_keepenv_table; *p; p++) {
982         cur = emalloc(sizeof(struct list_member));
983         cur->value = estrdup(*p);
984         cur->next = def_env_keep;
985         def_env_keep = cur;
986     }
987 }