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