conf.c revision 1.47
1/*	$OpenBSD: conf.c,v 1.47 2002/11/15 14:58:38 ho Exp $	*/
2/*	$EOM: conf.c,v 1.48 2000/12/04 02:04:29 angelos Exp $	*/
3
4/*
5 * Copyright (c) 1998, 1999, 2000, 2001 Niklas Hallqvist.  All rights reserved.
6 * Copyright (c) 2000, 2001, 2002 H�kan Olsson.  All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 *    must display the following acknowledgement:
18 *	This product includes software developed by Ericsson Radio Systems.
19 * 4. The name of the author may not be used to endorse or promote products
20 *    derived from this software without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
27 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
31 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 */
33
34/*
35 * This code was written under funding by Ericsson Radio Systems.
36 */
37
38#include <sys/param.h>
39#include <sys/mman.h>
40#include <sys/queue.h>
41#include <sys/socket.h>
42#include <sys/stat.h>
43#include <netinet/in.h>
44#include <arpa/inet.h>
45#include <ctype.h>
46#include <fcntl.h>
47#include <stdio.h>
48#include <stdlib.h>
49#include <string.h>
50#include <unistd.h>
51#include <errno.h>
52
53#include "sysdep.h"
54
55#include "app.h"
56#include "conf.h"
57#include "log.h"
58#include "util.h"
59
60static char *conf_get_trans_str (int, char *, char *);
61static void conf_load_defaults (int);
62#if 0
63static int conf_find_trans_xf (int, char *);
64#endif
65
66struct conf_trans {
67  TAILQ_ENTRY (conf_trans) link;
68  int trans;
69  enum conf_op { CONF_SET, CONF_REMOVE, CONF_REMOVE_SECTION } op;
70  char *section;
71  char *tag;
72  char *value;
73  int override;
74  int is_default;
75};
76
77TAILQ_HEAD (conf_trans_head, conf_trans) conf_trans_queue;
78
79/*
80 * Radix-64 Encoding.
81 */
82const u_int8_t bin2asc[]
83  = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
84
85const u_int8_t asc2bin[] =
86{
87  255, 255, 255, 255, 255, 255, 255, 255,
88  255, 255, 255, 255, 255, 255, 255, 255,
89  255, 255, 255, 255, 255, 255, 255, 255,
90  255, 255, 255, 255, 255, 255, 255, 255,
91  255, 255, 255, 255, 255, 255, 255, 255,
92  255, 255, 255,  62, 255, 255, 255,  63,
93   52,  53,  54,  55,  56,  57,  58,  59,
94   60,  61, 255, 255, 255, 255, 255, 255,
95  255,   0,   1,   2,   3,   4,   5,   6,
96    7,   8,   9,  10,  11,  12,  13,  14,
97   15,  16,  17,  18,  19,  20,  21,  22,
98   23,  24,  25, 255, 255, 255, 255, 255,
99  255,  26,  27,  28,  29,  30,  31,  32,
100   33,  34,  35,  36,  37,  38,  39,  40,
101   41,  42,  43,  44,  45,  46,  47,  48,
102   49,  50,  51, 255, 255, 255, 255, 255
103};
104
105struct conf_binding {
106  LIST_ENTRY (conf_binding) link;
107  char *section;
108  char *tag;
109  char *value;
110  int is_default;
111};
112
113char *conf_path = CONFIG_FILE;
114LIST_HEAD (conf_bindings, conf_binding) conf_bindings[256];
115
116static char *conf_addr;
117
118static __inline__ u_int8_t
119conf_hash (char *s)
120{
121  u_int8_t hash = 0;
122
123  while (*s)
124    {
125      hash = ((hash << 1) | (hash >> 7)) ^ tolower (*s);
126      s++;
127    }
128  return hash;
129}
130
131/*
132 * Insert a tag-value combination from LINE (the equal sign is at POS)
133 */
134static int
135conf_remove_now (char *section, char *tag)
136{
137  struct conf_binding *cb, *next;
138
139  for (cb = LIST_FIRST (&conf_bindings[conf_hash (section)]); cb; cb = next)
140    {
141      next = LIST_NEXT (cb, link);
142      if (strcasecmp (cb->section, section) == 0
143	  && strcasecmp (cb->tag, tag) == 0)
144	{
145	  LIST_REMOVE (cb, link);
146	  LOG_DBG ((LOG_MISC, 95, "[%s]:%s->%s removed", section, tag,
147		    cb->value));
148	  free (cb->section);
149	  free (cb->tag);
150	  free (cb->value);
151	  free (cb);
152	  return 0;
153	}
154    }
155  return 1;
156}
157
158static int
159conf_remove_section_now (char *section)
160{
161  struct conf_binding *cb, *next;
162  int unseen = 1;
163
164  for (cb = LIST_FIRST (&conf_bindings[conf_hash (section)]); cb; cb = next)
165    {
166      next = LIST_NEXT (cb, link);
167      if (strcasecmp (cb->section, section) == 0)
168	{
169	  unseen = 0;
170	  LIST_REMOVE (cb, link);
171	  LOG_DBG ((LOG_MISC, 95, "[%s]:%s->%s removed", section, cb->tag,
172		    cb->value));
173	  free (cb->section);
174	  free (cb->tag);
175	  free (cb->value);
176	  free (cb);
177	}
178    }
179  return unseen;
180}
181
182/*
183 * Insert a tag-value combination from LINE (the equal sign is at POS)
184 * into SECTION of our configuration database.
185 */
186static int
187conf_set_now (char *section, char *tag, char *value, int override,
188	      int is_default)
189{
190  struct conf_binding *node = 0;
191
192  if (override)
193    conf_remove_now (section, tag);
194  else if (conf_get_str (section, tag))
195    {
196      if (!is_default)
197	log_print ("conf_set: duplicate tag [%s]:%s, ignoring...\n", section,
198		   tag);
199      return 1;
200    }
201
202  node = calloc (1, sizeof *node);
203  if (!node)
204    {
205      log_error ("conf_set: calloc (1, %lu) failed", (unsigned long)sizeof *node);
206      return 1;
207    }
208  node->section = strdup (section);
209  node->tag = strdup (tag);
210  node->value = strdup (value);
211  node->is_default = is_default;
212
213  LIST_INSERT_HEAD (&conf_bindings[conf_hash (section)], node, link);
214  LOG_DBG ((LOG_MISC, 95, "conf_set: [%s]:%s->%s", node->section, node->tag,
215	    node->value));
216  return 0;
217}
218
219/*
220 * Parse the line LINE of SZ bytes.  Skip Comments, recognize section
221 * headers and feed tag-value pairs into our configuration database.
222 */
223static void
224conf_parse_line (int trans, char *line, size_t sz)
225{
226  char *val;
227  size_t i;
228  int j;
229  static char *section = 0;
230  static int ln = 0;
231
232  ln++;
233
234  /* Lines starting with '#' or ';' are comments.  */
235  if (*line == '#' || *line == ';')
236    return;
237
238  /* '[section]' parsing...  */
239  if (*line == '[')
240    {
241      for (i = 1; i < sz; i++)
242	if (line[i] == ']')
243	  break;
244      if (section)
245	free (section);
246      if (i == sz)
247	{
248	  log_print ("conf_parse_line: %d:"
249		     "non-matched ']', ignoring until next section", ln);
250	  section = 0;
251	  return;
252	}
253      section = malloc (i);
254      if (!section)
255	{
256	  log_print ("conf_parse_line: %d: malloc (%d) failed", ln, i);
257	  return;
258	}
259      strlcpy (section, line + 1, i);
260      return;
261    }
262
263  /* Deal with assignments.  */
264  for (i = 0; i < sz; i++)
265    if (line[i] == '=')
266      {
267	/* If no section, we are ignoring the lines.  */
268	if (!section)
269	  {
270	    log_print ("conf_parse_line: %d: ignoring line due to no section",
271		       ln);
272	    return;
273	  }
274	line[strcspn (line, " \t=")] = '\0';
275	val = line + i + 1 + strspn (line + i + 1, " \t");
276	/* Skip trailing whitespace, if any */
277	for (j = sz - (val - line) - 1; j > 0 && isspace (val[j]); j--)
278	  val[j] = '\0';
279	/* XXX Perhaps should we not ignore errors?  */
280	conf_set (trans, section, line, val, 0, 0);
281	return;
282      }
283
284  /* Other non-empty lines are weird.  */
285  i = strspn (line, " \t");
286  if (line[i])
287    log_print ("conf_parse_line: %d: syntax error", ln);
288
289  return;
290}
291
292/* Parse the mapped configuration file.  */
293static void
294conf_parse (int trans, char *buf, size_t sz)
295{
296  char *cp = buf;
297  char *bufend = buf + sz;
298  char *line;
299
300  line = cp;
301  while (cp < bufend)
302    {
303      if (*cp == '\n')
304	{
305	  /* Check for escaped newlines.  */
306	  if (cp > buf && *(cp - 1) == '\\')
307	    *(cp - 1) = *cp = ' ';
308	  else
309	    {
310	      *cp = '\0';
311	      conf_parse_line (trans, line, cp - line);
312	      line = cp + 1;
313	    }
314	}
315      cp++;
316    }
317  if (cp != line)
318    log_print ("conf_parse: last line non-terminated, ignored.");
319}
320
321/*
322 * Auto-generate default configuration values for the transforms and
323 * suites the user wants.
324 *
325 * Resulting section names can be:
326 *  For main mode:
327 *     {DES,BLF,3DES,CAST}-{MD5,SHA}[-GRP{1,2,5}][-{DSS,RSA_SIG}]
328 *  For quick mode:
329 *     QM-{proto}[-TRP]-{cipher}[-{hash}][-PFS[-{group}]]-SUITE
330 *     where
331 *       {proto}  = ESP, AH
332 *       {cipher} = DES, 3DES, CAST, BLF, AES
333 *       {hash}   = MD5, SHA, RIPEMD
334 *       {group}  = GRP1, GRP2, GRP5
335 *
336 * DH group defaults to MODP_1024.
337 *
338 * XXX We may want to support USE_BLOWFISH, USE_TRIPLEDES, etc...
339 * XXX No EC2N DH support here yet.
340 */
341
342/* Find the value for a section+tag in the transaction list.  */
343static char *
344conf_get_trans_str (int trans, char *section, char *tag)
345{
346  struct conf_trans *node, *nf = 0;
347
348  for (node = TAILQ_FIRST (&conf_trans_queue); node;
349       node = TAILQ_NEXT (node, link))
350    if (node->trans == trans && strcmp (section, node->section) == 0
351	&& strcmp (tag, node->tag) == 0)
352      {
353	if (!nf)
354	  nf = node;
355	else if (node->override)
356	  nf = node;
357      }
358  return nf ? nf->value : 0;
359}
360
361#if 0
362/* XXX Currently unused.  */
363static int
364conf_find_trans_xf (int phase, char *xf)
365{
366  struct conf_trans *node;
367  char *p;
368
369  /* Find the relevant transforms and suites, if any.  */
370  for (node = TAILQ_FIRST (&conf_trans_queue); node;
371       node = TAILQ_NEXT (node, link))
372    if ((phase == 1 && strcmp ("Transforms", node->tag) == 0) ||
373	(phase == 2 && strcmp ("Suites", node->tag) == 0))
374      {
375	p = node->value;
376	while ((p = strstr (p, xf)) != NULL)
377	  if (*(p + strlen (p)) && *(p + strlen (p)) != ',')
378	    p += strlen (p);
379	  else
380	    return 1;
381      }
382  return 0;
383}
384#endif
385
386static void
387conf_load_defaults (int tr)
388{
389#define CONF_MAX 256
390  int enc, auth, hash, group, group_max, proto, mode, pfs;
391  char sect[CONF_MAX], *dflt;
392
393  char *mm_auth[]   = { "PRE_SHARED", "DSS", "RSA_SIG", 0 };
394  char *mm_hash[]   = { "MD5", "SHA", 0 };
395  char *mm_enc[]    = { "DES_CBC", "BLOWFISH_CBC", "3DES_CBC",
396			"CAST_CBC", 0 };
397  char *dh_group[]  = { "MODP_768", "MODP_1024", "MODP_1536", 0 };
398  char *qm_enc[]    = { "DES", "3DES", "CAST", "BLOWFISH", "AES", 0 };
399  char *qm_hash[]   = { "HMAC_MD5", "HMAC_SHA", "HMAC_RIPEMD", "NONE", 0 };
400
401  /* Abbreviations to make section names a bit shorter.  */
402  char *mm_auth_p[] = { "", "-DSS", "-RSA_SIG", 0 };
403  char *mm_enc_p[]  = { "DES", "BLF", "3DES", "CAST", 0 };
404  char *dh_group_p[]= { "-GRP1", "-GRP2", "-GRP5", "", 0 };
405  char *qm_enc_p[]  = { "-DES", "-3DES", "-CAST", "-BLF", "-AES", 0 };
406  char *qm_hash_p[] = { "-MD5", "-SHA", "-RIPEMD", "", 0 };
407
408  /* Helper #defines, incl abbreviations.  */
409#define PROTO(x)  ((x) ? "AH" : "ESP")
410#define PFS(x)    ((x) ? "-PFS" : "")
411#define MODE(x)   ((x) ? "TRANSPORT" : "TUNNEL")
412#define MODE_p(x) ((x) ? "-TRP" : "")
413  group_max = sizeof dh_group / sizeof *dh_group - 1;
414
415  /* General and X509 defaults */
416  conf_set (tr, "General", "Retransmits", CONF_DFLT_RETRANSMITS, 0, 1);
417  conf_set (tr, "General", "Exchange-max-time", CONF_DFLT_EXCH_MAX_TIME, 0, 1);
418  conf_set (tr, "General", "Policy-file", CONF_DFLT_POLICY_FILE, 0, 1);
419
420#ifdef USE_X509
421  conf_set (tr, "X509-certificates", "CA-directory", CONF_DFLT_X509_CA_DIR, 0,
422	    1);
423  conf_set (tr, "X509-certificates", "Cert-directory", CONF_DFLT_X509_CERT_DIR,
424	    0, 1);
425  conf_set (tr, "X509-certificates", "Private-key", CONF_DFLT_X509_PRIVATE_KEY,
426	    0, 1);
427  conf_set (tr, "X509-certificates", "CRL-directory", CONF_DFLT_X509_CRL_DIR,
428	    0, 1);
429#endif
430
431#ifdef USE_KEYNOTE
432  conf_set (tr, "KeyNote", "Credential-directory", CONF_DFLT_KEYNOTE_CRED_DIR,
433	    0, 1);
434#endif
435
436  /* Lifetimes. XXX p1/p2 vs main/quick mode may be unclear.  */
437  dflt = conf_get_trans_str (tr, "General", "Default-phase-1-lifetime");
438  conf_set (tr, CONF_DFLT_TAG_LIFE_MAIN_MODE, "LIFE_TYPE",
439	    CONF_DFLT_TYPE_LIFE_MAIN_MODE, 0, 1);
440  conf_set (tr, CONF_DFLT_TAG_LIFE_MAIN_MODE, "LIFE_DURATION",
441	    (dflt ? dflt : CONF_DFLT_VAL_LIFE_MAIN_MODE), 0, 1);
442
443  dflt = conf_get_trans_str (tr, "General", "Default-phase-2-lifetime");
444  conf_set (tr, CONF_DFLT_TAG_LIFE_QUICK_MODE, "LIFE_TYPE",
445	    CONF_DFLT_TYPE_LIFE_QUICK_MODE, 0, 1);
446  conf_set (tr, CONF_DFLT_TAG_LIFE_QUICK_MODE, "LIFE_DURATION",
447	    (dflt ? dflt : CONF_DFLT_VAL_LIFE_QUICK_MODE), 0, 1);
448
449  /* Default Phase-1 Configuration section */
450  conf_set (tr, CONF_DFLT_TAG_PHASE1_CONFIG, "EXCHANGE_TYPE",
451	    CONF_DFLT_PHASE1_EXCH_TYPE, 0, 1);
452  conf_set (tr, CONF_DFLT_TAG_PHASE1_CONFIG, "Transforms",
453	    CONF_DFLT_PHASE1_TRANSFORMS, 0, 1);
454
455  /* Main modes */
456  for (enc = 0; mm_enc[enc]; enc ++)
457    for (hash = 0; mm_hash[hash]; hash ++)
458      for (auth = 0; mm_auth[auth]; auth ++)
459	for (group = 0; dh_group_p[group]; group ++) /* special */
460	  {
461	    snprintf (sect, CONF_MAX, "%s-%s%s%s", mm_enc_p[enc],
462		      mm_hash[hash], dh_group_p[group], mm_auth_p[auth]);
463
464#if 0
465	    if (!conf_find_trans_xf (1, sect))
466	      continue;
467#endif
468
469	    LOG_DBG ((LOG_MISC, 90, "conf_load_defaults : main mode %s",
470		      sect));
471
472	    conf_set (tr, sect, "ENCRYPTION_ALGORITHM", mm_enc[enc], 0, 1);
473	    if (strcmp (mm_enc[enc], "BLOWFISH_CBC") == 0)
474	      conf_set (tr, sect, "KEY_LENGTH", CONF_DFLT_VAL_BLF_KEYLEN, 0,
475			1);
476
477	    conf_set (tr, sect, "HASH_ALGORITHM", mm_hash[hash], 0, 1);
478	    conf_set (tr, sect, "AUTHENTICATION_METHOD", mm_auth[auth], 0, 1);
479
480	    /* XXX Always DH group 2 (MODP_1024) */
481	    conf_set (tr, sect, "GROUP_DESCRIPTION",
482		      dh_group[group < group_max ? group : 1], 0, 1);
483
484	    conf_set (tr, sect, "Life", CONF_DFLT_TAG_LIFE_MAIN_MODE, 0, 1);
485	}
486
487  /* Setup a default Phase 1 entry */
488  conf_set (tr, "Phase 1", "Default", "Default-phase-1", 0, 1);
489
490  conf_set (tr, "Default-phase-1", "Phase", "1", 0, 1);
491  conf_set (tr, "Default-phase-1", "Configuration",
492            "Default-phase-1-configuration", 0, 1);
493  dflt = conf_get_trans_str (tr, "General", "Default-phase-1-ID");
494  if (dflt)
495    conf_set (tr, "Default-phase-1", "ID", dflt, 0, 1);
496
497  conf_set (tr, "Default-phase-1-configuration",
498            "EXCHANGE_TYPE", "ID_PROT", 0, 1);
499  conf_set (tr, "Default-phase-1-configuration", "Transforms",
500            "3DES-SHA-RSA_SIG", 0, 1);
501
502   /* Quick modes */
503  for (enc = 0; qm_enc[enc]; enc ++)
504    for (proto = 0; proto < 2; proto ++)
505      for (mode = 0; mode < 2; mode ++)
506	for (pfs = 0; pfs < 2; pfs ++)
507	  for (hash = 0; qm_hash[hash]; hash ++)
508	    for (group = 0; dh_group_p[group]; group ++)
509	      if ((proto == 1 && strcmp (qm_hash[hash], "NONE") == 0)) /* AH */
510		continue;
511	      else
512		{
513		  char tmp[CONF_MAX];
514
515		  snprintf (tmp, CONF_MAX, "QM-%s%s%s%s%s%s", PROTO (proto),
516			    MODE_p (mode), qm_enc_p[enc], qm_hash_p[hash],
517			    PFS (pfs), dh_group_p[group]);
518
519		  strlcpy (sect, tmp, CONF_MAX);
520		  strlcat (sect, "-SUITE", CONF_MAX);
521
522#if 0
523		  if (!conf_find_trans_xf (2, sect))
524		    continue;
525#endif
526
527		  LOG_DBG ((LOG_MISC, 90, "conf_load_defaults : quick mode %s",
528			    sect));
529
530		  conf_set (tr, sect, "Protocols", tmp, 0, 1);
531
532		  snprintf (sect, CONF_MAX, "IPSEC_%s", PROTO (proto));
533		  conf_set (tr, tmp, "PROTOCOL_ID", sect, 0, 1);
534
535		  strlcpy (sect, tmp, CONF_MAX);
536		  strlcat (sect, "-XF", CONF_MAX);
537		  conf_set (tr, tmp, "Transforms", sect, 0, 1);
538
539		  /* XXX For now, defaults contain one xf per protocol.  */
540
541		  conf_set (tr, sect, "TRANSFORM_ID", qm_enc[enc], 0, 1);
542
543		  if (strcmp (qm_enc[enc], "BLOWFISH") == 0)
544		    conf_set (tr, sect, "KEY_LENGTH", CONF_DFLT_VAL_BLF_KEYLEN,
545			      0, 1);
546
547		  conf_set (tr, sect, "ENCAPSULATION_MODE", MODE (mode), 0, 1);
548
549		  if (strcmp (qm_hash[hash], "NONE"))
550		    {
551		      conf_set (tr, sect, "AUTHENTICATION_ALGORITHM",
552				qm_hash[hash], 0, 1);
553
554		      /* XXX Another shortcut -- to keep length down.  */
555		      if (pfs)
556			conf_set (tr, sect, "GROUP_DESCRIPTION",
557				  dh_group[group < group_max ? group : 1], 0,
558				  1);
559		    }
560
561		  /* XXX Lifetimes depending on enc/auth strength?  */
562		  conf_set (tr, sect, "Life", CONF_DFLT_TAG_LIFE_QUICK_MODE, 0,
563			    1);
564	      }
565  return;
566}
567
568void
569conf_init (void)
570{
571  unsigned int i;
572
573  for (i = 0; i < sizeof conf_bindings / sizeof conf_bindings[0]; i++)
574    LIST_INIT (&conf_bindings[i]);
575  TAILQ_INIT (&conf_trans_queue);
576  conf_reinit ();
577}
578
579/* Open the config file and map it into our address space, then parse it.  */
580void
581conf_reinit (void)
582{
583  struct conf_binding *cb = 0;
584  int fd, trans;
585  unsigned int i;
586  size_t sz;
587  char *new_conf_addr = 0;
588  struct stat sb;
589
590  if ((stat (conf_path, &sb) == 0) || (errno != ENOENT))
591    {
592      if (check_file_secrecy (conf_path, &sz))
593	return;
594
595      fd = open (conf_path, O_RDONLY);
596      if (fd == -1)
597        {
598	  log_error ("conf_reinit: open (\"%s\", O_RDONLY) failed", conf_path);
599	  return;
600	}
601
602      new_conf_addr = malloc (sz);
603      if (!new_conf_addr)
604        {
605	  log_error ("conf_reinit: malloc (%lu) failed", (unsigned long)sz);
606	  goto fail;
607	}
608
609      /* XXX I assume short reads won't happen here.  */
610      if (read (fd, new_conf_addr, sz) != (int)sz)
611        {
612	    log_error ("conf_reinit: read (%d, %p, %lu) failed",
613		       fd, new_conf_addr, (unsigned long)sz);
614	    goto fail;
615	}
616      close (fd);
617
618      trans = conf_begin ();
619
620      /* XXX Should we not care about errors and rollback?  */
621      conf_parse (trans, new_conf_addr, sz);
622    }
623  else
624    trans = conf_begin ();
625
626  /* Load default configuration values.  */
627  conf_load_defaults (trans);
628
629  /* Free potential existing configuration.  */
630  if (conf_addr)
631    {
632      for (i = 0; i < sizeof conf_bindings / sizeof conf_bindings[0]; i++)
633	for (cb = LIST_FIRST (&conf_bindings[i]); cb;
634	     cb = LIST_FIRST (&conf_bindings[i]))
635	  conf_remove_now (cb->section, cb->tag);
636      free (conf_addr);
637    }
638
639  conf_end (trans, 1);
640  conf_addr = new_conf_addr;
641  return;
642
643 fail:
644  if (new_conf_addr)
645    free (new_conf_addr);
646  close (fd);
647}
648
649/*
650 * Return the numeric value denoted by TAG in section SECTION or DEF
651 * if that tag does not exist.
652 */
653int
654conf_get_num (char *section, char *tag, int def)
655{
656  char *value = conf_get_str (section, tag);
657
658  if (value)
659      return atoi (value);
660  return def;
661}
662
663/*
664 * Return the socket endpoint address denoted by TAG in SECTION as a
665 * struct sockaddr.  It is the callers responsibility to deallocate
666 * this structure when it is finished with it.
667 */
668struct sockaddr *
669conf_get_address (char *section, char *tag)
670{
671  char *value = conf_get_str (section, tag);
672  struct sockaddr *sa;
673
674  if (!value)
675    return 0;
676  if (text2sockaddr (value, 0, &sa) == -1)
677    return 0;
678  return sa;
679}
680
681/* Validate X according to the range denoted by TAG in section SECTION.  */
682int
683conf_match_num (char *section, char *tag, int x)
684{
685  char *value = conf_get_str (section, tag);
686  int val, min, max, n;
687
688  if (!value)
689    return 0;
690  n = sscanf (value, "%d,%d:%d", &val, &min, &max);
691  switch (n)
692    {
693    case 1:
694      LOG_DBG ((LOG_MISC, 90, "conf_match_num: %s:%s %d==%d?", section, tag,
695		val, x));
696      return x == val;
697    case 3:
698      LOG_DBG ((LOG_MISC, 90, "conf_match_num: %s:%s %d<=%d<=%d?", section,
699		tag, min, x, max));
700      return min <= x && max >= x;
701    default:
702      log_error ("conf_match_num: section %s tag %s: invalid number spec %s",
703		 section, tag, value);
704    }
705  return 0;
706}
707
708/* Return the string value denoted by TAG in section SECTION.  */
709char *
710conf_get_str (char *section, char *tag)
711{
712  struct conf_binding *cb;
713
714  for (cb = LIST_FIRST (&conf_bindings[conf_hash (section)]); cb;
715       cb = LIST_NEXT (cb, link))
716    if (strcasecmp (section, cb->section) == 0
717	&& strcasecmp (tag, cb->tag) == 0)
718      {
719	LOG_DBG ((LOG_MISC, 95, "conf_get_str: [%s]:%s->%s", section,
720		  tag, cb->value));
721	return cb->value;
722      }
723  LOG_DBG ((LOG_MISC, 95,
724	    "conf_get_str: configuration value not found [%s]:%s", section,
725	    tag));
726  return 0;
727}
728
729/*
730 * Build a list of string values out of the comma separated value denoted by
731 * TAG in SECTION.
732 */
733struct conf_list *
734conf_get_list (char *section, char *tag)
735{
736  char *liststr = 0, *p, *field, *t;
737  struct conf_list *list = 0;
738  struct conf_list_node *node;
739
740  list = malloc (sizeof *list);
741  if (!list)
742    goto cleanup;
743  TAILQ_INIT (&list->fields);
744  list->cnt = 0;
745  liststr = conf_get_str (section, tag);
746  if (!liststr)
747    goto cleanup;
748  liststr = strdup (liststr);
749  if (!liststr)
750    goto cleanup;
751  p = liststr;
752  while ((field = strsep (&p, ",")) != NULL)
753    {
754      /* Skip leading whitespace */
755      while (isspace (*field))
756	field++;
757      /* Skip trailing whitespace */
758      if (p)
759	for (t = p - 1; t > field && isspace (*t); t--)
760	  *t = '\0';
761      if (*field == '\0')
762	{
763	  log_print ("conf_get_list: empty field, ignoring...");
764	  continue;
765	}
766      list->cnt++;
767      node = calloc (1, sizeof *node);
768      if (!node)
769	goto cleanup;
770      node->field = strdup (field);
771      if (!node->field)
772	goto cleanup;
773      TAILQ_INSERT_TAIL (&list->fields, node, link);
774    }
775  free (liststr);
776  return list;
777
778 cleanup:
779  if (list)
780    conf_free_list (list);
781  if (liststr)
782    free (liststr);
783  return 0;
784}
785
786struct conf_list *
787conf_get_tag_list (char *section)
788{
789  struct conf_list *list = 0;
790  struct conf_list_node *node;
791  struct conf_binding *cb;
792
793  list = malloc (sizeof *list);
794  if (!list)
795    goto cleanup;
796  TAILQ_INIT (&list->fields);
797  list->cnt = 0;
798  for (cb = LIST_FIRST (&conf_bindings[conf_hash (section)]); cb;
799       cb = LIST_NEXT (cb, link))
800    if (strcasecmp (section, cb->section) == 0)
801      {
802	list->cnt++;
803	node = calloc (1, sizeof *node);
804	if (!node)
805	  goto cleanup;
806	node->field = strdup (cb->tag);
807	if (!node->field)
808	  goto cleanup;
809	TAILQ_INSERT_TAIL (&list->fields, node, link);
810      }
811  return list;
812
813 cleanup:
814  if (list)
815    conf_free_list (list);
816  return 0;
817}
818
819/* Decode a PEM encoded buffer.  */
820int
821conf_decode_base64 (u_int8_t *out, u_int32_t *len, u_char *buf)
822{
823  u_int32_t c = 0;
824  u_int8_t c1, c2, c3, c4;
825
826  while (*buf)
827    {
828      if (*buf > 127 || (c1 = asc2bin[*buf]) == 255)
829	return 0;
830      buf++;
831
832      if (*buf > 127 || (c2 = asc2bin[*buf]) == 255)
833	return 0;
834      buf++;
835
836      if (*buf == '=')
837	{
838	  c3 = c4 = 0;
839	  c++;
840
841	  /* Check last four bit */
842	  if (c2 & 0xF)
843	    return 0;
844
845	  if (strcmp ((char *)buf, "==") == 0)
846	    buf++;
847	  else
848	    return 0;
849	}
850      else if (*buf > 127 || (c3 = asc2bin[*buf]) == 255)
851	return 0;
852      else
853	{
854	  if (*++buf == '=')
855	    {
856	      c4 = 0;
857	      c += 2;
858
859	      /* Check last two bit */
860	      if (c3 & 3)
861		return 0;
862
863	      if (strcmp ((char *)buf, "="))
864		return 0;
865
866	    }
867	  else if (*buf > 127 || (c4 = asc2bin[*buf]) == 255)
868	      return 0;
869	  else
870	      c += 3;
871	}
872
873      buf++;
874      *out++ = (c1 << 2) | (c2 >> 4);
875      *out++ = (c2 << 4) | (c3 >> 2);
876      *out++ = (c3 << 6) | c4;
877    }
878
879  *len = c;
880  return 1;
881
882}
883
884void
885conf_free_list (struct conf_list *list)
886{
887  struct conf_list_node *node = TAILQ_FIRST (&list->fields);
888
889  while (node)
890    {
891      TAILQ_REMOVE (&list->fields, node, link);
892      if (node->field)
893	free (node->field);
894      free (node);
895      node = TAILQ_FIRST (&list->fields);
896    }
897  free (list);
898}
899
900int
901conf_begin (void)
902{
903  static int seq = 0;
904
905  return ++seq;
906}
907
908static struct conf_trans *
909conf_trans_node (int transaction, enum conf_op op)
910{
911  struct conf_trans *node;
912
913  node = calloc (1, sizeof *node);
914  if (!node)
915    {
916      log_error ("conf_trans_node: calloc (1, %lu) failed",
917	(unsigned long)sizeof *node);
918      return 0;
919    }
920  node->trans = transaction;
921  node->op = op;
922  TAILQ_INSERT_TAIL (&conf_trans_queue, node, link);
923  return node;
924}
925
926/* Queue a set operation.  */
927int
928conf_set (int transaction, char *section, char *tag, char *value, int override,
929	  int is_default)
930{
931  struct conf_trans *node;
932
933  node = conf_trans_node (transaction, CONF_SET);
934  if (!node)
935    return 1;
936  node->section = strdup (section);
937  if (!node->section)
938    {
939      log_error ("conf_set: strdup (\"%s\") failed", section);
940      goto fail;
941    }
942  node->tag = strdup (tag);
943  if (!node->tag)
944    {
945      log_error ("conf_set: strdup (\"%s\") failed", tag);
946      goto fail;
947    }
948  node->value = strdup (value);
949  if (!node->value)
950    {
951      log_error ("conf_set: strdup (\"%s\") failed", value);
952      goto fail;
953    }
954  node->override = override;
955  node->is_default = is_default;
956  return 0;
957
958 fail:
959  if (node->tag)
960    free (node->tag);
961  if (node->section)
962    free (node->section);
963  if (node)
964    free (node);
965  return 1;
966}
967
968/* Queue a remove operation.  */
969int
970conf_remove (int transaction, char *section, char *tag)
971{
972  struct conf_trans *node;
973
974  node = conf_trans_node (transaction, CONF_REMOVE);
975  if (!node)
976    goto fail;
977  node->section = strdup (section);
978  if (!node->section)
979    {
980      log_error ("conf_remove: strdup (\"%s\") failed", section);
981      goto fail;
982    }
983  node->tag = strdup (tag);
984  if (!node->tag)
985    {
986      log_error ("conf_remove: strdup (\"%s\") failed", tag);
987      goto fail;
988    }
989  return 0;
990
991 fail:
992  if (node->section)
993    free (node->section);
994  if (node)
995    free (node);
996  return 1;
997}
998
999/* Queue a remove section operation.  */
1000int
1001conf_remove_section (int transaction, char *section)
1002{
1003  struct conf_trans *node;
1004
1005  node = conf_trans_node (transaction, CONF_REMOVE_SECTION);
1006  if (!node)
1007    goto fail;
1008  node->section = strdup (section);
1009  if (!node->section)
1010    {
1011      log_error ("conf_remove_section: strdup (\"%s\") failed", section);
1012      goto fail;
1013    }
1014  return 0;
1015
1016 fail:
1017  if (node)
1018    free (node);
1019  return 1;
1020}
1021
1022/* Execute all queued operations for this transaction.  Cleanup.  */
1023int
1024conf_end (int transaction, int commit)
1025{
1026  struct conf_trans *node, *next;
1027
1028  for (node = TAILQ_FIRST (&conf_trans_queue); node; node = next)
1029    {
1030      next = TAILQ_NEXT (node, link);
1031      if (node->trans == transaction)
1032	{
1033	  if (commit)
1034	    switch (node->op)
1035	      {
1036	      case CONF_SET:
1037		conf_set_now (node->section, node->tag, node->value,
1038			      node->override, node->is_default);
1039		break;
1040	      case CONF_REMOVE:
1041		conf_remove_now (node->section, node->tag);
1042		break;
1043	      case CONF_REMOVE_SECTION:
1044		conf_remove_section_now (node->section);
1045		break;
1046	      default:
1047		log_print ("conf_end: unknown operation: %d", node->op);
1048	      }
1049	  TAILQ_REMOVE (&conf_trans_queue, node, link);
1050	  if (node->section)
1051	    free (node->section);
1052	  if (node->tag)
1053	    free (node->tag);
1054	  if (node->value)
1055	    free (node->value);
1056	  free (node);
1057	}
1058    }
1059  return 0;
1060}
1061
1062/*
1063 * Dump running configuration upon SIGUSR1.
1064 * Configuration is "stored in reverse order", so reverse it again.
1065 */
1066struct dumper {
1067  char *s, *v;
1068  struct dumper *next;
1069};
1070
1071static void
1072conf_report_dump (struct dumper *node)
1073{
1074  /* Recursive, cleanup when we're done.  */
1075
1076  if (node->next)
1077    conf_report_dump (node->next);
1078
1079  if (node->v)
1080    LOG_DBG ((LOG_REPORT, 0, "%s=\t%s", node->s, node->v));
1081  else if (node->s)
1082    {
1083      LOG_DBG ((LOG_REPORT, 0, "%s", node->s));
1084      if (strlen (node->s) > 0)
1085	free (node->s);
1086    }
1087
1088  free (node);
1089}
1090
1091void
1092conf_report (void)
1093{
1094  struct conf_binding *cb, *last = 0;
1095  unsigned int i, len;
1096  char *current_section = (char *)0;
1097  struct dumper *dumper, *dnode;
1098
1099  dumper = dnode = (struct dumper *)calloc (1, sizeof *dumper);
1100  if (!dumper)
1101    goto mem_fail;
1102
1103  LOG_DBG ((LOG_REPORT, 0, "conf_report: dumping running configuration"));
1104
1105  for (i = 0; i < sizeof conf_bindings / sizeof conf_bindings[0]; i++)
1106    for (cb = LIST_FIRST (&conf_bindings[i]); cb;
1107	 cb = LIST_NEXT (cb, link))
1108      {
1109	if (!cb->is_default)
1110	  {
1111	    /* Dump this entry.  */
1112	    if (!current_section || strcmp (cb->section, current_section))
1113	      {
1114		if (current_section)
1115		  {
1116		    len = strlen (current_section) + 3;
1117		    dnode->s = malloc (len);
1118		    if (!dnode->s)
1119		      goto mem_fail;
1120
1121		    snprintf (dnode->s, len, "[%s]", current_section);
1122		    dnode->next
1123		      = (struct dumper *)calloc (1, sizeof (struct dumper));
1124		    dnode = dnode->next;
1125		    if (!dnode)
1126		      goto mem_fail;
1127
1128		    dnode->s = "";
1129		    dnode->next
1130		      = (struct dumper *)calloc (1, sizeof (struct dumper));
1131		    dnode = dnode->next;
1132		    if (!dnode)
1133		      goto mem_fail;
1134		  }
1135		current_section = cb->section;
1136	      }
1137	    dnode->s = cb->tag;
1138	    dnode->v = cb->value;
1139	    dnode->next = (struct dumper *)calloc (1, sizeof (struct dumper));
1140	    dnode = dnode->next;
1141	    if (!dnode)
1142	      goto mem_fail;
1143	    last = cb;
1144	  }
1145      }
1146
1147  if (last)
1148    {
1149      len = strlen (last->section) + 3;
1150      dnode->s = malloc (len);
1151      if (!dnode->s)
1152	goto mem_fail;
1153      snprintf (dnode->s, len, "[%s]", last->section);
1154    }
1155
1156  conf_report_dump (dumper);
1157
1158  return;
1159
1160 mem_fail:
1161  log_error ("conf_report: malloc/calloc failed");
1162  while ((dnode = dumper) != 0)
1163    {
1164      dumper = dumper->next;
1165      if (dnode->s)
1166	free (dnode->s);
1167      free (dnode);
1168    }
1169  return;
1170}
1171