1 /* $OpenBSD: table_static.c,v 1.24 2018/12/26 20:13:43 eric Exp $ */ 2 3 /* 4 * Copyright (c) 2013 Eric Faurot <eric@openbsd.org> 5 * Copyright (c) 2012 Gilles Chehade <gilles@poolp.org> 6 * 7 * Permission to use, copy, modify, and distribute this software for any 8 * purpose with or without fee is hereby granted, provided that the above 9 * copyright notice and this permission notice appear in all copies. 10 * 11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 */ 19 20 #include <sys/types.h> 21 #include <sys/queue.h> 22 #include <sys/tree.h> 23 #include <sys/socket.h> 24 25 #include <netinet/in.h> 26 #include <arpa/inet.h> 27 28 #include <ctype.h> 29 #include <err.h> 30 #include <event.h> 31 #include <fcntl.h> 32 #include <imsg.h> 33 #include <stdio.h> 34 #include <stdlib.h> 35 #include <limits.h> 36 #include <string.h> 37 38 #include "smtpd.h" 39 #include "log.h" 40 41 /* static backend */ 42 static int table_static_config(struct table *); 43 static int table_static_update(struct table *); 44 static void *table_static_open(struct table *); 45 static int table_static_lookup(void *, enum table_service, const char *, 46 char **); 47 static int table_static_fetch(void *, enum table_service, char **); 48 static void table_static_close(void *); 49 50 struct table_backend table_backend_static = { 51 "static", 52 K_ALIAS|K_CREDENTIALS|K_DOMAIN|K_NETADDR|K_USERINFO| 53 K_SOURCE|K_MAILADDR|K_ADDRNAME|K_MAILADDRMAP|K_RELAYHOST| 54 K_STRING|K_REGEX, 55 table_static_config, 56 table_static_open, 57 table_static_update, 58 table_static_close, 59 table_static_lookup, 60 table_static_fetch 61 }; 62 63 static struct keycmp { 64 enum table_service service; 65 int (*func)(const char *, const char *); 66 } keycmp[] = { 67 { K_DOMAIN, table_domain_match }, 68 { K_NETADDR, table_netaddr_match }, 69 { K_MAILADDR, table_mailaddr_match }, 70 { K_REGEX, table_regex_match }, 71 }; 72 73 74 static int 75 table_static_config(struct table *t) 76 { 77 FILE *fp; 78 char *buf = NULL, *p; 79 int lineno = 0; 80 size_t sz = 0; 81 ssize_t flen; 82 char *keyp; 83 char *valp; 84 size_t ret = 0; 85 86 /* no config ? ok */ 87 if (*t->t_config == '\0') 88 return 1; 89 90 if ((fp = fopen(t->t_config, "r")) == NULL) { 91 log_warn("warn: Table \"%s\"", t->t_config); 92 return 0; 93 } 94 95 while ((flen = getline(&buf, &sz, fp)) != -1) { 96 lineno++; 97 if (buf[flen - 1] == '\n') 98 buf[--flen] = '\0'; 99 100 keyp = buf; 101 while (isspace((unsigned char)*keyp)) { 102 ++keyp; 103 --flen; 104 } 105 if (*keyp == '\0') 106 continue; 107 while (isspace((unsigned char)keyp[flen - 1])) 108 keyp[--flen] = '\0'; 109 if (*keyp == '#') { 110 if (t->t_type == T_NONE) { 111 keyp++; 112 while (isspace((unsigned char)*keyp)) 113 ++keyp; 114 if (!strcmp(keyp, "@list")) 115 t->t_type = T_LIST; 116 } 117 continue; 118 } 119 120 if (t->t_type == T_NONE) { 121 for (p = keyp; *p; p++) { 122 if (*p == ' ' || *p == '\t' || *p == ':') { 123 t->t_type = T_HASH; 124 break; 125 } 126 } 127 if (t->t_type == T_NONE) 128 t->t_type = T_LIST; 129 } 130 131 if (t->t_type == T_LIST) { 132 table_add(t, keyp, NULL); 133 continue; 134 } 135 136 /* T_HASH */ 137 valp = keyp; 138 strsep(&valp, " \t:"); 139 if (valp) { 140 while (*valp) { 141 if (!isspace((unsigned char)*valp) && 142 !(*valp == ':' && 143 isspace((unsigned char)*(valp + 1)))) 144 break; 145 ++valp; 146 } 147 if (*valp == '\0') 148 valp = NULL; 149 } 150 if (valp == NULL) { 151 log_warnx("%s: invalid map entry line %d", t->t_config, 152 lineno); 153 goto end; 154 } 155 156 table_add(t, keyp, valp); 157 } 158 159 if (ferror(fp)) { 160 log_warn("%s: getline", t->t_config); 161 goto end; 162 } 163 164 /* Accept empty alias files; treat them as hashes */ 165 if (t->t_type == T_NONE && t->t_backend->services & K_ALIAS) 166 t->t_type = T_HASH; 167 168 ret = 1; 169 end: 170 free(buf); 171 fclose(fp); 172 return ret; 173 } 174 175 static int 176 table_static_update(struct table *table) 177 { 178 struct table *t; 179 void *p = NULL; 180 181 /* no config ? ok */ 182 if (table->t_config[0] == '\0') 183 goto ok; 184 185 t = table_create(env, "static", table->t_name, "update", table->t_config); 186 if (!table_config(t)) 187 goto err; 188 189 /* replace former table, frees t */ 190 while (dict_poproot(&table->t_dict, (void **)&p)) 191 free(p); 192 dict_merge(&table->t_dict, &t->t_dict); 193 table_destroy(env, t); 194 195 ok: 196 log_info("info: Table \"%s\" successfully updated", table->t_name); 197 return 1; 198 199 err: 200 table_destroy(env, t); 201 log_info("info: Failed to update table \"%s\"", table->t_name); 202 return 0; 203 } 204 205 static void * 206 table_static_open(struct table *table) 207 { 208 return table; 209 } 210 211 static void 212 table_static_close(void *hdl) 213 { 214 return; 215 } 216 217 static int 218 table_static_lookup(void *hdl, enum table_service service, const char *key, 219 char **dst) 220 { 221 struct table *m = hdl; 222 char *line; 223 int ret; 224 int (*match)(const char *, const char *) = NULL; 225 size_t i; 226 void *iter; 227 const char *k; 228 char *v; 229 230 for (i = 0; i < nitems(keycmp); ++i) 231 if (keycmp[i].service == service) 232 match = keycmp[i].func; 233 234 line = NULL; 235 iter = NULL; 236 ret = 0; 237 while (dict_iter(&m->t_dict, &iter, &k, (void **)&v)) { 238 if (match) { 239 if (match(key, k)) { 240 line = v; 241 ret = 1; 242 } 243 } 244 else { 245 if (strcmp(key, k) == 0) { 246 line = v; 247 ret = 1; 248 } 249 } 250 if (ret) 251 break; 252 } 253 254 if (dst == NULL) 255 return ret ? 1 : 0; 256 257 if (ret == 0) 258 return 0; 259 260 *dst = strdup(line); 261 if (*dst == NULL) 262 return -1; 263 264 return 1; 265 } 266 267 static int 268 table_static_fetch(void *hdl, enum table_service service, char **dst) 269 { 270 struct table *t = hdl; 271 const char *k; 272 273 if (!dict_iter(&t->t_dict, &t->t_iter, &k, (void **)NULL)) { 274 t->t_iter = NULL; 275 if (!dict_iter(&t->t_dict, &t->t_iter, &k, (void **)NULL)) 276 return 0; 277 } 278 279 if (dst == NULL) 280 return 1; 281 282 *dst = strdup(k); 283 if (*dst == NULL) 284 return -1; 285 286 return 1; 287 } 288