lib/env: add function to save and restore unwanted variables

Signed-off-by: Karel Zak <kzak@redhat.com>
This commit is contained in:
Karel Zak 2020-08-25 10:43:07 +02:00
parent 80a54e2b3e
commit e113093ce9
2 changed files with 107 additions and 3 deletions

View File

@ -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);

103
lib/env.c
View File

@ -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