*/
#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(struct rule *rule)
{
struct env *env;
u_int i;
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 const 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;
}
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, ©->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(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;
- }
-
- copy = malloc(sizeof(*copy));
- if (!copy)
- err(1, NULL);
- RB_INIT(©->root);
- copy->count = 0;
+ struct env *env;
+
+ 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);
}