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