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