Imported Debian patch 1.6.9p11-1
[debian/sudo] / env.c
1 /*
2  * Copyright (c) 2000-2007 Todd C. Miller <Todd.Miller@courtesan.com>
3  *
4  * Permission to use, copy, modify, and distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15  *
16  * Sponsored in part by the Defense Advanced Research Projects
17  * Agency (DARPA) and Air Force Research Laboratory, Air Force
18  * Materiel Command, USAF, under agreement number F39502-99-1-0512.
19  */
20
21 #include <config.h>
22
23 #include <sys/types.h>
24 #include <sys/param.h>
25 #include <sys/stat.h>
26 #include <stdio.h>
27 #ifdef STDC_HEADERS
28 # include <stdlib.h>
29 # include <stddef.h>
30 #else
31 # ifdef HAVE_STDLIB_H
32 #  include <stdlib.h>
33 # endif
34 #endif /* STDC_HEADERS */
35 #ifdef HAVE_STRING_H
36 # include <string.h>
37 #else
38 # ifdef HAVE_STRINGS_H
39 #  include <strings.h>
40 # endif
41 #endif /* HAVE_STRING_H */
42 #ifdef HAVE_UNISTD_H
43 # include <unistd.h>
44 #endif /* HAVE_UNISTD_H */
45 #ifdef HAVE_ERR_H
46 # include <err.h>
47 #else
48 # include "emul/err.h"
49 #endif /* HAVE_ERR_H */
50 #include <pwd.h>
51
52 #include "sudo.h"
53
54 #ifndef lint
55 __unused static const char rcsid[] = "$Sudo: env.c,v 1.39.2.17 2007/07/31 18:04:31 millert Exp $";
56 #endif /* lint */
57
58 /*
59  * Flags used in rebuild_env()
60  */
61 #undef DID_TERM
62 #define DID_TERM        0x0001
63 #undef DID_PATH
64 #define DID_PATH        0x0002
65 #undef DID_HOME
66 #define DID_HOME        0x0004
67 #undef DID_SHELL
68 #define DID_SHELL       0x0008
69 #undef DID_LOGNAME
70 #define DID_LOGNAME     0x0010
71 #undef DID_USER
72 #define DID_USER        0x0020
73 #undef DID_USERNAME
74 #define DID_USERNAME    0x0040
75 #undef DID_MAX
76 #define DID_MAX         0x00ff
77
78 #undef KEPT_TERM
79 #define KEPT_TERM       0x0100
80 #undef KEPT_PATH
81 #define KEPT_PATH       0x0200
82 #undef KEPT_HOME
83 #define KEPT_HOME       0x0400
84 #undef KEPT_SHELL
85 #define KEPT_SHELL      0x0800
86 #undef KEPT_LOGNAME
87 #define KEPT_LOGNAME    0x1000
88 #undef KEPT_USER
89 #define KEPT_USER       0x2000
90 #undef KEPT_USERNAME
91 #define KEPT_USERNAME   0x4000
92 #undef KEPT_MAX
93 #define KEPT_MAX        0xff00
94
95 #undef VNULL
96 #define VNULL   (VOID *)NULL
97
98 struct environment {
99     char **envp;                /* pointer to the new environment */
100     size_t env_size;            /* size of new_environ in char **'s */
101     size_t env_len;             /* number of slots used, not counting NULL */
102 };
103
104 /*
105  * Prototypes
106  */
107 char **rebuild_env              __P((char **, int, int));
108 static void insert_env          __P((char *, struct environment *, int));
109 static char *format_env         __P((char *, ...));
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     "SHELLOPTS",
124     "PS4",
125     "LOCALDOMAIN",
126     "RES_OPTIONS",
127     "HOSTALIASES",
128     "NLSPATH",
129     "PATH_LOCALE",
130     "LD_*",
131     "_RLD*",
132 #ifdef __hpux
133     "SHLIB_PATH",
134 #endif /* __hpux */
135 #ifdef _AIX
136     "LDR_*",
137     "LIBPATH",
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     "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  * Given a variable and value, allocate and format an environment string.
218  */
219 static char *
220 #ifdef __STDC__
221 format_env(char *var, ...)
222 #else
223 format_env(var, va_alist)
224     char *var;
225     va_dcl
226 #endif
227 {
228     char *estring;
229     char *val;
230     size_t esize;
231     va_list ap;
232
233 #ifdef __STDC__
234     va_start(ap, var);
235 #else
236     va_start(ap);
237 #endif
238     esize = strlen(var) + 2;
239     while ((val = va_arg(ap, char *)) != NULL)
240         esize += strlen(val);
241     va_end(ap);
242     estring = (char *) emalloc(esize);
243
244     /* Store variable name and the '=' separator.  */
245     if (strlcpy(estring, var, esize) >= esize ||
246         strlcat(estring, "=", esize) >= esize) {
247
248         errx(1, "internal error, format_env() overflow");
249     }
250
251     /* Now store the variable's value (if any) */
252 #ifdef __STDC__
253     va_start(ap, var);
254 #else
255     va_start(ap);
256 #endif
257     while ((val = va_arg(ap, char *)) != NULL) {
258         if (strlcat(estring, val, esize) >= esize)
259             errx(1, "internal error, format_env() overflow");
260     }
261     va_end(ap);
262
263     return(estring);
264 }
265
266 /*
267  * Insert str into e->envp, assumes str has an '=' in it.
268  */
269 static void
270 insert_env(str, e, dupcheck)
271     char *str;
272     struct environment *e;
273     int dupcheck;
274 {
275     char **nep;
276     size_t varlen;
277
278     /* Make sure there is room for the new entry plus a NULL. */
279     if (e->env_len + 2 > e->env_size) {
280         e->env_size += 128;
281         e->envp = erealloc3(e->envp, e->env_size, sizeof(char *));
282     }
283
284     if (dupcheck) {
285             varlen = (strchr(str, '=') - str) + 1;
286
287             for (nep = e->envp; *nep; nep++) {
288                 if (strncmp(str, *nep, varlen) == 0) {
289                     *nep = str;
290                     return;
291                 }
292             }
293     } else
294         nep = e->envp + e->env_len;
295
296     e->env_len++;
297     *nep++ = str;
298     *nep = NULL;
299 }
300
301 /*
302  * Check the env_delete blacklist.
303  * Returns TRUE if the variable was found, else false.
304  */
305 static int
306 matches_env_delete(var)
307     const char *var;
308 {
309     struct list_member *cur;
310     size_t len;
311     int iswild, match = FALSE;
312
313     /* Skip anything listed in env_delete. */
314     for (cur = def_env_delete; cur; cur = cur->next) {
315         len = strlen(cur->value);
316         /* Deal with '*' wildcard */
317         if (cur->value[len - 1] == '*') {
318             len--;
319             iswild = TRUE;
320         } else
321             iswild = FALSE;
322         if (strncmp(cur->value, var, len) == 0 &&
323             (iswild || var[len] == '=')) {
324             match = TRUE;
325             break;
326         }
327     }
328     return(match);
329 }
330
331 /*
332  * Apply the env_check list.
333  * Returns TRUE if the variable is allowed, FALSE if denied
334  * or -1 if no match.
335  */
336 static int
337 matches_env_check(var)
338     const char *var;
339 {
340     struct list_member *cur;
341     size_t len;
342     int iswild, keepit = -1;
343
344     for (cur = def_env_check; cur; cur = cur->next) {
345         len = strlen(cur->value);
346         /* Deal with '*' wildcard */
347         if (cur->value[len - 1] == '*') {
348             len--;
349             iswild = TRUE;
350         } else
351             iswild = FALSE;
352         if (strncmp(cur->value, var, len) == 0 &&
353             (iswild || var[len] == '=')) {
354             keepit = !strpbrk(var, "/%");
355             break;
356         }
357     }
358     return(keepit);
359 }
360
361 /*
362  * Check the env_keep list.
363  * Returns TRUE if the variable is allowed else FALSE.
364  */
365 static int
366 matches_env_keep(var)
367     const char *var;
368 {
369     struct list_member *cur;
370     size_t len;
371     int iswild, keepit = FALSE;
372
373     for (cur = def_env_keep; cur; cur = cur->next) {
374         len = strlen(cur->value);
375         /* Deal with '*' wildcard */
376         if (cur->value[len - 1] == '*') {
377             len--;
378             iswild = TRUE;
379         } else
380             iswild = FALSE;
381         if (strncmp(cur->value, var, len) == 0 &&
382             (iswild || var[len] == '=')) {
383             keepit = TRUE;
384             break;
385         }
386     }
387     return(keepit);
388 }
389
390 /*
391  * Build a new environment and ether clear potentially dangerous
392  * variables from the old one or start with a clean slate.
393  * Also adds sudo-specific variables (SUDO_*).
394  */
395 char **
396 rebuild_env(envp, sudo_mode, noexec)
397     char **envp;
398     int sudo_mode;
399     int noexec;
400 {
401     char **ep, *cp, *ps1;
402     unsigned int didvar;
403
404     /*
405      * Either clean out the environment or reset to a safe default.
406      */
407     ps1 = NULL;
408     didvar = 0;
409     memset(&env, 0, sizeof(env));
410     if (def_env_reset) {
411         /* Pull in vars we want to keep from the old environment. */
412         for (ep = envp; *ep; ep++) {
413             int keepit;
414
415             /* Skip variables with values beginning with () (bash functions) */
416             if ((cp = strchr(*ep, '=')) != NULL) {
417                 if (strncmp(cp, "=() ", 3) == 0)
418                     continue;
419             }
420
421             /*
422              * First check certain variables for '%' and '/' characters.
423              * If no match there, check the keep list.
424              * If nothing matched, we remove it from the environment.
425              */
426             keepit = matches_env_check(*ep);
427             if (keepit == -1)
428                 keepit = matches_env_keep(*ep);
429
430             if (!strncmp (*ep, "DISPLAY=",8)
431                 || !strncmp (*ep, "XAUTHORITY=", 11)
432                 || !strncmp (*ep, "XAUTHORIZATION=", 15)
433                 || !strncmp (*ep, "XAPPLRESDIR=", 12)
434                 || !strncmp (*ep, "XFILESEARCHPATH=", 16)
435                 || !strncmp (*ep, "XUSERFILESEARCHPATH=", 20)
436                 || !strncmp (*ep, "LANG=", 5)
437                 || !strncmp (*ep, "LANGUAGE=", 9)
438                 || !strncmp (*ep, "LC_", 3))
439               keepit = 1;
440
441             /* For SUDO_PS1 -> PS1 conversion. */
442             if (strncmp(*ep, "SUDO_PS1=", 8) == 0)
443                 ps1 = *ep + 5;
444
445             if (keepit) {
446                 /* Preserve variable. */
447                 switch (**ep) {
448                     case 'H':
449                         if (strncmp(*ep, "HOME=", 5) == 0)
450                             SET(didvar, DID_HOME);
451                         break;
452                     case 'L':
453                         if (strncmp(*ep, "LOGNAME=", 8) == 0)
454                             SET(didvar, DID_LOGNAME);
455                         break;
456                     case 'P':
457                         if (strncmp(*ep, "PATH=", 5) == 0)
458                             SET(didvar, DID_PATH);
459                         break;
460                     case 'S':
461                         if (strncmp(*ep, "SHELL=", 6) == 0)
462                             SET(didvar, DID_SHELL);
463                         break;
464                     case 'T':
465                         if (strncmp(*ep, "TERM=", 5) == 0)
466                             SET(didvar, DID_TERM);
467                         break;
468                     case 'U':
469                         if (strncmp(*ep, "USER=", 5) == 0)
470                             SET(didvar, DID_USER);
471                         if (strncmp(*ep, "USERNAME=", 5) == 0)
472                             SET(didvar, DID_USERNAME);
473                         break;
474                 }
475                 insert_env(*ep, &env, 0);
476             }
477         }
478         didvar |= didvar << 8;          /* convert DID_* to KEPT_* */
479
480         /*
481          * Add in defaults.  In -i mode these come from the runas user,
482          * otherwise they may be from the user's environment (depends
483          * on sudoers options).
484          */
485         if (ISSET(sudo_mode, MODE_LOGIN_SHELL)) {
486             insert_env(format_env("HOME", runas_pw->pw_dir, VNULL), &env,
487                 ISSET(didvar, DID_HOME));
488             insert_env(format_env("SHELL", runas_pw->pw_shell, VNULL), &env,
489                 ISSET(didvar, DID_SHELL));
490             insert_env(format_env("LOGNAME", runas_pw->pw_name, VNULL), &env,
491                 ISSET(didvar, DID_LOGNAME));
492             insert_env(format_env("USER", runas_pw->pw_name, VNULL), &env,
493                 ISSET(didvar, DID_USER));
494             insert_env(format_env("USERNAME", runas_pw->pw_name, VNULL), &env,
495                 ISSET(didvar, DID_USERNAME));
496         } else {
497             if (!ISSET(didvar, DID_HOME))
498                 insert_env(format_env("HOME", user_dir, VNULL), &env, 0);
499             if (!ISSET(didvar, DID_SHELL))
500                 insert_env(format_env("SHELL", sudo_user.pw->pw_shell, VNULL),
501                     &env, 0);
502             if (!ISSET(didvar, DID_LOGNAME))
503                 insert_env(format_env("LOGNAME", user_name, VNULL), &env, 0);
504             if (!ISSET(didvar, DID_USER))
505                 insert_env(format_env("USER", user_name, VNULL), &env, 0);
506             if (!ISSET(didvar, DID_USERNAME))
507                 insert_env(format_env("USERNAME", user_name, VNULL), &env, 0);
508         }
509     } else {
510         /*
511          * Copy envp entries as long as they don't match env_delete or
512          * env_check.
513          */
514         for (ep = envp; *ep; ep++) {
515             int okvar;
516
517             /* Skip variables with values beginning with () (bash functions) */
518             if ((cp = strchr(*ep, '=')) != NULL) {
519                 if (strncmp(cp, "=() ", 3) == 0)
520                     continue;
521             }
522
523             /*
524              * First check variables against the blacklist in env_delete.
525              * If no match there check for '%' and '/' characters.
526              */
527             okvar = matches_env_delete(*ep) != TRUE;
528             if (okvar)
529                 okvar = matches_env_check(*ep) != FALSE;
530
531             if (okvar) {
532                 if (strncmp(*ep, "SUDO_PS1=", 9) == 0)
533                     ps1 = *ep + 5;
534                 else if (strncmp(*ep, "PATH=", 5) == 0)
535                     SET(didvar, DID_PATH);
536                 else if (strncmp(*ep, "TERM=", 5) == 0)
537                     SET(didvar, DID_TERM);
538                 insert_env(*ep, &env, 0);
539             }
540         }
541     }
542
543 #ifdef SECURE_PATH
544     /* Replace the PATH envariable with a secure one. */
545     if (!user_is_exempt()) {
546         insert_env(format_env("PATH", SECURE_PATH, VNULL), &env, 1);
547         SET(didvar, DID_PATH);
548     }
549 #endif
550
551     /* Set $USER, $LOGNAME and $USERNAME to target if "set_logname" is true. */
552     if (def_set_logname && runas_pw->pw_name) {
553         if (!ISSET(didvar, KEPT_LOGNAME))
554             insert_env(format_env("LOGNAME", runas_pw->pw_name, VNULL), &env, 1);
555         if (!ISSET(didvar, KEPT_USER))
556             insert_env(format_env("USER", runas_pw->pw_name, VNULL), &env, 1);
557         if (!ISSET(didvar, KEPT_USERNAME))
558             insert_env(format_env("USERNAME", runas_pw->pw_name, VNULL), &env, 1);
559     }
560
561     /* Set $HOME for `sudo -H'.  Only valid at PERM_FULL_RUNAS. */
562     if (runas_pw->pw_dir) {
563         if (ISSET(sudo_mode, MODE_RESET_HOME) ||
564             (ISSET(sudo_mode, MODE_RUN) && (def_always_set_home ||
565             (ISSET(sudo_mode, MODE_SHELL) && def_set_home))))
566             insert_env(format_env("HOME", runas_pw->pw_dir, VNULL), &env, 1);
567     }
568
569     /* Provide default values for $TERM and $PATH if they are not set. */
570     if (!ISSET(didvar, DID_TERM))
571         insert_env("TERM=unknown", &env, 0);
572     if (!ISSET(didvar, DID_PATH))
573         insert_env(format_env("PATH", _PATH_DEFPATH, VNULL), &env, 0);
574
575     /*
576      * Preload a noexec file?  For a list of LD_PRELOAD-alikes, see
577      * http://www.fortran-2000.com/ArnaudRecipes/sharedlib.html
578      * XXX - should prepend to original value, if any
579      */
580     if (noexec && def_noexec_file != NULL) {
581 #if defined(__darwin__) || defined(__APPLE__)
582         insert_env(format_env("DYLD_INSERT_LIBRARIES", def_noexec_file, VNULL),
583             &env, 1);
584         insert_env(format_env("DYLD_FORCE_FLAT_NAMESPACE", VNULL), &env, 1);
585 #else
586 # if defined(__osf__) || defined(__sgi)
587         insert_env(format_env("_RLD_LIST", def_noexec_file, ":DEFAULT", VNULL),
588             &env, 1);
589 # else
590 #  ifdef _AIX
591         insert_env(format_env("LDR_PRELOAD", def_noexec_file, VNULL), &env, 1);
592 #  else
593         insert_env(format_env("LD_PRELOAD", def_noexec_file, VNULL), &env, 1);
594 #  endif /* _AIX */
595 # endif /* __osf__ || __sgi */
596 #endif /* __darwin__ || __APPLE__ */
597     }
598
599     /* Set PS1 if SUDO_PS1 is set. */
600     if (ps1)
601         insert_env(ps1, &env, 1);
602
603     /* Add the SUDO_COMMAND envariable (cmnd + args). */
604     if (user_args)
605         insert_env(format_env("SUDO_COMMAND", user_cmnd, " ", user_args, VNULL),
606             &env, 1);
607     else
608         insert_env(format_env("SUDO_COMMAND", user_cmnd, VNULL), &env, 1);
609
610     /* Add the SUDO_USER, SUDO_UID, SUDO_GID environment variables. */
611     insert_env(format_env("SUDO_USER", user_name, VNULL), &env, 1);
612     easprintf(&cp, "SUDO_UID=%lu", (unsigned long) user_uid);
613     insert_env(cp, &env, 1);
614     easprintf(&cp, "SUDO_GID=%lu", (unsigned long) user_gid);
615     insert_env(cp, &env, 1);
616
617     return(env.envp);
618 }
619
620 char **
621 insert_env_vars(envp, env_vars)
622     char **envp;
623     struct list_member *env_vars;
624 {
625     struct list_member *cur;
626
627     if (env_vars == NULL)
628         return (envp);
629
630     /*
631      * Make sure we still own the environment and steal it back if not.
632      */
633     if (env.envp != envp) {
634         size_t evlen;
635         char **ep;
636
637         for (ep = envp; *ep != NULL; ep++)
638             continue;
639         evlen = ep - envp;
640         if (evlen + 1 > env.env_size) {
641             efree(env.envp);
642             env.env_size = evlen + 1 + 128;
643             env.envp = emalloc2(env.env_size, sizeof(char *));
644         }
645         memcpy(env.envp, envp, (evlen + 1) * sizeof(char *));
646         env.env_len = evlen;
647     }
648
649     /* Add user-specified environment variables. */
650     for (cur = env_vars; cur != NULL; cur = cur->next)
651         insert_env(cur->value, &env, 1);
652
653     return(env.envp);
654 }
655
656 /*
657  * Validate the list of environment variables passed in on the command
658  * line against env_delete, env_check, and env_keep.
659  * Calls log_error() if any specified variables are not allowed.
660  */
661 void
662 validate_env_vars(env_vars)
663     struct list_member *env_vars;
664 {
665     struct list_member *var;
666     char *eq, *bad = NULL;
667     size_t len, blen = 0, bsize = 0;
668     int okvar;
669
670     for (var = env_vars; var != NULL; var = var->next) {
671 #ifdef SECURE_PATH
672         if (!user_is_exempt() && strncmp(var->value, "PATH=", 5) == 0) {
673             okvar = FALSE;
674         } else
675 #endif
676         if (def_env_reset) {
677             okvar = matches_env_check(var->value);
678             if (okvar == -1)
679                 okvar = matches_env_keep(var->value);
680         } else {
681             okvar = matches_env_delete(var->value) == FALSE;
682             if (okvar == FALSE)
683                 okvar = matches_env_check(var->value) != FALSE;
684         }
685         if (okvar == FALSE) {
686             /* Not allowed, add to error string, allocating as needed. */
687             if ((eq = strchr(var->value, '=')) != NULL)
688                 *eq = '\0';
689             len = strlen(var->value) + 2;
690             if (blen + len >= bsize) {
691                 do {
692                     bsize += 1024;
693                 } while (blen + len >= bsize);
694                 bad = erealloc(bad, bsize);
695                 bad[blen] = '\0';
696             }
697             strlcat(bad, var->value, bsize);
698             strlcat(bad, ", ", bsize);
699             blen += len;
700             if (eq != NULL)
701                 *eq = '=';
702         }
703     }
704     if (bad != NULL) {
705         bad[blen - 2] = '\0';           /* remove trailing ", " */
706         log_error(NO_MAIL,
707             "sorry, you are not allowed to set the following environment variables: %s", bad);
708         /* NOTREACHED */
709         efree(bad);
710     }
711 }
712
713 void
714 init_envtables()
715 {
716     struct list_member *cur;
717     const char **p;
718
719     /* Fill in the "env_delete" list. */
720     for (p = initial_badenv_table; *p; p++) {
721         cur = emalloc(sizeof(struct list_member));
722         cur->value = estrdup(*p);
723         cur->next = def_env_delete;
724         def_env_delete = cur;
725     }
726
727     /* Fill in the "env_check" list. */
728     for (p = initial_checkenv_table; *p; p++) {
729         cur = emalloc(sizeof(struct list_member));
730         cur->value = estrdup(*p);
731         cur->next = def_env_check;
732         def_env_check = cur;
733     }
734
735     /* Fill in the "env_keep" list. */
736     for (p = initial_keepenv_table; *p; p++) {
737         cur = emalloc(sizeof(struct list_member));
738         cur->value = estrdup(*p);
739         cur->next = def_env_keep;
740         def_env_keep = cur;
741     }
742 }