aboutsummaryrefslogtreecommitdiffstats
path: root/lib/env.c
diff options
context:
space:
mode:
authorKarel Zak <kzak@redhat.com>2020-08-25 10:43:07 +0200
committerKarel Zak <kzak@redhat.com>2020-08-25 10:43:07 +0200
commite113093ce94ac1145f9986e072746e8b6e8d0da9 (patch)
treec2264850ae9aa49b04dbfe8dd048f0dcfb601495 /lib/env.c
parent80a54e2b3e4ddfb89e4cdfbedc659c6fc5c9e598 (diff)
downloadutil-linux-e113093ce94ac1145f9986e072746e8b6e8d0da9.tar.gz
lib/env: add function to save and restore unwanted variables
Signed-off-by: Karel Zak <kzak@redhat.com>
Diffstat (limited to 'lib/env.c')
-rw-r--r--lib/env.c103
1 files changed, 100 insertions, 3 deletions
diff --git a/lib/env.c b/lib/env.c
index 301b332b47..c26a5be3a4 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