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