version 1.13, 2005/02/06 15:56:27 |
version 1.14, 2007/07/26 16:10:16 |
|
|
/* |
/* |
* Copyright (c) 2000-2004 Todd C. Miller <Todd.Miller@courtesan.com> |
* Copyright (c) 2000-2007 Todd C. Miller <Todd.Miller@courtesan.com> |
* |
* |
* Permission to use, copy, modify, and distribute this software for any |
* Permission to use, copy, modify, and distribute this software for any |
* purpose with or without fee is hereby granted, provided that the above |
* purpose with or without fee is hereby granted, provided that the above |
|
|
* Materiel Command, USAF, under agreement number F39502-99-1-0512. |
* Materiel Command, USAF, under agreement number F39502-99-1-0512. |
*/ |
*/ |
|
|
#include "config.h" |
#include <config.h> |
|
|
#include <sys/types.h> |
#include <sys/types.h> |
#include <sys/param.h> |
#include <sys/param.h> |
|
|
#include "sudo.h" |
#include "sudo.h" |
|
|
#ifndef lint |
#ifndef lint |
static const char rcsid[] = "$Sudo: env.c,v 1.42 2004/09/08 15:57:49 millert Exp $"; |
__unused static const char rcsid[] = "$Sudo: env.c,v 1.39.2.15 2007/07/09 19:15:43 millert Exp $"; |
#endif /* lint */ |
#endif /* lint */ |
|
|
/* |
/* |
* Flags used in rebuild_env() |
* Flags used in rebuild_env() |
*/ |
*/ |
#undef DID_TERM |
#undef DID_TERM |
#define DID_TERM 0x01 |
#define DID_TERM 0x0001 |
#undef DID_PATH |
#undef DID_PATH |
#define DID_PATH 0x02 |
#define DID_PATH 0x0002 |
#undef DID_HOME |
#undef DID_HOME |
#define DID_HOME 0x04 |
#define DID_HOME 0x0004 |
#undef DID_SHELL |
#undef DID_SHELL |
#define DID_SHELL 0x08 |
#define DID_SHELL 0x0008 |
#undef DID_LOGNAME |
#undef DID_LOGNAME |
#define DID_LOGNAME 0x10 |
#define DID_LOGNAME 0x0010 |
#undef DID_USER |
#undef DID_USER |
#define DID_USER 0x20 |
#define DID_USER 0x0020 |
|
#undef DID_USERNAME |
|
#define DID_USERNAME 0x0040 |
|
#undef DID_MAX |
|
#define DID_MAX 0x00ff |
|
|
|
#undef KEPT_TERM |
|
#define KEPT_TERM 0x0100 |
|
#undef KEPT_PATH |
|
#define KEPT_PATH 0x0200 |
|
#undef KEPT_HOME |
|
#define KEPT_HOME 0x0400 |
|
#undef KEPT_SHELL |
|
#define KEPT_SHELL 0x0800 |
|
#undef KEPT_LOGNAME |
|
#define KEPT_LOGNAME 0x1000 |
|
#undef KEPT_USER |
|
#define KEPT_USER 0x2000 |
|
#undef KEPT_USERNAME |
|
#define KEPT_USERNAME 0x4000 |
|
#undef KEPT_MAX |
|
#define KEPT_MAX 0xff00 |
|
|
#undef VNULL |
#undef VNULL |
#define VNULL (VOID *)NULL |
#define VNULL (VOID *)NULL |
|
|
|
struct environment { |
|
char **envp; /* pointer to the new environment */ |
|
size_t env_size; /* size of new_environ in char **'s */ |
|
size_t env_len; /* number of slots used, not counting NULL */ |
|
}; |
|
|
/* |
/* |
* Prototypes |
* Prototypes |
*/ |
*/ |
char **rebuild_env __P((char **, int, int)); |
char **rebuild_env __P((char **, int, int)); |
char **zero_env __P((char **)); |
static void insert_env __P((char *, struct environment *, int)); |
static void insert_env __P((char *, int)); |
|
static char *format_env __P((char *, ...)); |
static char *format_env __P((char *, ...)); |
|
|
/* |
/* |
|
* Copy of the sudo-managed environment. |
|
*/ |
|
static struct environment env; |
|
|
|
/* |
* Default table of "bad" variables to remove from the environment. |
* Default table of "bad" variables to remove from the environment. |
* XXX - how to omit TERMCAP if it starts with '/'? |
* XXX - how to omit TERMCAP if it starts with '/'? |
*/ |
*/ |
|
|
"SHLIB_PATH", |
"SHLIB_PATH", |
#endif /* __hpux */ |
#endif /* __hpux */ |
#ifdef _AIX |
#ifdef _AIX |
|
"LDR_*", |
"LIBPATH", |
"LIBPATH", |
#endif /* _AIX */ |
#endif |
#ifdef __APPLE__ |
#ifdef __APPLE__ |
"DYLD_*", |
"DYLD_*", |
#endif |
#endif |
|
|
#endif /* HAVE_KERB4 */ |
#endif /* HAVE_KERB4 */ |
#ifdef HAVE_KERB5 |
#ifdef HAVE_KERB5 |
"KRB5_CONFIG*", |
"KRB5_CONFIG*", |
|
"KRB5_KTNAME", |
#endif /* HAVE_KERB5 */ |
#endif /* HAVE_KERB5 */ |
#ifdef HAVE_SECURID |
#ifdef HAVE_SECURID |
"VAR_ACE", |
"VAR_ACE", |
"USR_ACE", |
"USR_ACE", |
"DLC_ACE", |
"DLC_ACE", |
#endif /* HAVE_SECURID */ |
#endif /* HAVE_SECURID */ |
"TERMINFO", |
"TERMINFO", /* terminfo, exclusive path to terminfo files */ |
"TERMINFO_DIRS", |
"TERMINFO_DIRS", /* terminfo, path(s) to terminfo files */ |
"TERMPATH", |
"TERMPATH", /* termcap, path(s) to termcap files */ |
"TERMCAP", /* XXX - only if it starts with '/' */ |
"TERMCAP", /* XXX - only if it starts with '/' */ |
"ENV", |
"ENV", /* ksh, file to source before script runs */ |
"BASH_ENV", |
"BASH_ENV", /* bash, file to source before script runs */ |
|
"PS4", /* bash, prefix for lines in xtrace mode */ |
|
"GLOBIGNORE", /* bash, globbing patterns to ignore */ |
|
"SHELLOPTS", /* bash, extra command line options */ |
|
"JAVA_TOOL_OPTIONS", /* java, extra command line options */ |
|
"PERLIO_DEBUG ", /* perl, debugging output file */ |
|
"PERLLIB", /* perl, search path for modules/includes */ |
|
"PERL5LIB", /* perl 5, search path for modules/includes */ |
|
"PERL5OPT", /* perl 5, extra command line options */ |
|
"PERL5DB", /* perl 5, command used to load debugger */ |
|
"FPATH", /* ksh, search path for functions */ |
|
"NULLCMD", /* zsh, command for null file redirection */ |
|
"READNULLCMD", /* zsh, command for null file redirection */ |
|
"ZDOTDIR", /* zsh, search path for dot files */ |
|
"TMPPREFIX", /* zsh, prefix for temporary files */ |
|
"PYTHONHOME", /* python, module search path */ |
|
"PYTHONPATH", /* python, search path */ |
|
"PYTHONINSPEC", /* python, allow inspection */ |
|
"RUBYLIB", /* ruby, library load path */ |
|
"RUBYOPT", /* ruby, extra command line options */ |
NULL |
NULL |
}; |
}; |
|
|
|
|
* Default table of variables to check for '%' and '/' characters. |
* Default table of variables to check for '%' and '/' characters. |
*/ |
*/ |
static const char *initial_checkenv_table[] = { |
static const char *initial_checkenv_table[] = { |
"LC_*", |
"COLORTERM", |
"LANG", |
"LANG", |
"LANGUAGE", |
"LANGUAGE", |
|
"LC_*", |
|
"LINGUAS", |
|
"TERM", |
NULL |
NULL |
}; |
}; |
|
|
static char **new_environ; /* Modified copy of the environment */ |
|
static size_t env_size; /* size of new_environ in char **'s */ |
|
static size_t env_len; /* number of slots used, not counting NULL */ |
|
|
|
/* |
/* |
* Zero out environment and replace with a minimal set of KRB5CCNAME |
* Default table of variables to preserve in the environment. |
* USER, LOGNAME, HOME, TZ, PATH (XXX - should just set path to default) |
|
* May set user_path, user_shell, and/or user_prompt as side effects. |
|
*/ |
*/ |
char ** |
static const char *initial_keepenv_table[] = { |
zero_env(envp) |
"COLORS", |
char **envp; |
"DISPLAY", |
{ |
"HOSTNAME", |
static char *newenv[9]; |
"KRB5CCNAME", |
char **ep, **nep = newenv; |
"LS_COLORS", |
char **ne_last = &newenv[(sizeof(newenv) / sizeof(newenv[0])) - 1]; |
"MAIL", |
extern char *prev_user; |
"PATH", |
|
"PS1", |
|
"PS2", |
|
"TZ", |
|
"XAUTHORITY", |
|
"XAUTHORIZATION", |
|
NULL |
|
}; |
|
|
for (ep = envp; *ep; ep++) { |
|
switch (**ep) { |
|
case 'H': |
|
if (strncmp("HOME=", *ep, 5) == 0) |
|
break; |
|
continue; |
|
case 'K': |
|
if (strncmp("KRB5CCNAME=", *ep, 11) == 0) |
|
break; |
|
continue; |
|
case 'L': |
|
if (strncmp("LOGNAME=", *ep, 8) == 0) |
|
break; |
|
continue; |
|
case 'P': |
|
if (strncmp("PATH=", *ep, 5) == 0) { |
|
user_path = *ep + 5; |
|
/* XXX - set to sane default instead of user's? */ |
|
break; |
|
} |
|
continue; |
|
case 'S': |
|
if (strncmp("SHELL=", *ep, 6) == 0) |
|
user_shell = *ep + 6; |
|
else if (!user_prompt && strncmp("SUDO_PROMPT=", *ep, 12) == 0) |
|
user_prompt = *ep + 12; |
|
else if (strncmp("SUDO_USER=", *ep, 10) == 0) |
|
prev_user = *ep + 10; |
|
continue; |
|
case 'T': |
|
if (strncmp("TZ=", *ep, 3) == 0) |
|
break; |
|
continue; |
|
case 'U': |
|
if (strncmp("USER=", *ep, 5) == 0) |
|
break; |
|
continue; |
|
default: |
|
continue; |
|
} |
|
|
|
/* Deal with multiply defined variables (take first instance) */ |
|
for (nep = newenv; *nep; nep++) { |
|
if (**nep == **ep) |
|
break; |
|
} |
|
if (*nep == NULL) { |
|
if (nep < ne_last) |
|
*nep++ = *ep; |
|
else |
|
errx(1, "internal error, attempt to write outside newenv"); |
|
} |
|
} |
|
|
|
#ifdef HAVE_LDAP |
|
/* |
|
* Prevent OpenLDAP from reading any user dotfiles |
|
* or files in the current directory. |
|
* |
|
*/ |
|
if (nep < ne_last) |
|
*nep++ = "LDAPNOINIT=1"; |
|
else |
|
errx(1, "internal error, attempt to write outside newenv"); |
|
#endif |
|
|
|
return(&newenv[0]); |
|
} |
|
|
|
/* |
/* |
* Given a variable and value, allocate and format an environment string. |
* Given a variable and value, allocate and format an environment string. |
*/ |
*/ |
|
|
} |
} |
|
|
/* |
/* |
* Insert str into new_environ, assumes str has an '=' in it. |
* Insert str into e->envp, assumes str has an '=' in it. |
* NOTE: no other routines may modify new_environ, env_size, or env_len. |
|
*/ |
*/ |
static void |
static void |
insert_env(str, dupcheck) |
insert_env(str, e, dupcheck) |
char *str; |
char *str; |
|
struct environment *e; |
int dupcheck; |
int dupcheck; |
{ |
{ |
char **nep; |
char **nep; |
size_t varlen; |
size_t varlen; |
|
|
/* Make sure there is room for the new entry plus a NULL. */ |
/* Make sure there is room for the new entry plus a NULL. */ |
if (env_len + 2 > env_size) { |
if (e->env_len + 2 > e->env_size) { |
env_size += 128; |
e->env_size += 128; |
new_environ = erealloc3(new_environ, env_size, sizeof(char *)); |
e->envp = erealloc3(e->envp, e->env_size, sizeof(char *)); |
} |
} |
|
|
if (dupcheck) { |
if (dupcheck) { |
varlen = (strchr(str, '=') - str) + 1; |
varlen = (strchr(str, '=') - str) + 1; |
|
|
for (nep = new_environ; *nep; nep++) { |
for (nep = e->envp; *nep; nep++) { |
if (strncmp(str, *nep, varlen) == 0) { |
if (strncmp(str, *nep, varlen) == 0) { |
*nep = str; |
*nep = str; |
return; |
return; |
} |
} |
} |
} |
} else |
} else |
nep = &new_environ[env_len]; |
nep = e->envp + e->env_len; |
|
|
env_len++; |
e->env_len++; |
*nep++ = str; |
*nep++ = str; |
*nep = NULL; |
*nep = NULL; |
} |
} |
|
|
/* |
/* |
|
* Check the env_delete blacklist. |
|
* Returns TRUE if the variable was found, else false. |
|
*/ |
|
static int |
|
matches_env_delete(var) |
|
const char *var; |
|
{ |
|
struct list_member *cur; |
|
size_t len; |
|
int iswild, match = FALSE; |
|
|
|
/* Skip anything listed in env_delete. */ |
|
for (cur = def_env_delete; cur; cur = cur->next) { |
|
len = strlen(cur->value); |
|
/* Deal with '*' wildcard */ |
|
if (cur->value[len - 1] == '*') { |
|
len--; |
|
iswild = TRUE; |
|
} else |
|
iswild = FALSE; |
|
if (strncmp(cur->value, var, len) == 0 && |
|
(iswild || var[len] == '=')) { |
|
match = TRUE; |
|
break; |
|
} |
|
} |
|
return(match); |
|
} |
|
|
|
/* |
|
* Apply the env_check list. |
|
* Returns TRUE if the variable is allowed, FALSE if denied |
|
* or -1 if no match. |
|
*/ |
|
static int |
|
matches_env_check(var) |
|
const char *var; |
|
{ |
|
struct list_member *cur; |
|
size_t len; |
|
int iswild, keepit = -1; |
|
|
|
for (cur = def_env_check; cur; cur = cur->next) { |
|
len = strlen(cur->value); |
|
/* Deal with '*' wildcard */ |
|
if (cur->value[len - 1] == '*') { |
|
len--; |
|
iswild = TRUE; |
|
} else |
|
iswild = FALSE; |
|
if (strncmp(cur->value, var, len) == 0 && |
|
(iswild || var[len] == '=')) { |
|
keepit = !strpbrk(var, "/%"); |
|
break; |
|
} |
|
} |
|
return(keepit); |
|
} |
|
|
|
/* |
|
* Check the env_keep list. |
|
* Returns TRUE if the variable is allowed else FALSE. |
|
*/ |
|
static int |
|
matches_env_keep(var) |
|
const char *var; |
|
{ |
|
struct list_member *cur; |
|
size_t len; |
|
int iswild, keepit = FALSE; |
|
|
|
for (cur = def_env_keep; cur; cur = cur->next) { |
|
len = strlen(cur->value); |
|
/* Deal with '*' wildcard */ |
|
if (cur->value[len - 1] == '*') { |
|
len--; |
|
iswild = TRUE; |
|
} else |
|
iswild = FALSE; |
|
if (strncmp(cur->value, var, len) == 0 && |
|
(iswild || var[len] == '=')) { |
|
keepit = TRUE; |
|
break; |
|
} |
|
} |
|
return(keepit); |
|
} |
|
|
|
/* |
* Build a new environment and ether clear potentially dangerous |
* Build a new environment and ether clear potentially dangerous |
* variables from the old one or start with a clean slate. |
* variables from the old one or start with a clean slate. |
* Also adds sudo-specific variables (SUDO_*). |
* Also adds sudo-specific variables (SUDO_*). |
|
|
int noexec; |
int noexec; |
{ |
{ |
char **ep, *cp, *ps1; |
char **ep, *cp, *ps1; |
int okvar, iswild, didvar; |
unsigned int didvar; |
size_t len; |
|
struct list_member *cur; |
|
|
|
/* |
/* |
* Either clean out the environment or reset to a safe default. |
* Either clean out the environment or reset to a safe default. |
*/ |
*/ |
ps1 = NULL; |
ps1 = NULL; |
didvar = 0; |
didvar = 0; |
|
memset(&env, 0, sizeof(env)); |
if (def_env_reset) { |
if (def_env_reset) { |
int keepit; |
|
|
|
/* Pull in vars we want to keep from the old environment. */ |
/* Pull in vars we want to keep from the old environment. */ |
for (ep = envp; *ep; ep++) { |
for (ep = envp; *ep; ep++) { |
keepit = 0; |
int keepit; |
|
|
/* Skip variables with values beginning with () (bash functions) */ |
/* Skip variables with values beginning with () (bash functions) */ |
if ((cp = strchr(*ep, '=')) != NULL) { |
if ((cp = strchr(*ep, '=')) != NULL) { |
|
|
continue; |
continue; |
} |
} |
|
|
for (cur = def_env_keep; cur; cur = cur->next) { |
/* |
len = strlen(cur->value); |
* First check certain variables for '%' and '/' characters. |
/* Deal with '*' wildcard */ |
* If no match there, check the keep list. |
if (cur->value[len - 1] == '*') { |
* If nothing matched, we remove it from the environment. |
len--; |
*/ |
iswild = 1; |
keepit = matches_env_check(*ep); |
} else |
if (keepit == -1) |
iswild = 0; |
keepit = matches_env_keep(*ep); |
if (strncmp(cur->value, *ep, len) == 0 && |
|
(iswild || (*ep)[len] == '=')) { |
|
/* We always preserve TERM, no special treatment needed. */ |
|
if (strncmp(*ep, "TERM=", 5) != 0) |
|
keepit = 1; |
|
break; |
|
} |
|
} |
|
|
|
/* For SUDO_PS1 -> PS1 conversion. */ |
/* For SUDO_PS1 -> PS1 conversion. */ |
if (strncmp(*ep, "SUDO_PS1=", 8) == 0) |
if (strncmp(*ep, "SUDO_PS1=", 8) == 0) |
|
|
if (strncmp(*ep, "HOME=", 5) == 0) |
if (strncmp(*ep, "HOME=", 5) == 0) |
SET(didvar, DID_HOME); |
SET(didvar, DID_HOME); |
break; |
break; |
|
case 'L': |
|
if (strncmp(*ep, "LOGNAME=", 8) == 0) |
|
SET(didvar, DID_LOGNAME); |
|
break; |
|
case 'P': |
|
if (strncmp(*ep, "PATH=", 5) == 0) |
|
SET(didvar, DID_PATH); |
|
break; |
case 'S': |
case 'S': |
if (strncmp(*ep, "SHELL=", 6) == 0) |
if (strncmp(*ep, "SHELL=", 6) == 0) |
SET(didvar, DID_SHELL); |
SET(didvar, DID_SHELL); |
break; |
break; |
case 'L': |
case 'T': |
if (strncmp(*ep, "LOGNAME=", 8) == 0) |
if (strncmp(*ep, "TERM=", 5) == 0) |
SET(didvar, DID_LOGNAME); |
SET(didvar, DID_TERM); |
break; |
break; |
case 'U': |
case 'U': |
if (strncmp(*ep, "USER=", 5) == 0) |
if (strncmp(*ep, "USER=", 5) == 0) |
SET(didvar, DID_USER); |
SET(didvar, DID_USER); |
|
if (strncmp(*ep, "USERNAME=", 5) == 0) |
|
SET(didvar, DID_USERNAME); |
break; |
break; |
} |
} |
insert_env(*ep, 0); |
insert_env(*ep, &env, 0); |
} else { |
|
/* Preserve TERM and PATH, ignore anything else. */ |
|
if (!ISSET(didvar, DID_TERM) && strncmp(*ep, "TERM=", 5) == 0) { |
|
insert_env(*ep, 0); |
|
SET(didvar, DID_TERM); |
|
} else if (!ISSET(didvar, DID_PATH) && strncmp(*ep, "PATH=", 5) == 0) { |
|
insert_env(*ep, 0); |
|
SET(didvar, DID_PATH); |
|
} |
|
} |
} |
} |
} |
|
didvar |= didvar << 8; /* convert DID_* to KEPT_* */ |
|
|
/* |
/* |
* Add in defaults. In -i mode these come from the runas user, |
* Add in defaults. In -i mode these come from the runas user, |
|
|
* on sudoers options). |
* on sudoers options). |
*/ |
*/ |
if (ISSET(sudo_mode, MODE_LOGIN_SHELL)) { |
if (ISSET(sudo_mode, MODE_LOGIN_SHELL)) { |
insert_env(format_env("HOME", runas_pw->pw_dir, VNULL), 0); |
insert_env(format_env("HOME", runas_pw->pw_dir, VNULL), &env, |
insert_env(format_env("SHELL", runas_pw->pw_shell, VNULL), 0); |
ISSET(didvar, DID_HOME)); |
insert_env(format_env("LOGNAME", runas_pw->pw_name, VNULL), 0); |
insert_env(format_env("SHELL", runas_pw->pw_shell, VNULL), &env, |
insert_env(format_env("USER", runas_pw->pw_name, VNULL), 0); |
ISSET(didvar, DID_SHELL)); |
|
insert_env(format_env("LOGNAME", runas_pw->pw_name, VNULL), &env, |
|
ISSET(didvar, DID_LOGNAME)); |
|
insert_env(format_env("USER", runas_pw->pw_name, VNULL), &env, |
|
ISSET(didvar, DID_USER)); |
|
insert_env(format_env("USERNAME", runas_pw->pw_name, VNULL), &env, |
|
ISSET(didvar, DID_USERNAME)); |
} else { |
} else { |
if (!ISSET(didvar, DID_HOME)) |
if (!ISSET(didvar, DID_HOME)) |
insert_env(format_env("HOME", user_dir, VNULL), 0); |
insert_env(format_env("HOME", user_dir, VNULL), &env, 0); |
if (!ISSET(didvar, DID_SHELL)) |
if (!ISSET(didvar, DID_SHELL)) |
insert_env(format_env("SHELL", sudo_user.pw->pw_shell, VNULL), 0); |
insert_env(format_env("SHELL", sudo_user.pw->pw_shell, VNULL), |
|
&env, 0); |
if (!ISSET(didvar, DID_LOGNAME)) |
if (!ISSET(didvar, DID_LOGNAME)) |
insert_env(format_env("LOGNAME", user_name, VNULL), 0); |
insert_env(format_env("LOGNAME", user_name, VNULL), &env, 0); |
if (!ISSET(didvar, DID_USER)) |
if (!ISSET(didvar, DID_USER)) |
insert_env(format_env("USER", user_name, VNULL), 0); |
insert_env(format_env("USER", user_name, VNULL), &env, 0); |
|
if (!ISSET(didvar, DID_USERNAME)) |
|
insert_env(format_env("USERNAME", user_name, VNULL), &env, 0); |
} |
} |
} else { |
} else { |
/* |
/* |
|
|
* env_check. |
* env_check. |
*/ |
*/ |
for (ep = envp; *ep; ep++) { |
for (ep = envp; *ep; ep++) { |
okvar = 1; |
int okvar; |
|
|
/* Skip variables with values beginning with () (bash functions) */ |
/* Skip variables with values beginning with () (bash functions) */ |
if ((cp = strchr(*ep, '=')) != NULL) { |
if ((cp = strchr(*ep, '=')) != NULL) { |
|
|
continue; |
continue; |
} |
} |
|
|
/* Skip anything listed in env_delete. */ |
/* |
for (cur = def_env_delete; cur && okvar; cur = cur->next) { |
* First check variables against the blacklist in env_delete. |
len = strlen(cur->value); |
* If no match there check for '%' and '/' characters. |
/* Deal with '*' wildcard */ |
*/ |
if (cur->value[len - 1] == '*') { |
okvar = matches_env_delete(*ep) != TRUE; |
len--; |
if (okvar) |
iswild = 1; |
okvar = matches_env_check(*ep) != FALSE; |
} else |
|
iswild = 0; |
|
if (strncmp(cur->value, *ep, len) == 0 && |
|
(iswild || (*ep)[len] == '=')) { |
|
okvar = 0; |
|
} |
|
} |
|
|
|
/* Check certain variables for '%' and '/' characters. */ |
|
for (cur = def_env_check; cur && okvar; cur = cur->next) { |
|
len = strlen(cur->value); |
|
/* Deal with '*' wildcard */ |
|
if (cur->value[len - 1] == '*') { |
|
len--; |
|
iswild = 1; |
|
} else |
|
iswild = 0; |
|
if (strncmp(cur->value, *ep, len) == 0 && |
|
(iswild || (*ep)[len] == '=') && |
|
strpbrk(*ep, "/%")) { |
|
okvar = 0; |
|
} |
|
} |
|
|
|
if (okvar) { |
if (okvar) { |
if (strncmp(*ep, "SUDO_PS1=", 9) == 0) |
if (strncmp(*ep, "SUDO_PS1=", 9) == 0) |
ps1 = *ep + 5; |
ps1 = *ep + 5; |
|
|
SET(didvar, DID_PATH); |
SET(didvar, DID_PATH); |
else if (strncmp(*ep, "TERM=", 5) == 0) |
else if (strncmp(*ep, "TERM=", 5) == 0) |
SET(didvar, DID_TERM); |
SET(didvar, DID_TERM); |
insert_env(*ep, 0); |
insert_env(*ep, &env, 0); |
} |
} |
} |
} |
} |
} |
/* Provide default values for $TERM and $PATH if they are not set. */ |
|
if (!ISSET(didvar, DID_TERM)) |
|
insert_env("TERM=unknown", 0); |
|
if (!ISSET(didvar, DID_PATH)) |
|
insert_env(format_env("PATH", _PATH_DEFPATH, VNULL), 0); |
|
|
|
#ifdef SECURE_PATH |
#ifdef SECURE_PATH |
/* Replace the PATH envariable with a secure one. */ |
/* Replace the PATH envariable with a secure one. */ |
insert_env(format_env("PATH", SECURE_PATH, VNULL), 1); |
if (!user_is_exempt()) { |
|
insert_env(format_env("PATH", SECURE_PATH, VNULL), &env, 1); |
|
SET(didvar, DID_PATH); |
|
} |
#endif |
#endif |
|
|
/* Set $USER and $LOGNAME to target if "set_logname" is true. */ |
/* Set $USER, $LOGNAME and $USERNAME to target if "set_logname" is true. */ |
if (def_set_logname && runas_pw->pw_name) { |
if (def_set_logname && runas_pw->pw_name) { |
insert_env(format_env("LOGNAME", runas_pw->pw_name, VNULL), 1); |
if (!ISSET(didvar, KEPT_LOGNAME)) |
insert_env(format_env("USER", runas_pw->pw_name, VNULL), 1); |
insert_env(format_env("LOGNAME", runas_pw->pw_name, VNULL), &env, 1); |
|
if (!ISSET(didvar, KEPT_USER)) |
|
insert_env(format_env("USER", runas_pw->pw_name, VNULL), &env, 1); |
|
if (!ISSET(didvar, KEPT_USERNAME)) |
|
insert_env(format_env("USERNAME", runas_pw->pw_name, VNULL), &env, 1); |
} |
} |
|
|
/* Set $HOME for `sudo -H'. Only valid at PERM_FULL_RUNAS. */ |
/* Set $HOME for `sudo -H'. Only valid at PERM_FULL_RUNAS. */ |
if (ISSET(sudo_mode, MODE_RESET_HOME) && runas_pw->pw_dir) |
if (runas_pw->pw_dir) { |
insert_env(format_env("HOME", runas_pw->pw_dir, VNULL), 1); |
if (ISSET(sudo_mode, MODE_RESET_HOME) || |
|
(ISSET(sudo_mode, MODE_RUN) && (def_always_set_home || |
|
(ISSET(sudo_mode, MODE_SHELL) && def_set_home)))) |
|
insert_env(format_env("HOME", runas_pw->pw_dir, VNULL), &env, 1); |
|
} |
|
|
|
/* Provide default values for $TERM and $PATH if they are not set. */ |
|
if (!ISSET(didvar, DID_TERM)) |
|
insert_env("TERM=unknown", &env, 0); |
|
if (!ISSET(didvar, DID_PATH)) |
|
insert_env(format_env("PATH", _PATH_DEFPATH, VNULL), &env, 0); |
|
|
/* |
/* |
* Preload a noexec file? For a list of LD_PRELOAD-alikes, see |
* Preload a noexec file? For a list of LD_PRELOAD-alikes, see |
* http://www.fortran-2000.com/ArnaudRecipes/sharedlib.html |
* http://www.fortran-2000.com/ArnaudRecipes/sharedlib.html |
|
|
*/ |
*/ |
if (noexec && def_noexec_file != NULL) { |
if (noexec && def_noexec_file != NULL) { |
#if defined(__darwin__) || defined(__APPLE__) |
#if defined(__darwin__) || defined(__APPLE__) |
insert_env(format_env("DYLD_INSERT_LIBRARIES", def_noexec_file, VNULL), 1); |
insert_env(format_env("DYLD_INSERT_LIBRARIES", def_noexec_file, VNULL), |
insert_env(format_env("DYLD_FORCE_FLAT_NAMESPACE", VNULL), 1); |
&env, 1); |
|
insert_env(format_env("DYLD_FORCE_FLAT_NAMESPACE", VNULL), &env, 1); |
#else |
#else |
# if defined(__osf__) || defined(__sgi) |
# if defined(__osf__) || defined(__sgi) |
insert_env(format_env("_RLD_LIST", def_noexec_file, ":DEFAULT", VNULL), 1); |
insert_env(format_env("_RLD_LIST", def_noexec_file, ":DEFAULT", VNULL), |
|
&env, 1); |
# else |
# else |
insert_env(format_env("LD_PRELOAD", def_noexec_file, VNULL), 1); |
# ifdef _AIX |
# endif |
insert_env(format_env("LDR_PRELOAD", def_noexec_file, VNULL), &env, 1); |
#endif |
# else |
|
insert_env(format_env("LD_PRELOAD", def_noexec_file, VNULL), &env, 1); |
|
# endif /* _AIX */ |
|
# endif /* __osf__ || __sgi */ |
|
#endif /* __darwin__ || __APPLE__ */ |
} |
} |
|
|
/* Set PS1 if SUDO_PS1 is set. */ |
/* Set PS1 if SUDO_PS1 is set. */ |
if (ps1) |
if (ps1) |
insert_env(ps1, 1); |
insert_env(ps1, &env, 1); |
|
|
/* Add the SUDO_COMMAND envariable (cmnd + args). */ |
/* Add the SUDO_COMMAND envariable (cmnd + args). */ |
if (user_args) |
if (user_args) |
insert_env(format_env("SUDO_COMMAND", user_cmnd, " ", user_args, VNULL), 1); |
insert_env(format_env("SUDO_COMMAND", user_cmnd, " ", user_args, VNULL), |
|
&env, 1); |
else |
else |
insert_env(format_env("SUDO_COMMAND", user_cmnd, VNULL), 1); |
insert_env(format_env("SUDO_COMMAND", user_cmnd, VNULL), &env, 1); |
|
|
/* Add the SUDO_USER, SUDO_UID, SUDO_GID environment variables. */ |
/* Add the SUDO_USER, SUDO_UID, SUDO_GID environment variables. */ |
insert_env(format_env("SUDO_USER", user_name, VNULL), 1); |
insert_env(format_env("SUDO_USER", user_name, VNULL), &env, 1); |
easprintf(&cp, "SUDO_UID=%lu", (unsigned long) user_uid); |
easprintf(&cp, "SUDO_UID=%lu", (unsigned long) user_uid); |
insert_env(cp, 1); |
insert_env(cp, &env, 1); |
easprintf(&cp, "SUDO_GID=%lu", (unsigned long) user_gid); |
easprintf(&cp, "SUDO_GID=%lu", (unsigned long) user_gid); |
insert_env(cp, 1); |
insert_env(cp, &env, 1); |
|
|
return(new_environ); |
return(env.envp); |
} |
} |
|
|
|
char ** |
|
insert_env_vars(envp, env_vars) |
|
char **envp; |
|
struct list_member *env_vars; |
|
{ |
|
struct list_member *cur; |
|
|
|
if (env_vars == NULL) |
|
return (envp); |
|
|
|
/* |
|
* Make sure we still own the environment and steal it back if not. |
|
*/ |
|
if (env.envp != envp) { |
|
size_t evlen; |
|
char **ep; |
|
|
|
for (ep = envp; *ep != NULL; ep++) |
|
continue; |
|
evlen = ep - envp; |
|
if (evlen + 1 > env.env_size) { |
|
efree(env.envp); |
|
env.env_size = evlen + 1 + 128; |
|
env.envp = emalloc2(env.env_size, sizeof(char *)); |
|
} |
|
memcpy(env.envp, envp, evlen + 1); |
|
env.env_len = evlen; |
|
} |
|
|
|
/* Add user-specified environment variables. */ |
|
for (cur = env_vars; cur != NULL; cur = cur->next) |
|
insert_env(cur->value, &env, 1); |
|
|
|
return(env.envp); |
|
} |
|
|
|
/* |
|
* Validate the list of environment variables passed in on the command |
|
* line against env_delete, env_check, and env_keep. |
|
* Calls log_error() if any specified variables are not allowed. |
|
*/ |
void |
void |
|
validate_env_vars(env_vars) |
|
struct list_member *env_vars; |
|
{ |
|
struct list_member *var; |
|
char *eq, *bad = NULL; |
|
size_t len, blen = 0, bsize = 0; |
|
int okvar; |
|
|
|
for (var = env_vars; var != NULL; var = var->next) { |
|
#ifdef SECURE_PATH |
|
if (!user_is_exempt() && strncmp(var->value, "PATH=", 5) == 0) { |
|
okvar = FALSE; |
|
} else |
|
#endif |
|
if (def_env_reset) { |
|
okvar = matches_env_check(var->value); |
|
if (okvar == -1) |
|
okvar = matches_env_keep(var->value); |
|
} else { |
|
okvar = matches_env_delete(var->value) == FALSE; |
|
if (okvar == FALSE) |
|
okvar = matches_env_check(var->value) != FALSE; |
|
} |
|
if (okvar == FALSE) { |
|
/* Not allowed, add to error string, allocating as needed. */ |
|
if ((eq = strchr(var->value, '=')) != NULL) |
|
*eq = '\0'; |
|
len = strlen(var->value) + 2; |
|
if (blen + len >= bsize) { |
|
do { |
|
bsize += 1024; |
|
} while (blen + len >= bsize); |
|
bad = erealloc(bad, bsize); |
|
bad[blen] = '\0'; |
|
} |
|
strlcat(bad, var->value, bsize); |
|
strlcat(bad, ", ", bsize); |
|
blen += len; |
|
if (eq != NULL) |
|
*eq = '='; |
|
} |
|
} |
|
if (bad != NULL) { |
|
bad[blen - 2] = '\0'; /* remove trailing ", " */ |
|
log_error(NO_MAIL, |
|
"sorry, you are not allowed to set the following environment variables: %s", bad); |
|
/* NOTREACHED */ |
|
efree(bad); |
|
} |
|
} |
|
|
|
void |
init_envtables() |
init_envtables() |
{ |
{ |
struct list_member *cur; |
struct list_member *cur; |
const char **p; |
const char **p; |
|
|
/* Fill in "env_delete" variable. */ |
/* Fill in the "env_delete" list. */ |
for (p = initial_badenv_table; *p; p++) { |
for (p = initial_badenv_table; *p; p++) { |
cur = emalloc(sizeof(struct list_member)); |
cur = emalloc(sizeof(struct list_member)); |
cur->value = estrdup(*p); |
cur->value = estrdup(*p); |
|
|
def_env_delete = cur; |
def_env_delete = cur; |
} |
} |
|
|
/* Fill in "env_check" variable. */ |
/* Fill in the "env_check" list. */ |
for (p = initial_checkenv_table; *p; p++) { |
for (p = initial_checkenv_table; *p; p++) { |
cur = emalloc(sizeof(struct list_member)); |
cur = emalloc(sizeof(struct list_member)); |
cur->value = estrdup(*p); |
cur->value = estrdup(*p); |
cur->next = def_env_check; |
cur->next = def_env_check; |
def_env_check = cur; |
def_env_check = cur; |
|
} |
|
|
|
/* Fill in the "env_keep" list. */ |
|
for (p = initial_keepenv_table; *p; p++) { |
|
cur = emalloc(sizeof(struct list_member)); |
|
cur->value = estrdup(*p); |
|
cur->next = def_env_keep; |
|
def_env_keep = cur; |
} |
} |
} |
} |