X-Git-Url: https://git.armaanb.net/?p=opendoas.git;a=blobdiff_plain;f=env.c;h=e2286fc83b0232425f67a8cda355ef1453f7739f;hp=77b243479ef1cf6a87aeca3eb6e42f387961f330;hb=HEAD;hpb=a3ceebbcdde17d0fbfb0a334ad88cc4b4f73f533 diff --git a/env.c b/env.c index 77b2434..e2286fc 100644 --- a/env.c +++ b/env.c @@ -15,8 +15,10 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "config.h" + #include -#include +#include "sys-tree.h" #include #include @@ -24,9 +26,13 @@ #include #include #include +#include +#include "openbsd.h" #include "doas.h" +const char *formerpath; + struct envnode { RB_ENTRY(envnode) node; const char *key; @@ -38,20 +44,56 @@ struct env { u_int count; }; -int +static void fillenv(struct env *env, const char **envlist); + +static 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 *); +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 void +addnode(struct env *env, const char *key, const char *value) +{ + struct envnode *node; -struct env * -createenv(char **envp) + node = createnode(key, value); + RB_INSERT(envtree, &env->root, node); + env->count++; +} + +static struct env * +createenv(const struct rule *rule, const struct passwd *mypw, + const struct passwd *targpw) { + static const char *copyset[] = { + "DISPLAY", "TERM", + NULL + }; struct env *env; u_int i; @@ -61,34 +103,49 @@ 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++; + addnode(env, "DOAS_USER", mypw->pw_name); + addnode(env, "HOME", targpw->pw_dir); + addnode(env, "LOGNAME", targpw->pw_name); + addnode(env, "PATH", getenv("PATH")); + addnode(env, "SHELL", targpw->pw_shell); + addnode(env, "USER", targpw->pw_name); + + fillenv(env, copyset); + + 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; @@ -109,72 +166,73 @@ 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, ©->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--; } - } -} - -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 (*name == '-') + continue; - 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--; + /* assign value or inherit from environ */ + if (eq) { + val = eq + 1; + if (*val == '$') { + if (strcmp(val + 1, "PATH") == 0) + val = formerpath; + else + val = getenv(val + 1); } + } else { + if (strcmp(name, "PATH") == 0) + val = formerpath; + 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++; } - 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) +prepenv(const struct rule *rule, const struct passwd *mypw, + const struct passwd *targpw) { - extern char **environ; struct env *env; - - env = createenv(environ); - env = filterenv(env, rule); + + env = createenv(rule, mypw, targpw); + if (rule->envlist) + fillenv(env, rule->envlist); + return flattenenv(env); }