1 /* $OpenBSD: table_static.c,v 1.15 2016/01/22 13:08:44 gilles 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 *, struct dict *, const char *, 46 enum table_service, union lookup *); 47 static int table_static_fetch(void *, struct dict *, enum table_service, 48 union lookup *); 49 static void table_static_close(void *); 50 static int table_static_parse(struct table *, const char *, enum table_type); 51 52 struct table_backend table_backend_static = { 53 K_ALIAS|K_CREDENTIALS|K_DOMAIN|K_NETADDR|K_USERINFO| 54 K_SOURCE|K_MAILADDR|K_ADDRNAME|K_MAILADDRMAP, 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 }; 71 72 73 static int 74 table_static_config(struct table *table) 75 { 76 /* no config ? ok */ 77 if (*table->t_config == '\0') 78 return 1; 79 80 return table_static_parse(table, table->t_config, T_LIST|T_HASH); 81 } 82 83 static int 84 table_static_parse(struct table *t, const char *config, enum table_type type) 85 { 86 FILE *fp; 87 char *buf = NULL; 88 size_t sz = 0; 89 ssize_t flen; 90 char *keyp; 91 char *valp; 92 size_t ret = 0; 93 94 if ((fp = fopen(config, "r")) == NULL) { 95 log_warn("warn: Table \"%s\"", config); 96 return 0; 97 } 98 99 while ((flen = getline(&buf, &sz, fp)) != -1) { 100 if (buf[flen - 1] == '\n') 101 buf[flen - 1] = '\0'; 102 103 keyp = buf; 104 while (isspace((unsigned char)*keyp)) 105 ++keyp; 106 if (*keyp == '\0' || *keyp == '#') 107 continue; 108 valp = keyp; 109 strsep(&valp, " \t:"); 110 if (valp) { 111 while (*valp) { 112 if (!isspace((unsigned char)*valp) && 113 !(*valp == ':' && 114 isspace((unsigned char)*(valp + 1)))) 115 break; 116 ++valp; 117 } 118 if (*valp == '\0') 119 valp = NULL; 120 } 121 122 if (t->t_type == 0) 123 t->t_type = (valp == keyp || valp == NULL) ? T_LIST : 124 T_HASH; 125 126 if (!(t->t_type & type)) 127 goto end; 128 129 if ((valp == keyp || valp == NULL) && t->t_type == T_LIST) 130 table_add(t, keyp, NULL); 131 else if ((valp != keyp && valp != NULL) && t->t_type == T_HASH) 132 table_add(t, keyp, valp); 133 else 134 goto end; 135 } 136 /* Accept empty alias files; treat them as hashes */ 137 if (t->t_type == T_NONE && t->t_backend->services & K_ALIAS) 138 t->t_type = T_HASH; 139 140 ret = 1; 141 end: 142 free(buf); 143 fclose(fp); 144 return ret; 145 } 146 147 static int 148 table_static_update(struct table *table) 149 { 150 struct table *t; 151 void *p = NULL; 152 153 /* no config ? ok */ 154 if (table->t_config[0] == '\0') 155 goto ok; 156 157 t = table_create("static", table->t_name, "update", table->t_config); 158 if (!table_config(t)) 159 goto err; 160 161 /* replace former table, frees t */ 162 while (dict_poproot(&table->t_dict, (void **)&p)) 163 free(p); 164 dict_merge(&table->t_dict, &t->t_dict); 165 table_destroy(t); 166 167 ok: 168 log_info("info: Table \"%s\" successfully updated", table->t_name); 169 return 1; 170 171 err: 172 table_destroy(t); 173 log_info("info: Failed to update table \"%s\"", table->t_name); 174 return 0; 175 } 176 177 static void * 178 table_static_open(struct table *table) 179 { 180 return table; 181 } 182 183 static void 184 table_static_close(void *hdl) 185 { 186 return; 187 } 188 189 static int 190 table_static_lookup(void *hdl, struct dict *params, const char *key, 191 enum table_service service, union lookup *lk) 192 { 193 struct table *m = hdl; 194 char *line; 195 int ret; 196 int (*match)(const char *, const char *) = NULL; 197 size_t i; 198 void *iter; 199 const char *k; 200 char *v; 201 202 for (i = 0; i < nitems(keycmp); ++i) 203 if (keycmp[i].service == service) 204 match = keycmp[i].func; 205 206 line = NULL; 207 iter = NULL; 208 ret = 0; 209 while (dict_iter(&m->t_dict, &iter, &k, (void **)&v)) { 210 if (match) { 211 if (match(key, k)) { 212 line = v; 213 ret = 1; 214 } 215 } 216 else { 217 if (strcmp(key, k) == 0) { 218 line = v; 219 ret = 1; 220 } 221 } 222 if (ret) 223 break; 224 } 225 226 if (lk == NULL) 227 return ret ? 1 : 0; 228 229 if (ret == 0) 230 return 0; 231 232 return table_parse_lookup(service, key, line, lk); 233 } 234 235 static int 236 table_static_fetch(void *hdl, struct dict *params, 237 enum table_service service, union lookup *lk) 238 { 239 struct table *t = hdl; 240 const char *k; 241 242 if (!dict_iter(&t->t_dict, &t->t_iter, &k, (void **)NULL)) { 243 t->t_iter = NULL; 244 if (!dict_iter(&t->t_dict, &t->t_iter, &k, (void **)NULL)) 245 return 0; 246 } 247 248 if (lk == NULL) 249 return 1; 250 251 return table_parse_lookup(service, NULL, k, lk); 252 } 253