fix typo in changelog
[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.19 2008/06/21 19:04:07 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     "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  * Given a variable and value, allocate and format an environment string.
219  */
220 static char *
221 #ifdef __STDC__
222 format_env(char *var, ...)
223 #else
224 format_env(var, va_alist)
225     char *var;
226     va_dcl
227 #endif
228 {
229     char *estring;
230     char *val;
231     size_t esize;
232     va_list ap;
233
234 #ifdef __STDC__
235     va_start(ap, var);
236 #else
237     va_start(ap);
238 #endif
239     esize = strlen(var) + 2;
240     while ((val = va_arg(ap, char *)) != NULL)
241         esize += strlen(val);
242     va_end(ap);
243     estring = (char *) emalloc(esize);
244
245     /* Store variable name and the '=' separator.  */
246     if (strlcpy(estring, var, esize) >= esize ||
247         strlcat(estring, "=", esize) >= esize) {
248
249         errx(1, "internal error, format_env() overflow");
250     }
251
252     /* Now store the variable's value (if any) */
253 #ifdef __STDC__
254     va_start(ap, var);
255 #else
256     va_start(ap);
257 #endif
258     while ((val = va_arg(ap, char *)) != NULL) {
259         if (strlcat(estring, val, esize) >= esize)
260             errx(1, "internal error, format_env() overflow");
261     }
262     va_end(ap);
263
264     return(estring);
265 }
266
267 /*
268  * Insert str into e->envp, assumes str has an '=' in it.
269  */
270 static void
271 insert_env(str, e, dupcheck)
272     char *str;
273     struct environment *e;
274     int dupcheck;
275 {
276     char **nep;
277     size_t varlen;
278
279     /* Make sure there is room for the new entry plus a NULL. */
280     if (e->env_len + 2 > e->env_size) {
281         e->env_size += 128;
282         e->envp = erealloc3(e->envp, e->env_size, sizeof(char *));
283     }
284
285     if (dupcheck) {
286             varlen = (strchr(str, '=') - str) + 1;
287
288             for (nep = e->envp; *nep; nep++) {
289                 if (strncmp(str, *nep, varlen) == 0) {
290                     *nep = str;
291                     return;
292                 }
293             }
294     } else
295         nep = e->envp + e->env_len;
296
297     e->env_len++;
298     *nep++ = str;
299     *nep = NULL;
300 }
301
302 /*
303  * Check the env_delete blacklist.
304  * Returns TRUE if the variable was found, else false.
305  */
306 static int
307 matches_env_delete(var)
308     const char *var;
309 {
310     struct list_member *cur;
311     size_t len;
312     int iswild, match = FALSE;
313
314     /* Skip anything listed in env_delete. */
315     for (cur = def_env_delete; cur; cur = cur->next) {
316         len = strlen(cur->value);
317         /* Deal with '*' wildcard */
318         if (cur->value[len - 1] == '*') {
319             len--;
320             iswild = TRUE;
321         } else
322             iswild = FALSE;
323         if (strncmp(cur->value, var, len) == 0 &&
324             (iswild || var[len] == '=')) {
325             match = TRUE;
326             break;
327         }
328     }
329     return(match);
330 }
331
332 /*
333  * Apply the env_check list.
334  * Returns TRUE if the variable is allowed, FALSE if denied
335  * or -1 if no match.
336  */
337 static int
338 matches_env_check(var)
339     const char *var;
340 {
341     struct list_member *cur;
342     size_t len;
343     int iswild, keepit = -1;
344
345     for (cur = def_env_check; cur; cur = cur->next) {
346         len = strlen(cur->value);
347         /* Deal with '*' wildcard */
348         if (cur->value[len - 1] == '*') {
349             len--;
350             iswild = TRUE;
351         } else
352             iswild = FALSE;
353         if (strncmp(cur->value, var, len) == 0 &&
354             (iswild || var[len] == '=')) {
355             keepit = !strpbrk(var, "/%");
356             break;
357         }
358     }
359     return(keepit);
360 }
361
362 /*
363  * Check the env_keep list.
364  * Returns TRUE if the variable is allowed else FALSE.
365  */
366 static int
367 matches_env_keep(var)
368     const char *var;
369 {
370     struct list_member *cur;
371     size_t len;
372     int iswild, keepit = FALSE;
373
374     for (cur = def_env_keep; cur; cur = cur->next) {
375         len = strlen(cur->value);
376         /* Deal with '*' wildcard */
377         if (cur->value[len - 1] == '*') {
378             len--;
379             iswild = TRUE;
380         } else
381             iswild = FALSE;
382         if (strncmp(cur->value, var, len) == 0 &&
383             (iswild || var[len] == '=')) {
384             keepit = TRUE;
385             break;
386         }
387     }
388     return(keepit);
389 }
390
391 /*
392  * Build a new environment and ether clear potentially dangerous
393  * variables from the old one or start with a clean slate.
394  * Also adds sudo-specific variables (SUDO_*).
395  */
396 char **
397 rebuild_env(envp, sudo_mode, noexec)
398     char **envp;
399     int sudo_mode;
400     int noexec;
401 {
402     char **ep, *cp, *ps1;
403     unsigned int didvar;
404
405     /*
406      * Either clean out the environment or reset to a safe default.
407      */
408     ps1 = NULL;
409     didvar = 0;
410     memset(&env, 0, sizeof(env));
411     if (def_env_reset || ISSET(sudo_mode, MODE_LOGIN_SHELL)) {
412         /* Pull in vars we want to keep from the old environment. */
413         for (ep = envp; *ep; ep++) {
414             int keepit;
415
416             /* Skip variables with values beginning with () (bash functions) */
417             if ((cp = strchr(*ep, '=')) != NULL) {
418                 if (strncmp(cp, "=() ", 3) == 0)
419                     continue;
420             }
421
422             /*
423              * First check certain variables for '%' and '/' characters.
424              * If no match there, check the keep list.
425              * If nothing matched, we remove it from the environment.
426              */
427             keepit = matches_env_check(*ep);
428             if (keepit == -1)
429                 keepit = matches_env_keep(*ep);
430
431             if (!strncmp (*ep, "DISPLAY=",8)
432                 || !strncmp (*ep, "XAUTHORITY=", 11)
433                 || !strncmp (*ep, "XAUTHORIZATION=", 15)
434                 || !strncmp (*ep, "XAPPLRESDIR=", 12)
435                 || !strncmp (*ep, "XFILESEARCHPATH=", 16)
436                 || !strncmp (*ep, "XUSERFILESEARCHPATH=", 20)
437                 || !strncmp (*ep, "LANG=", 5)
438                 || !strncmp (*ep, "LANGUAGE=", 9)
439                 || !strncmp (*ep, "LC_", 3))
440               keepit = 1;
441
442             /* For SUDO_PS1 -> PS1 conversion. */
443             if (strncmp(*ep, "SUDO_PS1=", 8) == 0)
444                 ps1 = *ep + 5;
445
446             if (keepit) {
447                 /* Preserve variable. */
448                 switch (**ep) {
449                     case 'H':
450                         if (strncmp(*ep, "HOME=", 5) == 0)
451                             SET(didvar, DID_HOME);
452                         break;
453                     case 'L':
454                         if (strncmp(*ep, "LOGNAME=", 8) == 0)
455                             SET(didvar, DID_LOGNAME);
456                         break;
457                     case 'P':
458                         if (strncmp(*ep, "PATH=", 5) == 0)
459                             SET(didvar, DID_PATH);
460                         break;
461                     case 'S':
462                         if (strncmp(*ep, "SHELL=", 6) == 0)
463                             SET(didvar, DID_SHELL);
464                         break;
465                     case 'T':
466                         if (strncmp(*ep, "TERM=", 5) == 0)
467                             SET(didvar, DID_TERM);
468                         break;
469                     case 'U':
470                         if (strncmp(*ep, "USER=", 5) == 0)
471                             SET(didvar, DID_USER);
472                         if (strncmp(*ep, "USERNAME=", 5) == 0)
473                             SET(didvar, DID_USERNAME);
474                         break;
475                 }
476                 insert_env(*ep, &env, 0);
477             }
478         }
479         didvar |= didvar << 8;          /* convert DID_* to KEPT_* */
480
481         /*
482          * Add in defaults.  In -i mode these come from the runas user,
483          * otherwise they may be from the user's environment (depends
484          * on sudoers options).
485          */
486         if (ISSET(sudo_mode, MODE_LOGIN_SHELL)) {
487             insert_env(format_env("HOME", runas_pw->pw_dir, VNULL), &env,
488                 ISSET(didvar, DID_HOME));
489             insert_env(format_env("SHELL", runas_pw->pw_shell, VNULL), &env,
490                 ISSET(didvar, DID_SHELL));
491             insert_env(format_env("LOGNAME", runas_pw->pw_name, VNULL), &env,
492                 ISSET(didvar, DID_LOGNAME));
493             insert_env(format_env("USER", runas_pw->pw_name, VNULL), &env,
494                 ISSET(didvar, DID_USER));
495             insert_env(format_env("USERNAME", runas_pw->pw_name, VNULL), &env,
496                 ISSET(didvar, DID_USERNAME));
497         } else {
498             if (!ISSET(didvar, DID_HOME))
499                 insert_env(format_env("HOME", user_dir, VNULL), &env, 0);
500             if (!ISSET(didvar, DID_SHELL))
501                 insert_env(format_env("SHELL", sudo_user.pw->pw_shell, VNULL),
502                     &env, 0);
503             if (!ISSET(didvar, DID_LOGNAME))
504                 insert_env(format_env("LOGNAME", user_name, VNULL), &env, 0);
505             if (!ISSET(didvar, DID_USER))
506                 insert_env(format_env("USER", user_name, VNULL), &env, 0);
507             if (!ISSET(didvar, DID_USERNAME))
508                 insert_env(format_env("USERNAME", user_name, VNULL), &env, 0);
509         }
510     } else {
511         /*
512          * Copy envp entries as long as they don't match env_delete or
513          * env_check.
514          */
515         for (ep = envp; *ep; ep++) {
516             int okvar;
517
518             /* Skip variables with values beginning with () (bash functions) */
519             if ((cp = strchr(*ep, '=')) != NULL) {
520                 if (strncmp(cp, "=() ", 3) == 0)
521                     continue;
522             }
523
524             /*
525              * First check variables against the blacklist in env_delete.
526              * If no match there check for '%' and '/' characters.
527              */
528             okvar = matches_env_delete(*ep) != TRUE;
529             if (okvar)
530                 okvar = matches_env_check(*ep) != FALSE;
531
532             if (okvar) {
533                 if (strncmp(*ep, "SUDO_PS1=", 9) == 0)
534                     ps1 = *ep + 5;
535                 else if (strncmp(*ep, "PATH=", 5) == 0)
536                     SET(didvar, DID_PATH);
537                 else if (strncmp(*ep, "TERM=", 5) == 0)
538                     SET(didvar, DID_TERM);
539                 insert_env(*ep, &env, 0);
540             }
541         }
542     }
543
544 #ifdef SECURE_PATH
545     /* Replace the PATH envariable with a secure one. */
546     if (!user_is_exempt()) {
547         insert_env(format_env("PATH", SECURE_PATH, VNULL), &env, 1);
548         SET(didvar, DID_PATH);
549     }
550 #endif
551
552     /* Set $USER, $LOGNAME and $USERNAME to target if "set_logname" is true. */
553     /* XXX - not needed for MODE_LOGIN_SHELL */
554     if (def_set_logname && runas_pw->pw_name) {
555         if (!ISSET(didvar, KEPT_LOGNAME))
556             insert_env(format_env("LOGNAME", runas_pw->pw_name, VNULL), &env, 1);
557         if (!ISSET(didvar, KEPT_USER))
558             insert_env(format_env("USER", runas_pw->pw_name, VNULL), &env, 1);
559         if (!ISSET(didvar, KEPT_USERNAME))
560             insert_env(format_env("USERNAME", runas_pw->pw_name, VNULL), &env, 1);
561     }
562
563     /* Set $HOME for `sudo -H'.  Only valid at PERM_FULL_RUNAS. */
564     /* XXX - not needed for MODE_LOGIN_SHELL */
565     if (runas_pw->pw_dir) {
566         if (ISSET(sudo_mode, MODE_RESET_HOME) ||
567             (ISSET(sudo_mode, MODE_RUN) && (def_always_set_home ||
568             (ISSET(sudo_mode, MODE_SHELL) && def_set_home))))
569             insert_env(format_env("HOME", runas_pw->pw_dir, VNULL), &env, 1);
570     }
571
572     /* Provide default values for $TERM and $PATH if they are not set. */
573     if (!ISSET(didvar, DID_TERM))
574         insert_env("TERM=unknown", &env, 0);
575     if (!ISSET(didvar, DID_PATH))
576         insert_env(format_env("PATH", _PATH_DEFPATH, VNULL), &env, 0);
577
578     /*
579      * Preload a noexec file?  For a list of LD_PRELOAD-alikes, see
580      * http://www.fortran-2000.com/ArnaudRecipes/sharedlib.html
581      * XXX - should prepend to original value, if any
582      */
583     if (noexec && def_noexec_file != NULL) {
584 #if defined(__darwin__) || defined(__APPLE__)
585         insert_env(format_env("DYLD_INSERT_LIBRARIES", def_noexec_file, VNULL),
586             &env, 1);
587         insert_env(format_env("DYLD_FORCE_FLAT_NAMESPACE", VNULL), &env, 1);
588 #else
589 # if defined(__osf__) || defined(__sgi)
590         insert_env(format_env("_RLD_LIST", def_noexec_file, ":DEFAULT", VNULL),
591             &env, 1);
592 # else
593 #  ifdef _AIX
594         insert_env(format_env("LDR_PRELOAD", def_noexec_file, VNULL), &env, 1);
595 #  else
596         insert_env(format_env("LD_PRELOAD", def_noexec_file, VNULL), &env, 1);
597 #  endif /* _AIX */
598 # endif /* __osf__ || __sgi */
599 #endif /* __darwin__ || __APPLE__ */
600     }
601
602     /* Set PS1 if SUDO_PS1 is set. */
603     if (ps1)
604         insert_env(ps1, &env, 1);
605
606     /* Add the SUDO_COMMAND envariable (cmnd + args). */
607     if (user_args)
608         insert_env(format_env("SUDO_COMMAND", user_cmnd, " ", user_args, VNULL),
609             &env, 1);
610     else
611         insert_env(format_env("SUDO_COMMAND", user_cmnd, VNULL), &env, 1);
612
613     /* Add the SUDO_USER, SUDO_UID, SUDO_GID environment variables. */
614     insert_env(format_env("SUDO_USER", user_name, VNULL), &env, 1);
615     easprintf(&cp, "SUDO_UID=%lu", (unsigned long) user_uid);
616     insert_env(cp, &env, 1);
617     easprintf(&cp, "SUDO_GID=%lu", (unsigned long) user_gid);
618     insert_env(cp, &env, 1);
619
620     return(env.envp);
621 }
622
623 char **
624 insert_env_vars(envp, env_vars)
625     char **envp;
626     struct list_member *env_vars;
627 {
628     struct list_member *cur;
629
630     if (env_vars == NULL)
631         return (envp);
632
633     /*
634      * Make sure we still own the environment and steal it back if not.
635      */
636     if (env.envp != envp) {
637         size_t evlen;
638         char **ep;
639
640         for (ep = envp; *ep != NULL; ep++)
641             continue;
642         evlen = ep - envp;
643         if (evlen + 1 > env.env_size) {
644             efree(env.envp);
645             env.env_size = evlen + 1 + 128;
646             env.envp = emalloc2(env.env_size, sizeof(char *));
647         }
648         memcpy(env.envp, envp, (evlen + 1) * sizeof(char *));
649         env.env_len = evlen;
650     }
651
652     /* Add user-specified environment variables. */
653     for (cur = env_vars; cur != NULL; cur = cur->next)
654         insert_env(cur->value, &env, 1);
655
656     return(env.envp);
657 }
658
659 /*
660  * Validate the list of environment variables passed in on the command
661  * line against env_delete, env_check, and env_keep.
662  * Calls log_error() if any specified variables are not allowed.
663  */
664 void
665 validate_env_vars(env_vars)
666     struct list_member *env_vars;
667 {
668     struct list_member *var;
669     char *eq, *bad = NULL;
670     size_t len, blen = 0, bsize = 0;
671     int okvar;
672
673     for (var = env_vars; var != NULL; var = var->next) {
674 #ifdef SECURE_PATH
675         if (!user_is_exempt() && strncmp(var->value, "PATH=", 5) == 0) {
676             okvar = FALSE;
677         } else
678 #endif
679         if (def_env_reset) {
680             okvar = matches_env_check(var->value);
681             if (okvar == -1)
682                 okvar = matches_env_keep(var->value);
683         } else {
684             okvar = matches_env_delete(var->value) == FALSE;
685             if (okvar == FALSE)
686                 okvar = matches_env_check(var->value) != FALSE;
687         }
688         if (okvar == FALSE) {
689             /* Not allowed, add to error string, allocating as needed. */
690             if ((eq = strchr(var->value, '=')) != NULL)
691                 *eq = '\0';
692             len = strlen(var->value) + 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, var->value, 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 void
717 init_envtables()
718 {
719     struct list_member *cur;
720     const char **p;
721
722     /* Fill in the "env_delete" list. */
723     for (p = initial_badenv_table; *p; p++) {
724         cur = emalloc(sizeof(struct list_member));
725         cur->value = estrdup(*p);
726         cur->next = def_env_delete;
727         def_env_delete = cur;
728     }
729
730     /* Fill in the "env_check" list. */
731     for (p = initial_checkenv_table; *p; p++) {
732         cur = emalloc(sizeof(struct list_member));
733         cur->value = estrdup(*p);
734         cur->next = def_env_check;
735         def_env_check = cur;
736     }
737
738     /* Fill in the "env_keep" list. */
739     for (p = initial_keepenv_table; *p; p++) {
740         cur = emalloc(sizeof(struct list_member));
741         cur->value = estrdup(*p);
742         cur->next = def_env_keep;
743         def_env_keep = cur;
744     }
745 }