]> git.armaanb.net Git - opendoas.git/blob - env.c
timestamp: error out if fstat and lstat st_ino and st_dev are not the same
[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 #include "includes.h"
30
31 struct envnode {
32         RB_ENTRY(envnode) node;
33         const char *key;
34         const char *value;
35 };
36
37 struct env {
38         RB_HEAD(envtree, envnode) root;
39         u_int count;
40 };
41
42 static int
43 envcmp(struct envnode *a, struct envnode *b)
44 {
45         return strcmp(a->key, b->key);
46 }
47 RB_GENERATE_STATIC(envtree, envnode, node, envcmp)
48
49 static struct envnode *
50 createnode(const char *key, const char *value)
51 {
52         struct envnode *node;
53
54         node = malloc(sizeof(*node));
55         if (!node)
56                 err(1, NULL);
57         node->key = strdup(key);
58         node->value = strdup(value);
59         if (!node->key || !node->value)
60                 err(1, NULL);
61         return node;
62 }
63
64 static void
65 freenode(struct envnode *node)
66 {
67         free((char *)node->key);
68         free((char *)node->value);
69         free(node);
70 }
71
72 static struct env *
73 createenv(const struct rule *rule)
74 {
75         struct env *env;
76         u_int i;
77
78         env = malloc(sizeof(*env));
79         if (!env)
80                 err(1, NULL);
81         RB_INIT(&env->root);
82         env->count = 0;
83
84         if (rule->options & KEEPENV) {
85                 extern char **environ;
86
87                 for (i = 0; environ[i] != NULL; i++) {
88                         struct envnode *node;
89                         const char *e, *eq;
90                         size_t len;
91                         char keybuf[1024];
92
93                         e = environ[i];
94
95                         /* ignore invalid or overlong names */
96                         if ((eq = strchr(e, '=')) == NULL || eq == e)
97                                 continue;
98                         len = eq - e;
99                         if (len > sizeof(keybuf) - 1)
100                                 continue;
101                         memcpy(keybuf, e, len);
102                         keybuf[len] = '\0';
103
104                         node = createnode(keybuf, eq + 1);
105                         if (RB_INSERT(envtree, &env->root, node)) {
106                                 /* ignore any later duplicates */
107                                 freenode(node);
108                         } else {
109                                 env->count++;
110                         }
111                 }
112         }
113
114         return env;
115 }
116
117 static char **
118 flattenenv(struct env *env)
119 {
120         char **envp;
121         struct envnode *node;
122         u_int i;
123
124         envp = reallocarray(NULL, env->count + 1, sizeof(char *));
125         if (!envp)
126                 err(1, NULL);
127         i = 0;
128         RB_FOREACH(node, envtree, &env->root) {
129                 if (asprintf(&envp[i], "%s=%s", node->key, node->value) == -1)
130                         err(1, NULL);
131                 i++;
132         }
133         envp[i] = NULL;
134         return envp;
135 }
136
137 static void
138 fillenv(struct env *env, const char **envlist)
139 {
140         struct envnode *node, key;
141         const char *e, *eq;
142         const char *val;
143         char name[1024];
144         u_int i;
145         size_t len;
146
147         for (i = 0; envlist[i]; i++) {
148                 e = envlist[i];
149
150                 /* parse out env name */
151                 if ((eq = strchr(e, '=')) == NULL)
152                         len = strlen(e);
153                 else
154                         len = eq - e;
155                 if (len > sizeof(name) - 1)
156                         continue;
157                 memcpy(name, e, len);
158                 name[len] = '\0';
159
160                 /* delete previous copies */
161                 key.key = name;
162                 if (*name == '-')
163                         key.key = name + 1;
164                 if ((node = RB_FIND(envtree, &env->root, &key))) {
165                         RB_REMOVE(envtree, &env->root, node);
166                         freenode(node);
167                         env->count--;
168                 }
169                 if (*name == '-')
170                         continue;
171
172                 /* assign value or inherit from environ */
173                 if (eq) {
174                         val = eq + 1;
175                         if (*val == '$')
176                                 val = getenv(val + 1);
177                 } else {
178                         val = getenv(name);
179                 }
180                 /* at last, we have something to insert */
181                 if (val) {
182                         node = createnode(name, val);
183                         RB_INSERT(envtree, &env->root, node);
184                         env->count++;
185                 }
186         }
187 }
188
189 char **
190 prepenv(const struct rule *rule)
191 {
192         static const char *safeset[] = {
193                 "DISPLAY", "HOME", "LOGNAME", "MAIL",
194                 "PATH", "TERM", "USER", "USERNAME",
195                 NULL
196         };
197         struct env *env;
198
199         env = createenv(rule);
200
201         /* if we started with blank, fill some defaults then apply rules */
202         if (!(rule->options & KEEPENV))
203                 fillenv(env, safeset);
204         if (rule->envlist)
205                 fillenv(env, rule->envlist);
206
207         return flattenenv(env);
208 }