1 /* $OpenBSD: aliases.c,v 1.71 2016/08/31 10:18:08 gilles Exp $ */ 2 3 /* 4 * Copyright (c) 2008 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 <ctype.h> 25 #include <errno.h> 26 #include <event.h> 27 #include <imsg.h> 28 #include <stdio.h> 29 #include <stdlib.h> 30 #include <string.h> 31 #include <limits.h> 32 #include <util.h> 33 34 #include "smtpd.h" 35 #include "log.h" 36 37 static int aliases_expand_include(struct expand *, const char *); 38 39 int 40 aliases_get(struct expand *expand, const char *username) 41 { 42 struct expandnode *xn; 43 char buf[SMTPD_MAXLOCALPARTSIZE]; 44 size_t nbaliases; 45 int ret; 46 union lookup lk; 47 struct table *mapping = NULL; 48 struct table *userbase = NULL; 49 char *pbuf; 50 51 mapping = expand->rule->r_mapping; 52 userbase = expand->rule->r_userbase; 53 54 xlowercase(buf, username, sizeof(buf)); 55 56 /* first, check if entry has a user-part tag */ 57 pbuf = strchr(buf, *env->sc_subaddressing_delim); 58 if (pbuf) { 59 ret = table_lookup(mapping, NULL, buf, K_ALIAS, &lk); 60 if (ret < 0) 61 return (-1); 62 if (ret) 63 goto expand; 64 *pbuf = '\0'; 65 } 66 67 /* no user-part tag, try looking up user */ 68 ret = table_lookup(mapping, NULL, buf, K_ALIAS, &lk); 69 if (ret <= 0) 70 return ret; 71 72 expand: 73 /* foreach node in table_alias expandtree, we merge */ 74 nbaliases = 0; 75 RB_FOREACH(xn, expandtree, &lk.expand->tree) { 76 if (xn->type == EXPAND_INCLUDE) 77 nbaliases += aliases_expand_include(expand, 78 xn->u.buffer); 79 else { 80 xn->mapping = mapping; 81 xn->userbase = userbase; 82 expand_insert(expand, xn); 83 nbaliases++; 84 } 85 } 86 87 expand_free(lk.expand); 88 89 log_debug("debug: aliases_get: returned %zd aliases", nbaliases); 90 return nbaliases; 91 } 92 93 int 94 aliases_virtual_get(struct expand *expand, const struct mailaddr *maddr) 95 { 96 struct expandnode *xn; 97 union lookup lk; 98 char buf[LINE_MAX]; 99 char user[LINE_MAX]; 100 char tag[LINE_MAX]; 101 char domain[LINE_MAX]; 102 char *pbuf; 103 int nbaliases; 104 int ret; 105 struct table *mapping = NULL; 106 struct table *userbase = NULL; 107 108 mapping = expand->rule->r_mapping; 109 userbase = expand->rule->r_userbase; 110 111 if (!bsnprintf(user, sizeof(user), "%s", maddr->user)) 112 return 0; 113 if (!bsnprintf(domain, sizeof(domain), "%s", maddr->domain)) 114 return 0; 115 xlowercase(user, user, sizeof(user)); 116 xlowercase(domain, domain, sizeof(domain)); 117 118 memset(tag, '\0', sizeof tag); 119 pbuf = strchr(user, *env->sc_subaddressing_delim); 120 if (pbuf) { 121 if (!bsnprintf(tag, sizeof(tag), "%s", pbuf + 1)) 122 return 0; 123 xlowercase(tag, tag, sizeof(tag)); 124 *pbuf = '\0'; 125 } 126 127 /* first, check if entry has a user-part tag */ 128 if (tag[0]) { 129 if (!bsnprintf(buf, sizeof(buf), "%s%c%s@%s", 130 user, *env->sc_subaddressing_delim, tag, domain)) 131 return 0; 132 ret = table_lookup(mapping, NULL, buf, K_ALIAS, &lk); 133 if (ret < 0) 134 return (-1); 135 if (ret) 136 goto expand; 137 } 138 139 /* then, check if entry exists without user-part tag */ 140 if (!bsnprintf(buf, sizeof(buf), "%s@%s", user, domain)) 141 return 0; 142 ret = table_lookup(mapping, NULL, buf, K_ALIAS, &lk); 143 if (ret < 0) 144 return (-1); 145 if (ret) 146 goto expand; 147 148 if (tag[0]) { 149 /* Failed ? We lookup for username + user-part tag */ 150 if (!bsnprintf(buf, sizeof(buf), "%s%c%s", 151 user, *env->sc_subaddressing_delim, tag)) 152 return 0; 153 ret = table_lookup(mapping, NULL, buf, K_ALIAS, &lk); 154 if (ret < 0) 155 return (-1); 156 if (ret) 157 goto expand; 158 } 159 160 /* Failed ? We lookup for username only */ 161 if (!bsnprintf(buf, sizeof(buf), "%s", user)) 162 return 0; 163 ret = table_lookup(mapping, NULL, buf, K_ALIAS, &lk); 164 if (ret < 0) 165 return (-1); 166 if (ret) 167 goto expand; 168 169 if (!bsnprintf(buf, sizeof(buf), "@%s", domain)) 170 return 0; 171 /* Failed ? We lookup for catch all for virtual domain */ 172 ret = table_lookup(mapping, NULL, buf, K_ALIAS, &lk); 173 if (ret < 0) 174 return (-1); 175 if (ret) 176 goto expand; 177 178 /* Failed ? We lookup for a *global* catch all */ 179 ret = table_lookup(mapping, NULL, "@", K_ALIAS, &lk); 180 if (ret <= 0) 181 return (ret); 182 183 expand: 184 /* foreach node in table_virtual expand, we merge */ 185 nbaliases = 0; 186 RB_FOREACH(xn, expandtree, &lk.expand->tree) { 187 if (xn->type == EXPAND_INCLUDE) 188 nbaliases += aliases_expand_include(expand, 189 xn->u.buffer); 190 else { 191 xn->mapping = mapping; 192 xn->userbase = userbase; 193 expand_insert(expand, xn); 194 nbaliases++; 195 } 196 } 197 198 expand_free(lk.expand); 199 200 log_debug("debug: aliases_virtual_get: '%s' resolved to %d nodes", 201 buf, nbaliases); 202 203 return nbaliases; 204 } 205 206 static int 207 aliases_expand_include(struct expand *expand, const char *filename) 208 { 209 FILE *fp; 210 char *line; 211 size_t len, lineno = 0; 212 char delim[3] = { '\\', '#', '\0' }; 213 214 fp = fopen(filename, "r"); 215 if (fp == NULL) { 216 log_warn("warn: failed to open include file \"%s\".", filename); 217 return 0; 218 } 219 220 while ((line = fparseln(fp, &len, &lineno, delim, 0)) != NULL) { 221 expand_line(expand, line, 0); 222 free(line); 223 } 224 225 fclose(fp); 226 return 1; 227 } 228