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