Annotation of src/usr.bin/doas/env.c, Revision 1.4
1.4 ! tedu 1: /* $OpenBSD: env.c,v 1.3 2016/06/27 15:41:17 tedu 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;
1.4 ! tedu 90: char name[1024];
1.3 tedu 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;
1.4 ! tedu 98: if (len > sizeof(name) - 1)
1.3 tedu 99: continue;
1.4 ! tedu 100: memcpy(name, e, len);
! 101: name[len] = '\0';
1.3 tedu 102:
1.4 ! tedu 103: node = createnode(name, eq + 1);
1.3 tedu 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: }