diff options
author | Niklas Hallqvist <niklas@cvs.openbsd.org> | 1999-08-05 22:41:09 +0000 |
---|---|---|
committer | Niklas Hallqvist <niklas@cvs.openbsd.org> | 1999-08-05 22:41:09 +0000 |
commit | d17098ca8f462d80cb591547dd68ab2a9007b0f0 (patch) | |
tree | 11e20d13c71fd3cfed591d35a57fbc91b7e1a5eb /sbin/isakmpd/conf.c | |
parent | 9fe49dd5198bd4a239db52c52b299b4d735b581c (diff) |
DESIGN-NOTES: Merge with EOM 1.47
conf.c: Merge with EOM 1.19
conf.h: Merge with EOM 1.10
ui.c: Merge with EOM 1.34
author: niklas
Dynamic updates of the configuration database is now possible, either through
ui, or through the new conf_* API described in DESIGN-NOTES
Diffstat (limited to 'sbin/isakmpd/conf.c')
-rw-r--r-- | sbin/isakmpd/conf.c | 392 |
1 files changed, 330 insertions, 62 deletions
diff --git a/sbin/isakmpd/conf.c b/sbin/isakmpd/conf.c index 1d79a0e1eac..66fdb32af04 100644 --- a/sbin/isakmpd/conf.c +++ b/sbin/isakmpd/conf.c @@ -1,5 +1,5 @@ -/* $OpenBSD: conf.c,v 1.9 1999/05/01 20:43:42 niklas Exp $ */ -/* $EOM: conf.c,v 1.18 1999/05/01 20:21:07 niklas Exp $ */ +/* $OpenBSD: conf.c,v 1.10 1999/08/05 22:41:08 niklas Exp $ */ +/* $EOM: conf.c,v 1.19 1999/08/05 14:57:59 niklas Exp $ */ /* * Copyright (c) 1998, 1999 Niklas Hallqvist. All rights reserved. @@ -51,10 +51,21 @@ #include "conf.h" #include "log.h" +struct conf_trans { + TAILQ_ENTRY (conf_trans) link; + int trans; + enum conf_op { CONF_SET, CONF_REMOVE, CONF_REMOVE_SECTION } op; + char *section; + char *tag; + char *value; + int override; +}; + +TAILQ_HEAD (conf_trans_head, conf_trans) conf_trans_queue; + /* * Radix-64 Encoding. */ - const u_int8_t bin2asc[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; @@ -86,40 +97,106 @@ struct conf_binding { }; char *conf_path = CONFIG_FILE; -LIST_HEAD (conf_bindings, conf_binding) conf_bindings; +LIST_HEAD (conf_bindings, conf_binding) conf_bindings[256]; -static off_t conf_sz; static char *conf_addr; +static __inline__ u_int8_t +conf_hash (char *s) +{ + u_int8_t hash = 0; + + while (*s) + { + hash = ((hash << 1) | (hash >> 7)) ^ tolower (*s); + s++; + } + return hash; +} + +/* + * Insert a tag-value combination from LINE (the equal sign is at POS) + */ +static int +conf_remove_now (char *section, char *tag) +{ + struct conf_binding *cb, *next; + + for (cb = LIST_FIRST (&conf_bindings[conf_hash (section)]); cb; cb = next) + { + next = LIST_NEXT (cb, link); + if (strcasecmp (cb->section, section) == 0 + && strcasecmp (cb->tag, tag) == 0) + { + LIST_REMOVE (cb, link); + log_debug (LOG_MISC, 70, "[%s]:%s->%s removed", section, tag, + cb->value); + free (cb->section); + free (cb->tag); + free (cb->value); + free (cb); + return 0; + } + } + return 1; +} + +static int +conf_remove_section_now (char *section) +{ + struct conf_binding *cb, *next; + int unseen = 1; + + for (cb = LIST_FIRST (&conf_bindings[conf_hash (section)]); cb; cb = next) + { + next = LIST_NEXT (cb, link); + if (strcasecmp (cb->section, section) == 0) + { + unseen = 0; + LIST_REMOVE (cb, link); + log_debug (LOG_MISC, 70, "[%s]:%s->%s removed", section, cb->tag, + cb->value); + free (cb->section); + free (cb->tag); + free (cb->value); + free (cb); + } + } + return unseen; +} + /* * Insert a tag-value combination from LINE (the equal sign is at POS) * into SECTION of our configuration database. - * XXX Should really be a hash table implementation. */ -static void -conf_set (char *section, char *line, int pos) +static int +conf_set_now (char *section, char *tag, char *value, int override) { - struct conf_binding *node; - int i; + struct conf_binding *node = 0; - node = malloc (sizeof *node); - if (!node) - log_fatal ("conf_set: out of memory"); - node->section = section; - node->tag = line; - for (i = 0; line[i] && i < pos; i++) - ; - line[i] = '\0'; - if (conf_get_str (section, line)) + if (override) + conf_remove_now (section, tag); + else if (conf_get_str (section, tag)) { log_print ("conf_set: duplicate tag [%s]:%s, ignoring...\n", section, - line); - return; + tag); + return 1; } - node->value = line + pos + 1 + strspn (line + pos + 1, " \t"); - LIST_INSERT_HEAD (&conf_bindings, node, link); - log_debug (LOG_MISC, 70, "(%s,%s)->%s", node->section, node->tag, + + node = calloc (1, sizeof *node); + if (!node) + { + log_error ("conf_set: calloc (1, %d) failed", sizeof *node); + return 1; + } + node->section = section; + node->tag = tag; + node->value = value; + + LIST_INSERT_HEAD (&conf_bindings[conf_hash (section)], node, link); + log_debug (LOG_MISC, 70, "[%s]:%s->%s", node->section, node->tag, node->value); + return 0; } /* @@ -127,7 +204,7 @@ conf_set (char *section, char *line, int pos) * headers and feed tag-value pairs into our configuration database. */ static void -conf_parse_line (char *line, size_t sz) +conf_parse_line (int trans, char *line, size_t sz) { char *cp = line; int i; @@ -170,7 +247,10 @@ conf_parse_line (char *line, size_t sz) ln); return; } - conf_set (section, line, i); + line[strcspn (line, " \t=")] = '\0'; + /* XXX Perhaps should we not ignore errors? */ + conf_set (trans, section, line, + line + i + 1 + strspn (line + i + 1, " \t"), 0); return; } @@ -184,24 +264,24 @@ conf_parse_line (char *line, size_t sz) /* Parse the mapped configuration file. */ static void -conf_parse (void) +conf_parse (int trans, char *buf, size_t sz) { - char *cp = conf_addr; - char *conf_end = conf_addr + conf_sz; + char *cp = buf; + char *bufend = buf + sz; char *line; line = cp; - while (cp < conf_end) + while (cp < bufend) { if (*cp == '\n') { /* Check for escaped newlines. */ - if (cp > conf_addr && *(cp - 1) == '\\') + if (cp > buf && *(cp - 1) == '\\') *(cp - 1) = *cp = ' '; else { *cp = '\0'; - conf_parse_line (line, cp - line); + conf_parse_line (trans, line, cp - line); line = cp + 1; } } @@ -211,43 +291,76 @@ conf_parse (void) log_print ("conf_parse: last line non-terminated, ignored."); } -/* Open the config file and map it into our address space, then parse it. */ void conf_init (void) { - int fd; - struct stat st; + int i; - /* - * Start by freeing potential existing configuration. - * - * XXX One could envision doing this late, surviving failures with just - * a warning log message that the new configuration did not get read - * and that the former one persists. - */ - if (conf_addr) - { - while (LIST_FIRST (&conf_bindings)) - LIST_REMOVE (LIST_FIRST (&conf_bindings), link); - free (conf_addr); - } + for (i = 0; i < sizeof conf_bindings / sizeof conf_bindings[0]; i++) + LIST_INIT (&conf_bindings[i]); + TAILQ_INIT (&conf_trans_queue); + conf_reinit (); +} + +/* Open the config file and map it into our address space, then parse it. */ +void +conf_reinit (void) +{ + struct conf_binding *cb = 0; + int fd, i, trans; + struct stat st; + off_t sz; + char *new_conf_addr = 0; fd = open (conf_path, O_RDONLY); if (fd == -1) - log_fatal ("open (\"%s\", O_RDONLY)", conf_path); + { + log_error ("open (\"%s\", O_RDONLY) failed", conf_path); + return; + } if (fstat (fd, &st) == -1) - log_fatal ("fstat (%d, &st)", fd); - conf_sz = st.st_size; - conf_addr = malloc (conf_sz); - if (!conf_addr) - log_fatal ("malloc (%d)", conf_sz); + { + log_error ("fstat (%d, &st) failed", fd); + goto fail; + } + sz = st.st_size; + new_conf_addr = malloc (sz); + if (!new_conf_addr) + { + log_error ("malloc (%d) failed", sz); + goto fail; + } /* XXX I assume short reads won't happen here. */ - if (read (fd, conf_addr, conf_sz) != conf_sz) - log_fatal ("read (%d, %p, %d)", fd, conf_addr, conf_sz); + if (read (fd, new_conf_addr, sz) != sz) + { + log_error ("read (%d, %p, %d) failed", fd, new_conf_addr, sz); + goto fail; + } close (fd); - LIST_INIT (&conf_bindings); - conf_parse (); + trans = conf_begin (); + + /* XXX Should we not care about errors and rollback? */ + conf_parse (trans, new_conf_addr, sz); + + /* Free potential existing configuration. */ + if (conf_addr) + { + for (i = 0; i < sizeof conf_bindings / sizeof conf_bindings[0]; i++) + for (cb = LIST_FIRST (&conf_bindings[i]); cb; + cb = LIST_FIRST (&conf_bindings[i])) + conf_remove_now (cb->section, cb->tag); + free (conf_addr); + } + + conf_end (trans, 1); + conf_addr = new_conf_addr; + return; + + fail: + if (new_conf_addr) + free (new_conf_addr); + close (fd); } /* @@ -297,16 +410,17 @@ conf_get_str (char *section, char *tag) { struct conf_binding *cb; - for (cb = LIST_FIRST (&conf_bindings); cb; cb = LIST_NEXT (cb, link)) + for (cb = LIST_FIRST (&conf_bindings[conf_hash (section)]); cb; + cb = LIST_NEXT (cb, link)) if (strcasecmp (section, cb->section) == 0 && strcasecmp (tag, cb->tag) == 0) { - log_debug (LOG_MISC, 60, "conf_get_str: (%s, %s) -> %s", section, + log_debug (LOG_MISC, 60, "conf_get_str: [%s]:%s->%s", section, tag, cb->value); return cb->value; } log_debug (LOG_MISC, 60, - "conf_get_str: configuration value not found (%s, %s)", section, + "conf_get_str: configuration value not found [%s]:%s", section, tag); return 0; } @@ -373,7 +487,8 @@ conf_get_tag_list (char *section) goto cleanup; TAILQ_INIT (&list->fields); list->cnt = 0; - for (cb = LIST_FIRST (&conf_bindings); cb; cb = LIST_NEXT (cb, link)) + for (cb = LIST_FIRST (&conf_bindings[conf_hash (section)]); cb; + cb = LIST_NEXT (cb, link)) if (strcasecmp (section, cb->section) == 0) { list->cnt++; @@ -497,3 +612,156 @@ conf_free_list (struct conf_list *list) } free (list); } + +int +conf_begin (void) +{ + static int seq = 0; + + return ++seq; +} + +static struct conf_trans * +conf_trans_node (int transaction, enum conf_op op) +{ + struct conf_trans *node; + + node = calloc (1, sizeof *node); + if (!node) + { + log_error ("conf_trans_node: calloc (1, %d) failed", sizeof *node); + return 0; + } + node->trans = transaction; + node->op = op; + TAILQ_INSERT_TAIL (&conf_trans_queue, node, link); + return node; +} + +/* Queue a set operation. */ +int +conf_set (int transaction, char *section, char *tag, char *value, int override) +{ + struct conf_trans *node; + + node = conf_trans_node (transaction, CONF_SET); + if (!node) + return 1; + node->section = strdup (section); + if (!node->section) + { + log_error ("conf_set: strdup (\"%s\") failed", section); + goto fail; + } + node->tag = strdup (tag); + if (!node->tag) + { + log_error ("conf_set: strdup (\"%s\") failed", tag); + goto fail; + } + node->value = strdup (value); + if (!node->value) + { + log_error ("conf_set: strdup (\"%s\") failed", value); + goto fail; + } + node->override = override; + return 0; + + fail: + if (node->tag) + free (node->tag); + if (node->section) + free (node->section); + if (node) + free (node); + return 1; +} + +/* Queue a remove operation. */ +int +conf_remove (int transaction, char *section, char *tag) +{ + struct conf_trans *node; + + node = conf_trans_node (transaction, CONF_REMOVE); + if (!node) + goto fail; + node->section = strdup (section); + if (!node->section) + { + log_error ("conf_remove: strdup (\"%s\") failed", section); + goto fail; + } + node->tag = strdup (tag); + if (!node->tag) + { + log_error ("conf_remove: strdup (\"%s\") failed", tag); + goto fail; + } + return 0; + + fail: + if (node->section) + free (node->section); + if (node) + free (node); + return 1; +} + +/* Queue a remove section operation. */ +int +conf_remove_section (int transaction, char *section) +{ + struct conf_trans *node; + + node = conf_trans_node (transaction, CONF_REMOVE_SECTION); + if (!node) + goto fail; + node->section = strdup (section); + if (!node->section) + { + log_error ("conf_remove_section: strdup (\"%s\") failed", section); + goto fail; + } + return 0; + + fail: + if (node) + free (node); + return 1; +} + +/* Execute all queued operations for this transaction. Cleanup. */ +int +conf_end (int transaction, int commit) +{ + struct conf_trans *node, *next; + + for (node = TAILQ_FIRST (&conf_trans_queue); node; node = next) + { + next = TAILQ_NEXT (node, link); + if (node->trans == transaction) + { + if (commit) + switch (node->op) + { + case CONF_SET: + conf_set_now (node->section, node->tag, node->value, + node->override); + break; + case CONF_REMOVE: + conf_remove_now (node->section, node->tag); + break; + case CONF_REMOVE_SECTION: + conf_remove_section_now (node->section); + break; + default: + log_print ("conf_end: unknown operation: %d", node->op); + } + TAILQ_REMOVE (&conf_trans_queue, node, link); + free (node); + } + } + return 0; +} |