1/*
2 * Copyright (c) 2000-2005, 2007-2010
3 *	Todd C. Miller <Todd.Miller@courtesan.com>
4 *
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 *
17 * Sponsored in part by the Defense Advanced Research Projects
18 * Agency (DARPA) and Air Force Research Laboratory, Air Force
19 * Materiel Command, USAF, under agreement number F39502-99-1-0512.
20 */
21
22#include <config.h>
23
24#include <sys/types.h>
25#include <sys/param.h>
26#include <sys/stat.h>
27#include <stdio.h>
28#ifdef STDC_HEADERS
29# include <stdlib.h>
30# include <stddef.h>
31#else
32# ifdef HAVE_STDLIB_H
33#  include <stdlib.h>
34# endif
35#endif /* STDC_HEADERS */
36#ifdef HAVE_STRING_H
37# include <string.h>
38#endif /* HAVE_STRING_H */
39#ifdef HAVE_STRINGS_H
40# include <strings.h>
41#endif /* HAVE_STRINGS_H */
42#ifdef HAVE_UNISTD_H
43# include <unistd.h>
44#endif /* HAVE_UNISTD_H */
45#ifdef HAVE_INTTYPES_H
46# include <inttypes.h>
47#endif
48#ifdef HAVE_LOGIN_CAP_H
49# include <login_cap.h>
50# ifndef LOGIN_SETENV
51#  define LOGIN_SETENV	0
52# endif
53#endif /* HAVE_LOGIN_CAP_H */
54#include <ctype.h>
55#include <errno.h>
56#include <limits.h>
57#include <pwd.h>
58
59#include "sudo.h"
60
61/*
62 * If there is no SIZE_MAX or SIZE_T_MAX we have to assume that size_t
63 * could be signed (as it is on SunOS 4.x).  This just means that
64 * emalloc2() and erealloc3() cannot allocate huge amounts on such a
65 * platform but that is OK since sudo doesn't need to do so anyway.
66 */
67#ifndef SIZE_MAX
68# ifdef SIZE_T_MAX
69#  define SIZE_MAX	SIZE_T_MAX
70# else
71#  define SIZE_MAX	INT_MAX
72# endif /* SIZE_T_MAX */
73#endif /* SIZE_MAX */
74
75/*
76 * Flags used in rebuild_env()
77 */
78#undef DID_TERM
79#define DID_TERM	0x0001
80#undef DID_PATH
81#define DID_PATH	0x0002
82#undef DID_HOME
83#define DID_HOME	0x0004
84#undef DID_SHELL
85#define DID_SHELL	0x0008
86#undef DID_LOGNAME
87#define DID_LOGNAME	0x0010
88#undef DID_USER
89#define DID_USER    	0x0020
90#undef DID_USERNAME
91#define DID_USERNAME   	0x0040
92#undef DID_MAIL
93#define DID_MAIL   	0x0080
94#undef DID_MAX
95#define DID_MAX    	0x00ff
96
97#undef KEPT_TERM
98#define KEPT_TERM	0x0100
99#undef KEPT_PATH
100#define KEPT_PATH	0x0200
101#undef KEPT_HOME
102#define KEPT_HOME	0x0400
103#undef KEPT_SHELL
104#define KEPT_SHELL	0x0800
105#undef KEPT_LOGNAME
106#define KEPT_LOGNAME	0x1000
107#undef KEPT_USER
108#define KEPT_USER    	0x2000
109#undef KEPT_USERNAME
110#define KEPT_USERNAME	0x4000
111#undef KEPT_MAIL
112#define KEPT_MAIL	0x8000
113#undef KEPT_MAX
114#define KEPT_MAX    	0xff00
115
116struct environment {
117    char **envp;		/* pointer to the new environment */
118    size_t env_size;		/* size of new_environ in char **'s */
119    size_t env_len;		/* number of slots used, not counting NULL */
120    int owned;			/* do we own envp or is it the system's? */
121};
122
123/*
124 * Prototypes
125 */
126static void sudo_setenv		__P((const char *, const char *, int));
127static void sudo_putenv		__P((char *, int, int));
128
129extern char **environ;		/* global environment */
130
131/*
132 * Copy of the sudo-managed environment.
133 */
134static struct environment env;
135
136/*
137 * Default table of "bad" variables to remove from the environment.
138 * XXX - how to omit TERMCAP if it starts with '/'?
139 */
140static const char *initial_badenv_table[] = {
141    "IFS",
142    "CDPATH",
143    "LOCALDOMAIN",
144    "RES_OPTIONS",
145    "HOSTALIASES",
146    "NLSPATH",
147    "PATH_LOCALE",
148    "LD_*",
149    "_RLD*",
150#ifdef __hpux
151    "SHLIB_PATH",
152#endif /* __hpux */
153#ifdef _AIX
154    "LDR_*",
155    "LIBPATH",
156    "AUTHSTATE",
157#endif
158#ifdef __APPLE__
159    "DYLD_*",
160#endif
161#ifdef HAVE_KERB4
162    "KRB_CONF*",
163    "KRBCONFDIR",
164    "KRBTKFILE",
165#endif /* HAVE_KERB4 */
166#ifdef HAVE_KERB5
167    "KRB5_CONFIG*",
168    "KRB5_KTNAME",
169#endif /* HAVE_KERB5 */
170#ifdef HAVE_SECURID
171    "VAR_ACE",
172    "USR_ACE",
173    "DLC_ACE",
174#endif /* HAVE_SECURID */
175    "TERMINFO",			/* terminfo, exclusive path to terminfo files */
176    "TERMINFO_DIRS",		/* terminfo, path(s) to terminfo files */
177    "TERMPATH",			/* termcap, path(s) to termcap files */
178    "TERMCAP",			/* XXX - only if it starts with '/' */
179    "ENV",			/* ksh, file to source before script runs */
180    "BASH_ENV",			/* bash, file to source before script runs */
181    "PS4",			/* bash, prefix for lines in xtrace mode */
182    "GLOBIGNORE",		/* bash, globbing patterns to ignore */
183    "SHELLOPTS",		/* bash, extra command line options */
184    "JAVA_TOOL_OPTIONS",	/* java, extra command line options */
185    "PERLIO_DEBUG ",		/* perl, debugging output file */
186    "PERLLIB",			/* perl, search path for modules/includes */
187    "PERL5LIB",			/* perl 5, search path for modules/includes */
188    "PERL5OPT",			/* perl 5, extra command line options */
189    "PERL5DB",			/* perl 5, command used to load debugger */
190    "FPATH",			/* ksh, search path for functions */
191    "NULLCMD",			/* zsh, command for null file redirection */
192    "READNULLCMD",		/* zsh, command for null file redirection */
193    "ZDOTDIR",			/* zsh, search path for dot files */
194    "TMPPREFIX",		/* zsh, prefix for temporary files */
195    "PYTHONHOME",		/* python, module search path */
196    "PYTHONPATH",		/* python, search path */
197    "PYTHONINSPECT",		/* python, allow inspection */
198    "PYTHONUSERBASE",		/* python, per user site-packages directory */
199    "RUBYLIB",			/* ruby, library load path */
200    "RUBYOPT",			/* ruby, extra command line options */
201    NULL
202};
203
204/*
205 * Default table of variables to check for '%' and '/' characters.
206 */
207static const char *initial_checkenv_table[] = {
208    "COLORTERM",
209    "LANG",
210    "LANGUAGE",
211    "LC_*",
212    "LINGUAS",
213    "TERM",
214    NULL
215};
216
217/*
218 * Default table of variables to preserve in the environment.
219 */
220static const char *initial_keepenv_table[] = {
221    "COLORS",
222    "DISPLAY",
223    "HOME",
224    "HOSTNAME",
225    "KRB5CCNAME",
226    "LS_COLORS",
227    "MAIL",
228    "PATH",
229    "PS1",
230    "PS2",
231    "TZ",
232    "XAUTHORITY",
233    "XAUTHORIZATION",
234    NULL
235};
236
237/*
238 * Initialize env based on envp.
239 */
240void
241env_init(lazy)
242    int lazy;
243{
244    char * const *ep;
245    size_t len;
246
247    for (ep = environ; *ep != NULL; ep++)
248	continue;
249    len = (size_t)(ep - environ);
250
251    if (lazy) {
252	/*
253	 * If we are already initialized due to lazy init (usualy via getenv())
254	 * we need to avoid calling malloc() as it may call getenv() itself.
255	 */
256	env.envp = environ;
257	env.env_len = len;
258	env.env_size = len;
259    } else if (!env.owned) {
260	env.env_len = len;
261	env.env_size = len + 1 + 128;
262	env.envp = emalloc2(env.env_size, sizeof(char *));
263#ifdef ENV_DEBUG
264	memset(env.envp, 0, env.env_size * sizeof(char *));
265#endif
266	memcpy(env.envp, environ, len * sizeof(char *));
267	env.envp[len] = NULL;
268	env.owned = TRUE;
269    }
270}
271
272char **
273env_get()
274{
275    return env.envp;
276}
277
278/*
279 * Similar to setenv(3) but operates on sudo's private copy of the environment
280 * (not environ) and it always overwrites.  The dupcheck param determines
281 * whether we need to verify that the variable is not already set.
282 */
283static void
284sudo_setenv(var, val, dupcheck)
285    const char *var;
286    const char *val;
287    int dupcheck;
288{
289    char *estring;
290    size_t esize;
291
292    esize = strlen(var) + 1 + strlen(val) + 1;
293    estring = emalloc(esize);
294
295    /* Build environment string and insert it. */
296    if (strlcpy(estring, var, esize) >= esize ||
297	strlcat(estring, "=", esize) >= esize ||
298	strlcat(estring, val, esize) >= esize) {
299
300	errorx(1, "internal error, sudo_setenv() overflow");
301    }
302    sudo_putenv(estring, dupcheck, TRUE);
303}
304
305/*
306 * Version of getenv(3) that uses our own environ pointer.
307 */
308char *
309getenv(var)
310    const char *var;
311{
312    char *cp, **ev;
313    size_t vlen = strlen(var);
314
315    if (env.envp == NULL)
316	env_init(TRUE);
317
318    for (ev = env.envp; (cp = *ev) != NULL; ev++) {
319	if (strncmp(var, cp, vlen) == 0 && cp[vlen] == '=')
320	    return cp + vlen + 1;
321    }
322    return NULL;
323}
324
325/*
326 * Version of setenv(3) that uses our own environ pointer.
327 */
328int
329setenv(var, val, overwrite)
330    const char *var;
331    const char *val;
332    int overwrite;
333{
334    char *estring, *ep;
335    const char *cp;
336    size_t esize;
337
338    if (!var || *var == '\0') {
339	errno = EINVAL;
340	return -1;
341    }
342
343    if (env.envp == NULL)
344	env_init(TRUE);
345
346    /*
347     * POSIX says a var name with '=' is an error but BSD
348     * just ignores the '=' and anything after it.
349     */
350    for (cp = var; *cp && *cp != '='; cp++)
351	;
352    esize = (size_t)(cp - var) + 2;
353    if (val) {
354	esize += strlen(val);	/* glibc treats a NULL val as "" */
355    }
356
357    /* Allocate and fill in estring. */
358    estring = ep = emalloc(esize);
359    for (cp = var; *cp && *cp != '='; cp++)
360	*ep++ = *cp;
361    *ep++ = '=';
362    if (val) {
363	for (cp = val; *cp; cp++)
364	    *ep++ = *cp;
365    }
366    *ep = '\0';
367
368#ifdef ENV_DEBUG
369    if (env.envp[env.env_len] != NULL)
370	errorx(1, "setenv: corrupted envp, len mismatch");
371#endif
372    sudo_putenv(estring, TRUE, overwrite);
373    return 0;
374}
375
376/*
377 * Version of unsetenv(3) that uses our own environ pointer.
378 */
379#ifdef UNSETENV_VOID
380void
381#else
382int
383#endif
384unsetenv(var)
385    const char *var;
386{
387    char **ep;
388    size_t len;
389
390    if (var == NULL || *var == '\0' || strchr(var, '=') != NULL) {
391	errno = EINVAL;
392#ifdef UNSETENV_VOID
393	return;
394#else
395	return -1;
396#endif
397    }
398
399    if (env.envp == NULL)
400	env_init(TRUE);
401
402#ifdef ENV_DEBUG
403    if (env.envp[env.env_len] != NULL)
404	errorx(1, "unsetenv: corrupted envp, len mismatch");
405#endif
406
407    len = strlen(var);
408    for (ep = env.envp; *ep != NULL;) {
409	if (strncmp(var, *ep, len) == 0 && (*ep)[len] == '=') {
410	    /* Found it; shift remainder + NULL over by one. */
411	    char **cur = ep;
412	    while ((*cur = *(cur + 1)) != NULL)
413		cur++;
414	    /* Keep going, could be multiple instances of the var. */
415	} else {
416	    ep++;
417	}
418    }
419    env.env_len = ep - env.envp;
420#ifndef UNSETENV_VOID
421    return 0;
422#endif
423}
424
425/*
426 * Version of putenv(3) that uses our own environ pointer.
427 */
428int
429#ifdef PUTENV_CONST
430putenv(const char *string)
431#else
432putenv(string)
433    char *string;
434#endif
435{
436    if (env.envp == NULL)
437	env_init(TRUE);
438
439    if (strchr(string, '=') == NULL) {
440	errno = EINVAL;
441	return -1;
442    }
443#ifdef ENV_DEBUG
444    if (env.envp[env.env_len] != NULL)
445	errorx(1, "putenv: corrupted envp, len mismatch");
446#endif
447    sudo_putenv((char *)string, TRUE, TRUE);
448    return 0;
449}
450
451/*
452 * Similar to putenv(3) but operates on sudo's private copy of the
453 * environment (not environ) and it always overwrites.  The dupcheck param
454 * determines whether we need to verify that the variable is not already set.
455 * Will only overwrite an existing variable if overwrite is set.
456 */
457static void
458sudo_putenv(str, dupcheck, overwrite)
459    char *str;
460    int dupcheck;
461    int overwrite;
462{
463    char **ep;
464    size_t len;
465    int found = FALSE;
466
467    /* Make sure there is room for the new entry plus a NULL. */
468    if (env.env_size > 2 && env.env_len > env.env_size - 2) {
469	if (env.env_size > SIZE_MAX - 128)
470	    errorx(1, "internal error, sudo_putenv() overflow");
471	env.env_size += 128;
472	if (env.owned) {
473	    env.envp = erealloc3(env.envp, env.env_size, sizeof(char *));
474	} else {
475	    /* We don't own env.envp, allocate a new one. */
476	    ep = emalloc2(env.env_size, sizeof(char *));
477	    memcpy(ep, env.envp, env.env_size * sizeof(char *));
478	    env.envp = ep;
479	    env.owned = TRUE;
480	}
481#ifdef ENV_DEBUG
482	memset(env.envp + env.env_len, 0,
483	    (env.env_size - env.env_len) * sizeof(char *));
484#endif
485    }
486
487#ifdef ENV_DEBUG
488    if (env.envp[env.env_len] != NULL)
489	errorx(1, "sudo_putenv: corrupted envp, len mismatch");
490#endif
491
492    if (dupcheck) {
493	len = (strchr(str, '=') - str) + 1;
494	for (ep = env.envp; *ep != NULL; ep++) {
495	    if (strncmp(str, *ep, len) == 0) {
496		if (overwrite)
497		    *ep = str;
498		found = TRUE;
499		break;
500	    }
501	}
502	/* Prune out extra instances of the variable we just overwrote. */
503	if (found && overwrite) {
504	    while (*++ep != NULL) {
505		if (strncmp(str, *ep, len) == 0) {
506		    char **cur = ep;
507		    while ((*cur = *(cur + 1)) != NULL)
508			cur++;
509		    ep--;
510		}
511	    }
512	    env.env_len = ep - env.envp;
513	}
514    }
515
516    if (!found) {
517	ep = env.envp + env.env_len;
518	env.env_len++;
519	*ep++ = str;
520	*ep = NULL;
521    }
522}
523
524/*
525 * Merge another environment with our private copy.
526 */
527void
528env_merge(envp, overwrite)
529    char * const envp[];
530    int overwrite;
531{
532    char * const *ep;
533
534    for (ep = envp; *ep != NULL; ep++)
535	sudo_putenv(*ep, TRUE, overwrite);
536}
537
538/*
539 * Check the env_delete blacklist.
540 * Returns TRUE if the variable was found, else FALSE.
541 */
542static int
543matches_env_delete(var)
544    const char *var;
545{
546    struct list_member *cur;
547    size_t len;
548    int iswild, match = FALSE;
549
550    /* Skip anything listed in env_delete. */
551    for (cur = def_env_delete; cur; cur = cur->next) {
552	len = strlen(cur->value);
553	/* Deal with '*' wildcard */
554	if (cur->value[len - 1] == '*') {
555	    len--;
556	    iswild = TRUE;
557	} else
558	    iswild = FALSE;
559	if (strncmp(cur->value, var, len) == 0 &&
560	    (iswild || var[len] == '=')) {
561	    match = TRUE;
562	    break;
563	}
564    }
565    return match;
566}
567
568/*
569 * Apply the env_check list.
570 * Returns TRUE if the variable is allowed, FALSE if denied
571 * or -1 if no match.
572 */
573static int
574matches_env_check(var)
575    const char *var;
576{
577    struct list_member *cur;
578    size_t len;
579    int iswild, keepit = -1;
580
581    for (cur = def_env_check; cur; cur = cur->next) {
582	len = strlen(cur->value);
583	/* Deal with '*' wildcard */
584	if (cur->value[len - 1] == '*') {
585	    len--;
586	    iswild = TRUE;
587	} else
588	    iswild = FALSE;
589	if (strncmp(cur->value, var, len) == 0 &&
590	    (iswild || var[len] == '=')) {
591	    keepit = !strpbrk(var, "/%");
592	    break;
593	}
594    }
595    return keepit;
596}
597
598/*
599 * Check the env_keep list.
600 * Returns TRUE if the variable is allowed else FALSE.
601 */
602static int
603matches_env_keep(var)
604    const char *var;
605{
606    struct list_member *cur;
607    size_t len;
608    int iswild, keepit = FALSE;
609
610    /* Preserve SHELL variable for "sudo -s". */
611    if (ISSET(sudo_mode, MODE_SHELL) && strncmp(var, "SHELL=", 6) == 0)
612	return TRUE;
613
614    for (cur = def_env_keep; cur; cur = cur->next) {
615	len = strlen(cur->value);
616	/* Deal with '*' wildcard */
617	if (cur->value[len - 1] == '*') {
618	    len--;
619	    iswild = TRUE;
620	} else
621	    iswild = FALSE;
622	if (strncmp(cur->value, var, len) == 0 &&
623	    (iswild || var[len] == '=')) {
624	    keepit = TRUE;
625	    break;
626	}
627    }
628    return keepit;
629}
630
631static void
632env_update_didvar(ep, didvar)
633    const char *ep;
634    unsigned int *didvar;
635{
636    switch (*ep) {
637	case 'H':
638	    if (strncmp(ep, "HOME=", 5) == 0)
639		SET(*didvar, DID_HOME);
640	    break;
641	case 'L':
642	    if (strncmp(ep, "LOGNAME=", 8) == 0)
643		SET(*didvar, DID_LOGNAME);
644	    break;
645	case 'M':
646	    if (strncmp(ep, "MAIL=", 5) == 0)
647		SET(*didvar, DID_MAIL);
648	    break;
649	case 'P':
650	    if (strncmp(ep, "PATH=", 5) == 0)
651		SET(*didvar, DID_PATH);
652	    break;
653	case 'S':
654	    if (strncmp(ep, "SHELL=", 6) == 0)
655		SET(*didvar, DID_SHELL);
656	    break;
657	case 'T':
658	    if (strncmp(ep, "TERM=", 5) == 0)
659		SET(*didvar, DID_TERM);
660	    break;
661	case 'U':
662	    if (strncmp(ep, "USER=", 5) == 0)
663		SET(*didvar, DID_USER);
664	    if (strncmp(ep, "USERNAME=", 5) == 0)
665		SET(*didvar, DID_USERNAME);
666	    break;
667    }
668}
669
670/*
671 * Build a new environment and ether clear potentially dangerous
672 * variables from the old one or start with a clean slate.
673 * Also adds sudo-specific variables (SUDO_*).
674 */
675void
676rebuild_env(noexec)
677    int noexec;
678{
679    char **old_envp, **ep, *cp, *ps1;
680    char idbuf[MAX_UID_T_LEN + 1];
681    unsigned int didvar;
682    int reset_home = FALSE;
683
684    /*
685     * Either clean out the environment or reset to a safe default.
686     */
687    ps1 = NULL;
688    didvar = 0;
689    env.env_len = 0;
690    env.env_size = 128;
691    old_envp = env.envp;
692    env.envp = emalloc2(env.env_size, sizeof(char *));
693#ifdef ENV_DEBUG
694    memset(env.envp, 0, env.env_size * sizeof(char *));
695#else
696    env.envp[0] = NULL;
697#endif
698
699    /* Reset HOME based on target user if configured to. */
700    if (ISSET(sudo_mode, MODE_RUN)) {
701    if (def_always_set_home ||
702        ISSET(sudo_mode, MODE_RESET_HOME | MODE_LOGIN_SHELL) ||
703        (ISSET(sudo_mode, MODE_SHELL) && def_set_home))
704        reset_home = TRUE;
705    }
706
707    if (def_env_reset || ISSET(sudo_mode, MODE_LOGIN_SHELL)) {
708    /*
709     * If starting with a fresh environment, initialize it based on
710     * /etc/environment or login.conf.  For "sudo -i" we want those
711     * variables to override the invoking user's environment, so we
712     * defer reading them until later.
713     */
714     if (!ISSET(sudo_mode, MODE_LOGIN_SHELL)) {
715#ifdef HAVE_LOGIN_CAP_H
716        /* Insert login class environment variables. */
717        if (login_class) {
718        login_cap_t *lc = login_getclass(login_class);
719        if (lc != NULL) {
720            setusercontext(lc, runas_pw, runas_pw->pw_uid,
721            LOGIN_SETPATH|LOGIN_SETENV);
722            login_close(lc);
723        }
724        }
725#endif /* HAVE_LOGIN_CAP_H */
726#if defined(_AIX) || (defined(__linux__) && !defined(HAVE_PAM))
727        /* Insert system-wide environment variables. */
728        read_env_file(_PATH_ENVIRONMENT, TRUE);
729#endif
730        for (ep = env.envp; *ep; ep++)
731        env_update_didvar(*ep, &didvar);
732    }
733
734	/* Pull in vars we want to keep from the old environment. */
735	for (ep = old_envp; *ep; ep++) {
736	    int keepit;
737
738	    /* Skip variables with values beginning with () (bash functions) */
739	    if ((cp = strchr(*ep, '=')) != NULL) {
740		if (strncmp(cp, "=() ", 3) == 0)
741		    continue;
742	    }
743
744	    /*
745	     * First check certain variables for '%' and '/' characters.
746	     * If no match there, check the keep list.
747	     * If nothing matched, we remove it from the environment.
748	     */
749	    keepit = matches_env_check(*ep);
750	    if (keepit == -1)
751		keepit = matches_env_keep(*ep);
752
753	    /* For SUDO_PS1 -> PS1 conversion. */
754	    if (strncmp(*ep, "SUDO_PS1=", 8) == 0)
755		ps1 = *ep + 5;
756
757	    if (keepit) {
758		/* Preserve variable. */
759		switch (**ep) {
760		    case 'H':
761			if (strncmp(*ep, "HOME=", 5) == 0 && !ISSET(sudo_mode, MODE_RESET_HOME))
762			    SET(didvar, DID_HOME);
763			break;
764		    case 'L':
765			if (strncmp(*ep, "LOGNAME=", 8) == 0)
766			    SET(didvar, DID_LOGNAME);
767			break;
768		    case 'M':
769			if (strncmp(*ep, "MAIL=", 5) == 0)
770			    SET(didvar, DID_MAIL);
771			break;
772		    case 'P':
773			if (strncmp(*ep, "PATH=", 5) == 0)
774			    SET(didvar, DID_PATH);
775			break;
776		    case 'S':
777			if (strncmp(*ep, "SHELL=", 6) == 0)
778			    SET(didvar, DID_SHELL);
779			break;
780		    case 'T':
781			if (strncmp(*ep, "TERM=", 5) == 0)
782			    SET(didvar, DID_TERM);
783			break;
784		    case 'U':
785			if (strncmp(*ep, "USER=", 5) == 0)
786			    SET(didvar, DID_USER);
787			if (strncmp(*ep, "USERNAME=", 5) == 0)
788			    SET(didvar, DID_USERNAME);
789			break;
790		}
791		sudo_putenv(*ep, FALSE, FALSE);
792	    }
793	}
794	didvar |= didvar << 8;		/* convert DID_* to KEPT_* */
795
796	/*
797	 * Add in defaults.  In -i mode these come from the runas user,
798	 * otherwise they may be from the user's environment (depends
799	 * on sudoers options).
800	 */
801	if (ISSET(sudo_mode, MODE_LOGIN_SHELL)) {
802	    sudo_setenv("SHELL", runas_pw->pw_shell, ISSET(didvar, DID_SHELL));
803	    sudo_setenv("LOGNAME", runas_pw->pw_name,
804		ISSET(didvar, DID_LOGNAME));
805	    sudo_setenv("USER", runas_pw->pw_name, ISSET(didvar, DID_USER));
806	    sudo_setenv("USERNAME", runas_pw->pw_name,
807		ISSET(didvar, DID_USERNAME));
808	} else {
809	    if (!ISSET(didvar, DID_SHELL))
810		sudo_setenv("SHELL", sudo_user.pw->pw_shell, FALSE);
811	    /* We will set LOGNAME later in the !def_set_logname case. */
812	    if (!def_set_logname) {
813		if (!ISSET(didvar, DID_LOGNAME))
814		    sudo_setenv("LOGNAME", user_name, FALSE);
815		if (!ISSET(didvar, DID_USER))
816		    sudo_setenv("USER", user_name, FALSE);
817		if (!ISSET(didvar, DID_USERNAME))
818		    sudo_setenv("USERNAME", user_name, FALSE);
819	    }
820	}
821
822	/* If we didn't keep HOME, reset it based on target user. */
823	if (!ISSET(didvar, KEPT_HOME))
824	    reset_home = TRUE;
825
826	/*
827	 * Set MAIL to target user in -i mode or if MAIL is not preserved
828	 * from user's environment.
829	 */
830	if (ISSET(sudo_mode, MODE_LOGIN_SHELL) || !ISSET(didvar, KEPT_MAIL)) {
831	    cp = _PATH_MAILDIR;
832	    if (cp[sizeof(_PATH_MAILDIR) - 2] == '/')
833		easprintf(&cp, "MAIL=%s%s", _PATH_MAILDIR, runas_pw->pw_name);
834	    else
835		easprintf(&cp, "MAIL=%s/%s", _PATH_MAILDIR, runas_pw->pw_name);
836	    sudo_putenv(cp, ISSET(didvar, DID_MAIL), TRUE);
837	}
838    } else {
839	/*
840	 * Copy environ entries as long as they don't match env_delete or
841	 * env_check.
842	 */
843	for (ep = old_envp; *ep; ep++) {
844	    int okvar;
845
846	    /* Skip variables with values beginning with () (bash functions) */
847	    if ((cp = strchr(*ep, '=')) != NULL) {
848		if (strncmp(cp, "=() ", 3) == 0)
849		    continue;
850	    }
851
852	    /*
853	     * First check variables against the blacklist in env_delete.
854	     * If no match there check for '%' and '/' characters.
855	     */
856	    okvar = matches_env_delete(*ep) != TRUE;
857	    if (okvar)
858		okvar = matches_env_check(*ep) != FALSE;
859
860	    if (okvar) {
861		if (strncmp(*ep, "SUDO_PS1=", 9) == 0)
862		    ps1 = *ep + 5;
863		else if (strncmp(*ep, "PATH=", 5) == 0)
864		    SET(didvar, DID_PATH);
865		else if (strncmp(*ep, "TERM=", 5) == 0)
866		    SET(didvar, DID_TERM);
867		sudo_putenv(*ep, FALSE, FALSE);
868	    }
869	}
870    }
871    /* Replace the PATH envariable with a secure one? */
872    if (def_secure_path && !user_is_exempt()) {
873	sudo_setenv("PATH", def_secure_path, TRUE);
874	SET(didvar, DID_PATH);
875    }
876
877    /*
878     * Set $USER, $LOGNAME and $USERNAME to target if "set_logname" is not
879     * disabled.  We skip this if we are running a login shell (because
880     * they have already been set) or sudoedit (because we want the editor
881     * to find the invoking user's startup files).
882     */
883    if (def_set_logname && !ISSET(sudo_mode, MODE_LOGIN_SHELL|MODE_EDIT)) {
884	if (!ISSET(didvar, KEPT_LOGNAME))
885	    sudo_setenv("LOGNAME", runas_pw->pw_name, TRUE);
886	if (!ISSET(didvar, KEPT_USER))
887	    sudo_setenv("USER", runas_pw->pw_name, TRUE);
888	if (!ISSET(didvar, KEPT_USERNAME))
889	    sudo_setenv("USERNAME", runas_pw->pw_name, TRUE);
890    }
891
892    /* Set $HOME to target user if not preserving user's value. */
893    if (reset_home)
894	sudo_setenv("HOME", runas_pw->pw_dir, TRUE);
895
896    /* Provide default values for $TERM and $PATH if they are not set. */
897    if (!ISSET(didvar, DID_TERM))
898	sudo_putenv("TERM=unknown", FALSE, FALSE);
899    if (!ISSET(didvar, DID_PATH))
900	sudo_setenv("PATH", _PATH_STDPATH, FALSE);
901
902    /*
903     * Preload a noexec file?  For a list of LD_PRELOAD-alikes, see
904     * http://www.fortran-2000.com/ArnaudRecipes/sharedlib.html
905     * XXX - should prepend to original value, if any
906     */
907    if (noexec && def_noexec_file != NULL) {
908#if defined(__darwin__) || defined(__APPLE__)
909	sudo_setenv("DYLD_INSERT_LIBRARIES", def_noexec_file, TRUE);
910	sudo_setenv("DYLD_FORCE_FLAT_NAMESPACE", "", TRUE);
911#else
912# if defined(__osf__) || defined(__sgi)
913	easprintf(&cp, "%s:DEFAULT", def_noexec_file);
914	sudo_setenv("_RLD_LIST", cp, TRUE);
915	efree(cp);
916# else
917#  ifdef _AIX
918	sudo_setenv("LDR_PRELOAD", def_noexec_file, TRUE);
919#  else
920	sudo_setenv("LD_PRELOAD", def_noexec_file, TRUE);
921#  endif /* _AIX */
922# endif /* __osf__ || __sgi */
923#endif /* __darwin__ || __APPLE__ */
924    }
925
926    /* Set PS1 if SUDO_PS1 is set. */
927    if (ps1 != NULL)
928	sudo_putenv(ps1, TRUE, TRUE);
929
930    /* Add the SUDO_COMMAND envariable (cmnd + args). */
931    if (user_args) {
932	easprintf(&cp, "%s %s", user_cmnd, user_args);
933	sudo_setenv("SUDO_COMMAND", cp, TRUE);
934	efree(cp);
935    } else {
936	sudo_setenv("SUDO_COMMAND", user_cmnd, TRUE);
937    }
938
939    /* Add the SUDO_USER, SUDO_UID, SUDO_GID environment variables. */
940    sudo_setenv("SUDO_USER", user_name, TRUE);
941    snprintf(idbuf, sizeof(idbuf), "%u", (unsigned int) user_uid);
942    sudo_setenv("SUDO_UID", idbuf, TRUE);
943    snprintf(idbuf, sizeof(idbuf), "%u", (unsigned int) user_gid);
944    sudo_setenv("SUDO_GID", idbuf, TRUE);
945
946    /* Free old environment. */
947    efree(old_envp);
948}
949
950void
951insert_env_vars(env_vars)
952    struct list_member *env_vars;
953{
954    struct list_member *cur;
955
956    /* Add user-specified environment variables. */
957    for (cur = env_vars; cur != NULL; cur = cur->next)
958	putenv(cur->value);
959}
960
961/*
962 * Validate the list of environment variables passed in on the command
963 * line against env_delete, env_check, and env_keep.
964 * Calls log_fatal() if any specified variables are not allowed.
965 */
966void
967validate_env_vars(env_vars)
968    struct list_member *env_vars;
969{
970    struct list_member *var;
971    char *eq, *bad = NULL;
972    size_t len, blen = 0, bsize = 0;
973    int okvar;
974
975    /* Add user-specified environment variables. */
976    for (var = env_vars; var != NULL; var = var->next) {
977	if (def_secure_path && !user_is_exempt() &&
978	    strncmp(var->value, "PATH=", 5) == 0) {
979	    okvar = FALSE;
980	} else if (def_env_reset) {
981	    okvar = matches_env_check(var->value);
982	    if (okvar == -1)
983		okvar = matches_env_keep(var->value);
984	} else {
985	    okvar = matches_env_delete(var->value) == FALSE;
986	    if (okvar == FALSE)
987		okvar = matches_env_check(var->value) != FALSE;
988	}
989	if (okvar == FALSE) {
990	    /* Not allowed, add to error string, allocating as needed. */
991	    if ((eq = strchr(var->value, '=')) != NULL)
992		*eq = '\0';
993	    len = strlen(var->value) + 2;
994	    if (blen + len >= bsize) {
995		do {
996		    bsize += 1024;
997		} while (blen + len >= bsize);
998		bad = erealloc(bad, bsize);
999		bad[blen] = '\0';
1000	    }
1001	    strlcat(bad, var->value, bsize);
1002	    strlcat(bad, ", ", bsize);
1003	    blen += len;
1004	    if (eq != NULL)
1005		*eq = '=';
1006	}
1007    }
1008    if (bad != NULL) {
1009	bad[blen - 2] = '\0';		/* remove trailing ", " */
1010	log_fatal(NO_MAIL,
1011	    "sorry, you are not allowed to set the following environment variables: %s", bad);
1012	/* NOTREACHED */
1013	efree(bad);
1014    }
1015}
1016
1017/*
1018 * Read in /etc/environment ala AIX and Linux.
1019 * Lines may be in either of three formats:
1020 *  NAME=VALUE
1021 *  NAME="VALUE"
1022 *  NAME='VALUE'
1023 * with an optional "export" prefix so the shell can source the file.
1024 * Invalid lines, blank lines, or lines consisting solely of a comment
1025 * character are skipped.
1026 */
1027void
1028read_env_file(path, overwrite)
1029    const char *path;
1030    int overwrite;
1031{
1032    FILE *fp;
1033    char *cp, *var, *val;
1034    size_t var_len, val_len;
1035
1036    if ((fp = fopen(path, "r")) == NULL)
1037	return;
1038
1039    while ((var = sudo_parseln(fp)) != NULL) {
1040	/* Skip blank or comment lines */
1041	if (*var == '\0')
1042	    continue;
1043
1044	/* Skip optional "export " */
1045	if (strncmp(var, "export", 6) == 0 && isspace((unsigned char) var[6])) {
1046	    var += 7;
1047	    while (isspace((unsigned char) *var)) {
1048		var++;
1049	    }
1050	}
1051
1052	/* Must be of the form name=["']value['"] */
1053	for (val = var; *val != '\0' && *val != '='; val++)
1054	    ;
1055	if (var == val || *val != '=')
1056	    continue;
1057	var_len = (size_t)(val - var);
1058	val_len = strlen(++val);
1059
1060	/* Strip leading and trailing single/double quotes */
1061	if ((val[0] == '\'' || val[0] == '\"') && val[0] == val[val_len - 1]) {
1062	    val[val_len - 1] = '\0';
1063	    val++;
1064	    val_len -= 2;
1065	}
1066
1067	cp = emalloc(var_len + 1 + val_len + 1);
1068	memcpy(cp, var, var_len + 1); /* includes '=' */
1069	memcpy(cp + var_len + 1, val, val_len + 1); /* includes NUL */
1070
1071	sudo_putenv(cp, TRUE, overwrite);
1072    }
1073    fclose(fp);
1074}
1075
1076void
1077init_envtables()
1078{
1079    struct list_member *cur;
1080    const char **p;
1081
1082    /* Fill in the "env_delete" list. */
1083    for (p = initial_badenv_table; *p; p++) {
1084	cur = ecalloc(1, sizeof(struct list_member));
1085	cur->value = estrdup(*p);
1086	cur->next = def_env_delete;
1087	def_env_delete = cur;
1088    }
1089
1090    /* Fill in the "env_check" list. */
1091    for (p = initial_checkenv_table; *p; p++) {
1092	cur = ecalloc(1, sizeof(struct list_member));
1093	cur->value = estrdup(*p);
1094	cur->next = def_env_check;
1095	def_env_check = cur;
1096    }
1097
1098    /* Fill in the "env_keep" list. */
1099    for (p = initial_keepenv_table; *p; p++) {
1100	cur = ecalloc(1, sizeof(struct list_member));
1101	cur->value = estrdup(*p);
1102	cur->next = def_env_keep;
1103	def_env_keep = cur;
1104    }
1105}
1106