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