1*19503c5aSeric /* $OpenBSD: table_static.c,v 1.7 2013/11/18 11:47:16 eric 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> 3565c4fdfbSgilles #include <string.h> 3665c4fdfbSgilles 3765c4fdfbSgilles #include "smtpd.h" 3865c4fdfbSgilles #include "log.h" 3965c4fdfbSgilles 4065c4fdfbSgilles /* static backend */ 41299c4efeSeric static int table_static_config(struct table *); 4265c4fdfbSgilles static int table_static_update(struct table *); 4365c4fdfbSgilles static void *table_static_open(struct table *); 4465c4fdfbSgilles static int table_static_lookup(void *, const char *, enum table_service, 45299c4efeSeric union lookup *); 46299c4efeSeric static int table_static_fetch(void *, enum table_service, union lookup *); 4765c4fdfbSgilles static void table_static_close(void *); 48299c4efeSeric static int table_static_parse(struct table *, const char *, enum table_type); 4965c4fdfbSgilles 5065c4fdfbSgilles struct table_backend table_backend_static = { 5165c4fdfbSgilles K_ALIAS|K_CREDENTIALS|K_DOMAIN|K_NETADDR|K_USERINFO|K_SOURCE|K_MAILADDR|K_ADDRNAME, 5265c4fdfbSgilles table_static_config, 5365c4fdfbSgilles table_static_open, 5465c4fdfbSgilles table_static_update, 5565c4fdfbSgilles table_static_close, 5665c4fdfbSgilles table_static_lookup, 5765c4fdfbSgilles table_static_fetch 5865c4fdfbSgilles }; 5965c4fdfbSgilles 6065c4fdfbSgilles static struct keycmp { 6165c4fdfbSgilles enum table_service service; 6265c4fdfbSgilles int (*func)(const char *, const char *); 6365c4fdfbSgilles } keycmp[] = { 6465c4fdfbSgilles { K_DOMAIN, table_domain_match }, 6565c4fdfbSgilles { K_NETADDR, table_netaddr_match }, 6665c4fdfbSgilles { K_MAILADDR, table_mailaddr_match } 6765c4fdfbSgilles }; 6865c4fdfbSgilles 6965c4fdfbSgilles 7065c4fdfbSgilles static int 71299c4efeSeric table_static_config(struct table *table) 7265c4fdfbSgilles { 7365c4fdfbSgilles /* no config ? ok */ 74299c4efeSeric if (*table->t_config == '\0') 7565c4fdfbSgilles return 1; 7665c4fdfbSgilles 77299c4efeSeric return table_static_parse(table, table->t_config, T_LIST|T_HASH); 78299c4efeSeric } 79299c4efeSeric 80299c4efeSeric static int 81299c4efeSeric table_static_parse(struct table *t, const char *config, enum table_type type) 82299c4efeSeric { 83299c4efeSeric FILE *fp; 84299c4efeSeric char *buf, *lbuf; 85299c4efeSeric size_t flen; 86299c4efeSeric char *keyp; 87299c4efeSeric char *valp; 88299c4efeSeric size_t ret = 0; 89299c4efeSeric 90299c4efeSeric fp = fopen(config, "r"); 91299c4efeSeric if (fp == NULL) 92299c4efeSeric return 0; 93299c4efeSeric 94299c4efeSeric lbuf = NULL; 95299c4efeSeric while ((buf = fgetln(fp, &flen))) { 96299c4efeSeric if (buf[flen - 1] == '\n') 97299c4efeSeric buf[flen - 1] = '\0'; 98299c4efeSeric else { 99299c4efeSeric lbuf = xmalloc(flen + 1, "table_config_parse"); 100299c4efeSeric memcpy(lbuf, buf, flen); 101299c4efeSeric lbuf[flen] = '\0'; 102299c4efeSeric buf = lbuf; 103299c4efeSeric } 104299c4efeSeric 105299c4efeSeric keyp = buf; 106299c4efeSeric while (isspace((int)*keyp)) 107299c4efeSeric ++keyp; 108299c4efeSeric if (*keyp == '\0' || *keyp == '#') 109299c4efeSeric continue; 110299c4efeSeric valp = keyp; 111299c4efeSeric strsep(&valp, " \t:"); 112299c4efeSeric if (valp) { 113299c4efeSeric while (*valp) { 114299c4efeSeric if (!isspace(*valp) && 115299c4efeSeric !(*valp == ':' && isspace(*(valp + 1)))) 116299c4efeSeric break; 117299c4efeSeric ++valp; 118299c4efeSeric } 119299c4efeSeric if (*valp == '\0') 120299c4efeSeric valp = NULL; 121299c4efeSeric } 122299c4efeSeric 123299c4efeSeric /**/ 124299c4efeSeric if (t->t_type == 0) 125299c4efeSeric t->t_type = (valp == keyp || valp == NULL) ? T_LIST : 126299c4efeSeric T_HASH; 127299c4efeSeric 128299c4efeSeric if (!(t->t_type & type)) 129299c4efeSeric goto end; 130299c4efeSeric 131299c4efeSeric if ((valp == keyp || valp == NULL) && t->t_type == T_LIST) 132299c4efeSeric table_add(t, keyp, NULL); 133299c4efeSeric else if ((valp != keyp && valp != NULL) && t->t_type == T_HASH) 134299c4efeSeric table_add(t, keyp, valp); 135299c4efeSeric else 136299c4efeSeric goto end; 137299c4efeSeric } 1383f95a974Seric /* Accept empty alias files; treat them as hashes */ 1393f95a974Seric if (t->t_type == T_NONE && t->t_backend->services & K_ALIAS) 1403f95a974Seric t->t_type = T_HASH; 1413f95a974Seric 142299c4efeSeric ret = 1; 143299c4efeSeric end: 144299c4efeSeric free(lbuf); 145299c4efeSeric fclose(fp); 146299c4efeSeric return ret; 14765c4fdfbSgilles } 14865c4fdfbSgilles 14965c4fdfbSgilles static int 15065c4fdfbSgilles table_static_update(struct table *table) 15165c4fdfbSgilles { 15265c4fdfbSgilles struct table *t; 153299c4efeSeric void *p = NULL; 15465c4fdfbSgilles 15565c4fdfbSgilles /* no config ? ok */ 15665c4fdfbSgilles if (table->t_config[0] == '\0') 15765c4fdfbSgilles goto ok; 15865c4fdfbSgilles 159299c4efeSeric t = table_create("static", table->t_name, "update", table->t_config); 160299c4efeSeric if (!table_config(t)) 16165c4fdfbSgilles goto err; 16265c4fdfbSgilles 163dd047c3bSgilles /* replace former table, frees t */ 164*19503c5aSeric while (dict_poproot(&table->t_dict, (void **)&p)) 165299c4efeSeric free(p); 166299c4efeSeric dict_merge(&table->t_dict, &t->t_dict); 167299c4efeSeric table_destroy(t); 16865c4fdfbSgilles 16965c4fdfbSgilles ok: 170dd047c3bSgilles log_info("info: Table \"%s\" successfully updated", table->t_name); 17165c4fdfbSgilles return 1; 17265c4fdfbSgilles 17365c4fdfbSgilles err: 17465c4fdfbSgilles table_destroy(t); 175dd047c3bSgilles log_info("info: Failed to update table \"%s\"", table->t_name); 17665c4fdfbSgilles return 0; 17765c4fdfbSgilles } 17865c4fdfbSgilles 17965c4fdfbSgilles static void * 18065c4fdfbSgilles table_static_open(struct table *table) 18165c4fdfbSgilles { 18265c4fdfbSgilles return table; 18365c4fdfbSgilles } 18465c4fdfbSgilles 18565c4fdfbSgilles static void 18665c4fdfbSgilles table_static_close(void *hdl) 18765c4fdfbSgilles { 18865c4fdfbSgilles return; 18965c4fdfbSgilles } 19065c4fdfbSgilles 19165c4fdfbSgilles static int 19265c4fdfbSgilles table_static_lookup(void *hdl, const char *key, enum table_service service, 193299c4efeSeric union lookup *lk) 19465c4fdfbSgilles { 19565c4fdfbSgilles struct table *m = hdl; 19665c4fdfbSgilles char *line; 19765c4fdfbSgilles int ret; 19865c4fdfbSgilles int (*match)(const char *, const char *) = NULL; 19965c4fdfbSgilles size_t i; 20065c4fdfbSgilles void *iter; 20165c4fdfbSgilles const char *k; 20265c4fdfbSgilles char *v; 20365c4fdfbSgilles 20465c4fdfbSgilles for (i = 0; i < nitems(keycmp); ++i) 20565c4fdfbSgilles if (keycmp[i].service == service) 20665c4fdfbSgilles match = keycmp[i].func; 20765c4fdfbSgilles 20865c4fdfbSgilles line = NULL; 20965c4fdfbSgilles iter = NULL; 21065c4fdfbSgilles ret = 0; 21165c4fdfbSgilles while (dict_iter(&m->t_dict, &iter, &k, (void **)&v)) { 21265c4fdfbSgilles if (match) { 21365c4fdfbSgilles if (match(key, k)) { 21465c4fdfbSgilles line = v; 21565c4fdfbSgilles ret = 1; 21665c4fdfbSgilles } 21765c4fdfbSgilles } 21865c4fdfbSgilles else { 21965c4fdfbSgilles if (strcmp(key, k) == 0) { 22065c4fdfbSgilles line = v; 22165c4fdfbSgilles ret = 1; 22265c4fdfbSgilles } 22365c4fdfbSgilles } 22465c4fdfbSgilles if (ret) 22565c4fdfbSgilles break; 22665c4fdfbSgilles } 22765c4fdfbSgilles 228299c4efeSeric if (lk == NULL) 22965c4fdfbSgilles return ret ? 1 : 0; 23065c4fdfbSgilles 231299c4efeSeric if (ret == 0) 23265c4fdfbSgilles return 0; 23365c4fdfbSgilles 234299c4efeSeric return table_parse_lookup(service, key, line, lk); 23565c4fdfbSgilles } 23665c4fdfbSgilles 23765c4fdfbSgilles static int 238299c4efeSeric table_static_fetch(void *hdl, enum table_service service, union lookup *lk) 23965c4fdfbSgilles { 24065c4fdfbSgilles struct table *t = hdl; 24165c4fdfbSgilles const char *k; 24265c4fdfbSgilles 24365c4fdfbSgilles if (! dict_iter(&t->t_dict, &t->t_iter, &k, (void **)NULL)) { 24465c4fdfbSgilles t->t_iter = NULL; 24565c4fdfbSgilles if (! dict_iter(&t->t_dict, &t->t_iter, &k, (void **)NULL)) 24665c4fdfbSgilles return 0; 24765c4fdfbSgilles } 24865c4fdfbSgilles 249299c4efeSeric if (lk == NULL) 25065c4fdfbSgilles return 1; 25165c4fdfbSgilles 252299c4efeSeric return table_parse_lookup(service, NULL, k, lk); 25365c4fdfbSgilles } 254