xref: /openbsd/usr.sbin/smtpd/ruleset.c (revision 91f110e0)
1 /*	$OpenBSD: ruleset.c,v 1.29 2013/11/06 10:01:29 eric 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 
32 #include "smtpd.h"
33 #include "log.h"
34 
35 
36 static int ruleset_check_source(struct table *,
37     const struct sockaddr_storage *, int);
38 static int ruleset_check_mailaddr(struct table *, const struct mailaddr *);
39 
40 struct rule *
41 ruleset_match(const struct envelope *evp)
42 {
43 	const struct mailaddr		*maddr = &evp->dest;
44 	const struct sockaddr_storage	*ss = &evp->ss;
45 	struct rule			*r;
46 	int				 ret;
47 
48 	TAILQ_FOREACH(r, env->sc_rules, r_entry) {
49 
50 		if (r->r_tag[0] != '\0') {
51 			ret = strcmp(r->r_tag, evp->tag);
52 			if (ret != 0 && !r->r_nottag)
53 				continue;
54 			if (ret == 0 && r->r_nottag)
55 				continue;
56 		}
57 
58 		ret = ruleset_check_source(r->r_sources, ss, evp->flags);
59 		if (ret == -1) {
60 			errno = EAGAIN;
61 			return (NULL);
62 		}
63 		if ((ret == 0 && !r->r_notsources) || (ret != 0 && r->r_notsources))
64 			continue;
65 
66 		if (r->r_senders) {
67 			ret = ruleset_check_mailaddr(r->r_senders, &evp->sender);
68 			if (ret == -1) {
69 				errno = EAGAIN;
70 				return (NULL);
71 			}
72 			if ((ret == 0 && !r->r_notsenders) || (ret != 0 && r->r_notsenders))
73 				continue;
74 		}
75 
76 		if (r->r_recipients) {
77 			ret = ruleset_check_mailaddr(r->r_recipients, &evp->dest);
78 			if (ret == -1) {
79 				errno = EAGAIN;
80 				return (NULL);
81 			}
82 			if ((ret == 0 && !r->r_notrecipients) || (ret != 0 && r->r_notrecipients))
83 				continue;
84 		}
85 
86 		ret = r->r_destination == NULL ? 1 :
87 		    table_lookup(r->r_destination, maddr->domain, K_DOMAIN,
88 			NULL);
89 		if (ret == -1) {
90 			errno = EAGAIN;
91 			return NULL;
92 		}
93 		if ((ret == 0 && !r->r_notdestination) || (ret != 0 && r->r_notdestination))
94 			continue;
95 
96 		if (r->r_desttype == DEST_VDOM &&
97 		    (r->r_action == A_RELAY || r->r_action == A_RELAYVIA)) {
98 			if (! aliases_virtual_check(r->r_mapping,
99 				&evp->rcpt)) {
100 				return NULL;
101 			}
102 		}
103 		goto matched;
104 	}
105 
106 	errno = 0;
107 	log_trace(TRACE_RULES, "no rule matched");
108 	return (NULL);
109 
110 matched:
111 	log_trace(TRACE_RULES, "rule matched: %s", rule_to_text(r));
112 	return r;
113 }
114 
115 static int
116 ruleset_check_source(struct table *table, const struct sockaddr_storage *ss,
117     int evpflags)
118 {
119 	const char   *key;
120 
121 	if (evpflags & (EF_AUTHENTICATED | EF_INTERNAL))
122 		key = "local";
123 	else
124 		key = ss_to_text(ss);
125 	switch (table_lookup(table, key, K_NETADDR, NULL)) {
126 	case 1:
127 		return 1;
128 	case -1:
129 		log_warnx("warn: failure to perform a table lookup on table %s",
130 		    table->t_name);
131 		return -1;
132 	default:
133 		break;
134 	}
135 
136 	return 0;
137 }
138 
139 static int
140 ruleset_check_mailaddr(struct table *table, const struct mailaddr *maddr)
141 {
142 	const char	*key;
143 
144 	key = mailaddr_to_text(maddr);
145 	if (key == NULL)
146 		return -1;
147 
148 	switch (table_lookup(table, key, K_MAILADDR, NULL)) {
149 	case 1:
150 		return 1;
151 	case -1:
152 		log_warnx("warn: failure to perform a table lookup on table %s",
153 		    table->t_name);
154 		return -1;
155 	default:
156 		break;
157 	}
158 	return 0;
159 }
160