]> git.ipfire.org Git - thirdparty/util-linux.git/blobdiff - lib/env.c
Merge branch 'pager/less-quirk' of https://github.com/t-8ch/util-linux
[thirdparty/util-linux.git] / lib / env.c
index c79e0e0de04b170664b9ecbe826d17e57f6e84a6..2bdfe5697e900fdf0273ee83125ff60e2cb39918 100644 (file)
--- a/lib/env.c
+++ b/lib/env.c
@@ -1,10 +1,9 @@
 /*
- * Security checks of environment
- * Added from shadow-utils package
- * by Arkadiusz Miƛkiewicz <misiek@pld.ORG.PL>
+ * environ[] array cleanup code and getenv() wrappers
  *
+ * No copyright is claimed.  This code is in the public domain; do with
+ * it what you wish.
  */
-
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <sys/types.h>
 
 #include "env.h"
+#include "all-io.h"
 
 #ifndef HAVE_ENVIRON_DECL
 extern char **environ;
 #endif
 
 static char * const forbid[] = {
-        "_RLD_=",
         "BASH_ENV=",    /* GNU creeping featurism strikes again... */
         "ENV=",
         "HOME=",
@@ -51,19 +50,116 @@ static char * const noslash[] = {
         (char *) 0
 };
 
-void
-sanitize_env(void)
+
+struct ul_env_list {
+       char *env;
+       struct ul_env_list *next;
+};
+
+/*
+ * Saves @name env.variable 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);
+       if (!p)
+               return ls0;
+
+       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 env_from_fd() to read environment from @fd.
+ *
+ * @fd must be /proc/<pid>/environ file.
+*/
+struct ul_env_list *env_from_fd(int fd)
+{
+       char *buf = NULL, *p;
+       ssize_t rc = 0;
+       struct ul_env_list *ls = NULL;
+
+       if ((rc = read_all_alloc(fd, &buf)) < 1)
+               return NULL;
+       buf[rc] = '\0';
+       p = buf;
+
+       while (rc > 0) {
+               ls = env_list_add(ls, p);
+               p += strlen(p) + 1;
+               rc -= strlen(p) + 1;
+       }
+
+       free(buf);
+       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 @org is not NULL than stores
+ * unwnated variables to the list.
+ */
+void __sanitize_env(struct ul_env_list **org)
 {
         char **envp = environ;
         char * const *bad;
         char **cur;
-        char **move;
+        int last = 0;
+
+        for (cur = envp; *cur; cur++)
+                last++;
 
         for (cur = envp; *cur; cur++) {
                 for (bad = forbid; *bad; bad++) {
                         if (strncmp(*cur, *bad, strlen(*bad)) == 0) {
-                                for (move = cur; *move; move++)
-                                        *move = *(move + 1);
+                               if (org)
+                                       *org = env_list_add(*org, *cur);
+                                last = remove_entry(envp, cur - envp, last);
                                 cur--;
                                 break;
                         }
@@ -76,20 +172,23 @@ sanitize_env(void)
                                 continue;
                         if (!strchr(*cur, '/'))
                                 continue;  /* OK */
-                        for (move = cur; *move; move++)
-                                *move = *(move + 1);
+                       if (org)
+                               *org = env_list_add(*org, *cur);
+                        last = remove_entry(envp, cur - envp, last);
                         cur--;
                         break;
                 }
         }
 }
 
+void sanitize_env(void)
+{
+       __sanitize_env(NULL);
+}
 
 char *safe_getenv(const char *arg)
 {
-       uid_t ruid = getuid();
-
-       if (ruid != 0 || (ruid != geteuid()) || (getgid() != getegid()))
+       if ((getuid() != geteuid()) || (getgid() != getegid()))
                return NULL;
 #ifdef HAVE_PRCTL
        if (prctl(PR_GET_DUMPABLE, 0, 0, 0, 0) == 0)
@@ -108,3 +207,58 @@ return secure_getenv(arg);
        return getenv(arg);
 #endif
 }
+
+#ifdef TEST_PROGRAM
+int main(void)
+{
+       char *const *bad;
+       char copy[32];
+       char *p;
+       int retval = EXIT_SUCCESS;
+       struct ul_env_list *removed = NULL;
+
+       for (bad = forbid; *bad; bad++) {
+               strcpy(copy, *bad);
+               p = strchr(copy, '=');
+               if (p)
+                       *p = '\0';
+               setenv(copy, copy, 1);
+       }
+
+       /* removed */
+       __sanitize_env(&removed);
+
+       /* check removal */
+       for (bad = forbid; *bad; bad++) {
+               strcpy(copy, *bad);
+               p = strchr(copy, '=');
+               if (p)
+                       *p = '\0';
+               p = getenv(copy);
+               if (p) {
+                       warnx("%s was not removed", copy);
+                       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