summaryrefslogtreecommitdiff
path: root/sbin/isakmpd/conf.c
diff options
context:
space:
mode:
authorNiklas Hallqvist <niklas@cvs.openbsd.org>1999-08-05 22:41:09 +0000
committerNiklas Hallqvist <niklas@cvs.openbsd.org>1999-08-05 22:41:09 +0000
commitd17098ca8f462d80cb591547dd68ab2a9007b0f0 (patch)
tree11e20d13c71fd3cfed591d35a57fbc91b7e1a5eb /sbin/isakmpd/conf.c
parent9fe49dd5198bd4a239db52c52b299b4d735b581c (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.c392
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;
+}