]> git.armaanb.net Git - opendoas.git/blob - env.c
Move the RB_ code from doas.h to env.c, and limit the environment interface to a...
[opendoas.git] / env.c
1 /* $OpenBSD$ */
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>
19 #include <sys/tree.h>
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
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
41 int
42 envcmp(struct envnode *a, struct envnode *b)
43 {
44         return strcmp(a->key, b->key);
45 }
46 RB_GENERATE_STATIC(envtree, envnode, node, envcmp)
47
48 struct env *createenv(char **);
49 struct env *filterenv(struct env *, struct rule *);
50 char **flattenenv(struct env *);
51
52 struct env *
53 createenv(char **envp)
54 {
55         struct env *env;
56         u_int i;
57
58         env = malloc(sizeof(*env));
59         if (!env)
60                 err(1, NULL);
61         RB_INIT(&env->root);
62         env->count = 0;
63
64         for (i = 0; envp[i] != NULL; i++) {
65                 struct envnode *node;
66                 const char *e, *eq;
67
68                 e = envp[i];
69
70                 if ((eq = strchr(e, '=')) == NULL || eq == e)
71                         continue;
72                 node = malloc(sizeof(*node));
73                 if (!node)
74                         err(1, NULL);
75                 node->key = strndup(envp[i], eq - e);
76                 node->value = strdup(eq + 1);
77                 if (!node->key || !node->value)
78                         err(1, NULL);
79                 if (RB_FIND(envtree, &env->root, node)) {
80                         free((char *)node->key);
81                         free((char *)node->value);
82                         free(node);
83                 } else {
84                         RB_INSERT(envtree, &env->root, node);
85                         env->count++;
86                 }
87         }
88         return env;
89 }
90
91 char **
92 flattenenv(struct env *env)
93 {
94         char **envp;
95         struct envnode *node;
96         u_int i;
97
98         envp = reallocarray(NULL, env->count + 1, sizeof(char *));
99         if (!envp)
100                 err(1, NULL);
101         i = 0;
102         RB_FOREACH(node, envtree, &env->root) {
103                 if (asprintf(&envp[i], "%s=%s", node->key, node->value) == -1)
104                         err(1, NULL);
105                 i++;
106         }
107         envp[i] = NULL;
108         return envp;
109 }
110
111 static void
112 copyenv(struct env *orig, struct env *copy, const char **envlist)
113 {
114         struct envnode *node, key;
115         u_int i;
116
117         for (i = 0; envlist[i]; i++) {
118                 key.key = envlist[i];
119                 if ((node = RB_FIND(envtree, &orig->root, &key))) {
120                         RB_REMOVE(envtree, &orig->root, node);
121                         orig->count--;
122                         RB_INSERT(envtree, &copy->root, node);
123                         copy->count++;
124                 }
125         }
126 }
127
128 struct env *
129 filterenv(struct env *orig, struct rule *rule)
130 {
131         const char *safeset[] = {
132                 "DISPLAY", "HOME", "LOGNAME", "MAIL",
133                 "PATH", "TERM", "USER", "USERNAME",
134                 NULL
135         };
136         const char *badset[] = {
137                 "ENV",
138                 NULL
139         };
140         struct env *copy;
141         struct envnode *node, key;
142         u_int i;
143
144         if ((rule->options & KEEPENV) && !rule->envlist) {
145                 for (i = 0; badset[i]; i++) {
146                         key.key = badset[i];
147                         if ((node = RB_FIND(envtree, &orig->root, &key))) {
148                                 RB_REMOVE(envtree, &orig->root, node);
149                                 free((char *)node->key);
150                                 free((char *)node->value);
151                                 free(node);
152                                 orig->count--;
153                         }
154                 }
155                 return orig;
156         }
157
158         copy = malloc(sizeof(*copy));
159         if (!copy)
160                 err(1, NULL);
161         RB_INIT(&copy->root);
162         copy->count = 0;
163
164         if (rule->envlist)
165                 copyenv(orig, copy, rule->envlist);
166         copyenv(orig, copy, safeset);
167
168         return copy;
169 }
170
171 char **
172 prepenv(struct rule *rule)
173 {
174         extern char **environ;
175         struct env *env;
176         
177         env = createenv(environ);
178         env = filterenv(env, rule);
179         return flattenenv(env);
180 }