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