xref: /openbsd/usr.sbin/smtpd/table.c (revision 09467b48)
1 /*	$OpenBSD: table.c,v 1.48 2019/01/10 07:40:52 eric Exp $	*/
2 
3 /*
4  * Copyright (c) 2013 Eric Faurot <eric@openbsd.org>
5  * Copyright (c) 2008 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 #include <sys/stat.h>
25 
26 #include <netinet/in.h>
27 #include <arpa/inet.h>
28 #include <net/if.h>
29 
30 #include <errno.h>
31 #include <event.h>
32 #include <imsg.h>
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <regex.h>
36 #include <limits.h>
37 #include <string.h>
38 #include <unistd.h>
39 
40 #include "smtpd.h"
41 #include "log.h"
42 
43 struct table_backend *table_backend_lookup(const char *);
44 
45 extern struct table_backend table_backend_static;
46 extern struct table_backend table_backend_db;
47 extern struct table_backend table_backend_getpwnam;
48 extern struct table_backend table_backend_proc;
49 
50 static const char * table_service_name(enum table_service);
51 static int table_parse_lookup(enum table_service, const char *, const char *,
52     union lookup *);
53 static int parse_sockaddr(struct sockaddr *, int, const char *);
54 
55 static unsigned int last_table_id = 0;
56 
57 static struct table_backend *backends[] = {
58 	&table_backend_static,
59 	&table_backend_db,
60 	&table_backend_getpwnam,
61 	&table_backend_proc,
62 	NULL
63 };
64 
65 struct table_backend *
66 table_backend_lookup(const char *backend)
67 {
68 	int i;
69 
70 	if (!strcmp(backend, "file"))
71 		backend = "static";
72 
73 	for (i = 0; backends[i]; i++)
74 		if (!strcmp(backends[i]->name, backend))
75 			return (backends[i]);
76 
77 	return NULL;
78 }
79 
80 static const char *
81 table_service_name(enum table_service s)
82 {
83 	switch (s) {
84 	case K_NONE:		return "NONE";
85 	case K_ALIAS:		return "ALIAS";
86 	case K_DOMAIN:		return "DOMAIN";
87 	case K_CREDENTIALS:	return "CREDENTIALS";
88 	case K_NETADDR:		return "NETADDR";
89 	case K_USERINFO:	return "USERINFO";
90 	case K_SOURCE:		return "SOURCE";
91 	case K_MAILADDR:	return "MAILADDR";
92 	case K_ADDRNAME:	return "ADDRNAME";
93 	case K_MAILADDRMAP:	return "MAILADDRMAP";
94 	case K_RELAYHOST:	return "RELAYHOST";
95 	case K_STRING:		return "STRING";
96 	case K_REGEX:		return "REGEX";
97 	}
98 	return "???";
99 }
100 
101 struct table *
102 table_find(struct smtpd *conf, const char *name)
103 {
104 	return dict_get(conf->sc_tables_dict, name);
105 }
106 
107 int
108 table_match(struct table *table, enum table_service kind, const char *key)
109 {
110 	return table_lookup(table, kind, key, NULL);
111 }
112 
113 int
114 table_lookup(struct table *table, enum table_service kind, const char *key,
115     union lookup *lk)
116 {
117 	char lkey[1024], *buf = NULL;
118 	int r;
119 
120 	r = -1;
121 	if (table->t_backend->lookup == NULL)
122 		errno = ENOTSUP;
123 	else if (!lowercase(lkey, key, sizeof lkey)) {
124 		log_warnx("warn: lookup key too long: %s", key);
125 		errno = EINVAL;
126 	}
127 	else
128 		r = table->t_backend->lookup(table, kind, lkey, lk ? &buf : NULL);
129 
130 	if (r == 1) {
131 		log_trace(TRACE_LOOKUP, "lookup: %s \"%s\" as %s in table %s:%s -> %s%s%s",
132 		    lk ? "lookup" : "match",
133 		    key,
134 		    table_service_name(kind),
135 		    table->t_backend->name,
136 		    table->t_name,
137 		    lk ? "\"" : "",
138 		    lk ? buf : "true",
139 		    lk ? "\"" : "");
140 		if (buf)
141 			r = table_parse_lookup(kind, lkey, buf, lk);
142 	}
143 	else
144 		log_trace(TRACE_LOOKUP, "lookup: %s \"%s\" as %s in table %s:%s -> %s%s",
145 		    lk ? "lookup" : "match",
146 		    key,
147 		    table_service_name(kind),
148 		    table->t_backend->name,
149 		    table->t_name,
150 		    (r == -1) ? "error: " : (lk ? "none" : "false"),
151 		    (r == -1) ? strerror(errno) : "");
152 
153 	free(buf);
154 
155 	return (r);
156 }
157 
158 int
159 table_fetch(struct table *table, enum table_service kind, union lookup *lk)
160 {
161 	char *buf = NULL;
162 	int r;
163 
164 	r = -1;
165 	if (table->t_backend->fetch == NULL)
166 		errno = ENOTSUP;
167 	else
168 		r = table->t_backend->fetch(table, kind, &buf);
169 
170 	if (r == 1) {
171 		log_trace(TRACE_LOOKUP, "lookup: fetch %s from table %s:%s -> \"%s\"",
172 		    table_service_name(kind),
173 		    table->t_backend->name,
174 		    table->t_name,
175 		    buf);
176 		r = table_parse_lookup(kind, NULL, buf, lk);
177 	}
178 	else
179 		log_trace(TRACE_LOOKUP, "lookup: fetch %s from table %s:%s -> %s%s",
180 		    table_service_name(kind),
181 		    table->t_backend->name,
182 		    table->t_name,
183 		    (r == -1) ? "error: " : "none",
184 		    (r == -1) ? strerror(errno) : "");
185 
186 	free(buf);
187 
188 	return (r);
189 }
190 
191 struct table *
192 table_create(struct smtpd *conf, const char *backend, const char *name,
193     const char *config)
194 {
195 	struct table		*t;
196 	struct table_backend	*tb;
197 	char			 path[LINE_MAX];
198 	size_t			 n;
199 	struct stat		 sb;
200 
201 	if (name && table_find(conf, name))
202 		fatalx("table_create: table \"%s\" already defined", name);
203 
204 	if ((tb = table_backend_lookup(backend)) == NULL) {
205 		if ((size_t)snprintf(path, sizeof(path), PATH_LIBEXEC"/table-%s",
206 			backend) >= sizeof(path)) {
207 			fatalx("table_create: path too long \""
208 			    PATH_LIBEXEC"/table-%s\"", backend);
209 		}
210 		if (stat(path, &sb) == 0) {
211 			tb = table_backend_lookup("proc");
212 			(void)strlcpy(path, backend, sizeof(path));
213 			if (config) {
214 				(void)strlcat(path, ":", sizeof(path));
215 				if (strlcat(path, config, sizeof(path))
216 				    >= sizeof(path))
217 					fatalx("table_create: config file path too long");
218 			}
219 			config = path;
220 		}
221 	}
222 
223 	if (tb == NULL)
224 		fatalx("table_create: backend \"%s\" does not exist", backend);
225 
226 	t = xcalloc(1, sizeof(*t));
227 	t->t_backend = tb;
228 
229 	if (config) {
230 		if (strlcpy(t->t_config, config, sizeof t->t_config)
231 		    >= sizeof t->t_config)
232 			fatalx("table_create: table config \"%s\" too large",
233 			    t->t_config);
234 	}
235 
236 	if (strcmp(tb->name, "static") != 0)
237 		t->t_type = T_DYNAMIC;
238 
239 	if (name == NULL)
240 		(void)snprintf(t->t_name, sizeof(t->t_name), "<dynamic:%u>",
241 		    last_table_id++);
242 	else {
243 		n = strlcpy(t->t_name, name, sizeof(t->t_name));
244 		if (n >= sizeof(t->t_name))
245 			fatalx("table_create: table name too long");
246 	}
247 
248 	dict_set(conf->sc_tables_dict, t->t_name, t);
249 
250 	return (t);
251 }
252 
253 void
254 table_destroy(struct smtpd *conf, struct table *t)
255 {
256 	dict_xpop(conf->sc_tables_dict, t->t_name);
257 	free(t);
258 }
259 
260 int
261 table_config(struct table *t)
262 {
263 	if (t->t_backend->config == NULL)
264 		return (1);
265 	return (t->t_backend->config(t));
266 }
267 
268 void
269 table_add(struct table *t, const char *key, const char *val)
270 {
271 	if (t->t_backend->add == NULL)
272 		fatalx("table_add: cannot add to table");
273 
274 	if (t->t_backend->add(t, key, val) == 0)
275 		log_warnx("warn: failed to add \"%s\" in table \"%s\"", key, t->t_name);
276 }
277 
278 void
279 table_dump(struct table *t)
280 {
281 	const char *type;
282 	char buf[LINE_MAX];
283 
284 	switch(t->t_type) {
285 	case T_NONE:
286 		type = "NONE";
287 		break;
288 	case T_DYNAMIC:
289 		type = "DYNAMIC";
290 		break;
291 	case T_LIST:
292 		type = "LIST";
293 		break;
294 	case T_HASH:
295 		type = "HASH";
296 		break;
297 	default:
298 		type = "???";
299 		break;
300 	}
301 
302 	if (t->t_config[0])
303 		snprintf(buf, sizeof(buf), " config=\"%s\"", t->t_config);
304 	else
305 		buf[0] = '\0';
306 
307 	log_debug("TABLE \"%s\" backend=%s type=%s%s", t->t_name,
308 	    t->t_backend->name, type, buf);
309 
310 	if (t->t_backend->dump)
311 		t->t_backend->dump(t);
312 }
313 
314 int
315 table_check_type(struct table *t, uint32_t mask)
316 {
317 	return t->t_type & mask;
318 }
319 
320 int
321 table_check_service(struct table *t, uint32_t mask)
322 {
323 	return t->t_backend->services & mask;
324 }
325 
326 int
327 table_check_use(struct table *t, uint32_t tmask, uint32_t smask)
328 {
329 	return table_check_type(t, tmask) && table_check_service(t, smask);
330 }
331 
332 int
333 table_open(struct table *t)
334 {
335 	if (t->t_backend->open == NULL)
336 		return (1);
337 	return (t->t_backend->open(t));
338 }
339 
340 void
341 table_close(struct table *t)
342 {
343 	if (t->t_backend->close)
344 		t->t_backend->close(t);
345 }
346 
347 int
348 table_update(struct table *t)
349 {
350 	if (t->t_backend->update == NULL)
351 		return (1);
352 	return (t->t_backend->update(t));
353 }
354 
355 
356 /*
357  * quick reminder:
358  * in *_match() s1 comes from session, s2 comes from table
359  */
360 
361 int
362 table_domain_match(const char *s1, const char *s2)
363 {
364 	return hostname_match(s1, s2);
365 }
366 
367 int
368 table_mailaddr_match(const char *s1, const char *s2)
369 {
370 	struct mailaddr m1;
371 	struct mailaddr m2;
372 
373 	if (!text_to_mailaddr(&m1, s1))
374 		return 0;
375 	if (!text_to_mailaddr(&m2, s2))
376 		return 0;
377 	return mailaddr_match(&m1, &m2);
378 }
379 
380 static int table_match_mask(struct sockaddr_storage *, struct netaddr *);
381 static int table_inet4_match(struct sockaddr_in *, struct netaddr *);
382 static int table_inet6_match(struct sockaddr_in6 *, struct netaddr *);
383 
384 int
385 table_netaddr_match(const char *s1, const char *s2)
386 {
387 	struct netaddr n1;
388 	struct netaddr n2;
389 
390 	if (strcasecmp(s1, s2) == 0)
391 		return 1;
392 	if (!text_to_netaddr(&n1, s1))
393 		return 0;
394 	if (!text_to_netaddr(&n2, s2))
395 		return 0;
396 	if (n1.ss.ss_family != n2.ss.ss_family)
397 		return 0;
398 	if (n1.ss.ss_len != n2.ss.ss_len)
399 		return 0;
400 	return table_match_mask(&n1.ss, &n2);
401 }
402 
403 static int
404 table_match_mask(struct sockaddr_storage *ss, struct netaddr *ssmask)
405 {
406 	if (ss->ss_family == AF_INET)
407 		return table_inet4_match((struct sockaddr_in *)ss, ssmask);
408 
409 	if (ss->ss_family == AF_INET6)
410 		return table_inet6_match((struct sockaddr_in6 *)ss, ssmask);
411 
412 	return (0);
413 }
414 
415 static int
416 table_inet4_match(struct sockaddr_in *ss, struct netaddr *ssmask)
417 {
418 	in_addr_t mask;
419 	int i;
420 
421 	/* a.b.c.d/8 -> htonl(0xff000000) */
422 	mask = 0;
423 	for (i = 0; i < ssmask->bits; ++i)
424 		mask = (mask >> 1) | 0x80000000;
425 	mask = htonl(mask);
426 
427 	/* (addr & mask) == (net & mask) */
428 	if ((ss->sin_addr.s_addr & mask) ==
429 	    (((struct sockaddr_in *)ssmask)->sin_addr.s_addr & mask))
430 		return 1;
431 
432 	return 0;
433 }
434 
435 static int
436 table_inet6_match(struct sockaddr_in6 *ss, struct netaddr *ssmask)
437 {
438 	struct in6_addr	*in;
439 	struct in6_addr	*inmask;
440 	struct in6_addr	 mask;
441 	int		 i;
442 
443 	memset(&mask, 0, sizeof(mask));
444 	for (i = 0; i < ssmask->bits / 8; i++)
445 		mask.s6_addr[i] = 0xff;
446 	i = ssmask->bits % 8;
447 	if (i)
448 		mask.s6_addr[ssmask->bits / 8] = 0xff00 >> i;
449 
450 	in = &ss->sin6_addr;
451 	inmask = &((struct sockaddr_in6 *)&ssmask->ss)->sin6_addr;
452 
453 	for (i = 0; i < 16; i++) {
454 		if ((in->s6_addr[i] & mask.s6_addr[i]) !=
455 		    (inmask->s6_addr[i] & mask.s6_addr[i]))
456 			return (0);
457 	}
458 
459 	return (1);
460 }
461 
462 int
463 table_regex_match(const char *string, const char *pattern)
464 {
465 	regex_t preg;
466 	int	cflags = REG_EXTENDED|REG_NOSUB;
467 
468 	if (strncmp(pattern, "(?i)", 4) == 0) {
469 		cflags |= REG_ICASE;
470 		pattern += 4;
471 	}
472 
473 	if (regcomp(&preg, pattern, cflags) != 0)
474 		return (0);
475 
476 	if (regexec(&preg, string, 0, NULL, 0) != 0)
477 		return (0);
478 
479 	return (1);
480 }
481 
482 void
483 table_dump_all(struct smtpd *conf)
484 {
485 	struct table	*t;
486 	void		*iter;
487 
488 	iter = NULL;
489 	while (dict_iter(conf->sc_tables_dict, &iter, NULL, (void **)&t))
490 		table_dump(t);
491 }
492 
493 void
494 table_open_all(struct smtpd *conf)
495 {
496 	struct table	*t;
497 	void		*iter;
498 
499 	iter = NULL;
500 	while (dict_iter(conf->sc_tables_dict, &iter, NULL, (void **)&t))
501 		if (!table_open(t))
502 			fatalx("failed to open table %s", t->t_name);
503 }
504 
505 void
506 table_close_all(struct smtpd *conf)
507 {
508 	struct table	*t;
509 	void		*iter;
510 
511 	iter = NULL;
512 	while (dict_iter(conf->sc_tables_dict, &iter, NULL, (void **)&t))
513 		table_close(t);
514 }
515 
516 static int
517 table_parse_lookup(enum table_service service, const char *key,
518     const char *line, union lookup *lk)
519 {
520 	char	buffer[LINE_MAX], *p;
521 	size_t	len;
522 
523 	len = strlen(line);
524 
525 	switch (service) {
526 	case K_ALIAS:
527 		lk->expand = calloc(1, sizeof(*lk->expand));
528 		if (lk->expand == NULL)
529 			return (-1);
530 		if (!expand_line(lk->expand, line, 1)) {
531 			expand_free(lk->expand);
532 			return (-1);
533 		}
534 		return (1);
535 
536 	case K_DOMAIN:
537 		if (strlcpy(lk->domain.name, line, sizeof(lk->domain.name))
538 		    >= sizeof(lk->domain.name))
539 			return (-1);
540 		return (1);
541 
542 	case K_CREDENTIALS:
543 
544 		/* credentials are stored as user:password */
545 		if (len < 3)
546 			return (-1);
547 
548 		/* too big to fit in a smtp session line */
549 		if (len >= LINE_MAX)
550 			return (-1);
551 
552 		p = strchr(line, ':');
553 		if (p == NULL) {
554 			if (strlcpy(lk->creds.username, key, sizeof (lk->creds.username))
555 			    >= sizeof (lk->creds.username))
556 				return (-1);
557 			if (strlcpy(lk->creds.password, line, sizeof(lk->creds.password))
558 			    >= sizeof(lk->creds.password))
559 				return (-1);
560 			return (1);
561 		}
562 
563 		if (p == line || p == line + len - 1)
564 			return (-1);
565 
566 		memmove(lk->creds.username, line, p - line);
567 		lk->creds.username[p - line] = '\0';
568 
569 		if (strlcpy(lk->creds.password, p+1, sizeof(lk->creds.password))
570 		    >= sizeof(lk->creds.password))
571 			return (-1);
572 
573 		return (1);
574 
575 	case K_NETADDR:
576 		if (!text_to_netaddr(&lk->netaddr, line))
577 			return (-1);
578 		return (1);
579 
580 	case K_USERINFO:
581 		if (!bsnprintf(buffer, sizeof(buffer), "%s:%s", key, line))
582 			return (-1);
583 		if (!text_to_userinfo(&lk->userinfo, buffer))
584 			return (-1);
585  		return (1);
586 
587 	case K_SOURCE:
588 		if (parse_sockaddr((struct sockaddr *)&lk->source.addr,
589 		    PF_UNSPEC, line) == -1)
590 			return (-1);
591 		return (1);
592 
593 	case K_MAILADDR:
594 		if (!text_to_mailaddr(&lk->mailaddr, line))
595 			return (-1);
596 		return (1);
597 
598 	case K_MAILADDRMAP:
599 		lk->maddrmap = calloc(1, sizeof(*lk->maddrmap));
600 		if (lk->maddrmap == NULL)
601 			return (-1);
602 		maddrmap_init(lk->maddrmap);
603 		if (!mailaddr_line(lk->maddrmap, line)) {
604 			maddrmap_free(lk->maddrmap);
605 			return (-1);
606 		}
607 		return (1);
608 
609 	case K_ADDRNAME:
610 		if (parse_sockaddr((struct sockaddr *)&lk->addrname.addr,
611 		    PF_UNSPEC, key) == -1)
612 			return (-1);
613 		if (strlcpy(lk->addrname.name, line, sizeof(lk->addrname.name))
614 		    >= sizeof(lk->addrname.name))
615 			return (-1);
616 		return (1);
617 
618 	case K_RELAYHOST:
619 		if (strlcpy(lk->relayhost, line, sizeof(lk->relayhost))
620 		    >= sizeof(lk->relayhost))
621 			return (-1);
622 		return (1);
623 
624 	default:
625 		return (-1);
626 	}
627 }
628 
629 static int
630 parse_sockaddr(struct sockaddr *sa, int family, const char *str)
631 {
632 	struct in_addr		 ina;
633 	struct in6_addr		 in6a;
634 	struct sockaddr_in	*sin;
635 	struct sockaddr_in6	*sin6;
636 	char			*cp, *str2;
637 	const char		*errstr;
638 
639 	switch (family) {
640 	case PF_UNSPEC:
641 		if (parse_sockaddr(sa, PF_INET, str) == 0)
642 			return (0);
643 		return parse_sockaddr(sa, PF_INET6, str);
644 
645 	case PF_INET:
646 		if (inet_pton(PF_INET, str, &ina) != 1)
647 			return (-1);
648 
649 		sin = (struct sockaddr_in *)sa;
650 		memset(sin, 0, sizeof *sin);
651 		sin->sin_len = sizeof(struct sockaddr_in);
652 		sin->sin_family = PF_INET;
653 		sin->sin_addr.s_addr = ina.s_addr;
654 		return (0);
655 
656 	case PF_INET6:
657 		if (strncasecmp("ipv6:", str, 5) == 0)
658 			str += 5;
659 		cp = strchr(str, SCOPE_DELIMITER);
660 		if (cp) {
661 			str2 = strdup(str);
662 			if (str2 == NULL)
663 				return (-1);
664 			str2[cp - str] = '\0';
665 			if (inet_pton(PF_INET6, str2, &in6a) != 1) {
666 				free(str2);
667 				return (-1);
668 			}
669 			cp++;
670 			free(str2);
671 		} else if (inet_pton(PF_INET6, str, &in6a) != 1)
672 			return (-1);
673 
674 		sin6 = (struct sockaddr_in6 *)sa;
675 		memset(sin6, 0, sizeof *sin6);
676 		sin6->sin6_len = sizeof(struct sockaddr_in6);
677 		sin6->sin6_family = PF_INET6;
678 		sin6->sin6_addr = in6a;
679 
680 		if (cp == NULL)
681 			return (0);
682 
683 		if (IN6_IS_ADDR_LINKLOCAL(&in6a) ||
684 		    IN6_IS_ADDR_MC_LINKLOCAL(&in6a) ||
685 		    IN6_IS_ADDR_MC_INTFACELOCAL(&in6a))
686 			if ((sin6->sin6_scope_id = if_nametoindex(cp)))
687 				return (0);
688 
689 		sin6->sin6_scope_id = strtonum(cp, 0, UINT32_MAX, &errstr);
690 		if (errstr)
691 			return (-1);
692 		return (0);
693 
694 	default:
695 		break;
696 	}
697 
698 	return (-1);
699 }
700