summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sbin/isakmpd/DESIGN-NOTES39
-rw-r--r--sbin/isakmpd/conf.c392
-rw-r--r--sbin/isakmpd/conf.h10
-rw-r--r--sbin/isakmpd/ui.c54
4 files changed, 427 insertions, 68 deletions
diff --git a/sbin/isakmpd/DESIGN-NOTES b/sbin/isakmpd/DESIGN-NOTES
index 5937064de16..ecdfafbb24c 100644
--- a/sbin/isakmpd/DESIGN-NOTES
+++ b/sbin/isakmpd/DESIGN-NOTES
@@ -1,5 +1,5 @@
-$OpenBSD: DESIGN-NOTES,v 1.13 1999/07/17 21:54:39 niklas Exp $
-$EOM: DESIGN-NOTES,v 1.46 1999/07/17 20:44:07 niklas Exp $
+$OpenBSD: DESIGN-NOTES,v 1.14 1999/08/05 22:41:08 niklas Exp $
+$EOM: DESIGN-NOTES,v 1.47 1999/08/05 14:57:59 niklas Exp $
General coding conventions
--------------------------
@@ -211,6 +211,7 @@ isakmpd.fifo. The commands are one-letter codes followed by arguments.
For now, only five such commands are implemented:
c connect Establish a connection with a peer
+C configure Add or remove configuration entries.
d delete Delete an SA given cookies and message-IDs
D debug Change logging level for a debug class
r report Report status information of the daemon
@@ -230,6 +231,16 @@ D 0 99
The report command is just an "r", and results in a list of active exchanges
and security associations.
+The "C" command takes 3 subcommands: set, rm and rms, for adding and removing
+entries + remove complete sections respectively. Examples:
+
+C set [Net-A]:Address=192.168.0.0
+C rm [Net-A]:Address
+C rms [Net-A]
+
+All these commands are atomic, i.e. they are not collected into larger
+transactions, which there should be a way to do, but currently isn't.
+
I am thinking about adding a "q" command for quit.
In addition to giving commands over the FIFO, you may send signals to the
@@ -299,6 +310,30 @@ case RECORD_A_SZ == RECORD_B_FIELD_F_OFF. All this data are collected
in struct field arrays which makes it possible to symbolically print out
entire payloads in readable form via field_dump_payload.
+Configuration
+-------------
+
+Internally isakmpd uses a section-tag-value triplet database for
+configuration. Currently this happen to map really well to the
+configuration file format, which on the other hand does not map
+equally well to humans. It is envisioned that the configuration
+database should be dynamically modifiable, and through a lot of
+differnet mechanisms. Therefore we have designed an API for this
+purpose.
+
+int conf_begin ();
+int conf_set (int transaction, char *section, char *tag, char *value,
+ int override);
+int conf_remove (int transaction, char *section, char *tag);
+int conf_remove_section (int transaction, char *section);
+int conf_end (int transaction, int commit);
+
+The caller will always be responsible for the memory management of the
+passed strings, conf_set will copy the values, and not use the original
+strings after it has returned. Return value will be zero on success and
+non-zero otherwise. Note that the conf_remove* functions consider not
+finding anything to remove as failure.
+
Identification
--------------
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;
+}
diff --git a/sbin/isakmpd/conf.h b/sbin/isakmpd/conf.h
index 71b6db90ec3..8e8578e7435 100644
--- a/sbin/isakmpd/conf.h
+++ b/sbin/isakmpd/conf.h
@@ -1,5 +1,5 @@
-/* $OpenBSD: conf.h,v 1.8 1999/07/18 09:33:21 niklas Exp $ */
-/* $EOM: conf.h,v 1.9 1999/07/18 09:20:27 niklas Exp $ */
+/* $OpenBSD: conf.h,v 1.9 1999/08/05 22:41:08 niklas Exp $ */
+/* $EOM: conf.h,v 1.10 1999/08/05 14:57:59 niklas Exp $ */
/*
* Copyright (c) 1998, 1999 Niklas Hallqvist. All rights reserved.
@@ -55,7 +55,9 @@ struct conf_list {
extern char *conf_path;
+extern int conf_begin (void);
extern int conf_decode_base64 (u_int8_t *out, u_int32_t *len, u_char *buf);
+extern int conf_end (int, int);
extern void conf_free_list (struct conf_list *);
extern int conf_get_line (FILE *, char *, u_int32_t);
extern struct conf_list *conf_get_list (char *, char *);
@@ -64,5 +66,9 @@ extern int conf_get_num (char *, char *, int);
extern char *conf_get_str (char *, char *);
extern void conf_init (void);
extern int conf_match_num (char *, char *, int);
+extern void conf_reinit (void);
+extern int conf_remove (int, char *, char *);
+extern int conf_remove_section (int, char *);
+extern int conf_set (int, char *, char *, char *, int);
#endif /* _CONF_H_ */
diff --git a/sbin/isakmpd/ui.c b/sbin/isakmpd/ui.c
index 1cc2eaf64a6..08b9cbfb24d 100644
--- a/sbin/isakmpd/ui.c
+++ b/sbin/isakmpd/ui.c
@@ -1,5 +1,5 @@
-/* $OpenBSD: ui.c,v 1.9 1999/06/02 06:29:55 niklas Exp $ */
-/* $EOM: ui.c,v 1.33 1999/05/19 22:40:13 ho Exp $ */
+/* $OpenBSD: ui.c,v 1.10 1999/08/05 22:41:08 niklas Exp $ */
+/* $EOM: ui.c,v 1.34 1999/08/05 14:58:00 niklas Exp $ */
/*
* Copyright (c) 1998, 1999 Niklas Hallqvist. All rights reserved.
@@ -115,6 +115,52 @@ ui_teardown (char *cmd)
sa_delete (sa, 1);
}
+/*
+ * Call the configuration API.
+ * XXX Error handling! How to do multi-line transactions? Too short arbitrary
+ * limit on the parameters?
+ */
+static void
+ui_config (char *cmd)
+{
+ char subcmd[81], section[81], tag[81], value[81];
+ int override, trans = 0;
+
+ if (sscanf (cmd, "C %80s", subcmd) != 1)
+ goto fail;
+
+ trans = conf_begin ();
+ if (strcasecmp (subcmd, "set") == 0)
+ {
+ if (sscanf (cmd, "C %*s [%80[^]]]:%80[^=]=%80s %d", section, tag, value,
+ &override) != 4)
+ goto fail;
+ conf_set (trans, section, tag, value, override);
+ }
+ else if (strcasecmp (cmd, "rm") == 0)
+ {
+ if (sscanf (cmd, "C %*s [%80[^]]]:%80s", section, tag) != 2)
+ goto fail;
+ conf_remove (trans, section, tag);
+ }
+ else if (strcasecmp (cmd, "rms") == 0)
+ {
+ if (sscanf (cmd, "C %*s [%80[^]]]", section) != 1)
+ goto fail;
+ conf_remove_section (trans, section);
+ }
+ else
+ goto fail;
+
+ conf_end (trans, 1);
+ return;
+
+ fail:
+ if (trans)
+ conf_end (trans, 0);
+ log_print ("ui_config: command \"%s\" malformed", cmd);
+}
+
static void
ui_delete (char *cmd)
{
@@ -191,6 +237,10 @@ ui_handle_command (char *line)
ui_connect (line);
break;
+ case 'C':
+ ui_config (line);
+ break;
+
case 'd':
ui_delete (line);
break;