Annotation of src/usr.bin/doas/env.c, Revision 1.10
1.10 ! tedu 1: /* $OpenBSD: env.c,v 1.9 2019/06/17 19:51:23 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>
1.7 tedu 27: #include <pwd.h>
1.1 tedu 28:
29: #include "doas.h"
30:
1.9 tedu 31: const char *formerpath;
32:
1.2 martijn 33: struct envnode {
34: RB_ENTRY(envnode) node;
35: const char *key;
36: const char *value;
37: };
38:
39: struct env {
40: RB_HEAD(envtree, envnode) root;
41: u_int count;
42: };
43:
1.7 tedu 44: static void fillenv(struct env *env, const char **envlist);
45:
1.3 tedu 46: static int
1.1 tedu 47: envcmp(struct envnode *a, struct envnode *b)
48: {
49: return strcmp(a->key, b->key);
50: }
1.2 martijn 51: RB_GENERATE_STATIC(envtree, envnode, node, envcmp)
52:
1.3 tedu 53: static struct envnode *
54: createnode(const char *key, const char *value)
55: {
56: struct envnode *node;
1.1 tedu 57:
1.3 tedu 58: node = malloc(sizeof(*node));
59: if (!node)
60: err(1, NULL);
61: node->key = strdup(key);
62: node->value = strdup(value);
63: if (!node->key || !node->value)
64: err(1, NULL);
65: return node;
66: }
67:
68: static void
69: freenode(struct envnode *node)
70: {
71: free((char *)node->key);
72: free((char *)node->value);
73: free(node);
74: }
75:
1.7 tedu 76: static void
77: addnode(struct env *env, const char *key, const char *value)
78: {
79: struct envnode *node;
80:
81: node = createnode(key, value);
82: RB_INSERT(envtree, &env->root, node);
83: env->count++;
84: }
85:
1.3 tedu 86: static struct env *
1.7 tedu 87: createenv(const struct rule *rule, const struct passwd *mypw,
88: const struct passwd *targpw)
1.1 tedu 89: {
1.8 tedu 90: static const char *copyset[] = {
91: "DISPLAY", "TERM",
92: NULL
93: };
1.1 tedu 94: struct env *env;
95: u_int i;
96:
97: env = malloc(sizeof(*env));
98: if (!env)
99: err(1, NULL);
100: RB_INIT(&env->root);
101: env->count = 0;
102:
1.7 tedu 103: addnode(env, "DOAS_USER", mypw->pw_name);
1.8 tedu 104: addnode(env, "HOME", targpw->pw_dir);
105: addnode(env, "LOGNAME", targpw->pw_name);
106: addnode(env, "PATH", getenv("PATH"));
107: addnode(env, "SHELL", targpw->pw_shell);
108: addnode(env, "USER", targpw->pw_name);
109:
110: fillenv(env, copyset);
1.7 tedu 111:
1.3 tedu 112: if (rule->options & KEEPENV) {
113: extern const char **environ;
1.1 tedu 114:
1.3 tedu 115: for (i = 0; environ[i] != NULL; i++) {
116: struct envnode *node;
117: const char *e, *eq;
118: size_t len;
1.4 tedu 119: char name[1024];
1.3 tedu 120:
121: e = environ[i];
122:
123: /* ignore invalid or overlong names */
124: if ((eq = strchr(e, '=')) == NULL || eq == e)
125: continue;
126: len = eq - e;
1.4 tedu 127: if (len > sizeof(name) - 1)
1.3 tedu 128: continue;
1.4 tedu 129: memcpy(name, e, len);
130: name[len] = '\0';
1.3 tedu 131:
1.4 tedu 132: node = createnode(name, eq + 1);
1.3 tedu 133: if (RB_INSERT(envtree, &env->root, node)) {
134: /* ignore any later duplicates */
135: freenode(node);
136: } else {
137: env->count++;
138: }
1.1 tedu 139: }
140: }
1.3 tedu 141:
1.1 tedu 142: return env;
143: }
144:
1.3 tedu 145: static char **
1.1 tedu 146: flattenenv(struct env *env)
147: {
148: char **envp;
149: struct envnode *node;
150: u_int i;
151:
152: envp = reallocarray(NULL, env->count + 1, sizeof(char *));
153: if (!envp)
154: err(1, NULL);
155: i = 0;
156: RB_FOREACH(node, envtree, &env->root) {
157: if (asprintf(&envp[i], "%s=%s", node->key, node->value) == -1)
158: err(1, NULL);
159: i++;
160: }
161: envp[i] = NULL;
162: return envp;
163: }
164:
165: static void
1.3 tedu 166: fillenv(struct env *env, const char **envlist)
1.1 tedu 167: {
168: struct envnode *node, key;
1.3 tedu 169: const char *e, *eq;
170: const char *val;
171: char name[1024];
1.1 tedu 172: u_int i;
1.3 tedu 173: size_t len;
1.1 tedu 174:
175: for (i = 0; envlist[i]; i++) {
1.3 tedu 176: e = envlist[i];
177:
178: /* parse out env name */
179: if ((eq = strchr(e, '=')) == NULL)
180: len = strlen(e);
181: else
182: len = eq - e;
183: if (len > sizeof(name) - 1)
184: continue;
185: memcpy(name, e, len);
186: name[len] = '\0';
187:
188: /* delete previous copies */
189: key.key = name;
190: if (*name == '-')
191: key.key = name + 1;
192: if ((node = RB_FIND(envtree, &env->root, &key))) {
193: RB_REMOVE(envtree, &env->root, node);
194: freenode(node);
195: env->count--;
196: }
197: if (*name == '-')
198: continue;
199:
200: /* assign value or inherit from environ */
201: if (eq) {
202: val = eq + 1;
1.9 tedu 203: if (*val == '$') {
204: if (strcmp(val + 1, "PATH") == 0)
205: val = formerpath;
206: else
207: val = getenv(val + 1);
208: }
1.3 tedu 209: } else {
1.10 ! tedu 210: if (strcmp(name, "PATH") == 0)
! 211: val = formerpath;
! 212: else
! 213: val = getenv(name);
1.3 tedu 214: }
215: /* at last, we have something to insert */
216: if (val) {
217: node = createnode(name, val);
218: RB_INSERT(envtree, &env->root, node);
219: env->count++;
1.1 tedu 220: }
221: }
222: }
223:
1.3 tedu 224: char **
1.7 tedu 225: prepenv(const struct rule *rule, const struct passwd *mypw,
226: const struct passwd *targpw)
1.1 tedu 227: {
1.3 tedu 228: struct env *env;
1.5 deraadt 229:
1.7 tedu 230: env = createenv(rule, mypw, targpw);
1.1 tedu 231: if (rule->envlist)
1.3 tedu 232: fillenv(env, rule->envlist);
1.2 martijn 233:
234: return flattenenv(env);
1.1 tedu 235: }