1*299c4efeSeric /* $OpenBSD: table_static.c,v 1.5 2013/05/24 17:03:14 eric Exp $ */ 265c4fdfbSgilles 365c4fdfbSgilles /* 4*299c4efeSeric * 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 */ 41*299c4efeSeric 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, 45*299c4efeSeric union lookup *); 46*299c4efeSeric static int table_static_fetch(void *, enum table_service, union lookup *); 4765c4fdfbSgilles static void table_static_close(void *); 48*299c4efeSeric 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 71*299c4efeSeric table_static_config(struct table *table) 7265c4fdfbSgilles { 7365c4fdfbSgilles /* no config ? ok */ 74*299c4efeSeric if (*table->t_config == '\0') 7565c4fdfbSgilles return 1; 7665c4fdfbSgilles 77*299c4efeSeric return table_static_parse(table, table->t_config, T_LIST|T_HASH); 78*299c4efeSeric } 79*299c4efeSeric 80*299c4efeSeric static int 81*299c4efeSeric table_static_parse(struct table *t, const char *config, enum table_type type) 82*299c4efeSeric { 83*299c4efeSeric FILE *fp; 84*299c4efeSeric char *buf, *lbuf; 85*299c4efeSeric size_t flen; 86*299c4efeSeric char *keyp; 87*299c4efeSeric char *valp; 88*299c4efeSeric size_t ret = 0; 89*299c4efeSeric 90*299c4efeSeric fp = fopen(config, "r"); 91*299c4efeSeric if (fp == NULL) 92*299c4efeSeric return 0; 93*299c4efeSeric 94*299c4efeSeric lbuf = NULL; 95*299c4efeSeric while ((buf = fgetln(fp, &flen))) { 96*299c4efeSeric if (buf[flen - 1] == '\n') 97*299c4efeSeric buf[flen - 1] = '\0'; 98*299c4efeSeric else { 99*299c4efeSeric lbuf = xmalloc(flen + 1, "table_config_parse"); 100*299c4efeSeric memcpy(lbuf, buf, flen); 101*299c4efeSeric lbuf[flen] = '\0'; 102*299c4efeSeric buf = lbuf; 103*299c4efeSeric } 104*299c4efeSeric 105*299c4efeSeric keyp = buf; 106*299c4efeSeric while (isspace((int)*keyp)) 107*299c4efeSeric ++keyp; 108*299c4efeSeric if (*keyp == '\0' || *keyp == '#') 109*299c4efeSeric continue; 110*299c4efeSeric valp = keyp; 111*299c4efeSeric strsep(&valp, " \t:"); 112*299c4efeSeric if (valp) { 113*299c4efeSeric while (*valp) { 114*299c4efeSeric if (!isspace(*valp) && 115*299c4efeSeric !(*valp == ':' && isspace(*(valp + 1)))) 116*299c4efeSeric break; 117*299c4efeSeric ++valp; 118*299c4efeSeric } 119*299c4efeSeric if (*valp == '\0') 120*299c4efeSeric valp = NULL; 121*299c4efeSeric } 122*299c4efeSeric 123*299c4efeSeric /**/ 124*299c4efeSeric if (t->t_type == 0) 125*299c4efeSeric t->t_type = (valp == keyp || valp == NULL) ? T_LIST : 126*299c4efeSeric T_HASH; 127*299c4efeSeric 128*299c4efeSeric if (!(t->t_type & type)) 129*299c4efeSeric goto end; 130*299c4efeSeric 131*299c4efeSeric if ((valp == keyp || valp == NULL) && t->t_type == T_LIST) 132*299c4efeSeric table_add(t, keyp, NULL); 133*299c4efeSeric else if ((valp != keyp && valp != NULL) && t->t_type == T_HASH) 134*299c4efeSeric table_add(t, keyp, valp); 135*299c4efeSeric else 136*299c4efeSeric goto end; 137*299c4efeSeric } 138*299c4efeSeric ret = 1; 139*299c4efeSeric end: 140*299c4efeSeric free(lbuf); 141*299c4efeSeric fclose(fp); 142*299c4efeSeric return ret; 14365c4fdfbSgilles } 14465c4fdfbSgilles 14565c4fdfbSgilles static int 14665c4fdfbSgilles table_static_update(struct table *table) 14765c4fdfbSgilles { 14865c4fdfbSgilles struct table *t; 149*299c4efeSeric void *p = NULL; 15065c4fdfbSgilles 15165c4fdfbSgilles /* no config ? ok */ 15265c4fdfbSgilles if (table->t_config[0] == '\0') 15365c4fdfbSgilles goto ok; 15465c4fdfbSgilles 155*299c4efeSeric t = table_create("static", table->t_name, "update", table->t_config); 156*299c4efeSeric if (!table_config(t)) 15765c4fdfbSgilles goto err; 15865c4fdfbSgilles 159dd047c3bSgilles /* replace former table, frees t */ 160*299c4efeSeric while (dict_poproot(&table->t_dict, NULL, (void **)&p)) 161*299c4efeSeric free(p); 162*299c4efeSeric dict_merge(&table->t_dict, &t->t_dict); 163*299c4efeSeric table_destroy(t); 16465c4fdfbSgilles 16565c4fdfbSgilles ok: 166dd047c3bSgilles log_info("info: Table \"%s\" successfully updated", table->t_name); 16765c4fdfbSgilles return 1; 16865c4fdfbSgilles 16965c4fdfbSgilles err: 17065c4fdfbSgilles table_destroy(t); 171dd047c3bSgilles log_info("info: Failed to update table \"%s\"", table->t_name); 17265c4fdfbSgilles return 0; 17365c4fdfbSgilles } 17465c4fdfbSgilles 17565c4fdfbSgilles static void * 17665c4fdfbSgilles table_static_open(struct table *table) 17765c4fdfbSgilles { 17865c4fdfbSgilles return table; 17965c4fdfbSgilles } 18065c4fdfbSgilles 18165c4fdfbSgilles static void 18265c4fdfbSgilles table_static_close(void *hdl) 18365c4fdfbSgilles { 18465c4fdfbSgilles return; 18565c4fdfbSgilles } 18665c4fdfbSgilles 18765c4fdfbSgilles static int 18865c4fdfbSgilles table_static_lookup(void *hdl, const char *key, enum table_service service, 189*299c4efeSeric union lookup *lk) 19065c4fdfbSgilles { 19165c4fdfbSgilles struct table *m = hdl; 19265c4fdfbSgilles char *line; 19365c4fdfbSgilles int ret; 19465c4fdfbSgilles int (*match)(const char *, const char *) = NULL; 19565c4fdfbSgilles size_t i; 19665c4fdfbSgilles void *iter; 19765c4fdfbSgilles const char *k; 19865c4fdfbSgilles char *v; 19965c4fdfbSgilles 20065c4fdfbSgilles for (i = 0; i < nitems(keycmp); ++i) 20165c4fdfbSgilles if (keycmp[i].service == service) 20265c4fdfbSgilles match = keycmp[i].func; 20365c4fdfbSgilles 20465c4fdfbSgilles line = NULL; 20565c4fdfbSgilles iter = NULL; 20665c4fdfbSgilles ret = 0; 20765c4fdfbSgilles while (dict_iter(&m->t_dict, &iter, &k, (void **)&v)) { 20865c4fdfbSgilles if (match) { 20965c4fdfbSgilles if (match(key, k)) { 21065c4fdfbSgilles line = v; 21165c4fdfbSgilles ret = 1; 21265c4fdfbSgilles } 21365c4fdfbSgilles } 21465c4fdfbSgilles else { 21565c4fdfbSgilles if (strcmp(key, k) == 0) { 21665c4fdfbSgilles line = v; 21765c4fdfbSgilles ret = 1; 21865c4fdfbSgilles } 21965c4fdfbSgilles } 22065c4fdfbSgilles if (ret) 22165c4fdfbSgilles break; 22265c4fdfbSgilles } 22365c4fdfbSgilles 224*299c4efeSeric if (lk == NULL) 22565c4fdfbSgilles return ret ? 1 : 0; 22665c4fdfbSgilles 227*299c4efeSeric if (ret == 0) 22865c4fdfbSgilles return 0; 22965c4fdfbSgilles 230*299c4efeSeric return table_parse_lookup(service, key, line, lk); 23165c4fdfbSgilles } 23265c4fdfbSgilles 23365c4fdfbSgilles static int 234*299c4efeSeric table_static_fetch(void *hdl, enum table_service service, union lookup *lk) 23565c4fdfbSgilles { 23665c4fdfbSgilles struct table *t = hdl; 23765c4fdfbSgilles const char *k; 23865c4fdfbSgilles 23965c4fdfbSgilles if (! dict_iter(&t->t_dict, &t->t_iter, &k, (void **)NULL)) { 24065c4fdfbSgilles t->t_iter = NULL; 24165c4fdfbSgilles if (! dict_iter(&t->t_dict, &t->t_iter, &k, (void **)NULL)) 24265c4fdfbSgilles return 0; 24365c4fdfbSgilles } 24465c4fdfbSgilles 245*299c4efeSeric if (lk == NULL) 24665c4fdfbSgilles return 1; 24765c4fdfbSgilles 248*299c4efeSeric return table_parse_lookup(service, NULL, k, lk); 24965c4fdfbSgilles } 250