prepare to upload
[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     NULL
209 };
210
211 /*
212  * Initialize env based on envp.
213  */
214 void
215 env_init(lazy)
216     int lazy;
217 {
218     char * const *ep;
219     size_t len;
220
221     for (ep = environ; *ep != NULL; ep++)
222         continue;
223     len = (size_t)(ep - environ);
224
225     if (lazy) {
226         /*
227          * If we are already initialized due to lazy init (usualy via getenv())
228          * we need to avoid calling malloc() as it may call getenv() itself.
229          */
230         env.envp = environ;
231         env.env_len = len;
232         env.env_size = len;
233     } else if (!env.owned) {
234         env.env_len = len;
235         env.env_size = len + 1 + 128;
236         env.envp = emalloc2(env.env_size, sizeof(char *));
237 #ifdef ENV_DEBUG
238         memset(env.envp, 0, env.env_size * sizeof(char *));
239 #endif
240         memcpy(env.envp, environ, len * sizeof(char *));
241         env.envp[len] = '\0';
242         env.owned = TRUE;
243     }
244 }
245
246 char **
247 env_get()
248 {
249     return env.envp;
250 }
251
252 /*
253  * Similar to setenv(3) but operates on sudo's private copy of the environment
254  * (not environ) and it always overwrites.  The dupcheck param determines
255  * whether we need to verify that the variable is not already set.
256  */
257 static void
258 sudo_setenv(var, val, dupcheck)
259     const char *var;
260     const char *val;
261     int dupcheck;
262 {
263     char *estring;
264     size_t esize;
265
266     esize = strlen(var) + 1 + strlen(val) + 1;
267     estring = emalloc(esize);
268
269     /* Build environment string and insert it. */
270     if (strlcpy(estring, var, esize) >= esize ||
271         strlcat(estring, "=", esize) >= esize ||
272         strlcat(estring, val, esize) >= esize) {
273
274         errorx(1, "internal error, sudo_setenv() overflow");
275     }
276     sudo_putenv(estring, dupcheck, TRUE);
277 }
278
279 /*
280  * Version of getenv(3) that uses our own environ pointer.
281  */
282 char *
283 getenv(var)
284     const char *var;
285 {
286     char *cp, **ev;
287     size_t vlen = strlen(var);
288
289     if (env.envp == NULL)
290         env_init(TRUE);
291
292     for (ev = env.envp; (cp = *ev) != NULL; ev++) {
293         if (strncmp(var, cp, vlen) == 0 && cp[vlen] == '=')
294             return cp + vlen + 1;
295     }
296     return NULL;
297 }
298
299 /*
300  * Version of setenv(3) that uses our own environ pointer.
301  */
302 int
303 setenv(var, val, overwrite)
304     const char *var;
305     const char *val;
306     int overwrite;
307 {
308     char *estring, *ep;
309     const char *cp;
310     size_t esize;
311
312     if (!var || *var == '\0') {
313         errno = EINVAL;
314         return(-1);
315     }
316
317     if (env.envp == NULL)
318         env_init(TRUE);
319
320     /*
321      * POSIX says a var name with '=' is an error but BSD
322      * just ignores the '=' and anything after it.
323      */
324     for (cp = var; *cp && *cp != '='; cp++)
325         ;
326     esize = (size_t)(cp - var) + 2;
327     if (val) {
328         esize += strlen(val);   /* glibc treats a NULL val as "" */
329     }
330
331     /* Allocate and fill in estring. */
332     estring = ep = emalloc(esize);
333     for (cp = var; *cp && *cp != '='; cp++)
334         *ep++ = *cp;
335     *ep++ = '=';
336     if (val) {
337         for (cp = val; *cp; cp++)
338             *ep++ = *cp;
339     }
340     *ep = '\0';
341
342 #ifdef ENV_DEBUG
343     if (env.envp[env.env_len] != NULL)
344         errorx(1, "setenv: corrupted envp, len mismatch");
345 #endif
346     sudo_putenv(estring, TRUE, overwrite);
347     return(0);
348 }
349
350 /*
351  * Version of unsetenv(3) that uses our own environ pointer.
352  */
353 #ifdef UNSETENV_VOID
354 void
355 #else
356 int
357 #endif
358 unsetenv(var)
359     const char *var;
360 {
361     char **ep;
362     size_t len;
363
364     if (var == NULL || *var == '\0' || strchr(var, '=') != NULL) {
365         errno = EINVAL;
366 #ifdef UNSETENV_VOID
367         return;
368 #else
369         return(-1);
370 #endif
371     }
372
373     if (env.envp == NULL)
374         env_init(TRUE);
375
376 #ifdef ENV_DEBUG
377     if (env.envp[env.env_len] != NULL)
378         errorx(1, "unsetenv: corrupted envp, len mismatch");
379 #endif
380
381     len = strlen(var);
382     for (ep = env.envp; *ep != NULL;) {
383         if (strncmp(var, *ep, len) == 0 && (*ep)[len] == '=') {
384             /* Found it; shift remainder + NULL over by one. */
385             char **cur = ep;
386             while ((*cur = *(cur + 1)) != NULL)
387                 cur++;
388             /* Keep going, could be multiple instances of the var. */
389         } else {
390             ep++;
391         }
392     }
393     env.env_len = ep - env.envp;
394 #ifndef UNSETENV_VOID
395     return(0);
396 #endif
397 }
398
399 /*
400  * Version of putenv(3) that uses our own environ pointer.
401  */
402 int
403 #ifdef PUTENV_CONST
404 putenv(const char *string)
405 #else
406 putenv(string)
407     char *string;
408 #endif
409 {
410     if (env.envp == NULL)
411         env_init(TRUE);
412
413     if (strchr(string, '=') == NULL) {
414         errno = EINVAL;
415         return(-1);
416     }
417 #ifdef ENV_DEBUG
418     if (env.envp[env.env_len] != NULL)
419         errorx(1, "putenv: corrupted envp, len mismatch");
420 #endif
421     sudo_putenv((char *)string, TRUE, TRUE);
422     return(0);
423 }
424
425 /*
426  * Similar to putenv(3) but operates on sudo's private copy of the
427  * environment (not environ) and it always overwrites.  The dupcheck param
428  * determines whether we need to verify that the variable is not already set.
429  * Will only overwrite an existing variable if overwrite is set.
430  */
431 static void
432 sudo_putenv(str, dupcheck, overwrite)
433     char *str;
434     int dupcheck;
435     int overwrite;
436 {
437     char **ep;
438     size_t len;
439     int found = FALSE;
440
441     /* Make sure there is room for the new entry plus a NULL. */
442     if (env.env_len + 2 > env.env_size) {
443         env.env_size += 128;
444         if (env.owned) {
445             env.envp = erealloc3(env.envp, env.env_size, sizeof(char *));
446         } else {
447             /* We don't own env.envp, allocate a new one. */
448             ep = emalloc2(env.env_size, sizeof(char *));
449             memcpy(ep, env.envp, env.env_size * sizeof(char *));
450             env.envp = ep;
451             env.owned = TRUE;
452         }
453 #ifdef ENV_DEBUG
454         memset(env.envp + env.env_len, 0,
455             (env.env_size - env.env_len) * sizeof(char *));
456 #endif
457     }
458
459 #ifdef ENV_DEBUG
460     if (env.envp[env.env_len] != NULL)
461         errorx(1, "sudo_putenv: corrupted envp, len mismatch");
462 #endif
463
464     if (dupcheck) {
465         len = (strchr(str, '=') - str) + 1;
466         for (ep = env.envp; !found && *ep != NULL; ep++) {
467             if (strncmp(str, *ep, len) == 0) {
468                 if (overwrite)
469                     *ep = str;
470                 found = TRUE;
471             }
472         }
473         /* Prune out duplicate variables. */
474         if (found && overwrite) {
475             while (*ep != NULL) {
476                 if (strncmp(str, *ep, len) == 0) {
477                     char **cur = ep;
478                     while ((*cur = *(cur + 1)) != NULL)
479                         cur++;
480                 } else {
481                     ep++;
482                 }
483             }
484             env.env_len = ep - env.envp;
485         }
486     }
487
488     if (!found) {
489         ep = env.envp + env.env_len;
490         env.env_len++;
491         *ep++ = str;
492         *ep = NULL;
493     }
494 }
495
496 /*
497  * Check the env_delete blacklist.
498  * Returns TRUE if the variable was found, else false.
499  */
500 static int
501 matches_env_delete(var)
502     const char *var;
503 {
504     struct list_member *cur;
505     size_t len;
506     int iswild, match = FALSE;
507
508     /* Skip anything listed in env_delete. */
509     for (cur = def_env_delete; cur; cur = cur->next) {
510         len = strlen(cur->value);
511         /* Deal with '*' wildcard */
512         if (cur->value[len - 1] == '*') {
513             len--;
514             iswild = TRUE;
515         } else
516             iswild = FALSE;
517         if (strncmp(cur->value, var, len) == 0 &&
518             (iswild || var[len] == '=')) {
519             match = TRUE;
520             break;
521         }
522     }
523     return(match);
524 }
525
526 /*
527  * Apply the env_check list.
528  * Returns TRUE if the variable is allowed, FALSE if denied
529  * or -1 if no match.
530  */
531 static int
532 matches_env_check(var)
533     const char *var;
534 {
535     struct list_member *cur;
536     size_t len;
537     int iswild, keepit = -1;
538
539     for (cur = def_env_check; cur; cur = cur->next) {
540         len = strlen(cur->value);
541         /* Deal with '*' wildcard */
542         if (cur->value[len - 1] == '*') {
543             len--;
544             iswild = TRUE;
545         } else
546             iswild = FALSE;
547         if (strncmp(cur->value, var, len) == 0 &&
548             (iswild || var[len] == '=')) {
549             keepit = !strpbrk(var, "/%");
550             break;
551         }
552     }
553     return(keepit);
554 }
555
556 /*
557  * Check the env_keep list.
558  * Returns TRUE if the variable is allowed else FALSE.
559  */
560 static int
561 matches_env_keep(var)
562     const char *var;
563 {
564     struct list_member *cur;
565     size_t len;
566     int iswild, keepit = FALSE;
567
568     for (cur = def_env_keep; cur; cur = cur->next) {
569         len = strlen(cur->value);
570         /* Deal with '*' wildcard */
571         if (cur->value[len - 1] == '*') {
572             len--;
573             iswild = TRUE;
574         } else
575             iswild = FALSE;
576         if (strncmp(cur->value, var, len) == 0 &&
577             (iswild || var[len] == '=')) {
578             keepit = TRUE;
579             break;
580         }
581     }
582     return(keepit);
583 }
584
585 /*
586  * Build a new environment and ether clear potentially dangerous
587  * variables from the old one or start with a clean slate.
588  * Also adds sudo-specific variables (SUDO_*).
589  */
590 void
591 rebuild_env(noexec)
592     int noexec;
593 {
594     char **old_envp, **ep, *cp, *ps1;
595     char idbuf[MAX_UID_T_LEN];
596     unsigned int didvar;
597     int reset_home = FALSE;
598
599     /*
600      * Either clean out the environment or reset to a safe default.
601      */
602     ps1 = NULL;
603     didvar = 0;
604     env.env_len = 0;
605     env.env_size = 128;
606     old_envp = env.envp;
607     env.envp = emalloc2(env.env_size, sizeof(char *));
608 #ifdef ENV_DEBUG
609     memset(env.envp, 0, env.env_size * sizeof(char *));
610 #endif
611
612     /* Reset HOME based on target user if configured to. */
613     if (ISSET(sudo_mode, MODE_RUN)) {
614         if (def_always_set_home ||
615             ISSET(sudo_mode, MODE_RESET_HOME | MODE_LOGIN_SHELL) || 
616             (ISSET(sudo_mode, MODE_SHELL) && def_set_home))
617             reset_home = TRUE;
618     }
619
620     if (def_env_reset || ISSET(sudo_mode, MODE_LOGIN_SHELL)) {
621         /* Pull in vars we want to keep from the old environment. */
622         for (ep = old_envp; *ep; ep++) {
623             int keepit;
624
625             /* Skip variables with values beginning with () (bash functions) */
626             if ((cp = strchr(*ep, '=')) != NULL) {
627                 if (strncmp(cp, "=() ", 3) == 0)
628                     continue;
629             }
630
631             /*
632              * First check certain variables for '%' and '/' characters.
633              * If no match there, check the keep list.
634              * If nothing matched, we remove it from the environment.
635              */
636             keepit = matches_env_check(*ep);
637             if (keepit == -1)
638                 keepit = matches_env_keep(*ep);
639
640             /* For SUDO_PS1 -> PS1 conversion. */
641             if (strncmp(*ep, "SUDO_PS1=", 8) == 0)
642                 ps1 = *ep + 5;
643
644             if (keepit) {
645                 /* Preserve variable. */
646                 switch (**ep) {
647                     case 'H':
648                         if (strncmp(*ep, "HOME=", 5) == 0)
649                             SET(didvar, DID_HOME);
650                         break;
651                     case 'L':
652                         if (strncmp(*ep, "LOGNAME=", 8) == 0)
653                             SET(didvar, DID_LOGNAME);
654                         break;
655                     case 'M':
656                         if (strncmp(*ep, "MAIL=", 5) == 0)
657                             SET(didvar, DID_MAIL);
658                         break;
659                     case 'P':
660                         if (strncmp(*ep, "PATH=", 5) == 0)
661                             SET(didvar, DID_PATH);
662                         break;
663                     case 'S':
664                         if (strncmp(*ep, "SHELL=", 6) == 0)
665                             SET(didvar, DID_SHELL);
666                         break;
667                     case 'T':
668                         if (strncmp(*ep, "TERM=", 5) == 0)
669                             SET(didvar, DID_TERM);
670                         break;
671                     case 'U':
672                         if (strncmp(*ep, "USER=", 5) == 0)
673                             SET(didvar, DID_USER);
674                         if (strncmp(*ep, "USERNAME=", 5) == 0)
675                             SET(didvar, DID_USERNAME);
676                         break;
677                 }
678                 sudo_putenv(*ep, FALSE, FALSE);
679             }
680         }
681         didvar |= didvar << 8;          /* convert DID_* to KEPT_* */
682
683         /*
684          * Add in defaults.  In -i mode these come from the runas user,
685          * otherwise they may be from the user's environment (depends
686          * on sudoers options).
687          */
688         if (ISSET(sudo_mode, MODE_LOGIN_SHELL)) {
689             sudo_setenv("SHELL", runas_pw->pw_shell, ISSET(didvar, DID_SHELL));
690             sudo_setenv("LOGNAME", runas_pw->pw_name,
691                 ISSET(didvar, DID_LOGNAME));
692             sudo_setenv("USER", runas_pw->pw_name, ISSET(didvar, DID_USER));
693             sudo_setenv("USERNAME", runas_pw->pw_name,
694                 ISSET(didvar, DID_USERNAME));
695         } else {
696             if (!ISSET(didvar, DID_SHELL))
697                 sudo_setenv("SHELL", sudo_user.pw->pw_shell, FALSE);
698             if (!ISSET(didvar, DID_LOGNAME))
699                 sudo_setenv("LOGNAME", user_name, FALSE);
700             if (!ISSET(didvar, DID_USER))
701                 sudo_setenv("USER", user_name, FALSE);
702             if (!ISSET(didvar, DID_USERNAME))
703                 sudo_setenv("USERNAME", user_name, FALSE);
704         }
705
706         /* If we didn't keep HOME, reset it based on target user. */
707         if (!ISSET(didvar, KEPT_HOME))
708             reset_home = TRUE;
709
710         /*
711          * Set MAIL to target user in -i mode or if MAIL is not preserved
712          * from user's environment.
713          */
714         if (ISSET(sudo_mode, MODE_LOGIN_SHELL) || !ISSET(didvar, KEPT_MAIL)) {
715             cp = _PATH_MAILDIR;
716             if (cp[sizeof(_PATH_MAILDIR) - 2] == '/')
717                 easprintf(&cp, "MAIL=%s%s", _PATH_MAILDIR, runas_pw->pw_name);
718             else
719                 easprintf(&cp, "MAIL=%s/%s", _PATH_MAILDIR, runas_pw->pw_name);
720             sudo_putenv(cp, ISSET(didvar, DID_MAIL), TRUE);
721         }
722     } else {
723         /*
724          * Copy environ entries as long as they don't match env_delete or
725          * env_check.
726          */
727         for (ep = old_envp; *ep; ep++) {
728             int okvar;
729
730             /* Skip variables with values beginning with () (bash functions) */
731             if ((cp = strchr(*ep, '=')) != NULL) {
732                 if (strncmp(cp, "=() ", 3) == 0)
733                     continue;
734             }
735
736             /*
737              * First check variables against the blacklist in env_delete.
738              * If no match there check for '%' and '/' characters.
739              */
740             okvar = matches_env_delete(*ep) != TRUE;
741             if (okvar)
742                 okvar = matches_env_check(*ep) != FALSE;
743
744             if (okvar) {
745                 if (strncmp(*ep, "SUDO_PS1=", 9) == 0)
746                     ps1 = *ep + 5;
747                 else if (strncmp(*ep, "PATH=", 5) == 0)
748                     SET(didvar, DID_PATH);
749                 else if (strncmp(*ep, "TERM=", 5) == 0)
750                     SET(didvar, DID_TERM);
751                 sudo_putenv(*ep, FALSE, FALSE);
752             }
753         }
754     }
755     /* Replace the PATH envariable with a secure one? */
756     if (def_secure_path && !user_is_exempt()) {
757         sudo_setenv("PATH", def_secure_path, TRUE);
758         SET(didvar, DID_PATH);
759     }
760
761     /* Set $USER, $LOGNAME and $USERNAME to target if "set_logname" is true. */
762     if (def_set_logname && !ISSET(sudo_mode, MODE_LOGIN_SHELL)) {
763         if (!ISSET(didvar, KEPT_LOGNAME))
764             sudo_setenv("LOGNAME", runas_pw->pw_name, TRUE);
765         if (!ISSET(didvar, KEPT_USER))
766             sudo_setenv("USER", runas_pw->pw_name, TRUE);
767         if (!ISSET(didvar, KEPT_USERNAME))
768             sudo_setenv("USERNAME", runas_pw->pw_name, TRUE);
769     }
770
771     /* Set $HOME to target user if not preserving user's value. */
772     if (reset_home)
773         sudo_setenv("HOME", runas_pw->pw_dir, TRUE);
774
775     /* Provide default values for $TERM and $PATH if they are not set. */
776     if (!ISSET(didvar, DID_TERM))
777         sudo_putenv("TERM=unknown", FALSE, FALSE);
778     if (!ISSET(didvar, DID_PATH))
779         sudo_setenv("PATH", _PATH_STDPATH, FALSE);
780
781     /*
782      * Preload a noexec file?  For a list of LD_PRELOAD-alikes, see
783      * http://www.fortran-2000.com/ArnaudRecipes/sharedlib.html
784      * XXX - should prepend to original value, if any
785      */
786     if (noexec && def_noexec_file != NULL) {
787 #if defined(__darwin__) || defined(__APPLE__)
788         sudo_setenv("DYLD_INSERT_LIBRARIES", def_noexec_file, TRUE);
789         sudo_setenv("DYLD_FORCE_FLAT_NAMESPACE", "", TRUE);
790 #else
791 # if defined(__osf__) || defined(__sgi)
792         easprintf(&cp, "%s:DEFAULT", def_noexec_file);
793         sudo_setenv("_RLD_LIST", cp, TRUE);
794         efree(cp);
795 # else
796 #  ifdef _AIX
797         sudo_setenv("LDR_PRELOAD", def_noexec_file, TRUE);
798 #  else
799         sudo_setenv("LD_PRELOAD", def_noexec_file, TRUE);
800 #  endif /* _AIX */
801 # endif /* __osf__ || __sgi */
802 #endif /* __darwin__ || __APPLE__ */
803     }
804
805     /* Set PS1 if SUDO_PS1 is set. */
806     if (ps1 != NULL)
807         sudo_putenv(ps1, TRUE, TRUE);
808
809     /* Add the SUDO_COMMAND envariable (cmnd + args). */
810     if (user_args) {
811         easprintf(&cp, "%s %s", user_cmnd, user_args);
812         sudo_setenv("SUDO_COMMAND", cp, TRUE);
813         efree(cp);
814     } else {
815         sudo_setenv("SUDO_COMMAND", user_cmnd, TRUE);
816     }
817
818     /* Add the SUDO_USER, SUDO_UID, SUDO_GID environment variables. */
819     sudo_setenv("SUDO_USER", user_name, TRUE);
820     snprintf(idbuf, sizeof(idbuf), "%lu", (unsigned long) user_uid);
821     sudo_setenv("SUDO_UID", idbuf, TRUE);
822     snprintf(idbuf, sizeof(idbuf), "%lu", (unsigned long) user_gid);
823     sudo_setenv("SUDO_GID", idbuf, TRUE);
824
825     /* Free old environment. */
826     efree(old_envp);
827 }
828
829 void
830 insert_env_vars(env_vars)
831     struct list_member *env_vars;
832 {
833     struct list_member *cur;
834
835     /* Add user-specified environment variables. */
836     for (cur = env_vars; cur != NULL; cur = cur->next)
837         putenv(cur->value);
838 }
839
840 /*
841  * Validate the list of environment variables passed in on the command
842  * line against env_delete, env_check, and env_keep.
843  * Calls log_error() if any specified variables are not allowed.
844  */
845 void
846 validate_env_vars(env_vars)
847     struct list_member *env_vars;
848 {
849     struct list_member *var;
850     char *eq, *bad = NULL;
851     size_t len, blen = 0, bsize = 0;
852     int okvar;
853
854     /* Add user-specified environment variables. */
855     for (var = env_vars; var != NULL; var = var->next) {
856         if (def_secure_path && !user_is_exempt() &&
857             strncmp(var->value, "PATH=", 5) == 0) {
858             okvar = FALSE;
859         } else if (def_env_reset) {
860             okvar = matches_env_check(var->value);
861             if (okvar == -1)
862                 okvar = matches_env_keep(var->value);
863         } else {
864             okvar = matches_env_delete(var->value) == FALSE;
865             if (okvar == FALSE)
866                 okvar = matches_env_check(var->value) != FALSE;
867         }
868         if (okvar == FALSE) {
869             /* Not allowed, add to error string, allocating as needed. */
870             if ((eq = strchr(var->value, '=')) != NULL)
871                 *eq = '\0';
872             len = strlen(var->value) + 2;
873             if (blen + len >= bsize) {
874                 do {
875                     bsize += 1024;
876                 } while (blen + len >= bsize);
877                 bad = erealloc(bad, bsize);
878                 bad[blen] = '\0';
879             }
880             strlcat(bad, var->value, bsize);
881             strlcat(bad, ", ", bsize);
882             blen += len;
883             if (eq != NULL)
884                 *eq = '=';
885         }
886     }
887     if (bad != NULL) {
888         bad[blen - 2] = '\0';           /* remove trailing ", " */
889         log_error(NO_MAIL,
890             "sorry, you are not allowed to set the following environment variables: %s", bad);
891         /* NOTREACHED */
892         efree(bad);
893     }
894 }
895
896 /*
897  * Read in /etc/environment ala AIX and Linux.
898  * Lines may be in either of three formats:
899  *  NAME=VALUE
900  *  NAME="VALUE"
901  *  NAME='VALUE'
902  * with an optional "export" prefix so the shell can source the file.
903  * Invalid lines, blank lines, or lines consisting solely of a comment
904  * character are skipped.
905  */
906 void
907 read_env_file(path, overwrite)
908     const char *path;
909     int overwrite;
910 {
911     FILE *fp;
912     char *cp, *var, *val;
913     size_t var_len, val_len;
914
915     if ((fp = fopen(path, "r")) == NULL)
916         return;
917
918     while ((var = sudo_parseln(fp)) != NULL) {
919         /* Skip blank or comment lines */
920         if (*var == '\0')
921             continue;
922
923         /* Skip optional "export " */
924         if (strncmp(var, "export", 6) == 0 && isspace((unsigned char) var[6])) {
925             var += 7;
926             while (isspace((unsigned char) *var)) {
927                 var++;
928             }
929         }
930
931         /* Must be of the form name=["']value['"] */
932         for (val = var; *val != '\0' && *val != '='; val++)
933             ;
934         if (var == val || *val != '=')
935             continue;
936         var_len = (size_t)(val - var);
937         val_len = strlen(++val);
938
939         /* Strip leading and trailing single/double quotes */
940         if ((val[0] == '\'' || val[0] == '\"') && val[0] == val[val_len - 1]) {
941             val[val_len - 1] = '\0';
942             val++;
943             val_len -= 2;
944         }
945
946         cp = emalloc(var_len + 1 + val_len + 1);
947         memcpy(cp, var, var_len + 1); /* includes '=' */
948         memcpy(cp + var_len + 1, val, val_len + 1); /* includes NUL */
949
950         sudo_putenv(cp, TRUE, overwrite);
951     }
952     fclose(fp);
953 }
954
955 void
956 init_envtables()
957 {
958     struct list_member *cur;
959     const char **p;
960
961     /* Fill in the "env_delete" list. */
962     for (p = initial_badenv_table; *p; p++) {
963         cur = emalloc(sizeof(struct list_member));
964         cur->value = estrdup(*p);
965         cur->next = def_env_delete;
966         def_env_delete = cur;
967     }
968
969     /* Fill in the "env_check" list. */
970     for (p = initial_checkenv_table; *p; p++) {
971         cur = emalloc(sizeof(struct list_member));
972         cur->value = estrdup(*p);
973         cur->next = def_env_check;
974         def_env_check = cur;
975     }
976
977     /* Fill in the "env_keep" list. */
978     for (p = initial_keepenv_table; *p; p++) {
979         cur = emalloc(sizeof(struct list_member));
980         cur->value = estrdup(*p);
981         cur->next = def_env_keep;
982         def_env_keep = cur;
983     }
984 }