diff --git a/include/env.h b/include/env.h index 6cee8e698..c2caecbaa 100644 --- a/include/env.h +++ b/include/env.h @@ -4,7 +4,14 @@ #include "c.h" #include "nls.h" +struct ul_env_list; + extern void sanitize_env(void); +extern void __sanitize_env(struct ul_env_list **org); + +extern int env_list_setenv(struct ul_env_list *ls); +extern void env_list_free(struct ul_env_list *ls); + extern char *safe_getenv(const char *arg); diff --git a/lib/env.c b/lib/env.c index 301b332b4..c26a5be3a 100644 --- a/lib/env.c +++ b/lib/env.c @@ -50,8 +50,73 @@ static char * const noslash[] = { (char *) 0 }; -void -sanitize_env(void) + +struct ul_env_list { + char *env; + struct ul_env_list *next; +}; + +/* + * Saves @name env.varable to @ls, returns pointer to the new head of the list. + */ +static struct ul_env_list *env_list_add(struct ul_env_list *ls0, const char *str) +{ + struct ul_env_list *ls; + char *p; + size_t sz = 0; + + if (!str || !*str) + return ls0; + + sz = strlen(str) + 1; + p = malloc(sizeof(struct ul_env_list) + sz); + + ls = (struct ul_env_list *) p; + p += sizeof(struct ul_env_list); + memcpy(p, str, sz); + ls->env = p; + + ls->next = ls0; + return ls; +} + +/* + * Use setenv() for all stuff in @ls. + * + * It would be possible to use putenv(), but we want to keep @ls free()-able. + */ +int env_list_setenv(struct ul_env_list *ls) +{ + int rc = 0; + + while (ls && rc == 0) { + if (ls->env) { + char *val = strchr(ls->env, '='); + if (!val) + continue; + *val = '\0'; + rc = setenv(ls->env, val + 1, 0); + *val = '='; + } + ls = ls->next; + } + return rc; +} + +void env_list_free(struct ul_env_list *ls) +{ + while (ls) { + struct ul_env_list *x = ls; + ls = ls->next; + free(x); + } +} + +/* + * Removes unwanted variables from environ[]. If @ls is not NULL than stores + * unwnated variables to the list. + */ +void __sanitize_env(struct ul_env_list **org) { char **envp = environ; char * const *bad; @@ -64,6 +129,8 @@ sanitize_env(void) for (cur = envp; *cur; cur++) { for (bad = forbid; *bad; bad++) { if (strncmp(*cur, *bad, strlen(*bad)) == 0) { + if (org) + *org = env_list_add(*org, *cur); last = remote_entry(envp, cur - envp, last); cur--; break; @@ -77,6 +144,8 @@ sanitize_env(void) continue; if (!strchr(*cur, '/')) continue; /* OK */ + if (org) + *org = env_list_add(*org, *cur); last = remote_entry(envp, cur - envp, last); cur--; break; @@ -84,6 +153,10 @@ sanitize_env(void) } } +void sanitize_env(void) +{ + __sanitize_env(NULL); +} char *safe_getenv(const char *arg) { @@ -116,6 +189,7 @@ int main(void) char copy[32]; char *p; int retval = EXIT_SUCCESS; + struct ul_env_list *removed = NULL; for (bad = forbid; *bad; bad++) { strcpy(copy, *bad); @@ -124,7 +198,11 @@ int main(void) *p = '\0'; setenv(copy, copy, 1); } - sanitize_env(); + + /* removed */ + __sanitize_env(&removed); + + /* check removal */ for (bad = forbid; *bad; bad++) { strcpy(copy, *bad); p = strchr(copy, '='); @@ -136,6 +214,25 @@ int main(void) retval = EXIT_FAILURE; } } + + /* restore removed */ + env_list_setenv(removed); + + /* check restore */ + for (bad = forbid; *bad; bad++) { + strcpy(copy, *bad); + p = strchr(copy, '='); + if (p) + *p = '\0'; + p = getenv(copy); + if (!p) { + warnx("%s was not restored", copy); + retval = EXIT_FAILURE; + } + } + + env_list_free(removed); + return retval; } #endif