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