GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.bin/doas/env.c Lines: 0 75 0.0 %
Date: 2016-12-06 Branches: 0 236 0.0 %

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