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