1*81c7fb0aSgilles /* $OpenBSD: table_static.c,v 1.20 2018/11/01 10:47:46 gilles Exp $ */ 265c4fdfbSgilles 365c4fdfbSgilles /* 4299c4efeSeric * Copyright (c) 2013 Eric Faurot <eric@openbsd.org> 565c4fdfbSgilles * Copyright (c) 2012 Gilles Chehade <gilles@poolp.org> 665c4fdfbSgilles * 765c4fdfbSgilles * Permission to use, copy, modify, and distribute this software for any 865c4fdfbSgilles * purpose with or without fee is hereby granted, provided that the above 965c4fdfbSgilles * copyright notice and this permission notice appear in all copies. 1065c4fdfbSgilles * 1165c4fdfbSgilles * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 1265c4fdfbSgilles * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 1365c4fdfbSgilles * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 1465c4fdfbSgilles * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 1565c4fdfbSgilles * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 1665c4fdfbSgilles * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 1765c4fdfbSgilles * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 1865c4fdfbSgilles */ 1965c4fdfbSgilles 2065c4fdfbSgilles #include <sys/types.h> 2165c4fdfbSgilles #include <sys/queue.h> 2265c4fdfbSgilles #include <sys/tree.h> 2365c4fdfbSgilles #include <sys/socket.h> 2465c4fdfbSgilles 2565c4fdfbSgilles #include <netinet/in.h> 2665c4fdfbSgilles #include <arpa/inet.h> 2765c4fdfbSgilles 2865c4fdfbSgilles #include <ctype.h> 2965c4fdfbSgilles #include <err.h> 3065c4fdfbSgilles #include <event.h> 3165c4fdfbSgilles #include <fcntl.h> 3265c4fdfbSgilles #include <imsg.h> 3365c4fdfbSgilles #include <stdio.h> 3465c4fdfbSgilles #include <stdlib.h> 35953aae25Sderaadt #include <limits.h> 3665c4fdfbSgilles #include <string.h> 3765c4fdfbSgilles 3865c4fdfbSgilles #include "smtpd.h" 3965c4fdfbSgilles #include "log.h" 4065c4fdfbSgilles 4165c4fdfbSgilles /* static backend */ 42299c4efeSeric static int table_static_config(struct table *); 4365c4fdfbSgilles static int table_static_update(struct table *); 4465c4fdfbSgilles static void *table_static_open(struct table *); 4593262a01Ssunil static int table_static_lookup(void *, struct dict *, const char *, 4693262a01Ssunil enum table_service, union lookup *); 4793262a01Ssunil static int table_static_fetch(void *, struct dict *, enum table_service, 48299c4efeSeric union lookup *); 4965c4fdfbSgilles static void table_static_close(void *); 5065c4fdfbSgilles 5165c4fdfbSgilles struct table_backend table_backend_static = { 5293262a01Ssunil K_ALIAS|K_CREDENTIALS|K_DOMAIN|K_NETADDR|K_USERINFO| 53a8e22235Sgilles K_SOURCE|K_MAILADDR|K_ADDRNAME|K_MAILADDRMAP|K_RELAYHOST| 54*81c7fb0aSgilles K_STRING|K_REGEX, 5565c4fdfbSgilles table_static_config, 5665c4fdfbSgilles table_static_open, 5765c4fdfbSgilles table_static_update, 5865c4fdfbSgilles table_static_close, 5965c4fdfbSgilles table_static_lookup, 6065c4fdfbSgilles table_static_fetch 6165c4fdfbSgilles }; 6265c4fdfbSgilles 6365c4fdfbSgilles static struct keycmp { 6465c4fdfbSgilles enum table_service service; 6565c4fdfbSgilles int (*func)(const char *, const char *); 6665c4fdfbSgilles } keycmp[] = { 6765c4fdfbSgilles { K_DOMAIN, table_domain_match }, 6865c4fdfbSgilles { K_NETADDR, table_netaddr_match }, 69*81c7fb0aSgilles { K_MAILADDR, table_mailaddr_match }, 70*81c7fb0aSgilles { K_REGEX, table_regex_match }, 7165c4fdfbSgilles }; 7265c4fdfbSgilles 7365c4fdfbSgilles 7465c4fdfbSgilles static int 753cedc4a5Seric table_static_config(struct table *t) 76299c4efeSeric { 77299c4efeSeric FILE *fp; 78b7b75d53Seric char *buf = NULL, *p; 79b7b75d53Seric int lineno = 0; 80c17c2b51Ssunil size_t sz = 0; 81c17c2b51Ssunil ssize_t flen; 82299c4efeSeric char *keyp; 83299c4efeSeric char *valp; 84299c4efeSeric size_t ret = 0; 85299c4efeSeric 863cedc4a5Seric /* no config ? ok */ 873cedc4a5Seric if (*t->t_config == '\0') 883cedc4a5Seric return 1; 893cedc4a5Seric 903cedc4a5Seric if ((fp = fopen(t->t_config, "r")) == NULL) { 913cedc4a5Seric log_warn("warn: Table \"%s\"", t->t_config); 92299c4efeSeric return 0; 9327c7fbfbSgilles } 94299c4efeSeric 95c17c2b51Ssunil while ((flen = getline(&buf, &sz, fp)) != -1) { 96b7b75d53Seric lineno++; 97299c4efeSeric if (buf[flen - 1] == '\n') 98b7b75d53Seric buf[--flen] = '\0'; 99299c4efeSeric 100299c4efeSeric keyp = buf; 101b7b75d53Seric while (isspace((unsigned char)*keyp)) { 102b7b75d53Seric ++keyp; 103b7b75d53Seric --flen; 104b7b75d53Seric } 105b7b75d53Seric if (*keyp == '\0') 106b7b75d53Seric continue; 107b7b75d53Seric while (isspace((unsigned char)keyp[flen - 1])) 108b7b75d53Seric keyp[--flen] = '\0'; 109b7b75d53Seric if (*keyp == '#') { 110b7b75d53Seric if (t->t_type == T_NONE) { 111b7b75d53Seric keyp++; 112fc3a8311Seric while (isspace((unsigned char)*keyp)) 113299c4efeSeric ++keyp; 114b7b75d53Seric if (!strcmp(keyp, "@list")) 115b7b75d53Seric t->t_type = T_LIST; 116b7b75d53Seric } 117299c4efeSeric continue; 118b7b75d53Seric } 119b7b75d53Seric 120b7b75d53Seric if (t->t_type == T_NONE) { 121b7b75d53Seric for (p = keyp; *p; p++) { 122b7b75d53Seric if (*p == ' ' || *p == '\t' || *p == ':') { 123b7b75d53Seric t->t_type = T_HASH; 124b7b75d53Seric break; 125b7b75d53Seric } 126b7b75d53Seric } 127b7b75d53Seric if (t->t_type == T_NONE) 128b7b75d53Seric t->t_type = T_LIST; 129b7b75d53Seric } 130b7b75d53Seric 131b7b75d53Seric if (t->t_type == T_LIST) { 132b7b75d53Seric table_add(t, keyp, NULL); 133b7b75d53Seric continue; 134b7b75d53Seric } 135b7b75d53Seric 136b7b75d53Seric /* T_HASH */ 137299c4efeSeric valp = keyp; 138299c4efeSeric strsep(&valp, " \t:"); 139299c4efeSeric if (valp) { 140299c4efeSeric while (*valp) { 141fc3a8311Seric if (!isspace((unsigned char)*valp) && 14293262a01Ssunil !(*valp == ':' && 14393262a01Ssunil isspace((unsigned char)*(valp + 1)))) 144299c4efeSeric break; 145299c4efeSeric ++valp; 146299c4efeSeric } 147299c4efeSeric if (*valp == '\0') 148299c4efeSeric valp = NULL; 149299c4efeSeric } 150b7b75d53Seric if (valp == NULL) { 151b7b75d53Seric log_warnx("%s: invalid map entry line %d", t->t_config, 152b7b75d53Seric lineno); 153299c4efeSeric goto end; 154299c4efeSeric } 155b7b75d53Seric 156b7b75d53Seric table_add(t, keyp, valp); 157b7b75d53Seric } 158b7b75d53Seric 159b7b75d53Seric if (ferror(fp)) { 160b7b75d53Seric log_warn("%s: getline", t->t_config); 161b7b75d53Seric goto end; 162b7b75d53Seric } 163b7b75d53Seric 1643f95a974Seric /* Accept empty alias files; treat them as hashes */ 1653f95a974Seric if (t->t_type == T_NONE && t->t_backend->services & K_ALIAS) 1663f95a974Seric t->t_type = T_HASH; 1673f95a974Seric 168299c4efeSeric ret = 1; 169299c4efeSeric end: 170c17c2b51Ssunil free(buf); 171299c4efeSeric fclose(fp); 172299c4efeSeric return ret; 17365c4fdfbSgilles } 17465c4fdfbSgilles 17565c4fdfbSgilles static int 17665c4fdfbSgilles table_static_update(struct table *table) 17765c4fdfbSgilles { 17865c4fdfbSgilles struct table *t; 179299c4efeSeric void *p = NULL; 18065c4fdfbSgilles 18165c4fdfbSgilles /* no config ? ok */ 18265c4fdfbSgilles if (table->t_config[0] == '\0') 18365c4fdfbSgilles goto ok; 18465c4fdfbSgilles 185b80b41afSgilles t = table_create(env, "static", table->t_name, "update", table->t_config); 186299c4efeSeric if (!table_config(t)) 18765c4fdfbSgilles goto err; 18865c4fdfbSgilles 189dd047c3bSgilles /* replace former table, frees t */ 19019503c5aSeric while (dict_poproot(&table->t_dict, (void **)&p)) 191299c4efeSeric free(p); 192299c4efeSeric dict_merge(&table->t_dict, &t->t_dict); 193b80b41afSgilles table_destroy(env, t); 19465c4fdfbSgilles 19565c4fdfbSgilles ok: 196dd047c3bSgilles log_info("info: Table \"%s\" successfully updated", table->t_name); 19765c4fdfbSgilles return 1; 19865c4fdfbSgilles 19965c4fdfbSgilles err: 200b80b41afSgilles table_destroy(env, t); 201dd047c3bSgilles log_info("info: Failed to update table \"%s\"", table->t_name); 20265c4fdfbSgilles return 0; 20365c4fdfbSgilles } 20465c4fdfbSgilles 20565c4fdfbSgilles static void * 20665c4fdfbSgilles table_static_open(struct table *table) 20765c4fdfbSgilles { 20865c4fdfbSgilles return table; 20965c4fdfbSgilles } 21065c4fdfbSgilles 21165c4fdfbSgilles static void 21265c4fdfbSgilles table_static_close(void *hdl) 21365c4fdfbSgilles { 21465c4fdfbSgilles return; 21565c4fdfbSgilles } 21665c4fdfbSgilles 21765c4fdfbSgilles static int 21893262a01Ssunil table_static_lookup(void *hdl, struct dict *params, const char *key, 21993262a01Ssunil enum table_service service, union lookup *lk) 22065c4fdfbSgilles { 22165c4fdfbSgilles struct table *m = hdl; 22265c4fdfbSgilles char *line; 22365c4fdfbSgilles int ret; 22465c4fdfbSgilles int (*match)(const char *, const char *) = NULL; 22565c4fdfbSgilles size_t i; 22665c4fdfbSgilles void *iter; 22765c4fdfbSgilles const char *k; 22865c4fdfbSgilles char *v; 22965c4fdfbSgilles 23065c4fdfbSgilles for (i = 0; i < nitems(keycmp); ++i) 23165c4fdfbSgilles if (keycmp[i].service == service) 23265c4fdfbSgilles match = keycmp[i].func; 23365c4fdfbSgilles 23465c4fdfbSgilles line = NULL; 23565c4fdfbSgilles iter = NULL; 23665c4fdfbSgilles ret = 0; 23765c4fdfbSgilles while (dict_iter(&m->t_dict, &iter, &k, (void **)&v)) { 23865c4fdfbSgilles if (match) { 23965c4fdfbSgilles if (match(key, k)) { 24065c4fdfbSgilles line = v; 24165c4fdfbSgilles ret = 1; 24265c4fdfbSgilles } 24365c4fdfbSgilles } 24465c4fdfbSgilles else { 24565c4fdfbSgilles if (strcmp(key, k) == 0) { 24665c4fdfbSgilles line = v; 24765c4fdfbSgilles ret = 1; 24865c4fdfbSgilles } 24965c4fdfbSgilles } 25065c4fdfbSgilles if (ret) 25165c4fdfbSgilles break; 25265c4fdfbSgilles } 25365c4fdfbSgilles 254299c4efeSeric if (lk == NULL) 25565c4fdfbSgilles return ret ? 1 : 0; 25665c4fdfbSgilles 257299c4efeSeric if (ret == 0) 25865c4fdfbSgilles return 0; 25965c4fdfbSgilles 260299c4efeSeric return table_parse_lookup(service, key, line, lk); 26165c4fdfbSgilles } 26265c4fdfbSgilles 26365c4fdfbSgilles static int 26493262a01Ssunil table_static_fetch(void *hdl, struct dict *params, 26593262a01Ssunil enum table_service service, union lookup *lk) 26665c4fdfbSgilles { 26765c4fdfbSgilles struct table *t = hdl; 26865c4fdfbSgilles const char *k; 26965c4fdfbSgilles 27065c4fdfbSgilles if (!dict_iter(&t->t_dict, &t->t_iter, &k, (void **)NULL)) { 27165c4fdfbSgilles t->t_iter = NULL; 27265c4fdfbSgilles if (!dict_iter(&t->t_dict, &t->t_iter, &k, (void **)NULL)) 27365c4fdfbSgilles return 0; 27465c4fdfbSgilles } 27565c4fdfbSgilles 276299c4efeSeric if (lk == NULL) 27765c4fdfbSgilles return 1; 27865c4fdfbSgilles 279299c4efeSeric return table_parse_lookup(service, NULL, k, lk); 28065c4fdfbSgilles } 281