GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.sbin/smtpd/smtpctl/../expand.c Lines: 0 150 0.0 %
Date: 2017-11-13 Branches: 0 303 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: expand.c,v 1.29 2015/12/28 22:08:30 jung Exp $	*/
2
3
/*
4
 * Copyright (c) 2009 Gilles Chehade <gilles@poolp.org>
5
 * Copyright (c) 2012 Eric Faurot <eric@openbsd.org>
6
 *
7
 * Permission to use, copy, modify, and distribute this software for any
8
 * purpose with or without fee is hereby granted, provided that the above
9
 * copyright notice and this permission notice appear in all copies.
10
 *
11
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18
 */
19
20
#include <sys/types.h>
21
#include <sys/queue.h>
22
#include <sys/tree.h>
23
#include <sys/socket.h>
24
25
#include <ctype.h>
26
#include <event.h>
27
#include <imsg.h>
28
#include <stdio.h>
29
#include <limits.h>
30
#include <stdlib.h>
31
#include <string.h>
32
33
#include "smtpd.h"
34
#include "log.h"
35
36
static const char *expandnode_info(struct expandnode *);
37
38
struct expandnode *
39
expand_lookup(struct expand *expand, struct expandnode *key)
40
{
41
	return RB_FIND(expandtree, &expand->tree, key);
42
}
43
44
int
45
expand_to_text(struct expand *expand, char *buf, size_t sz)
46
{
47
	struct expandnode *xn;
48
49
	buf[0] = '\0';
50
51
	RB_FOREACH(xn, expandtree, &expand->tree) {
52
		if (buf[0])
53
			(void)strlcat(buf, ", ", sz);
54
		if (strlcat(buf, expandnode_to_text(xn), sz) >= sz)
55
			return 0;
56
	}
57
58
	return 1;
59
}
60
61
void
62
expand_insert(struct expand *expand, struct expandnode *node)
63
{
64
	struct expandnode *xn;
65
66
	node->parent = expand->parent;
67
68
	log_trace(TRACE_EXPAND, "expand: %p: expand_insert() called for %s",
69
	    expand, expandnode_info(node));
70
	if (node->type == EXPAND_USERNAME &&
71
	    expand->parent &&
72
	    expand->parent->type == EXPAND_USERNAME &&
73
	    !strcmp(expand->parent->u.user, node->u.user)) {
74
		log_trace(TRACE_EXPAND, "expand: %p: setting sameuser = 1",
75
		    expand);
76
		node->sameuser = 1;
77
	}
78
79
	if (expand_lookup(expand, node)) {
80
		log_trace(TRACE_EXPAND, "expand: %p: node found, discarding",
81
			expand);
82
		return;
83
	}
84
85
	xn = xmemdup(node, sizeof *xn, "expand_insert");
86
	xn->rule = expand->rule;
87
	xn->parent = expand->parent;
88
	xn->alias = expand->alias;
89
	if (xn->parent)
90
		xn->depth = xn->parent->depth + 1;
91
	else
92
		xn->depth = 0;
93
	RB_INSERT(expandtree, &expand->tree, xn);
94
	if (expand->queue)
95
		TAILQ_INSERT_TAIL(expand->queue, xn, tq_entry);
96
	expand->nb_nodes++;
97
	log_trace(TRACE_EXPAND, "expand: %p: inserted node %p", expand, xn);
98
}
99
100
void
101
expand_clear(struct expand *expand)
102
{
103
	struct expandnode *xn;
104
105
	log_trace(TRACE_EXPAND, "expand: %p: clearing expand tree", expand);
106
	if (expand->queue)
107
		while ((xn = TAILQ_FIRST(expand->queue)))
108
			TAILQ_REMOVE(expand->queue, xn, tq_entry);
109
110
	while ((xn = RB_ROOT(&expand->tree)) != NULL) {
111
		RB_REMOVE(expandtree, &expand->tree, xn);
112
		free(xn);
113
	}
114
}
115
116
void
117
expand_free(struct expand *expand)
118
{
119
	expand_clear(expand);
120
121
	log_trace(TRACE_EXPAND, "expand: %p: freeing expand tree", expand);
122
	free(expand);
123
}
124
125
int
126
expand_cmp(struct expandnode *e1, struct expandnode *e2)
127
{
128
	struct expandnode *p1, *p2;
129
	int		   r;
130
131
	if (e1->type < e2->type)
132
		return -1;
133
	if (e1->type > e2->type)
134
		return 1;
135
	if (e1->sameuser < e2->sameuser)
136
		return -1;
137
	if (e1->sameuser > e2->sameuser)
138
		return 1;
139
	if (e1->mapping < e2->mapping)
140
		return -1;
141
	if (e1->mapping > e2->mapping)
142
		return 1;
143
	if (e1->userbase < e2->userbase)
144
		return -1;
145
	if (e1->userbase > e2->userbase)
146
		return 1;
147
148
	r = memcmp(&e1->u, &e2->u, sizeof(e1->u));
149
	if (r)
150
		return (r);
151
152
153
	if (e1->parent == e2->parent)
154
		return (0);
155
156
	if (e1->parent == NULL)
157
		return (-1);
158
	if (e2->parent == NULL)
159
		return (1);
160
161
	/*
162
	 * The same node can be expanded in for different dest context.
163
	 * Wen need to distinguish between those.
164
	 */
165
	for(p1 = e1->parent; p1->type != EXPAND_ADDRESS; p1 = p1->parent)
166
		;
167
	for(p2 = e2->parent; p2->type != EXPAND_ADDRESS; p2 = p2->parent)
168
		;
169
	if (p1 < p2)
170
		return (-1);
171
	if (p1 > p2)
172
		return (1);
173
174
	if (e1->type != EXPAND_FILENAME && e1->type != EXPAND_FILTER)
175
		return (0);
176
177
	/*
178
	 * For external delivery, we need to distinguish between users.
179
	 * If we can't find a username, we assume it is _smtpd.
180
	 */
181
	for(p1 = e1->parent; p1 && p1->type != EXPAND_USERNAME; p1 = p1->parent)
182
		;
183
	for(p2 = e2->parent; p2 && p2->type != EXPAND_USERNAME; p2 = p2->parent)
184
		;
185
	if (p1 < p2)
186
		return (-1);
187
	if (p1 > p2)
188
		return (1);
189
190
	return (0);
191
}
192
193
static int
194
expand_line_split(char **line, char **ret)
195
{
196
	static char	buffer[LINE_MAX];
197
	int		esc, dq, sq;
198
	size_t		i;
199
	char	       *s;
200
201
	memset(buffer, 0, sizeof buffer);
202
	esc = dq = sq = 0;
203
	i = 0;
204
	for (s = *line; (*s) && (i < sizeof(buffer)); ++s) {
205
		if (esc) {
206
			buffer[i++] = *s;
207
			esc = 0;
208
			continue;
209
		}
210
		if (*s == '\\') {
211
			esc = 1;
212
			continue;
213
		}
214
		if (*s == ',' && !dq && !sq) {
215
			*ret = buffer;
216
			*line = s+1;
217
			return (1);
218
		}
219
220
		buffer[i++] = *s;
221
		esc = 0;
222
223
		if (*s == '"' && !sq)
224
			dq ^= 1;
225
		if (*s == '\'' && !dq)
226
			sq ^= 1;
227
	}
228
229
	if (esc || dq || sq || i == sizeof(buffer))
230
		return (-1);
231
232
	*ret = buffer;
233
	*line = s;
234
	return (i ? 1 : 0);
235
}
236
237
int
238
expand_line(struct expand *expand, const char *s, int do_includes)
239
{
240
	struct expandnode	xn;
241
	char			buffer[LINE_MAX];
242
	char		       *p, *subrcpt;
243
	int			ret;
244
245
	memset(buffer, 0, sizeof buffer);
246
	if (strlcpy(buffer, s, sizeof buffer) >= sizeof buffer)
247
		return 0;
248
249
	p = buffer;
250
	while ((ret = expand_line_split(&p, &subrcpt)) > 0) {
251
		subrcpt = strip(subrcpt);
252
		if (subrcpt[0] == '\0')
253
			continue;
254
		if (!text_to_expandnode(&xn, subrcpt))
255
			return 0;
256
		if (!do_includes)
257
			if (xn.type == EXPAND_INCLUDE)
258
				continue;
259
		expand_insert(expand, &xn);
260
	}
261
262
	if (ret >= 0)
263
		return 1;
264
265
	/* expand_line_split() returned < 0 */
266
	return 0;
267
}
268
269
static const char *
270
expandnode_info(struct expandnode *e)
271
{
272
	static char	buffer[1024];
273
	const char     *type = NULL;
274
	const char     *value = NULL;
275
	char		tmp[64];
276
277
	switch (e->type) {
278
	case EXPAND_FILTER:
279
		type = "filter";
280
		break;
281
	case EXPAND_FILENAME:
282
		type = "filename";
283
		break;
284
	case EXPAND_INCLUDE:
285
		type = "include";
286
		break;
287
	case EXPAND_USERNAME:
288
		type = "username";
289
		break;
290
	case EXPAND_ADDRESS:
291
		type = "address";
292
		break;
293
	case EXPAND_ERROR:
294
		type = "error";
295
		break;
296
	case EXPAND_INVALID:
297
	default:
298
		return NULL;
299
	}
300
301
	if ((value = expandnode_to_text(e)) == NULL)
302
		return NULL;
303
304
	(void)strlcpy(buffer, type, sizeof buffer);
305
	(void)strlcat(buffer, ":", sizeof buffer);
306
	if (strlcat(buffer, value, sizeof buffer) >= sizeof buffer)
307
		return NULL;
308
309
	(void)snprintf(tmp, sizeof(tmp), "[parent=%p", e->parent);
310
	if (strlcat(buffer, tmp, sizeof buffer) >= sizeof buffer)
311
		return NULL;
312
313
	if (e->mapping) {
314
		(void)strlcat(buffer, ", mapping=", sizeof buffer);
315
		(void)strlcat(buffer, e->mapping->t_name, sizeof buffer);
316
	}
317
318
	if (e->userbase) {
319
		(void)strlcat(buffer, ", userbase=", sizeof buffer);
320
		(void)strlcat(buffer, e->userbase->t_name, sizeof buffer);
321
	}
322
323
	if (strlcat(buffer, "]", sizeof buffer) >= sizeof buffer)
324
		return NULL;
325
326
	return buffer;
327
}
328
329
RB_GENERATE(expandtree, expandnode, entry, expand_cmp);