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