]> git.armaanb.net Git - opendoas.git/blobdiff - env.c
timestamp: error out if fstat and lstat st_ino and st_dev are not the same
[opendoas.git] / env.c
diff --git a/env.c b/env.c
index cf51e674788806db4f41f4d403c073fb805b0561..3e8b95d44c7c5c67096f3438278fc0fa4f26982c 100644 (file)
--- a/env.c
+++ b/env.c
@@ -16,6 +16,7 @@
  */
 
 #include <sys/types.h>
+#include "sys-tree.h"
 
 #include <string.h>
 #include <stdio.h>
 #include <errno.h>
 
 #include "doas.h"
+#include "includes.h"
 
-int
+struct envnode {
+       RB_ENTRY(envnode) node;
+       const char *key;
+       const char *value;
+};
+
+struct env {
+       RB_HEAD(envtree, envnode) root;
+       u_int count;
+};
+
+static int
 envcmp(struct envnode *a, struct envnode *b)
 {
        return strcmp(a->key, b->key);
 }
-RB_GENERATE(envtree, envnode, node, envcmp)
+RB_GENERATE_STATIC(envtree, envnode, node, envcmp)
+
+static struct envnode *
+createnode(const char *key, const char *value)
+{
+       struct envnode *node;
+
+       node = malloc(sizeof(*node));
+       if (!node)
+               err(1, NULL);
+       node->key = strdup(key);
+       node->value = strdup(value);
+       if (!node->key || !node->value)
+               err(1, NULL);
+       return node;
+}
+
+static void
+freenode(struct envnode *node)
+{
+       free((char *)node->key);
+       free((char *)node->value);
+       free(node);
+}
 
-struct env *
-createenv(char **envp)
+static struct env *
+createenv(const struct rule *rule)
 {
        struct env *env;
        u_int i;
@@ -45,34 +81,40 @@ createenv(char **envp)
        RB_INIT(&env->root);
        env->count = 0;
 
-       for (i = 0; envp[i] != NULL; i++) {
-               struct envnode *node;
-               const char *e, *eq;
-
-               e = envp[i];
-
-               if ((eq = strchr(e, '=')) == NULL || eq == e)
-                       continue;
-               node = malloc(sizeof(*node));
-               if (!node)
-                       err(1, NULL);
-               node->key = strndup(envp[i], eq - e);
-               node->value = strdup(eq + 1);
-               if (!node->key || !node->value)
-                       err(1, NULL);
-               if (RB_FIND(envtree, &env->root, node)) {
-                       free((char *)node->key);
-                       free((char *)node->value);
-                       free(node);
-               } else {
-                       RB_INSERT(envtree, &env->root, node);
-                       env->count++;
+       if (rule->options & KEEPENV) {
+               extern char **environ;
+
+               for (i = 0; environ[i] != NULL; i++) {
+                       struct envnode *node;
+                       const char *e, *eq;
+                       size_t len;
+                       char keybuf[1024];
+
+                       e = environ[i];
+
+                       /* ignore invalid or overlong names */
+                       if ((eq = strchr(e, '=')) == NULL || eq == e)
+                               continue;
+                       len = eq - e;
+                       if (len > sizeof(keybuf) - 1)
+                               continue;
+                       memcpy(keybuf, e, len);
+                       keybuf[len] = '\0';
+
+                       node = createnode(keybuf, eq + 1);
+                       if (RB_INSERT(envtree, &env->root, node)) {
+                               /* ignore any later duplicates */
+                               freenode(node);
+                       } else {
+                               env->count++;
+                       }
                }
        }
+
        return env;
 }
 
-char **
+static char **
 flattenenv(struct env *env)
 {
        char **envp;
@@ -93,61 +135,74 @@ flattenenv(struct env *env)
 }
 
 static void
-copyenv(struct env *orig, struct env *copy, const char **envlist)
+fillenv(struct env *env, const char **envlist)
 {
        struct envnode *node, key;
+       const char *e, *eq;
+       const char *val;
+       char name[1024];
        u_int i;
+       size_t len;
 
        for (i = 0; envlist[i]; i++) {
-               key.key = envlist[i];
-               if ((node = RB_FIND(envtree, &orig->root, &key))) {
-                       RB_REMOVE(envtree, &orig->root, node);
-                       orig->count--;
-                       RB_INSERT(envtree, &copy->root, node);
-                       copy->count++;
+               e = envlist[i];
+
+               /* parse out env name */
+               if ((eq = strchr(e, '=')) == NULL)
+                       len = strlen(e);
+               else
+                       len = eq - e;
+               if (len > sizeof(name) - 1)
+                       continue;
+               memcpy(name, e, len);
+               name[len] = '\0';
+
+               /* delete previous copies */
+               key.key = name;
+               if (*name == '-')
+                       key.key = name + 1;
+               if ((node = RB_FIND(envtree, &env->root, &key))) {
+                       RB_REMOVE(envtree, &env->root, node);
+                       freenode(node);
+                       env->count--;
+               }
+               if (*name == '-')
+                       continue;
+
+               /* assign value or inherit from environ */
+               if (eq) {
+                       val = eq + 1;
+                       if (*val == '$')
+                               val = getenv(val + 1);
+               } else {
+                       val = getenv(name);
+               }
+               /* at last, we have something to insert */
+               if (val) {
+                       node = createnode(name, val);
+                       RB_INSERT(envtree, &env->root, node);
+                       env->count++;
                }
        }
 }
 
-struct env *
-filterenv(struct env *orig, struct rule *rule)
+char **
+prepenv(const struct rule *rule)
 {
-       const char *safeset[] = {
+       static const char *safeset[] = {
                "DISPLAY", "HOME", "LOGNAME", "MAIL",
                "PATH", "TERM", "USER", "USERNAME",
                NULL
        };
-       const char *badset[] = {
-               "ENV",
-               NULL
-       };
-       struct env *copy;
-       struct envnode *node, key;
-       u_int i;
-
-       if ((rule->options & KEEPENV) && !rule->envlist) {
-               for (i = 0; badset[i]; i++) {
-                       key.key = badset[i];
-                       if ((node = RB_FIND(envtree, &orig->root, &key))) {
-                               RB_REMOVE(envtree, &orig->root, node);
-                               free((char *)node->key);
-                               free((char *)node->value);
-                               free(node);
-                               orig->count--;
-                       }
-               }
-               return orig;
-       }
+       struct env *env;
 
-       copy = malloc(sizeof(*copy));
-       if (!copy)
-               err(1, NULL);
-       RB_INIT(&copy->root);
-       copy->count = 0;
+       env = createenv(rule);
 
+       /* if we started with blank, fill some defaults then apply rules */
+       if (!(rule->options & KEEPENV))
+               fillenv(env, safeset);
        if (rule->envlist)
-               copyenv(orig, copy, rule->envlist);
-       copyenv(orig, copy, safeset);
+               fillenv(env, rule->envlist);
 
-       return copy;
+       return flattenenv(env);
 }