Annotation of src/usr.bin/sudo/env.c, Revision 1.23
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.23 ! millert 320: char **ep = env.envp;
1.19 millert 321: size_t len;
322:
323: if (strchr(var, '=') != NULL) {
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.23 ! millert 358: while (*ep != NULL) {
1.19 millert 359: if (strncmp(var, *ep, len) == 0 && (*ep)[len] == '=') {
360: /* Found it; shift remainder + NULL over by one and update len. */
361: memmove(ep, ep + 1,
362: (env.env_len - (ep - env.envp)) * sizeof(char *));
1.18 millert 363: env.env_len--;
1.23 ! millert 364: /* Keep going, could be multiple instances of the var. */
! 365: } else {
! 366: ep++;
1.18 millert 367: }
368: }
1.19 millert 369: #ifndef UNSETENV_VOID
370: return(0);
371: #endif
1.1 millert 372: }
373:
374: /*
1.19 millert 375: * Version of putenv(3) that uses our own environ pointer.
376: * Will sync with environ as needed.
377: */
378: int
379: #ifdef PUTENV_CONST
380: putenv(const char *string)
381: #else
382: putenv(string)
383: char *string;
384: #endif
385: {
386: if (strchr(string, '=') == NULL) {
387: errno = EINVAL;
388: return(-1);
389: }
390: /* Sync env.envp with environ as needed. */
391: if (env.envp != environ) {
392: char **ep;
393: size_t len;
394:
395: for (ep = environ; *ep != NULL; ep++)
396: continue;
397: len = ep - environ;
398: if (len + 2 > env.env_size) {
399: efree(env.envp);
400: env.env_size = len + 2 + 128;
401: env.envp = emalloc2(env.env_size, sizeof(char *));
402: #ifdef ENV_DEBUG
403: memset(env.envp, 0, env.env_size * sizeof(char *));
404: #endif
405: }
406: memcpy(env.envp, environ, len * sizeof(char *));
407: env.envp[len] = NULL;
408: env.env_len = len;
409: environ = env.envp;
410: #ifdef ENV_DEBUG
411: } else {
412: if (env.envp[env.env_len] != NULL)
413: errorx(1, "putenv: corrupted envp, len mismatch");
414: #endif
415: }
416: sudo_putenv((char *)string, TRUE, TRUE);
417: return(0);
418: }
419:
420: /*
421: * Similar to putenv(3) but operates on sudo's private copy of the
422: * environment (not environ) and it always overwrites. The dupcheck param
423: * determines whether we need to verify that the variable is not already set.
424: * Will only overwrite an existing variable if overwrite is set.
1.1 millert 425: */
426: static void
1.19 millert 427: sudo_putenv(str, dupcheck, overwrite)
1.1 millert 428: char *str;
1.5 millert 429: int dupcheck;
1.19 millert 430: int overwrite;
1.1 millert 431: {
1.19 millert 432: char **ep;
433: size_t len;
1.23 ! millert 434: int found = FALSE;
1.1 millert 435:
1.8 millert 436: /* Make sure there is room for the new entry plus a NULL. */
1.18 millert 437: if (env.env_len + 2 > env.env_size) {
438: env.env_size += 128;
439: env.envp = erealloc3(env.envp, env.env_size, sizeof(char *));
1.19 millert 440: #ifdef ENV_DEBUG
441: memset(env.envp + env.env_len, 0,
442: (env.env_size - env.env_len) * sizeof(char *));
443: #endif
444: environ = env.envp;
1.5 millert 445: }
446:
1.19 millert 447: #ifdef ENV_DEBUG
448: if (env.envp[env.env_len] != NULL)
449: errorx(1, "sudo_putenv: corrupted envp, len mismatch");
450: #endif
451:
1.5 millert 452: if (dupcheck) {
1.23 ! millert 453: len = (strchr(str, '=') - str) + 1;
! 454: for (ep = env.envp; !found && *ep != NULL; ep++) {
! 455: if (strncmp(str, *ep, len) == 0) {
! 456: if (overwrite)
! 457: *ep = str;
! 458: found = TRUE;
! 459: }
! 460: }
! 461: /* Prune out duplicate variables. */
! 462: if (found && overwrite) {
! 463: while (*ep != NULL) {
1.19 millert 464: if (strncmp(str, *ep, len) == 0) {
1.23 ! millert 465: memmove(ep, ep + 1,
! 466: (env.env_len - (ep - env.envp)) * sizeof(char *));
! 467: env.env_len--;
! 468: } else {
! 469: ep++;
1.5 millert 470: }
471: }
1.23 ! millert 472: }
! 473: }
! 474:
! 475: if (!found) {
1.19 millert 476: ep = env.envp + env.env_len;
1.23 ! millert 477: env.env_len++;
! 478: *ep++ = str;
! 479: *ep = NULL;
! 480: }
1.1 millert 481: }
482:
483: /*
1.14 millert 484: * Check the env_delete blacklist.
485: * Returns TRUE if the variable was found, else false.
486: */
487: static int
488: matches_env_delete(var)
489: const char *var;
490: {
491: struct list_member *cur;
492: size_t len;
493: int iswild, match = FALSE;
494:
495: /* Skip anything listed in env_delete. */
496: for (cur = def_env_delete; cur; cur = cur->next) {
497: len = strlen(cur->value);
498: /* Deal with '*' wildcard */
499: if (cur->value[len - 1] == '*') {
500: len--;
501: iswild = TRUE;
502: } else
503: iswild = FALSE;
504: if (strncmp(cur->value, var, len) == 0 &&
505: (iswild || var[len] == '=')) {
506: match = TRUE;
507: break;
508: }
509: }
510: return(match);
511: }
512:
513: /*
514: * Apply the env_check list.
515: * Returns TRUE if the variable is allowed, FALSE if denied
516: * or -1 if no match.
517: */
518: static int
519: matches_env_check(var)
520: const char *var;
521: {
522: struct list_member *cur;
523: size_t len;
524: int iswild, keepit = -1;
525:
526: for (cur = def_env_check; cur; cur = cur->next) {
527: len = strlen(cur->value);
528: /* Deal with '*' wildcard */
529: if (cur->value[len - 1] == '*') {
530: len--;
531: iswild = TRUE;
532: } else
533: iswild = FALSE;
534: if (strncmp(cur->value, var, len) == 0 &&
535: (iswild || var[len] == '=')) {
536: keepit = !strpbrk(var, "/%");
537: break;
538: }
539: }
540: return(keepit);
541: }
542:
543: /*
544: * Check the env_keep list.
545: * Returns TRUE if the variable is allowed else FALSE.
546: */
547: static int
548: matches_env_keep(var)
549: const char *var;
550: {
551: struct list_member *cur;
552: size_t len;
553: int iswild, keepit = FALSE;
554:
555: for (cur = def_env_keep; cur; cur = cur->next) {
556: len = strlen(cur->value);
557: /* Deal with '*' wildcard */
558: if (cur->value[len - 1] == '*') {
559: len--;
560: iswild = TRUE;
561: } else
562: iswild = FALSE;
563: if (strncmp(cur->value, var, len) == 0 &&
564: (iswild || var[len] == '=')) {
565: keepit = TRUE;
566: break;
567: }
568: }
569: return(keepit);
570: }
571:
572: /*
1.1 millert 573: * Build a new environment and ether clear potentially dangerous
574: * variables from the old one or start with a clean slate.
575: * Also adds sudo-specific variables (SUDO_*).
576: */
1.18 millert 577: void
578: rebuild_env(sudo_mode, noexec)
1.1 millert 579: int sudo_mode;
1.9 millert 580: int noexec;
1.1 millert 581: {
1.18 millert 582: char **old_envp, **ep, *cp, *ps1;
583: char idbuf[MAX_UID_T_LEN];
1.14 millert 584: unsigned int didvar;
1.1 millert 585:
586: /*
587: * Either clean out the environment or reset to a safe default.
588: */
589: ps1 = NULL;
590: didvar = 0;
1.18 millert 591: env.env_len = 0;
592: env.env_size = 128;
593: old_envp = env.envp;
594: env.envp = emalloc2(env.env_size, sizeof(char *));
1.19 millert 595: #ifdef ENV_DEBUG
596: memset(env.envp, 0, env.env_size * sizeof(char *));
597: #endif
1.17 millert 598: if (def_env_reset || ISSET(sudo_mode, MODE_LOGIN_SHELL)) {
1.1 millert 599: /* Pull in vars we want to keep from the old environment. */
1.18 millert 600: for (ep = environ; *ep; ep++) {
1.14 millert 601: int keepit;
1.10 millert 602:
603: /* Skip variables with values beginning with () (bash functions) */
604: if ((cp = strchr(*ep, '=')) != NULL) {
605: if (strncmp(cp, "=() ", 3) == 0)
606: continue;
607: }
608:
1.14 millert 609: /*
610: * First check certain variables for '%' and '/' characters.
611: * If no match there, check the keep list.
612: * If nothing matched, we remove it from the environment.
613: */
614: keepit = matches_env_check(*ep);
615: if (keepit == -1)
616: keepit = matches_env_keep(*ep);
1.1 millert 617:
618: /* For SUDO_PS1 -> PS1 conversion. */
619: if (strncmp(*ep, "SUDO_PS1=", 8) == 0)
620: ps1 = *ep + 5;
621:
622: if (keepit) {
623: /* Preserve variable. */
624: switch (**ep) {
625: case 'H':
626: if (strncmp(*ep, "HOME=", 5) == 0)
1.9 millert 627: SET(didvar, DID_HOME);
1.5 millert 628: break;
1.14 millert 629: case 'L':
630: if (strncmp(*ep, "LOGNAME=", 8) == 0)
631: SET(didvar, DID_LOGNAME);
632: break;
633: case 'P':
634: if (strncmp(*ep, "PATH=", 5) == 0)
635: SET(didvar, DID_PATH);
636: break;
1.1 millert 637: case 'S':
638: if (strncmp(*ep, "SHELL=", 6) == 0)
1.9 millert 639: SET(didvar, DID_SHELL);
1.5 millert 640: break;
1.14 millert 641: case 'T':
642: if (strncmp(*ep, "TERM=", 5) == 0)
643: SET(didvar, DID_TERM);
1.5 millert 644: break;
1.1 millert 645: case 'U':
646: if (strncmp(*ep, "USER=", 5) == 0)
1.9 millert 647: SET(didvar, DID_USER);
1.14 millert 648: if (strncmp(*ep, "USERNAME=", 5) == 0)
649: SET(didvar, DID_USERNAME);
1.5 millert 650: break;
1.1 millert 651: }
1.19 millert 652: sudo_putenv(*ep, FALSE, FALSE);
1.1 millert 653: }
654: }
1.14 millert 655: didvar |= didvar << 8; /* convert DID_* to KEPT_* */
1.1 millert 656:
657: /*
1.9 millert 658: * Add in defaults. In -i mode these come from the runas user,
659: * otherwise they may be from the user's environment (depends
660: * on sudoers options).
1.1 millert 661: */
1.9 millert 662: if (ISSET(sudo_mode, MODE_LOGIN_SHELL)) {
1.19 millert 663: sudo_setenv("HOME", runas_pw->pw_dir, ISSET(didvar, DID_HOME));
664: sudo_setenv("SHELL", runas_pw->pw_shell, ISSET(didvar, DID_SHELL));
665: sudo_setenv("LOGNAME", runas_pw->pw_name,
1.14 millert 666: ISSET(didvar, DID_LOGNAME));
1.19 millert 667: sudo_setenv("USER", runas_pw->pw_name, ISSET(didvar, DID_USER));
668: sudo_setenv("USERNAME", runas_pw->pw_name,
1.14 millert 669: ISSET(didvar, DID_USERNAME));
1.9 millert 670: } else {
671: if (!ISSET(didvar, DID_HOME))
1.19 millert 672: sudo_setenv("HOME", user_dir, FALSE);
1.9 millert 673: if (!ISSET(didvar, DID_SHELL))
1.19 millert 674: sudo_setenv("SHELL", sudo_user.pw->pw_shell, FALSE);
1.9 millert 675: if (!ISSET(didvar, DID_LOGNAME))
1.19 millert 676: sudo_setenv("LOGNAME", user_name, FALSE);
1.9 millert 677: if (!ISSET(didvar, DID_USER))
1.19 millert 678: sudo_setenv("USER", user_name, FALSE);
1.14 millert 679: if (!ISSET(didvar, DID_USERNAME))
1.19 millert 680: sudo_setenv("USERNAME", user_name, FALSE);
1.9 millert 681: }
1.1 millert 682: } else {
683: /*
1.18 millert 684: * Copy environ entries as long as they don't match env_delete or
1.1 millert 685: * env_check.
686: */
1.18 millert 687: for (ep = environ; *ep; ep++) {
1.14 millert 688: int okvar;
1.10 millert 689:
690: /* Skip variables with values beginning with () (bash functions) */
691: if ((cp = strchr(*ep, '=')) != NULL) {
692: if (strncmp(cp, "=() ", 3) == 0)
693: continue;
694: }
1.1 millert 695:
1.14 millert 696: /*
697: * First check variables against the blacklist in env_delete.
698: * If no match there check for '%' and '/' characters.
699: */
700: okvar = matches_env_delete(*ep) != TRUE;
701: if (okvar)
702: okvar = matches_env_check(*ep) != FALSE;
1.1 millert 703:
704: if (okvar) {
705: if (strncmp(*ep, "SUDO_PS1=", 9) == 0)
706: ps1 = *ep + 5;
707: else if (strncmp(*ep, "PATH=", 5) == 0)
1.9 millert 708: SET(didvar, DID_PATH);
1.1 millert 709: else if (strncmp(*ep, "TERM=", 5) == 0)
1.9 millert 710: SET(didvar, DID_TERM);
1.19 millert 711: sudo_putenv(*ep, FALSE, FALSE);
1.1 millert 712: }
713: }
714: }
1.18 millert 715: /* Replace the PATH envariable with a secure one? */
716: if (def_secure_path && !user_is_exempt()) {
1.19 millert 717: sudo_setenv("PATH", def_secure_path, TRUE);
1.14 millert 718: SET(didvar, DID_PATH);
719: }
1.1 millert 720:
1.14 millert 721: /* Set $USER, $LOGNAME and $USERNAME to target if "set_logname" is true. */
1.17 millert 722: /* XXX - not needed for MODE_LOGIN_SHELL */
1.9 millert 723: if (def_set_logname && runas_pw->pw_name) {
1.14 millert 724: if (!ISSET(didvar, KEPT_LOGNAME))
1.19 millert 725: sudo_setenv("LOGNAME", runas_pw->pw_name, TRUE);
1.14 millert 726: if (!ISSET(didvar, KEPT_USER))
1.19 millert 727: sudo_setenv("USER", runas_pw->pw_name, TRUE);
1.14 millert 728: if (!ISSET(didvar, KEPT_USERNAME))
1.19 millert 729: sudo_setenv("USERNAME", runas_pw->pw_name, TRUE);
1.1 millert 730: }
731:
1.9 millert 732: /* Set $HOME for `sudo -H'. Only valid at PERM_FULL_RUNAS. */
1.17 millert 733: /* XXX - not needed for MODE_LOGIN_SHELL */
1.14 millert 734: if (runas_pw->pw_dir) {
735: if (ISSET(sudo_mode, MODE_RESET_HOME) ||
736: (ISSET(sudo_mode, MODE_RUN) && (def_always_set_home ||
737: (ISSET(sudo_mode, MODE_SHELL) && def_set_home))))
1.19 millert 738: sudo_setenv("HOME", runas_pw->pw_dir, TRUE);
1.14 millert 739: }
740:
741: /* Provide default values for $TERM and $PATH if they are not set. */
742: if (!ISSET(didvar, DID_TERM))
1.19 millert 743: sudo_putenv("TERM=unknown", FALSE, FALSE);
1.14 millert 744: if (!ISSET(didvar, DID_PATH))
1.19 millert 745: sudo_setenv("PATH", _PATH_DEFPATH, FALSE);
1.9 millert 746:
747: /*
748: * Preload a noexec file? For a list of LD_PRELOAD-alikes, see
749: * http://www.fortran-2000.com/ArnaudRecipes/sharedlib.html
750: * XXX - should prepend to original value, if any
751: */
1.12 millert 752: if (noexec && def_noexec_file != NULL) {
1.9 millert 753: #if defined(__darwin__) || defined(__APPLE__)
1.19 millert 754: sudo_setenv("DYLD_INSERT_LIBRARIES", def_noexec_file, TRUE);
755: sudo_setenv("DYLD_FORCE_FLAT_NAMESPACE", "", TRUE);
1.9 millert 756: #else
757: # if defined(__osf__) || defined(__sgi)
1.18 millert 758: easprintf(&cp, "%s:DEFAULT", def_noexec_file);
1.19 millert 759: sudo_setenv("_RLD_LIST", cp, TRUE);
1.18 millert 760: efree(cp);
1.9 millert 761: # else
1.14 millert 762: # ifdef _AIX
1.19 millert 763: sudo_setenv("LDR_PRELOAD", def_noexec_file, TRUE);
1.14 millert 764: # else
1.19 millert 765: sudo_setenv("LD_PRELOAD", def_noexec_file, TRUE);
1.14 millert 766: # endif /* _AIX */
767: # endif /* __osf__ || __sgi */
768: #endif /* __darwin__ || __APPLE__ */
1.12 millert 769: }
1.1 millert 770:
771: /* Set PS1 if SUDO_PS1 is set. */
1.18 millert 772: if (ps1 != NULL)
1.19 millert 773: sudo_putenv(ps1, TRUE, TRUE);
1.1 millert 774:
775: /* Add the SUDO_COMMAND envariable (cmnd + args). */
1.18 millert 776: if (user_args) {
777: easprintf(&cp, "%s %s", user_cmnd, user_args);
1.19 millert 778: sudo_setenv("SUDO_COMMAND", cp, TRUE);
1.18 millert 779: efree(cp);
780: } else
1.19 millert 781: sudo_setenv("SUDO_COMMAND", user_cmnd, TRUE);
1.1 millert 782:
783: /* Add the SUDO_USER, SUDO_UID, SUDO_GID environment variables. */
1.19 millert 784: sudo_setenv("SUDO_USER", user_name, TRUE);
1.18 millert 785: snprintf(idbuf, sizeof(idbuf), "%lu", (unsigned long) user_uid);
1.19 millert 786: sudo_setenv("SUDO_UID", idbuf, TRUE);
1.18 millert 787: snprintf(idbuf, sizeof(idbuf), "%lu", (unsigned long) user_gid);
1.19 millert 788: sudo_setenv("SUDO_GID", idbuf, TRUE);
1.18 millert 789:
790: /* Install new environment. */
791: environ = env.envp;
792: efree(old_envp);
1.14 millert 793: }
794:
1.18 millert 795: void
796: insert_env_vars(env_vars)
1.14 millert 797: struct list_member *env_vars;
798: {
799: struct list_member *cur;
800:
801: if (env_vars == NULL)
1.18 millert 802: return;
1.14 millert 803:
804: /* Add user-specified environment variables. */
805: for (cur = env_vars; cur != NULL; cur = cur->next)
1.19 millert 806: putenv(cur->value);
1.14 millert 807: }
808:
809: /*
810: * Validate the list of environment variables passed in on the command
811: * line against env_delete, env_check, and env_keep.
812: * Calls log_error() if any specified variables are not allowed.
813: */
814: void
815: validate_env_vars(env_vars)
816: struct list_member *env_vars;
817: {
818: struct list_member *var;
819: char *eq, *bad = NULL;
820: size_t len, blen = 0, bsize = 0;
821: int okvar;
1.1 millert 822:
1.14 millert 823: for (var = env_vars; var != NULL; var = var->next) {
1.18 millert 824: if (def_secure_path && !user_is_exempt() &&
825: strncmp(var->value, "PATH=", 5) == 0) {
1.14 millert 826: okvar = FALSE;
1.18 millert 827: } else if (def_env_reset) {
1.14 millert 828: okvar = matches_env_check(var->value);
829: if (okvar == -1)
830: okvar = matches_env_keep(var->value);
831: } else {
832: okvar = matches_env_delete(var->value) == FALSE;
833: if (okvar == FALSE)
834: okvar = matches_env_check(var->value) != FALSE;
835: }
836: if (okvar == FALSE) {
837: /* Not allowed, add to error string, allocating as needed. */
838: if ((eq = strchr(var->value, '=')) != NULL)
839: *eq = '\0';
840: len = strlen(var->value) + 2;
841: if (blen + len >= bsize) {
842: do {
843: bsize += 1024;
844: } while (blen + len >= bsize);
845: bad = erealloc(bad, bsize);
846: bad[blen] = '\0';
847: }
848: strlcat(bad, var->value, bsize);
849: strlcat(bad, ", ", bsize);
850: blen += len;
851: if (eq != NULL)
852: *eq = '=';
853: }
854: }
855: if (bad != NULL) {
856: bad[blen - 2] = '\0'; /* remove trailing ", " */
857: log_error(NO_MAIL,
858: "sorry, you are not allowed to set the following environment variables: %s", bad);
859: /* NOTREACHED */
860: efree(bad);
861: }
1.18 millert 862: }
863:
864: /*
865: * Read in /etc/environment ala AIX and Linux.
1.21 millert 866: * Lines may be in either of three formats:
867: * NAME=VALUE
868: * NAME="VALUE"
869: * NAME='VALUE'
870: * with an optional "export" prefix so the shell can source the file.
1.18 millert 871: * Invalid lines, blank lines, or lines consisting solely of a comment
872: * character are skipped.
873: */
874: void
1.19 millert 875: read_env_file(path, overwrite)
1.18 millert 876: const char *path;
1.19 millert 877: int overwrite;
1.18 millert 878: {
879: FILE *fp;
1.21 millert 880: char *cp, *var, *val;
881: size_t var_len, val_len;
1.18 millert 882:
883: if ((fp = fopen(path, "r")) == NULL)
884: return;
885:
1.21 millert 886: while ((var = sudo_parseln(fp)) != NULL) {
1.18 millert 887: /* Skip blank or comment lines */
1.21 millert 888: if (*var == '\0')
1.18 millert 889: continue;
890:
1.21 millert 891: /* Skip optional "export " */
892: if (strncmp(var, "export", 6) == 0 && isspace((unsigned char) var[6])) {
893: var += 7;
894: while (isspace((unsigned char) *var)) {
895: var++;
896: }
897: }
898:
899: /* Must be of the form name=["']value['"] */
900: for (val = var; *val != '\0' && *val != '='; val++)
901: ;
902: if (var == val || *val != '=')
1.18 millert 903: continue;
1.21 millert 904: var_len = (size_t)(val - var);
905: val_len = strlen(++val);
906:
907: /* Strip leading and trailing single/double quotes */
908: if ((val[0] == '\'' || val[0] == '\"') && val[0] == val[val_len - 1]) {
909: val[val_len - 1] = '\0';
910: val++;
911: val_len -= 2;
912: }
913:
914: cp = emalloc(var_len + 1 + val_len + 1);
915: memcpy(cp, var, var_len + 1); /* includes '=' */
916: memcpy(cp + var_len + 1, val, val_len + 1); /* includes NUL */
1.18 millert 917:
1.21 millert 918: sudo_putenv(cp, TRUE, overwrite);
1.18 millert 919: }
920: fclose(fp);
1.1 millert 921: }
922:
923: void
924: init_envtables()
925: {
926: struct list_member *cur;
1.5 millert 927: const char **p;
1.1 millert 928:
1.14 millert 929: /* Fill in the "env_delete" list. */
1.1 millert 930: for (p = initial_badenv_table; *p; p++) {
931: cur = emalloc(sizeof(struct list_member));
932: cur->value = estrdup(*p);
1.9 millert 933: cur->next = def_env_delete;
934: def_env_delete = cur;
1.1 millert 935: }
936:
1.14 millert 937: /* Fill in the "env_check" list. */
1.1 millert 938: for (p = initial_checkenv_table; *p; p++) {
939: cur = emalloc(sizeof(struct list_member));
940: cur->value = estrdup(*p);
1.9 millert 941: cur->next = def_env_check;
942: def_env_check = cur;
1.14 millert 943: }
944:
945: /* Fill in the "env_keep" list. */
946: for (p = initial_keepenv_table; *p; p++) {
947: cur = emalloc(sizeof(struct list_member));
948: cur->value = estrdup(*p);
949: cur->next = def_env_keep;
950: def_env_keep = cur;
1.1 millert 951: }
952: }