Annotation of src/usr.bin/sudo/env.c, Revision 1.24
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.1 millert 189: NULL
190: };
191:
192: /*
1.14 millert 193: * Default table of variables to preserve in the environment.
1.1 millert 194: */
1.14 millert 195: static const char *initial_keepenv_table[] = {
196: "COLORS",
197: "DISPLAY",
1.17 millert 198: "HOME",
1.14 millert 199: "HOSTNAME",
200: "KRB5CCNAME",
201: "LS_COLORS",
202: "MAIL",
203: "PATH",
204: "PS1",
205: "PS2",
206: "TZ",
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: /*
516: * Apply the env_check list.
517: * Returns TRUE if the variable is allowed, FALSE if denied
518: * or -1 if no match.
519: */
520: static int
521: matches_env_check(var)
522: const char *var;
523: {
524: struct list_member *cur;
525: size_t len;
526: int iswild, keepit = -1;
527:
528: for (cur = def_env_check; cur; cur = cur->next) {
529: len = strlen(cur->value);
530: /* Deal with '*' wildcard */
531: if (cur->value[len - 1] == '*') {
532: len--;
533: iswild = TRUE;
534: } else
535: iswild = FALSE;
536: if (strncmp(cur->value, var, len) == 0 &&
537: (iswild || var[len] == '=')) {
538: keepit = !strpbrk(var, "/%");
539: break;
540: }
541: }
542: return(keepit);
543: }
544:
545: /*
546: * Check the env_keep list.
547: * Returns TRUE if the variable is allowed else FALSE.
548: */
549: static int
550: matches_env_keep(var)
551: const char *var;
552: {
553: struct list_member *cur;
554: size_t len;
555: int iswild, keepit = FALSE;
556:
557: for (cur = def_env_keep; cur; cur = cur->next) {
558: len = strlen(cur->value);
559: /* Deal with '*' wildcard */
560: if (cur->value[len - 1] == '*') {
561: len--;
562: iswild = TRUE;
563: } else
564: iswild = FALSE;
565: if (strncmp(cur->value, var, len) == 0 &&
566: (iswild || var[len] == '=')) {
567: keepit = TRUE;
568: break;
569: }
570: }
571: return(keepit);
572: }
573:
574: /*
1.1 millert 575: * Build a new environment and ether clear potentially dangerous
576: * variables from the old one or start with a clean slate.
577: * Also adds sudo-specific variables (SUDO_*).
578: */
1.18 millert 579: void
580: rebuild_env(sudo_mode, noexec)
1.1 millert 581: int sudo_mode;
1.9 millert 582: int noexec;
1.1 millert 583: {
1.18 millert 584: char **old_envp, **ep, *cp, *ps1;
585: char idbuf[MAX_UID_T_LEN];
1.14 millert 586: unsigned int didvar;
1.1 millert 587:
588: /*
589: * Either clean out the environment or reset to a safe default.
590: */
591: ps1 = NULL;
592: didvar = 0;
1.18 millert 593: env.env_len = 0;
594: env.env_size = 128;
595: old_envp = env.envp;
596: env.envp = emalloc2(env.env_size, sizeof(char *));
1.19 millert 597: #ifdef ENV_DEBUG
598: memset(env.envp, 0, env.env_size * sizeof(char *));
599: #endif
1.17 millert 600: if (def_env_reset || ISSET(sudo_mode, MODE_LOGIN_SHELL)) {
1.1 millert 601: /* Pull in vars we want to keep from the old environment. */
1.18 millert 602: for (ep = environ; *ep; ep++) {
1.14 millert 603: int keepit;
1.10 millert 604:
605: /* Skip variables with values beginning with () (bash functions) */
606: if ((cp = strchr(*ep, '=')) != NULL) {
607: if (strncmp(cp, "=() ", 3) == 0)
608: continue;
609: }
610:
1.14 millert 611: /*
612: * First check certain variables for '%' and '/' characters.
613: * If no match there, check the keep list.
614: * If nothing matched, we remove it from the environment.
615: */
616: keepit = matches_env_check(*ep);
617: if (keepit == -1)
618: keepit = matches_env_keep(*ep);
1.1 millert 619:
620: /* For SUDO_PS1 -> PS1 conversion. */
621: if (strncmp(*ep, "SUDO_PS1=", 8) == 0)
622: ps1 = *ep + 5;
623:
624: if (keepit) {
625: /* Preserve variable. */
626: switch (**ep) {
627: case 'H':
628: if (strncmp(*ep, "HOME=", 5) == 0)
1.9 millert 629: SET(didvar, DID_HOME);
1.5 millert 630: break;
1.14 millert 631: case 'L':
632: if (strncmp(*ep, "LOGNAME=", 8) == 0)
633: SET(didvar, DID_LOGNAME);
634: break;
635: case 'P':
636: if (strncmp(*ep, "PATH=", 5) == 0)
637: SET(didvar, DID_PATH);
638: break;
1.1 millert 639: case 'S':
640: if (strncmp(*ep, "SHELL=", 6) == 0)
1.9 millert 641: SET(didvar, DID_SHELL);
1.5 millert 642: break;
1.14 millert 643: case 'T':
644: if (strncmp(*ep, "TERM=", 5) == 0)
645: SET(didvar, DID_TERM);
1.5 millert 646: break;
1.1 millert 647: case 'U':
648: if (strncmp(*ep, "USER=", 5) == 0)
1.9 millert 649: SET(didvar, DID_USER);
1.14 millert 650: if (strncmp(*ep, "USERNAME=", 5) == 0)
651: SET(didvar, DID_USERNAME);
1.5 millert 652: break;
1.1 millert 653: }
1.19 millert 654: sudo_putenv(*ep, FALSE, FALSE);
1.1 millert 655: }
656: }
1.14 millert 657: didvar |= didvar << 8; /* convert DID_* to KEPT_* */
1.1 millert 658:
659: /*
1.9 millert 660: * Add in defaults. In -i mode these come from the runas user,
661: * otherwise they may be from the user's environment (depends
662: * on sudoers options).
1.1 millert 663: */
1.9 millert 664: if (ISSET(sudo_mode, MODE_LOGIN_SHELL)) {
1.19 millert 665: sudo_setenv("HOME", runas_pw->pw_dir, ISSET(didvar, DID_HOME));
666: sudo_setenv("SHELL", runas_pw->pw_shell, ISSET(didvar, DID_SHELL));
667: sudo_setenv("LOGNAME", runas_pw->pw_name,
1.14 millert 668: ISSET(didvar, DID_LOGNAME));
1.19 millert 669: sudo_setenv("USER", runas_pw->pw_name, ISSET(didvar, DID_USER));
670: sudo_setenv("USERNAME", runas_pw->pw_name,
1.14 millert 671: ISSET(didvar, DID_USERNAME));
1.9 millert 672: } else {
673: if (!ISSET(didvar, DID_HOME))
1.19 millert 674: sudo_setenv("HOME", user_dir, FALSE);
1.9 millert 675: if (!ISSET(didvar, DID_SHELL))
1.19 millert 676: sudo_setenv("SHELL", sudo_user.pw->pw_shell, FALSE);
1.9 millert 677: if (!ISSET(didvar, DID_LOGNAME))
1.19 millert 678: sudo_setenv("LOGNAME", user_name, FALSE);
1.9 millert 679: if (!ISSET(didvar, DID_USER))
1.19 millert 680: sudo_setenv("USER", user_name, FALSE);
1.14 millert 681: if (!ISSET(didvar, DID_USERNAME))
1.19 millert 682: sudo_setenv("USERNAME", user_name, FALSE);
1.9 millert 683: }
1.1 millert 684: } else {
685: /*
1.18 millert 686: * Copy environ entries as long as they don't match env_delete or
1.1 millert 687: * env_check.
688: */
1.18 millert 689: for (ep = environ; *ep; ep++) {
1.14 millert 690: int okvar;
1.10 millert 691:
692: /* Skip variables with values beginning with () (bash functions) */
693: if ((cp = strchr(*ep, '=')) != NULL) {
694: if (strncmp(cp, "=() ", 3) == 0)
695: continue;
696: }
1.1 millert 697:
1.14 millert 698: /*
699: * First check variables against the blacklist in env_delete.
700: * If no match there check for '%' and '/' characters.
701: */
702: okvar = matches_env_delete(*ep) != TRUE;
703: if (okvar)
704: okvar = matches_env_check(*ep) != FALSE;
1.1 millert 705:
706: if (okvar) {
707: if (strncmp(*ep, "SUDO_PS1=", 9) == 0)
708: ps1 = *ep + 5;
709: else if (strncmp(*ep, "PATH=", 5) == 0)
1.9 millert 710: SET(didvar, DID_PATH);
1.1 millert 711: else if (strncmp(*ep, "TERM=", 5) == 0)
1.9 millert 712: SET(didvar, DID_TERM);
1.19 millert 713: sudo_putenv(*ep, FALSE, FALSE);
1.1 millert 714: }
715: }
716: }
1.18 millert 717: /* Replace the PATH envariable with a secure one? */
718: if (def_secure_path && !user_is_exempt()) {
1.19 millert 719: sudo_setenv("PATH", def_secure_path, TRUE);
1.14 millert 720: SET(didvar, DID_PATH);
721: }
1.1 millert 722:
1.14 millert 723: /* Set $USER, $LOGNAME and $USERNAME to target if "set_logname" is true. */
1.17 millert 724: /* XXX - not needed for MODE_LOGIN_SHELL */
1.9 millert 725: if (def_set_logname && runas_pw->pw_name) {
1.14 millert 726: if (!ISSET(didvar, KEPT_LOGNAME))
1.19 millert 727: sudo_setenv("LOGNAME", runas_pw->pw_name, TRUE);
1.14 millert 728: if (!ISSET(didvar, KEPT_USER))
1.19 millert 729: sudo_setenv("USER", runas_pw->pw_name, TRUE);
1.14 millert 730: if (!ISSET(didvar, KEPT_USERNAME))
1.19 millert 731: sudo_setenv("USERNAME", runas_pw->pw_name, TRUE);
1.1 millert 732: }
733:
1.9 millert 734: /* Set $HOME for `sudo -H'. Only valid at PERM_FULL_RUNAS. */
1.17 millert 735: /* XXX - not needed for MODE_LOGIN_SHELL */
1.14 millert 736: if (runas_pw->pw_dir) {
737: if (ISSET(sudo_mode, MODE_RESET_HOME) ||
738: (ISSET(sudo_mode, MODE_RUN) && (def_always_set_home ||
739: (ISSET(sudo_mode, MODE_SHELL) && def_set_home))))
1.19 millert 740: sudo_setenv("HOME", runas_pw->pw_dir, TRUE);
1.14 millert 741: }
742:
743: /* Provide default values for $TERM and $PATH if they are not set. */
744: if (!ISSET(didvar, DID_TERM))
1.19 millert 745: sudo_putenv("TERM=unknown", FALSE, FALSE);
1.14 millert 746: if (!ISSET(didvar, DID_PATH))
1.19 millert 747: sudo_setenv("PATH", _PATH_DEFPATH, FALSE);
1.9 millert 748:
749: /*
750: * Preload a noexec file? For a list of LD_PRELOAD-alikes, see
751: * http://www.fortran-2000.com/ArnaudRecipes/sharedlib.html
752: * XXX - should prepend to original value, if any
753: */
1.12 millert 754: if (noexec && def_noexec_file != NULL) {
1.9 millert 755: #if defined(__darwin__) || defined(__APPLE__)
1.19 millert 756: sudo_setenv("DYLD_INSERT_LIBRARIES", def_noexec_file, TRUE);
757: sudo_setenv("DYLD_FORCE_FLAT_NAMESPACE", "", TRUE);
1.9 millert 758: #else
759: # if defined(__osf__) || defined(__sgi)
1.18 millert 760: easprintf(&cp, "%s:DEFAULT", def_noexec_file);
1.19 millert 761: sudo_setenv("_RLD_LIST", cp, TRUE);
1.18 millert 762: efree(cp);
1.9 millert 763: # else
1.14 millert 764: # ifdef _AIX
1.19 millert 765: sudo_setenv("LDR_PRELOAD", def_noexec_file, TRUE);
1.14 millert 766: # else
1.19 millert 767: sudo_setenv("LD_PRELOAD", def_noexec_file, TRUE);
1.14 millert 768: # endif /* _AIX */
769: # endif /* __osf__ || __sgi */
770: #endif /* __darwin__ || __APPLE__ */
1.12 millert 771: }
1.1 millert 772:
773: /* Set PS1 if SUDO_PS1 is set. */
1.18 millert 774: if (ps1 != NULL)
1.19 millert 775: sudo_putenv(ps1, TRUE, TRUE);
1.1 millert 776:
777: /* Add the SUDO_COMMAND envariable (cmnd + args). */
1.18 millert 778: if (user_args) {
779: easprintf(&cp, "%s %s", user_cmnd, user_args);
1.19 millert 780: sudo_setenv("SUDO_COMMAND", cp, TRUE);
1.18 millert 781: efree(cp);
782: } else
1.19 millert 783: sudo_setenv("SUDO_COMMAND", user_cmnd, TRUE);
1.1 millert 784:
785: /* Add the SUDO_USER, SUDO_UID, SUDO_GID environment variables. */
1.19 millert 786: sudo_setenv("SUDO_USER", user_name, TRUE);
1.18 millert 787: snprintf(idbuf, sizeof(idbuf), "%lu", (unsigned long) user_uid);
1.19 millert 788: sudo_setenv("SUDO_UID", idbuf, TRUE);
1.18 millert 789: snprintf(idbuf, sizeof(idbuf), "%lu", (unsigned long) user_gid);
1.19 millert 790: sudo_setenv("SUDO_GID", idbuf, TRUE);
1.18 millert 791:
792: /* Install new environment. */
793: environ = env.envp;
794: efree(old_envp);
1.14 millert 795: }
796:
1.18 millert 797: void
798: insert_env_vars(env_vars)
1.14 millert 799: struct list_member *env_vars;
800: {
801: struct list_member *cur;
802:
803: if (env_vars == NULL)
1.18 millert 804: return;
1.14 millert 805:
806: /* Add user-specified environment variables. */
807: for (cur = env_vars; cur != NULL; cur = cur->next)
1.19 millert 808: putenv(cur->value);
1.14 millert 809: }
810:
811: /*
812: * Validate the list of environment variables passed in on the command
813: * line against env_delete, env_check, and env_keep.
814: * Calls log_error() if any specified variables are not allowed.
815: */
816: void
817: validate_env_vars(env_vars)
818: struct list_member *env_vars;
819: {
820: struct list_member *var;
821: char *eq, *bad = NULL;
822: size_t len, blen = 0, bsize = 0;
823: int okvar;
1.1 millert 824:
1.14 millert 825: for (var = env_vars; var != NULL; var = var->next) {
1.18 millert 826: if (def_secure_path && !user_is_exempt() &&
827: strncmp(var->value, "PATH=", 5) == 0) {
1.14 millert 828: okvar = FALSE;
1.18 millert 829: } else if (def_env_reset) {
1.14 millert 830: okvar = matches_env_check(var->value);
831: if (okvar == -1)
832: okvar = matches_env_keep(var->value);
833: } else {
834: okvar = matches_env_delete(var->value) == FALSE;
835: if (okvar == FALSE)
836: okvar = matches_env_check(var->value) != FALSE;
837: }
838: if (okvar == FALSE) {
839: /* Not allowed, add to error string, allocating as needed. */
840: if ((eq = strchr(var->value, '=')) != NULL)
841: *eq = '\0';
842: len = strlen(var->value) + 2;
843: if (blen + len >= bsize) {
844: do {
845: bsize += 1024;
846: } while (blen + len >= bsize);
847: bad = erealloc(bad, bsize);
848: bad[blen] = '\0';
849: }
850: strlcat(bad, var->value, bsize);
851: strlcat(bad, ", ", bsize);
852: blen += len;
853: if (eq != NULL)
854: *eq = '=';
855: }
856: }
857: if (bad != NULL) {
858: bad[blen - 2] = '\0'; /* remove trailing ", " */
859: log_error(NO_MAIL,
860: "sorry, you are not allowed to set the following environment variables: %s", bad);
861: /* NOTREACHED */
862: efree(bad);
863: }
1.18 millert 864: }
865:
866: /*
867: * Read in /etc/environment ala AIX and Linux.
1.21 millert 868: * Lines may be in either of three formats:
869: * NAME=VALUE
870: * NAME="VALUE"
871: * NAME='VALUE'
872: * with an optional "export" prefix so the shell can source the file.
1.18 millert 873: * Invalid lines, blank lines, or lines consisting solely of a comment
874: * character are skipped.
875: */
876: void
1.19 millert 877: read_env_file(path, overwrite)
1.18 millert 878: const char *path;
1.19 millert 879: int overwrite;
1.18 millert 880: {
881: FILE *fp;
1.21 millert 882: char *cp, *var, *val;
883: size_t var_len, val_len;
1.18 millert 884:
885: if ((fp = fopen(path, "r")) == NULL)
886: return;
887:
1.21 millert 888: while ((var = sudo_parseln(fp)) != NULL) {
1.18 millert 889: /* Skip blank or comment lines */
1.21 millert 890: if (*var == '\0')
1.18 millert 891: continue;
892:
1.21 millert 893: /* Skip optional "export " */
894: if (strncmp(var, "export", 6) == 0 && isspace((unsigned char) var[6])) {
895: var += 7;
896: while (isspace((unsigned char) *var)) {
897: var++;
898: }
899: }
900:
901: /* Must be of the form name=["']value['"] */
902: for (val = var; *val != '\0' && *val != '='; val++)
903: ;
904: if (var == val || *val != '=')
1.18 millert 905: continue;
1.21 millert 906: var_len = (size_t)(val - var);
907: val_len = strlen(++val);
908:
909: /* Strip leading and trailing single/double quotes */
910: if ((val[0] == '\'' || val[0] == '\"') && val[0] == val[val_len - 1]) {
911: val[val_len - 1] = '\0';
912: val++;
913: val_len -= 2;
914: }
915:
916: cp = emalloc(var_len + 1 + val_len + 1);
917: memcpy(cp, var, var_len + 1); /* includes '=' */
918: memcpy(cp + var_len + 1, val, val_len + 1); /* includes NUL */
1.18 millert 919:
1.21 millert 920: sudo_putenv(cp, TRUE, overwrite);
1.18 millert 921: }
922: fclose(fp);
1.1 millert 923: }
924:
925: void
926: init_envtables()
927: {
928: struct list_member *cur;
1.5 millert 929: const char **p;
1.1 millert 930:
1.14 millert 931: /* Fill in the "env_delete" list. */
1.1 millert 932: for (p = initial_badenv_table; *p; p++) {
933: cur = emalloc(sizeof(struct list_member));
934: cur->value = estrdup(*p);
1.9 millert 935: cur->next = def_env_delete;
936: def_env_delete = cur;
1.1 millert 937: }
938:
1.14 millert 939: /* Fill in the "env_check" list. */
1.1 millert 940: for (p = initial_checkenv_table; *p; p++) {
941: cur = emalloc(sizeof(struct list_member));
942: cur->value = estrdup(*p);
1.9 millert 943: cur->next = def_env_check;
944: def_env_check = cur;
1.14 millert 945: }
946:
947: /* Fill in the "env_keep" list. */
948: for (p = initial_keepenv_table; *p; p++) {
949: cur = emalloc(sizeof(struct list_member));
950: cur->value = estrdup(*p);
951: cur->next = def_env_keep;
952: def_env_keep = cur;
1.1 millert 953: }
954: }