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