xref: /openbsd/usr.sbin/smtpd/table_static.c (revision b7b75d53)
1 /*	$OpenBSD: table_static.c,v 1.17 2017/08/29 07:37:11 eric Exp $	*/
2 
3 /*
4  * Copyright (c) 2013 Eric Faurot <eric@openbsd.org>
5  * Copyright (c) 2012 Gilles Chehade <gilles@poolp.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 <netinet/in.h>
26 #include <arpa/inet.h>
27 
28 #include <ctype.h>
29 #include <err.h>
30 #include <event.h>
31 #include <fcntl.h>
32 #include <imsg.h>
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <limits.h>
36 #include <string.h>
37 
38 #include "smtpd.h"
39 #include "log.h"
40 
41 /* static backend */
42 static int table_static_config(struct table *);
43 static int table_static_update(struct table *);
44 static void *table_static_open(struct table *);
45 static int table_static_lookup(void *, struct dict *, const char *,
46     enum table_service, union lookup *);
47 static int table_static_fetch(void *, struct dict *, enum table_service,
48     union lookup *);
49 static void  table_static_close(void *);
50 
51 struct table_backend table_backend_static = {
52 	K_ALIAS|K_CREDENTIALS|K_DOMAIN|K_NETADDR|K_USERINFO|
53 	K_SOURCE|K_MAILADDR|K_ADDRNAME|K_MAILADDRMAP,
54 	table_static_config,
55 	table_static_open,
56 	table_static_update,
57 	table_static_close,
58 	table_static_lookup,
59 	table_static_fetch
60 };
61 
62 static struct keycmp {
63 	enum table_service	service;
64 	int		       (*func)(const char *, const char *);
65 } keycmp[] = {
66 	{ K_DOMAIN, table_domain_match },
67 	{ K_NETADDR, table_netaddr_match },
68 	{ K_MAILADDR, table_mailaddr_match }
69 };
70 
71 
72 static int
73 table_static_config(struct table *t)
74 {
75 	FILE	*fp;
76 	char	*buf = NULL, *p;
77 	int	 lineno = 0;
78 	size_t	 sz = 0;
79 	ssize_t	 flen;
80 	char	*keyp;
81 	char	*valp;
82 	size_t	 ret = 0;
83 
84 	/* no config ? ok */
85 	if (*t->t_config == '\0')
86 		return 1;
87 
88 	if ((fp = fopen(t->t_config, "r")) == NULL) {
89 		log_warn("warn: Table \"%s\"", t->t_config);
90 		return 0;
91 	}
92 
93 	while ((flen = getline(&buf, &sz, fp)) != -1) {
94 		lineno++;
95 		if (buf[flen - 1] == '\n')
96 			buf[--flen] = '\0';
97 
98 		keyp = buf;
99 		while (isspace((unsigned char)*keyp)) {
100 			++keyp;
101 			--flen;
102 		}
103 		if (*keyp == '\0')
104 			continue;
105 		while (isspace((unsigned char)keyp[flen - 1]))
106 			keyp[--flen] = '\0';
107 		if (*keyp == '#') {
108 			if (t->t_type == T_NONE) {
109 				keyp++;
110 				while (isspace((unsigned char)*keyp))
111 					++keyp;
112 				if (!strcmp(keyp, "@list"))
113 					t->t_type = T_LIST;
114 			}
115 			continue;
116 		}
117 
118 		if (t->t_type == T_NONE) {
119 			for (p = keyp; *p; p++) {
120 				if (*p == ' ' || *p == '\t' || *p == ':') {
121 					t->t_type = T_HASH;
122 					break;
123 				}
124 			}
125 			if (t->t_type == T_NONE)
126 				t->t_type = T_LIST;
127 		}
128 
129 		if (t->t_type == T_LIST) {
130 			table_add(t, keyp, NULL);
131 			continue;
132 		}
133 
134 		/* T_HASH */
135 		valp = keyp;
136 		strsep(&valp, " \t:");
137 		if (valp) {
138 			while (*valp) {
139 				if (!isspace((unsigned char)*valp) &&
140 				    !(*valp == ':' &&
141 				    isspace((unsigned char)*(valp + 1))))
142 					break;
143 				++valp;
144 			}
145 			if (*valp == '\0')
146 				valp = NULL;
147 		}
148 		if (valp == NULL) {
149 			log_warnx("%s: invalid map entry line %d", t->t_config,
150 			    lineno);
151 			goto end;
152 		}
153 
154 		table_add(t, keyp, valp);
155 	}
156 
157 	if (ferror(fp)) {
158 		log_warn("%s: getline", t->t_config);
159 		goto end;
160 	}
161 
162 	/* Accept empty alias files; treat them as hashes */
163 	if (t->t_type == T_NONE && t->t_backend->services & K_ALIAS)
164 	    t->t_type = T_HASH;
165 
166 	ret = 1;
167 end:
168 	free(buf);
169 	fclose(fp);
170 	return ret;
171 }
172 
173 static int
174 table_static_update(struct table *table)
175 {
176 	struct table	*t;
177 	void		*p = NULL;
178 
179 	/* no config ? ok */
180 	if (table->t_config[0] == '\0')
181 		goto ok;
182 
183 	t = table_create("static", table->t_name, "update", table->t_config);
184 	if (!table_config(t))
185 		goto err;
186 
187 	/* replace former table, frees t */
188 	while (dict_poproot(&table->t_dict, (void **)&p))
189 		free(p);
190 	dict_merge(&table->t_dict, &t->t_dict);
191 	table_destroy(t);
192 
193 ok:
194 	log_info("info: Table \"%s\" successfully updated", table->t_name);
195 	return 1;
196 
197 err:
198 	table_destroy(t);
199 	log_info("info: Failed to update table \"%s\"", table->t_name);
200 	return 0;
201 }
202 
203 static void *
204 table_static_open(struct table *table)
205 {
206 	return table;
207 }
208 
209 static void
210 table_static_close(void *hdl)
211 {
212 	return;
213 }
214 
215 static int
216 table_static_lookup(void *hdl, struct dict *params, const char *key,
217     enum table_service service, union lookup *lk)
218 {
219 	struct table   *m  = hdl;
220 	char	       *line;
221 	int		ret;
222 	int	       (*match)(const char *, const char *) = NULL;
223 	size_t		i;
224 	void	       *iter;
225 	const char     *k;
226 	char	       *v;
227 
228 	for (i = 0; i < nitems(keycmp); ++i)
229 		if (keycmp[i].service == service)
230 			match = keycmp[i].func;
231 
232 	line = NULL;
233 	iter = NULL;
234 	ret = 0;
235 	while (dict_iter(&m->t_dict, &iter, &k, (void **)&v)) {
236 		if (match) {
237 			if (match(key, k)) {
238 				line = v;
239 				ret = 1;
240 			}
241 		}
242 		else {
243 			if (strcmp(key, k) == 0) {
244 				line = v;
245 				ret = 1;
246 			}
247 		}
248 		if (ret)
249 			break;
250 	}
251 
252 	if (lk == NULL)
253 		return ret ? 1 : 0;
254 
255 	if (ret == 0)
256 		return 0;
257 
258 	return table_parse_lookup(service, key, line, lk);
259 }
260 
261 static int
262 table_static_fetch(void *hdl, struct dict *params,
263     enum table_service service, union lookup *lk)
264 {
265 	struct table   *t = hdl;
266 	const char     *k;
267 
268 	if (!dict_iter(&t->t_dict, &t->t_iter, &k, (void **)NULL)) {
269 		t->t_iter = NULL;
270 		if (!dict_iter(&t->t_dict, &t->t_iter, &k, (void **)NULL))
271 			return 0;
272 	}
273 
274 	if (lk == NULL)
275 		return 1;
276 
277 	return table_parse_lookup(service, NULL, k, lk);
278 }
279