From 182362377fd4c35bea29f986416ec9a71b21febd Mon Sep 17 00:00:00 2001 From: eric Date: Fri, 28 Dec 2018 10:42:18 +0000 Subject: [PATCH] use private data structure for managing static table content ok gilles@ --- usr.sbin/smtpd/table_static.c | 190 +++++++++++++++++++++++----------- 1 file changed, 128 insertions(+), 62 deletions(-) diff --git a/usr.sbin/smtpd/table_static.c b/usr.sbin/smtpd/table_static.c index 361be8f4834..d7e9698a733 100644 --- a/usr.sbin/smtpd/table_static.c +++ b/usr.sbin/smtpd/table_static.c @@ -1,4 +1,4 @@ -/* $OpenBSD: table_static.c,v 1.29 2018/12/27 15:04:59 eric Exp $ */ +/* $OpenBSD: table_static.c,v 1.30 2018/12/28 10:42:18 eric Exp $ */ /* * Copyright (c) 2013 Eric Faurot @@ -26,7 +26,8 @@ #include #include -#include +#include + #include #include #include @@ -38,6 +39,12 @@ #include "smtpd.h" #include "log.h" +struct table_static_priv { + int type; + struct dict dict; + void *iter; +}; + /* static backend */ static int table_static_config(struct table *); static int table_static_add(struct table *, const char *, const char *); @@ -75,8 +82,47 @@ static struct keycmp { }; +static void +table_static_priv_free(struct table_static_priv *priv) +{ + void *p; + + while (dict_poproot(&priv->dict, (void **)&p)) + if (p != priv) + free(p); + free(priv); +} + static int -table_static_config(struct table *t) +table_static_priv_add(struct table_static_priv *priv, const char *key, const char *val) +{ + char lkey[1024]; + void *old, *new = NULL; + + if (!lowercase(lkey, key, sizeof lkey)) { + errno = ENAMETOOLONG; + return (-1); + } + + if (val) { + new = strdup(val); + if (new == NULL) + return (-1); + } + + /* use priv if value is null, so we can detect duplicate entries */ + old = dict_set(&priv->dict, lkey, new ? new : priv); + if (old) { + if (old != priv) + free(old); + return (1); + } + + return (0); +} + +static int +table_static_priv_load(struct table_static_priv *priv, const char *path) { FILE *fp; char *buf = NULL, *p; @@ -85,14 +131,10 @@ table_static_config(struct table *t) ssize_t flen; char *keyp; char *valp; - size_t ret = 0; - - /* no config ? ok */ - if (*t->t_config == '\0') - return 1; + int ret = 0; - if ((fp = fopen(t->t_config, "r")) == NULL) { - log_warn("warn: Table \"%s\"", t->t_config); + if ((fp = fopen(path, "r")) == NULL) { + log_warn("%s: fopen", path); return 0; } @@ -111,29 +153,29 @@ table_static_config(struct table *t) while (isspace((unsigned char)keyp[flen - 1])) keyp[--flen] = '\0'; if (*keyp == '#') { - if (t->t_type == T_NONE) { + if (priv->type == T_NONE) { keyp++; while (isspace((unsigned char)*keyp)) ++keyp; if (!strcmp(keyp, "@list")) - t->t_type = T_LIST; + priv->type = T_LIST; } continue; } - if (t->t_type == T_NONE) { + if (priv->type == T_NONE) { for (p = keyp; *p; p++) { if (*p == ' ' || *p == '\t' || *p == ':') { - t->t_type = T_HASH; + priv->type = T_HASH; break; } } - if (t->t_type == T_NONE) - t->t_type = T_LIST; + if (priv->type == T_NONE) + priv->type = T_LIST; } - if (t->t_type == T_LIST) { - table_add(t, keyp, NULL); + if (priv->type == T_LIST) { + table_static_priv_add(priv, keyp, NULL); continue; } @@ -152,22 +194,22 @@ table_static_config(struct table *t) valp = NULL; } if (valp == NULL) { - log_warnx("%s: invalid map entry line %d", t->t_config, - lineno); + log_warnx("%s: invalid map entry line %d", + path, lineno); goto end; } - table_add(t, keyp, valp); + table_static_priv_add(priv, keyp, valp); } if (ferror(fp)) { - log_warn("%s: getline", t->t_config); + log_warn("%s: getline", path); goto end; } /* Accept empty alias files; treat them as hashes */ - if (t->t_type == T_NONE && t->t_backend->services & K_ALIAS) - t->t_type = T_HASH; + if (priv->type == T_NONE) + priv->type = T_HASH; ret = 1; end: @@ -177,34 +219,69 @@ end: } static int -table_static_add(struct table *table, const char *key, const char *val) +table_static_config(struct table *t) { - char lkey[1024], *old; + struct table_static_priv *priv, *old; - if (!lowercase(lkey, key, sizeof lkey)) { - log_warnx("warn: lookup key too long: %s", key); + /* already up, and no config file? ok */ + if (t->t_handle && *t->t_config == '\0') + return 1; + + /* new config */ + priv = calloc(1, sizeof(*priv)); + if (priv == NULL) return 0; + priv->type = t->t_type; + dict_init(&priv->dict); + + if (*t->t_config) { + /* load the config file */ + if (table_static_priv_load(priv, t->t_config) == 0) { + table_static_priv_free(priv); + return 0; + } } - old = dict_set(&table->t_dict, lkey, val ? xstrdup(val) : NULL); - if (old) { - log_warnx("warn: duplicate key \"%s\" in static table \"%s\"", - lkey, table->t_name); - free(old); + if ((old = t->t_handle)) + table_static_priv_free(old); + t->t_handle = priv; + t->t_type = priv->type; + + return 1; +} + +static int +table_static_add(struct table *table, const char *key, const char *val) +{ + struct table_static_priv *priv = table->t_handle; + int r; + + /* cannot add to a table read from a file */ + if (*table->t_config) + return 0; + + if (priv == NULL) { + if (table_static_config(table) == 0) + return 0; + priv = table->t_handle; } + r = table_static_priv_add(priv, key, val); + if (r == -1) + return 0; return 1; } static void table_static_dump(struct table *table) { + struct table_static_priv *priv = table->t_handle; const char *key; char *value; void *iter; iter = NULL; - while (dict_iter(&table->t_dict, &iter, &key, (void**)&value)) { + while (dict_iter(&priv->dict, &iter, &key, (void**)&value)) { if (value) log_debug(" \"%s\" -> \"%s\"", key, value); else @@ -215,29 +292,11 @@ table_static_dump(struct table *table) static int table_static_update(struct table *table) { - struct table *t; - void *p = NULL; - - /* no config ? ok */ - if (table->t_config[0] == '\0') - goto ok; - - t = table_create(env, "static", table->t_name, "update", table->t_config); - if (!table_config(t)) - goto err; - - /* replace former table, frees t */ - while (dict_poproot(&table->t_dict, (void **)&p)) - free(p); - dict_merge(&table->t_dict, &t->t_dict); - table_destroy(env, t); - -ok: - log_info("info: Table \"%s\" successfully updated", table->t_name); - return 1; + if (table_static_config(table) == 1) { + log_info("info: Table \"%s\" successfully updated", table->t_name); + return 1; + } -err: - table_destroy(env, t); log_info("info: Failed to update table \"%s\"", table->t_name); return 0; } @@ -245,20 +304,26 @@ err: static int table_static_open(struct table *table) { - table->t_handle = table; + if (table->t_handle == NULL) + return table_static_config(table); return 1; } static void table_static_close(struct table *table) { + struct table_static_priv *priv = table->t_handle; + + if (priv) + table_static_priv_free(priv); table->t_handle = NULL; } static int -table_static_lookup(struct table *m, enum table_service service, const char *key, +table_static_lookup(struct table *table, enum table_service service, const char *key, char **dst) { + struct table_static_priv *priv = table->t_handle; char *line; int ret; int (*match)(const char *, const char *) = NULL; @@ -274,7 +339,7 @@ table_static_lookup(struct table *m, enum table_service service, const char *key line = NULL; iter = NULL; ret = 0; - while (dict_iter(&m->t_dict, &iter, &k, (void **)&v)) { + while (dict_iter(&priv->dict, &iter, &k, (void **)&v)) { if (match) { if (match(key, k)) { line = v; @@ -307,11 +372,12 @@ table_static_lookup(struct table *m, enum table_service service, const char *key static int table_static_fetch(struct table *t, enum table_service service, char **dst) { + struct table_static_priv *priv = t->t_handle; const char *k; - if (!dict_iter(&t->t_dict, &t->t_iter, &k, (void **)NULL)) { - t->t_iter = NULL; - if (!dict_iter(&t->t_dict, &t->t_iter, &k, (void **)NULL)) + if (!dict_iter(&priv->dict, &priv->iter, &k, (void **)NULL)) { + priv->iter = NULL; + if (!dict_iter(&priv->dict, &priv->iter, &k, (void **)NULL)) return 0; } -- 2.20.1