Updated license file.
[doas.git] / env.c
bloba2cd977589a90f73d216148f2f43689aba6a8a87
1 /* $OpenBSD: env.c,v 1.5 2016/09/15 00:58:23 deraadt Exp $ */
2 /*
3 * Copyright (c) 2016 Ted Unangst <tedu@openbsd.org>
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.
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.
18 #include <sys/types.h>
19 #ifndef linux
20 #include <sys/tree.h>
21 #endif
23 #include <string.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <err.h>
27 #include <unistd.h>
28 #include <errno.h>
30 #ifdef linux
31 #include "tree.h"
32 #endif
34 #include "doas.h"
36 struct envnode {
37 RB_ENTRY(envnode) node;
38 const char *key;
39 const char *value;
42 struct env {
43 RB_HEAD(envtree, envnode) root;
44 u_int count;
47 int
48 envcmp(struct envnode *a, struct envnode *b)
50 return strcmp(a->key, b->key);
52 #ifdef __DragonFly__
53 RB_PROTOTYPE_STATIC(envtree, envnode, node, envcmp);
54 #endif
55 RB_GENERATE_STATIC(envtree, envnode, node, envcmp)
57 static struct envnode *
58 createnode(const char *key, const char *value)
60 struct envnode *node;
62 node = malloc(sizeof(*node));
63 if (!node)
64 err(1, NULL);
65 node->key = strdup(key);
66 node->value = strdup(value);
67 if (!node->key || !node->value)
68 err(1, NULL);
69 return node;
72 static void
73 freenode(struct envnode *node)
75 free((char *)node->key);
76 free((char *)node->value);
77 free(node);
80 static struct env *
81 createenv(struct rule *rule)
83 struct env *env;
84 u_int i;
86 env = malloc(sizeof(*env));
87 if (!env)
88 err(1, NULL);
89 RB_INIT(&env->root);
90 env->count = 0;
92 if (rule->options & KEEPENV) {
93 extern const char **environ;
95 for (i = 0; environ[i] != NULL; i++) {
96 struct envnode *node;
97 const char *e, *eq;
98 size_t len;
99 char name[1024];
101 e = environ[i];
103 /* ignore invalid or overlong names */
104 if ((eq = strchr(e, '=')) == NULL || eq == e)
105 continue;
106 len = eq - e;
107 if (len > sizeof(name) - 1)
108 continue;
109 memcpy(name, e, len);
110 name[len] = '\0';
112 node = createnode(name, eq + 1);
113 if (RB_INSERT(envtree, &env->root, node)) {
114 /* ignore any later duplicates */
115 freenode(node);
116 } else {
117 env->count++;
122 return env;
125 static char **
126 flattenenv(struct env *env)
128 char **envp;
129 struct envnode *node;
130 u_int i;
132 envp = reallocarray(NULL, env->count + 1, sizeof(char *));
133 if (!envp)
134 err(1, NULL);
135 i = 0;
136 RB_FOREACH(node, envtree, &env->root) {
137 if (asprintf(&envp[i], "%s=%s", node->key, node->value) == -1)
138 err(1, NULL);
139 i++;
141 envp[i] = NULL;
142 return envp;
145 static void
146 fillenv(struct env *env, const char **envlist)
148 struct envnode *node, key;
149 const char *e, *eq;
150 const char *val;
151 char name[1024];
152 u_int i;
153 size_t len;
155 for (i = 0; envlist[i]; i++) {
156 e = envlist[i];
158 /* parse out env name */
159 if ((eq = strchr(e, '=')) == NULL)
160 len = strlen(e);
161 else
162 len = eq - e;
163 if (len > sizeof(name) - 1)
164 continue;
165 memcpy(name, e, len);
166 name[len] = '\0';
168 /* delete previous copies */
169 key.key = name;
170 if (*name == '-')
171 key.key = name + 1;
172 if ((node = RB_FIND(envtree, &env->root, &key))) {
173 RB_REMOVE(envtree, &env->root, node);
174 freenode(node);
175 env->count--;
177 if (*name == '-')
178 continue;
180 /* assign value or inherit from environ */
181 if (eq) {
182 val = eq + 1;
183 if (*val == '$')
184 val = getenv(val + 1);
185 } else {
186 val = getenv(name);
188 /* at last, we have something to insert */
189 if (val) {
190 node = createnode(name, val);
191 RB_INSERT(envtree, &env->root, node);
192 env->count++;
197 char **
198 prepenv(struct rule *rule)
200 static const char *safeset[] = {
201 "DISPLAY", "HOME", "LOGNAME", "MAIL",
202 "PATH", "TERM", "USER", "USERNAME",
203 NULL
205 struct env *env;
207 env = createenv(rule);
209 /* if we started with blank, fill some defaults then apply rules */
210 if (!(rule->options & KEEPENV))
211 fillenv(env, safeset);
212 if (rule->envlist)
213 fillenv(env, rule->envlist);
215 return flattenenv(env);