xref: /openbsd/usr.sbin/smtpd/table_static.c (revision 299c4efe)
1*299c4efeSeric /*	$OpenBSD: table_static.c,v 1.5 2013/05/24 17:03:14 eric Exp $	*/
265c4fdfbSgilles 
365c4fdfbSgilles /*
4*299c4efeSeric  * Copyright (c) 2013 Eric Faurot <eric@openbsd.org>
565c4fdfbSgilles  * Copyright (c) 2012 Gilles Chehade <gilles@poolp.org>
665c4fdfbSgilles  *
765c4fdfbSgilles  * Permission to use, copy, modify, and distribute this software for any
865c4fdfbSgilles  * purpose with or without fee is hereby granted, provided that the above
965c4fdfbSgilles  * copyright notice and this permission notice appear in all copies.
1065c4fdfbSgilles  *
1165c4fdfbSgilles  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1265c4fdfbSgilles  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1365c4fdfbSgilles  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1465c4fdfbSgilles  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1565c4fdfbSgilles  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1665c4fdfbSgilles  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1765c4fdfbSgilles  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1865c4fdfbSgilles  */
1965c4fdfbSgilles 
2065c4fdfbSgilles #include <sys/types.h>
2165c4fdfbSgilles #include <sys/queue.h>
2265c4fdfbSgilles #include <sys/tree.h>
2365c4fdfbSgilles #include <sys/socket.h>
2465c4fdfbSgilles 
2565c4fdfbSgilles #include <netinet/in.h>
2665c4fdfbSgilles #include <arpa/inet.h>
2765c4fdfbSgilles 
2865c4fdfbSgilles #include <ctype.h>
2965c4fdfbSgilles #include <err.h>
3065c4fdfbSgilles #include <event.h>
3165c4fdfbSgilles #include <fcntl.h>
3265c4fdfbSgilles #include <imsg.h>
3365c4fdfbSgilles #include <stdio.h>
3465c4fdfbSgilles #include <stdlib.h>
3565c4fdfbSgilles #include <string.h>
3665c4fdfbSgilles 
3765c4fdfbSgilles #include "smtpd.h"
3865c4fdfbSgilles #include "log.h"
3965c4fdfbSgilles 
4065c4fdfbSgilles /* static backend */
41*299c4efeSeric static int table_static_config(struct table *);
4265c4fdfbSgilles static int table_static_update(struct table *);
4365c4fdfbSgilles static void *table_static_open(struct table *);
4465c4fdfbSgilles static int table_static_lookup(void *, const char *, enum table_service,
45*299c4efeSeric     union lookup *);
46*299c4efeSeric static int table_static_fetch(void *, enum table_service, union lookup *);
4765c4fdfbSgilles static void  table_static_close(void *);
48*299c4efeSeric static int table_static_parse(struct table *, const char *, enum table_type);
4965c4fdfbSgilles 
5065c4fdfbSgilles struct table_backend table_backend_static = {
5165c4fdfbSgilles 	K_ALIAS|K_CREDENTIALS|K_DOMAIN|K_NETADDR|K_USERINFO|K_SOURCE|K_MAILADDR|K_ADDRNAME,
5265c4fdfbSgilles 	table_static_config,
5365c4fdfbSgilles 	table_static_open,
5465c4fdfbSgilles 	table_static_update,
5565c4fdfbSgilles 	table_static_close,
5665c4fdfbSgilles 	table_static_lookup,
5765c4fdfbSgilles 	table_static_fetch
5865c4fdfbSgilles };
5965c4fdfbSgilles 
6065c4fdfbSgilles static struct keycmp {
6165c4fdfbSgilles 	enum table_service	service;
6265c4fdfbSgilles 	int		       (*func)(const char *, const char *);
6365c4fdfbSgilles } keycmp[] = {
6465c4fdfbSgilles 	{ K_DOMAIN, table_domain_match },
6565c4fdfbSgilles 	{ K_NETADDR, table_netaddr_match },
6665c4fdfbSgilles 	{ K_MAILADDR, table_mailaddr_match }
6765c4fdfbSgilles };
6865c4fdfbSgilles 
6965c4fdfbSgilles 
7065c4fdfbSgilles static int
71*299c4efeSeric table_static_config(struct table *table)
7265c4fdfbSgilles {
7365c4fdfbSgilles 	/* no config ? ok */
74*299c4efeSeric 	if (*table->t_config == '\0')
7565c4fdfbSgilles 		return 1;
7665c4fdfbSgilles 
77*299c4efeSeric 	return table_static_parse(table, table->t_config, T_LIST|T_HASH);
78*299c4efeSeric }
79*299c4efeSeric 
80*299c4efeSeric static int
81*299c4efeSeric table_static_parse(struct table *t, const char *config, enum table_type type)
82*299c4efeSeric {
83*299c4efeSeric 	FILE	*fp;
84*299c4efeSeric 	char	*buf, *lbuf;
85*299c4efeSeric 	size_t	 flen;
86*299c4efeSeric 	char	*keyp;
87*299c4efeSeric 	char	*valp;
88*299c4efeSeric 	size_t	 ret = 0;
89*299c4efeSeric 
90*299c4efeSeric 	fp = fopen(config, "r");
91*299c4efeSeric 	if (fp == NULL)
92*299c4efeSeric 		return 0;
93*299c4efeSeric 
94*299c4efeSeric 	lbuf = NULL;
95*299c4efeSeric 	while ((buf = fgetln(fp, &flen))) {
96*299c4efeSeric 		if (buf[flen - 1] == '\n')
97*299c4efeSeric 			buf[flen - 1] = '\0';
98*299c4efeSeric 		else {
99*299c4efeSeric 			lbuf = xmalloc(flen + 1, "table_config_parse");
100*299c4efeSeric 			memcpy(lbuf, buf, flen);
101*299c4efeSeric 			lbuf[flen] = '\0';
102*299c4efeSeric 			buf = lbuf;
103*299c4efeSeric 		}
104*299c4efeSeric 
105*299c4efeSeric 		keyp = buf;
106*299c4efeSeric 		while (isspace((int)*keyp))
107*299c4efeSeric 			++keyp;
108*299c4efeSeric 		if (*keyp == '\0' || *keyp == '#')
109*299c4efeSeric 			continue;
110*299c4efeSeric 		valp = keyp;
111*299c4efeSeric 		strsep(&valp, " \t:");
112*299c4efeSeric 		if (valp) {
113*299c4efeSeric 			while (*valp) {
114*299c4efeSeric 				if (!isspace(*valp) &&
115*299c4efeSeric 				    !(*valp == ':' && isspace(*(valp + 1))))
116*299c4efeSeric 					break;
117*299c4efeSeric 				++valp;
118*299c4efeSeric 			}
119*299c4efeSeric 			if (*valp == '\0')
120*299c4efeSeric 				valp = NULL;
121*299c4efeSeric 		}
122*299c4efeSeric 
123*299c4efeSeric 		/**/
124*299c4efeSeric 		if (t->t_type == 0)
125*299c4efeSeric 			t->t_type = (valp == keyp || valp == NULL) ? T_LIST :
126*299c4efeSeric 			    T_HASH;
127*299c4efeSeric 
128*299c4efeSeric 		if (!(t->t_type & type))
129*299c4efeSeric 			goto end;
130*299c4efeSeric 
131*299c4efeSeric 		if ((valp == keyp || valp == NULL) && t->t_type == T_LIST)
132*299c4efeSeric 			table_add(t, keyp, NULL);
133*299c4efeSeric 		else if ((valp != keyp && valp != NULL) && t->t_type == T_HASH)
134*299c4efeSeric 			table_add(t, keyp, valp);
135*299c4efeSeric 		else
136*299c4efeSeric 			goto end;
137*299c4efeSeric 	}
138*299c4efeSeric 	ret = 1;
139*299c4efeSeric end:
140*299c4efeSeric 	free(lbuf);
141*299c4efeSeric 	fclose(fp);
142*299c4efeSeric 	return ret;
14365c4fdfbSgilles }
14465c4fdfbSgilles 
14565c4fdfbSgilles static int
14665c4fdfbSgilles table_static_update(struct table *table)
14765c4fdfbSgilles {
14865c4fdfbSgilles 	struct table	*t;
149*299c4efeSeric 	void		*p = NULL;
15065c4fdfbSgilles 
15165c4fdfbSgilles 	/* no config ? ok */
15265c4fdfbSgilles 	if (table->t_config[0] == '\0')
15365c4fdfbSgilles 		goto ok;
15465c4fdfbSgilles 
155*299c4efeSeric 	t = table_create("static", table->t_name, "update", table->t_config);
156*299c4efeSeric 	if (!table_config(t))
15765c4fdfbSgilles 		goto err;
15865c4fdfbSgilles 
159dd047c3bSgilles 	/* replace former table, frees t */
160*299c4efeSeric 	while (dict_poproot(&table->t_dict, NULL, (void **)&p))
161*299c4efeSeric 		free(p);
162*299c4efeSeric 	dict_merge(&table->t_dict, &t->t_dict);
163*299c4efeSeric 	table_destroy(t);
16465c4fdfbSgilles 
16565c4fdfbSgilles ok:
166dd047c3bSgilles 	log_info("info: Table \"%s\" successfully updated", table->t_name);
16765c4fdfbSgilles 	return 1;
16865c4fdfbSgilles 
16965c4fdfbSgilles err:
17065c4fdfbSgilles 	table_destroy(t);
171dd047c3bSgilles 	log_info("info: Failed to update table \"%s\"", table->t_name);
17265c4fdfbSgilles 	return 0;
17365c4fdfbSgilles }
17465c4fdfbSgilles 
17565c4fdfbSgilles static void *
17665c4fdfbSgilles table_static_open(struct table *table)
17765c4fdfbSgilles {
17865c4fdfbSgilles 	return table;
17965c4fdfbSgilles }
18065c4fdfbSgilles 
18165c4fdfbSgilles static void
18265c4fdfbSgilles table_static_close(void *hdl)
18365c4fdfbSgilles {
18465c4fdfbSgilles 	return;
18565c4fdfbSgilles }
18665c4fdfbSgilles 
18765c4fdfbSgilles static int
18865c4fdfbSgilles table_static_lookup(void *hdl, const char *key, enum table_service service,
189*299c4efeSeric     union lookup *lk)
19065c4fdfbSgilles {
19165c4fdfbSgilles 	struct table   *m  = hdl;
19265c4fdfbSgilles 	char	       *line;
19365c4fdfbSgilles 	int		ret;
19465c4fdfbSgilles 	int	       (*match)(const char *, const char *) = NULL;
19565c4fdfbSgilles 	size_t		i;
19665c4fdfbSgilles 	void	       *iter;
19765c4fdfbSgilles 	const char     *k;
19865c4fdfbSgilles 	char	       *v;
19965c4fdfbSgilles 
20065c4fdfbSgilles 	for (i = 0; i < nitems(keycmp); ++i)
20165c4fdfbSgilles 		if (keycmp[i].service == service)
20265c4fdfbSgilles 			match = keycmp[i].func;
20365c4fdfbSgilles 
20465c4fdfbSgilles 	line = NULL;
20565c4fdfbSgilles 	iter = NULL;
20665c4fdfbSgilles 	ret = 0;
20765c4fdfbSgilles 	while (dict_iter(&m->t_dict, &iter, &k, (void **)&v)) {
20865c4fdfbSgilles 		if (match) {
20965c4fdfbSgilles 			if (match(key, k)) {
21065c4fdfbSgilles 				line = v;
21165c4fdfbSgilles 				ret = 1;
21265c4fdfbSgilles 			}
21365c4fdfbSgilles 		}
21465c4fdfbSgilles 		else {
21565c4fdfbSgilles 			if (strcmp(key, k) == 0) {
21665c4fdfbSgilles 				line = v;
21765c4fdfbSgilles 				ret = 1;
21865c4fdfbSgilles 			}
21965c4fdfbSgilles 		}
22065c4fdfbSgilles 		if (ret)
22165c4fdfbSgilles 			break;
22265c4fdfbSgilles 	}
22365c4fdfbSgilles 
224*299c4efeSeric 	if (lk == NULL)
22565c4fdfbSgilles 		return ret ? 1 : 0;
22665c4fdfbSgilles 
227*299c4efeSeric 	if (ret == 0)
22865c4fdfbSgilles 		return 0;
22965c4fdfbSgilles 
230*299c4efeSeric 	return table_parse_lookup(service, key, line, lk);
23165c4fdfbSgilles }
23265c4fdfbSgilles 
23365c4fdfbSgilles static int
234*299c4efeSeric table_static_fetch(void *hdl, enum table_service service, union lookup *lk)
23565c4fdfbSgilles {
23665c4fdfbSgilles 	struct table   *t = hdl;
23765c4fdfbSgilles 	const char     *k;
23865c4fdfbSgilles 
23965c4fdfbSgilles 	if (! dict_iter(&t->t_dict, &t->t_iter, &k, (void **)NULL)) {
24065c4fdfbSgilles 		t->t_iter = NULL;
24165c4fdfbSgilles 		if (! dict_iter(&t->t_dict, &t->t_iter, &k, (void **)NULL))
24265c4fdfbSgilles 			return 0;
24365c4fdfbSgilles 	}
24465c4fdfbSgilles 
245*299c4efeSeric 	if (lk == NULL)
24665c4fdfbSgilles 		return 1;
24765c4fdfbSgilles 
248*299c4efeSeric 	return table_parse_lookup(service, NULL, k, lk);
24965c4fdfbSgilles }
250