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