=================================================================== RCS file: /cvsrepo/anoncvs/cvs/src/usr.bin/doas/env.c,v retrieving revision 1.2 retrieving revision 1.3 diff -c -r1.2 -r1.3 *** src/usr.bin/doas/env.c 2016/06/19 19:29:43 1.2 --- src/usr.bin/doas/env.c 2016/06/27 15:41:17 1.3 *************** *** 1,4 **** ! /* $OpenBSD: env.c,v 1.2 2016/06/19 19:29:43 martijn Exp $ */ /* * Copyright (c) 2016 Ted Unangst * --- 1,4 ---- ! /* $OpenBSD: env.c,v 1.3 2016/06/27 15:41:17 tedu Exp $ */ /* * Copyright (c) 2016 Ted Unangst * *************** *** 38,57 **** u_int count; }; ! int envcmp(struct envnode *a, struct envnode *b) { return strcmp(a->key, b->key); } RB_GENERATE_STATIC(envtree, envnode, node, envcmp) ! struct env *createenv(char **); ! struct env *filterenv(struct env *, struct rule *); ! char **flattenenv(struct env *); ! struct env * ! createenv(char **envp) { struct env *env; u_int i; --- 38,76 ---- u_int count; }; ! static int envcmp(struct envnode *a, struct envnode *b) { return strcmp(a->key, b->key); } 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); + } + + static struct env * + createenv(struct rule *rule) + { struct env *env; u_int i; *************** *** 61,94 **** 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++; } } return env; } ! char ** flattenenv(struct env *env) { char **envp; --- 80,119 ---- RB_INIT(&env->root); env->count = 0; ! 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; } ! static char ** flattenenv(struct env *env) { char **envp; *************** *** 109,180 **** } static void ! copyenv(struct env *orig, struct env *copy, const char **envlist) { struct envnode *node, key; u_int i; 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++; } } } ! struct env * ! filterenv(struct env *orig, struct rule *rule) { ! 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; ! if (rule->envlist) ! copyenv(orig, copy, rule->envlist); ! copyenv(orig, copy, safeset); - return copy; - } - - char ** - prepenv(struct rule *rule) - { - extern char **environ; - struct env *env; - - env = createenv(environ); - env = filterenv(env, rule); return flattenenv(env); } --- 134,207 ---- } static void ! 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++) { ! 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++; + } } } ! char ** ! prepenv(struct rule *rule) { ! static const char *safeset[] = { "DISPLAY", "HOME", "LOGNAME", "MAIL", "PATH", "TERM", "USER", "USERNAME", NULL }; ! 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) ! fillenv(env, rule->envlist); return flattenenv(env); }