xref: /openbsd-src/usr.sbin/smtpd/ruleset.c (revision 0b7734b3d77bb9b21afec6f4621cae6c805dbd45)
1 /*	$OpenBSD: ruleset.c,v 1.32 2015/10/27 20:14:19 gilles Exp $ */
2 
3 /*
4  * Copyright (c) 2009 Gilles Chehade <gilles@poolp.org>
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 #include <sys/types.h>
20 #include <sys/queue.h>
21 #include <sys/tree.h>
22 #include <sys/socket.h>
23 
24 #include <netinet/in.h>
25 
26 #include <errno.h>
27 #include <event.h>
28 #include <imsg.h>
29 #include <stdio.h>
30 #include <string.h>
31 #include <limits.h>
32 
33 #include "smtpd.h"
34 #include "log.h"
35 
36 
37 static int ruleset_check_source(struct table *,
38     const struct sockaddr_storage *, int);
39 static int ruleset_check_mailaddr(struct table *, const struct mailaddr *);
40 
41 struct rule *
42 ruleset_match(const struct envelope *evp)
43 {
44 	const struct mailaddr		*maddr = &evp->dest;
45 	const struct sockaddr_storage	*ss = &evp->ss;
46 	struct rule			*r;
47 	int				 ret;
48 
49 	TAILQ_FOREACH(r, env->sc_rules, r_entry) {
50 
51 		if (r->r_tag[0] != '\0') {
52 			ret = strcmp(r->r_tag, evp->tag);
53 			if (ret != 0 && !r->r_nottag)
54 				continue;
55 			if (ret == 0 && r->r_nottag)
56 				continue;
57 		}
58 
59 		ret = ruleset_check_source(r->r_sources, ss, evp->flags);
60 		if (ret == -1) {
61 			errno = EAGAIN;
62 			return (NULL);
63 		}
64 		if ((ret == 0 && !r->r_notsources) || (ret != 0 && r->r_notsources))
65 			continue;
66 
67 		if (r->r_senders) {
68 			ret = ruleset_check_mailaddr(r->r_senders, &evp->sender);
69 			if (ret == -1) {
70 				errno = EAGAIN;
71 				return (NULL);
72 			}
73 			if ((ret == 0 && !r->r_notsenders) || (ret != 0 && r->r_notsenders))
74 				continue;
75 		}
76 
77 		if (r->r_recipients) {
78 			ret = ruleset_check_mailaddr(r->r_recipients, &evp->dest);
79 			if (ret == -1) {
80 				errno = EAGAIN;
81 				return (NULL);
82 			}
83 			if ((ret == 0 && !r->r_notrecipients) || (ret != 0 && r->r_notrecipients))
84 				continue;
85 		}
86 
87 		ret = r->r_destination == NULL ? 1 :
88 		    table_lookup(r->r_destination, NULL, maddr->domain, K_DOMAIN,
89 			NULL);
90 		if (ret == -1) {
91 			errno = EAGAIN;
92 			return NULL;
93 		}
94 		if ((ret == 0 && !r->r_notdestination) || (ret != 0 && r->r_notdestination))
95 			continue;
96 
97 		goto matched;
98 	}
99 
100 	errno = 0;
101 	log_trace(TRACE_RULES, "no rule matched");
102 	return (NULL);
103 
104 matched:
105 	log_trace(TRACE_RULES, "rule matched: %s", rule_to_text(r));
106 	return r;
107 }
108 
109 static int
110 ruleset_check_source(struct table *table, const struct sockaddr_storage *ss,
111     int evpflags)
112 {
113 	const char   *key;
114 
115 	if (evpflags & (EF_AUTHENTICATED | EF_INTERNAL))
116 		key = "local";
117 	else
118 		key = ss_to_text(ss);
119 	switch (table_lookup(table, NULL, key, K_NETADDR, NULL)) {
120 	case 1:
121 		return 1;
122 	case -1:
123 		log_warnx("warn: failure to perform a table lookup on table %s",
124 		    table->t_name);
125 		return -1;
126 	default:
127 		break;
128 	}
129 
130 	return 0;
131 }
132 
133 static int
134 ruleset_check_mailaddr(struct table *table, const struct mailaddr *maddr)
135 {
136 	const char	*key;
137 
138 	key = mailaddr_to_text(maddr);
139 	if (key == NULL)
140 		return -1;
141 
142 	switch (table_lookup(table, NULL, key, K_MAILADDR, NULL)) {
143 	case 1:
144 		return 1;
145 	case -1:
146 		log_warnx("warn: failure to perform a table lookup on table %s",
147 		    table->t_name);
148 		return -1;
149 	default:
150 		break;
151 	}
152 	return 0;
153 }
154