summaryrefslogtreecommitdiff
path: root/usr.sbin/smtpd/ruleset.c
diff options
context:
space:
mode:
authorGilles Chehade <gilles@cvs.openbsd.org>2009-06-01 22:51:48 +0000
committerGilles Chehade <gilles@cvs.openbsd.org>2009-06-01 22:51:48 +0000
commited0f1bbb4bce13439e483538231f2a157ee188f5 (patch)
tree2f19ff49e6d24a799e2b388aae7d4c1cd1d514f4 /usr.sbin/smtpd/ruleset.c
parent276317b86ebb47f8e781ac4d05a5f61fb9d04b92 (diff)
add new file ruleset.c with code related to the ruleset matching, and kill
the two or three "almost" identical versions of ruleset matching loops from lka and mfa by having one unified function in ruleset.c; ok jacekm@ while at it, bring maildir support back to life; trivial one-liner by me
Diffstat (limited to 'usr.sbin/smtpd/ruleset.c')
-rw-r--r--usr.sbin/smtpd/ruleset.c147
1 files changed, 147 insertions, 0 deletions
diff --git a/usr.sbin/smtpd/ruleset.c b/usr.sbin/smtpd/ruleset.c
new file mode 100644
index 00000000000..6b2ab5568ea
--- /dev/null
+++ b/usr.sbin/smtpd/ruleset.c
@@ -0,0 +1,147 @@
+/* $OpenBSD: ruleset.c,v 1.1 2009/06/01 22:51:47 gilles Exp $ */
+
+/*
+ * Copyright (c) 2009 Gilles Chehade <gilles@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/types.h>
+#include <sys/queue.h>
+#include <sys/tree.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <db.h>
+#include <errno.h>
+#include <event.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "smtpd.h"
+
+struct rule *ruleset_match(struct smtpd *, struct path *, struct sockaddr_storage *);
+int ruleset_check_source(struct map *, struct sockaddr_storage *);
+int ruleset_match_mask(struct sockaddr_storage *, struct netaddr *);
+
+
+struct rule *
+ruleset_match(struct smtpd *env, struct path *path, struct sockaddr_storage *ss)
+{
+ struct rule *r;
+ struct cond *cond;
+ struct map *map;
+ struct mapel *me;
+
+ TAILQ_FOREACH(r, env->sc_rules, r_entry) {
+
+ if (ss != NULL &&
+ (!(path->flags & F_PATH_AUTHENTICATED) &&
+ ! ruleset_check_source(r->r_sources, ss)))
+ continue;
+
+ TAILQ_FOREACH(cond, &r->r_conditions, c_entry) {
+ if (cond->c_type == C_ALL)
+ return r;
+
+ if (cond->c_type == C_DOM) {
+ cond->c_match = map_find(env, cond->c_map);
+ if (cond->c_match == NULL)
+ fatal("failed to lookup map.");
+
+ map = cond->c_match;
+ TAILQ_FOREACH(me, &map->m_contents, me_entry) {
+ log_debug("matching: %s to %s",
+ path->domain, me->me_key.med_string);
+ if (hostname_match(path->domain, me->me_key.med_string)) {
+ return r;
+ }
+ }
+ }
+ }
+ }
+
+ return NULL;
+}
+
+int
+ruleset_check_source(struct map *map, struct sockaddr_storage *ss)
+{
+ struct mapel *me;
+
+ if (ss == NULL) {
+ /* This happens when caller is part of an internal
+ * lookup (ie: alias resolved to a remote address)
+ */
+ return 1;
+ }
+
+ TAILQ_FOREACH(me, &map->m_contents, me_entry) {
+
+ if (ss->ss_family != me->me_key.med_addr.ss.ss_family)
+ continue;
+
+ if (ss->ss_len != me->me_key.med_addr.ss.ss_len)
+ continue;
+
+ if (ruleset_match_mask(ss, &me->me_key.med_addr))
+ return 1;
+ }
+
+ return 0;
+}
+
+int
+ruleset_match_mask(struct sockaddr_storage *ss, struct netaddr *ssmask)
+{
+ if (ss->ss_family == AF_INET) {
+ struct sockaddr_in *ssin = (struct sockaddr_in *)ss;
+ struct sockaddr_in *ssinmask = (struct sockaddr_in *)&ssmask->ss;
+
+ if ((ssin->sin_addr.s_addr & ssinmask->sin_addr.s_addr) ==
+ ssinmask->sin_addr.s_addr)
+ return (1);
+ return (0);
+ }
+
+ if (ss->ss_family == AF_INET6) {
+ struct in6_addr *in;
+ struct in6_addr *inmask;
+ struct in6_addr mask;
+ int i;
+
+ bzero(&mask, sizeof(mask));
+ for (i = 0; i < (128 - ssmask->bits) / 8; i++)
+ mask.s6_addr[i] = 0xff;
+ i = ssmask->bits % 8;
+ if (i)
+ mask.s6_addr[ssmask->bits / 8] = 0xff00 >> i;
+
+ in = &((struct sockaddr_in6 *)ss)->sin6_addr;
+ inmask = &((struct sockaddr_in6 *)&ssmask->ss)->sin6_addr;
+
+ for (i = 0; i < 16; i++) {
+ if ((in->s6_addr[i] & mask.s6_addr[i]) !=
+ inmask->s6_addr[i])
+ return (0);
+ }
+ return (1);
+ }
+
+ return (0);
+}