1 /* $OpenBSD: ruleset.c,v 1.33 2016/08/31 15:24:04 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 if (r->r_wantauth && !(evp->flags & EF_AUTHENTICATED)) 60 continue; 61 62 ret = ruleset_check_source(r->r_sources, ss, evp->flags); 63 if (ret == -1) { 64 errno = EAGAIN; 65 return (NULL); 66 } 67 if ((ret == 0 && !r->r_notsources) || (ret != 0 && r->r_notsources)) 68 continue; 69 70 if (r->r_senders) { 71 ret = ruleset_check_mailaddr(r->r_senders, &evp->sender); 72 if (ret == -1) { 73 errno = EAGAIN; 74 return (NULL); 75 } 76 if ((ret == 0 && !r->r_notsenders) || (ret != 0 && r->r_notsenders)) 77 continue; 78 } 79 80 if (r->r_recipients) { 81 ret = ruleset_check_mailaddr(r->r_recipients, &evp->dest); 82 if (ret == -1) { 83 errno = EAGAIN; 84 return (NULL); 85 } 86 if ((ret == 0 && !r->r_notrecipients) || (ret != 0 && r->r_notrecipients)) 87 continue; 88 } 89 90 ret = r->r_destination == NULL ? 1 : 91 table_lookup(r->r_destination, NULL, maddr->domain, K_DOMAIN, 92 NULL); 93 if (ret == -1) { 94 errno = EAGAIN; 95 return NULL; 96 } 97 if ((ret == 0 && !r->r_notdestination) || (ret != 0 && r->r_notdestination)) 98 continue; 99 100 goto matched; 101 } 102 103 errno = 0; 104 log_trace(TRACE_RULES, "no rule matched"); 105 return (NULL); 106 107 matched: 108 log_trace(TRACE_RULES, "rule matched: %s", rule_to_text(r)); 109 return r; 110 } 111 112 static int 113 ruleset_check_source(struct table *table, const struct sockaddr_storage *ss, 114 int evpflags) 115 { 116 const char *key; 117 118 if (evpflags & (EF_AUTHENTICATED | EF_INTERNAL)) 119 key = "local"; 120 else 121 key = ss_to_text(ss); 122 switch (table_lookup(table, NULL, key, K_NETADDR, NULL)) { 123 case 1: 124 return 1; 125 case -1: 126 log_warnx("warn: failure to perform a table lookup on table %s", 127 table->t_name); 128 return -1; 129 default: 130 break; 131 } 132 133 return 0; 134 } 135 136 static int 137 ruleset_check_mailaddr(struct table *table, const struct mailaddr *maddr) 138 { 139 const char *key; 140 141 key = mailaddr_to_text(maddr); 142 if (key == NULL) 143 return -1; 144 145 switch (table_lookup(table, NULL, key, K_MAILADDR, NULL)) { 146 case 1: 147 return 1; 148 case -1: 149 log_warnx("warn: failure to perform a table lookup on table %s", 150 table->t_name); 151 return -1; 152 default: 153 break; 154 } 155 return 0; 156 } 157