Annotation of src/usr.bin/doas/env.c, Revision 1.3
1.3 ! tedu 1: /* $OpenBSD: env.c,v 1.2 2016/06/19 19:29:43 martijn Exp $ */
1.1 tedu 2: /*
3: * Copyright (c) 2016 Ted Unangst <tedu@openbsd.org>
4: *
5: * Permission to use, copy, modify, and distribute this software for any
6: * purpose with or without fee is hereby granted, provided that the above
7: * copyright notice and this permission notice appear in all copies.
8: *
9: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16: */
17:
18: #include <sys/types.h>
1.2 martijn 19: #include <sys/tree.h>
1.1 tedu 20:
21: #include <string.h>
22: #include <stdio.h>
23: #include <stdlib.h>
24: #include <err.h>
25: #include <unistd.h>
26: #include <errno.h>
27:
28: #include "doas.h"
29:
1.2 martijn 30: struct envnode {
31: RB_ENTRY(envnode) node;
32: const char *key;
33: const char *value;
34: };
35:
36: struct env {
37: RB_HEAD(envtree, envnode) root;
38: u_int count;
39: };
40:
1.3 ! tedu 41: static int
1.1 tedu 42: envcmp(struct envnode *a, struct envnode *b)
43: {
44: return strcmp(a->key, b->key);
45: }
1.2 martijn 46: RB_GENERATE_STATIC(envtree, envnode, node, envcmp)
47:
1.3 ! tedu 48: static struct envnode *
! 49: createnode(const char *key, const char *value)
! 50: {
! 51: struct envnode *node;
1.1 tedu 52:
1.3 ! tedu 53: node = malloc(sizeof(*node));
! 54: if (!node)
! 55: err(1, NULL);
! 56: node->key = strdup(key);
! 57: node->value = strdup(value);
! 58: if (!node->key || !node->value)
! 59: err(1, NULL);
! 60: return node;
! 61: }
! 62:
! 63: static void
! 64: freenode(struct envnode *node)
! 65: {
! 66: free((char *)node->key);
! 67: free((char *)node->value);
! 68: free(node);
! 69: }
! 70:
! 71: static struct env *
! 72: createenv(struct rule *rule)
1.1 tedu 73: {
74: struct env *env;
75: u_int i;
76:
77: env = malloc(sizeof(*env));
78: if (!env)
79: err(1, NULL);
80: RB_INIT(&env->root);
81: env->count = 0;
82:
1.3 ! tedu 83: if (rule->options & KEEPENV) {
! 84: extern const char **environ;
1.1 tedu 85:
1.3 ! tedu 86: for (i = 0; environ[i] != NULL; i++) {
! 87: struct envnode *node;
! 88: const char *e, *eq;
! 89: size_t len;
! 90: char keybuf[1024];
! 91:
! 92: e = environ[i];
! 93:
! 94: /* ignore invalid or overlong names */
! 95: if ((eq = strchr(e, '=')) == NULL || eq == e)
! 96: continue;
! 97: len = eq - e;
! 98: if (len > sizeof(keybuf) - 1)
! 99: continue;
! 100: memcpy(keybuf, e, len);
! 101: keybuf[len] = '\0';
! 102:
! 103: node = createnode(keybuf, eq + 1);
! 104: if (RB_INSERT(envtree, &env->root, node)) {
! 105: /* ignore any later duplicates */
! 106: freenode(node);
! 107: } else {
! 108: env->count++;
! 109: }
1.1 tedu 110: }
111: }
1.3 ! tedu 112:
1.1 tedu 113: return env;
114: }
115:
1.3 ! tedu 116: static char **
1.1 tedu 117: flattenenv(struct env *env)
118: {
119: char **envp;
120: struct envnode *node;
121: u_int i;
122:
123: envp = reallocarray(NULL, env->count + 1, sizeof(char *));
124: if (!envp)
125: err(1, NULL);
126: i = 0;
127: RB_FOREACH(node, envtree, &env->root) {
128: if (asprintf(&envp[i], "%s=%s", node->key, node->value) == -1)
129: err(1, NULL);
130: i++;
131: }
132: envp[i] = NULL;
133: return envp;
134: }
135:
136: static void
1.3 ! tedu 137: fillenv(struct env *env, const char **envlist)
1.1 tedu 138: {
139: struct envnode *node, key;
1.3 ! tedu 140: const char *e, *eq;
! 141: const char *val;
! 142: char name[1024];
1.1 tedu 143: u_int i;
1.3 ! tedu 144: size_t len;
1.1 tedu 145:
146: for (i = 0; envlist[i]; i++) {
1.3 ! tedu 147: e = envlist[i];
! 148:
! 149: /* parse out env name */
! 150: if ((eq = strchr(e, '=')) == NULL)
! 151: len = strlen(e);
! 152: else
! 153: len = eq - e;
! 154: if (len > sizeof(name) - 1)
! 155: continue;
! 156: memcpy(name, e, len);
! 157: name[len] = '\0';
! 158:
! 159: /* delete previous copies */
! 160: key.key = name;
! 161: if (*name == '-')
! 162: key.key = name + 1;
! 163: if ((node = RB_FIND(envtree, &env->root, &key))) {
! 164: RB_REMOVE(envtree, &env->root, node);
! 165: freenode(node);
! 166: env->count--;
! 167: }
! 168: if (*name == '-')
! 169: continue;
! 170:
! 171: /* assign value or inherit from environ */
! 172: if (eq) {
! 173: val = eq + 1;
! 174: if (*val == '$')
! 175: val = getenv(val + 1);
! 176: } else {
! 177: val = getenv(name);
! 178: }
! 179: /* at last, we have something to insert */
! 180: if (val) {
! 181: node = createnode(name, val);
! 182: RB_INSERT(envtree, &env->root, node);
! 183: env->count++;
1.1 tedu 184: }
185: }
186: }
187:
1.3 ! tedu 188: char **
! 189: prepenv(struct rule *rule)
1.1 tedu 190: {
1.3 ! tedu 191: static const char *safeset[] = {
1.1 tedu 192: "DISPLAY", "HOME", "LOGNAME", "MAIL",
193: "PATH", "TERM", "USER", "USERNAME",
194: NULL
195: };
1.3 ! tedu 196: struct env *env;
! 197:
! 198: env = createenv(rule);
1.1 tedu 199:
1.3 ! tedu 200: /* if we started with blank, fill some defaults then apply rules */
! 201: if (!(rule->options & KEEPENV))
! 202: fillenv(env, safeset);
1.1 tedu 203: if (rule->envlist)
1.3 ! tedu 204: fillenv(env, rule->envlist);
1.2 martijn 205:
206: return flattenenv(env);
1.1 tedu 207: }