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