conf.c revision 1.56
1/*	$OpenBSD: conf.c,v 1.56 2003/06/10 16:41:29 deraadt 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
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", 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", "NONE", 0 };
397
398  /* Abbreviations to make section names a bit shorter.  */
399  char *mm_auth_p[] = { "", "-DSS", "-RSA_SIG", 0 };
400  char *mm_enc_p[]  = { "DES", "BLF", "3DES", "CAST", 0 };
401  char *dh_group_p[]= { "-GRP1", "-GRP2", "-GRP5", "", 0 };
402  char *qm_enc_p[]  = { "-DES", "-3DES", "-CAST", "-BLF", "-AES", 0 };
403  char *qm_hash_p[] = { "-MD5", "-SHA", "-RIPEMD", "", 0 };
404
405  /* Helper #defines, incl abbreviations.  */
406#define PROTO(x)  ((x) ? "AH" : "ESP")
407#define PFS(x)    ((x) ? "-PFS" : "")
408#define MODE(x)   ((x) ? "TRANSPORT" : "TUNNEL")
409#define MODE_p(x) ((x) ? "-TRP" : "")
410  group_max = sizeof dh_group / sizeof *dh_group - 1;
411
412  /* General and X509 defaults */
413  conf_set (tr, "General", "Retransmits", CONF_DFLT_RETRANSMITS, 0, 1);
414  conf_set (tr, "General", "Exchange-max-time", CONF_DFLT_EXCH_MAX_TIME, 0, 1);
415  conf_set (tr, "General", "Policy-file", CONF_DFLT_POLICY_FILE, 0, 1);
416  conf_set (tr, "General", "Pubkey-directory", CONF_DFLT_PUBKEY_DIR, 0, 1);
417
418#ifdef USE_X509
419  conf_set (tr, "X509-certificates", "CA-directory", CONF_DFLT_X509_CA_DIR, 0,
420	    1);
421  conf_set (tr, "X509-certificates", "Cert-directory", CONF_DFLT_X509_CERT_DIR,
422	    0, 1);
423  conf_set (tr, "X509-certificates", "Private-key", CONF_DFLT_X509_PRIVATE_KEY,
424	    0, 1);
425  conf_set (tr, "X509-certificates", "CRL-directory", CONF_DFLT_X509_CRL_DIR,
426	    0, 1);
427#endif
428
429#ifdef USE_KEYNOTE
430  conf_set (tr, "KeyNote", "Credential-directory", CONF_DFLT_KEYNOTE_CRED_DIR,
431	    0, 1);
432#endif
433
434  /* Lifetimes. XXX p1/p2 vs main/quick mode may be unclear.  */
435  dflt = conf_get_trans_str (tr, "General", "Default-phase-1-lifetime");
436  conf_set (tr, CONF_DFLT_TAG_LIFE_MAIN_MODE, "LIFE_TYPE",
437	    CONF_DFLT_TYPE_LIFE_MAIN_MODE, 0, 1);
438  conf_set (tr, CONF_DFLT_TAG_LIFE_MAIN_MODE, "LIFE_DURATION",
439	    (dflt ? dflt : CONF_DFLT_VAL_LIFE_MAIN_MODE), 0, 1);
440
441  dflt = conf_get_trans_str (tr, "General", "Default-phase-2-lifetime");
442  conf_set (tr, CONF_DFLT_TAG_LIFE_QUICK_MODE, "LIFE_TYPE",
443	    CONF_DFLT_TYPE_LIFE_QUICK_MODE, 0, 1);
444  conf_set (tr, CONF_DFLT_TAG_LIFE_QUICK_MODE, "LIFE_DURATION",
445	    (dflt ? dflt : CONF_DFLT_VAL_LIFE_QUICK_MODE), 0, 1);
446
447  /* Default Phase-1 Configuration section */
448  conf_set (tr, CONF_DFLT_TAG_PHASE1_CONFIG, "EXCHANGE_TYPE",
449	    CONF_DFLT_PHASE1_EXCH_TYPE, 0, 1);
450  conf_set (tr, CONF_DFLT_TAG_PHASE1_CONFIG, "Transforms",
451	    CONF_DFLT_PHASE1_TRANSFORMS, 0, 1);
452
453  /* Main modes */
454  for (enc = 0; mm_enc[enc]; enc ++)
455    for (hash = 0; mm_hash[hash]; hash ++)
456      for (auth = 0; mm_auth[auth]; auth ++)
457	for (group = 0; dh_group_p[group]; group ++) /* special */
458	  {
459	    snprintf (sect, sizeof sect, "%s-%s%s%s", mm_enc_p[enc],
460		      mm_hash[hash], dh_group_p[group], mm_auth_p[auth]);
461
462#if 0
463	    if (!conf_find_trans_xf (1, sect))
464	      continue;
465#endif
466
467	    LOG_DBG ((LOG_MISC, 90, "conf_load_defaults : main mode %s",
468		      sect));
469
470	    conf_set (tr, sect, "ENCRYPTION_ALGORITHM", mm_enc[enc], 0, 1);
471	    if (strcmp (mm_enc[enc], "BLOWFISH_CBC") == 0)
472	      conf_set (tr, sect, "KEY_LENGTH", CONF_DFLT_VAL_BLF_KEYLEN, 0,
473			1);
474
475	    conf_set (tr, sect, "HASH_ALGORITHM", mm_hash[hash], 0, 1);
476	    conf_set (tr, sect, "AUTHENTICATION_METHOD", mm_auth[auth], 0, 1);
477
478	    /* XXX Always DH group 2 (MODP_1024) */
479	    conf_set (tr, sect, "GROUP_DESCRIPTION",
480		      dh_group[group < group_max ? group : 1], 0, 1);
481
482	    conf_set (tr, sect, "Life", CONF_DFLT_TAG_LIFE_MAIN_MODE, 0, 1);
483	}
484
485  /* Setup a default Phase 1 entry */
486  conf_set (tr, "Phase 1", "Default", "Default-phase-1", 0, 1);
487
488  conf_set (tr, "Default-phase-1", "Phase", "1", 0, 1);
489  conf_set (tr, "Default-phase-1", "Configuration",
490            "Default-phase-1-configuration", 0, 1);
491  dflt = conf_get_trans_str (tr, "General", "Default-phase-1-ID");
492  if (dflt)
493    conf_set (tr, "Default-phase-1", "ID", dflt, 0, 1);
494
495   /* Quick modes */
496  for (enc = 0; qm_enc[enc]; enc ++)
497    for (proto = 0; proto < 2; proto ++)
498      for (mode = 0; mode < 2; mode ++)
499	for (pfs = 0; pfs < 2; pfs ++)
500	  for (hash = 0; qm_hash[hash]; hash ++)
501	    for (group = 0; dh_group_p[group]; group ++)
502	      if ((proto == 1 && strcmp (qm_hash[hash], "NONE") == 0)) /* AH */
503		continue;
504	      else
505		{
506		  char tmp[CONF_MAX];
507
508		  snprintf (tmp, sizeof tmp, "QM-%s%s%s%s%s%s", PROTO (proto),
509			    MODE_p (mode), qm_enc_p[enc], qm_hash_p[hash],
510			    PFS (pfs), dh_group_p[group]);
511
512		  strlcpy (sect, tmp, CONF_MAX);
513		  strlcat (sect, "-SUITE", CONF_MAX);
514
515#if 0
516		  if (!conf_find_trans_xf (2, sect))
517		    continue;
518#endif
519
520		  LOG_DBG ((LOG_MISC, 90, "conf_load_defaults : quick mode %s",
521			    sect));
522
523		  conf_set (tr, sect, "Protocols", tmp, 0, 1);
524
525		  snprintf (sect, sizeof sect, "IPSEC_%s", PROTO (proto));
526		  conf_set (tr, tmp, "PROTOCOL_ID", sect, 0, 1);
527
528		  strlcpy (sect, tmp, CONF_MAX);
529		  strlcat (sect, "-XF", CONF_MAX);
530		  conf_set (tr, tmp, "Transforms", sect, 0, 1);
531
532		  /* XXX For now, defaults contain one xf per protocol.  */
533
534		  conf_set (tr, sect, "TRANSFORM_ID", qm_enc[enc], 0, 1);
535
536		  if (strcmp (qm_enc[enc], "BLOWFISH") == 0)
537		    conf_set (tr, sect, "KEY_LENGTH", CONF_DFLT_VAL_BLF_KEYLEN,
538			      0, 1);
539
540		  conf_set (tr, sect, "ENCAPSULATION_MODE", MODE (mode), 0, 1);
541
542		  if (strcmp (qm_hash[hash], "NONE"))
543		    {
544		      conf_set (tr, sect, "AUTHENTICATION_ALGORITHM",
545				qm_hash[hash], 0, 1);
546
547		      /* XXX Another shortcut -- to keep length down.  */
548		      if (pfs)
549			conf_set (tr, sect, "GROUP_DESCRIPTION",
550				  dh_group[group < group_max ? group : 1], 0,
551				  1);
552		    }
553
554		  /* XXX Lifetimes depending on enc/auth strength?  */
555		  conf_set (tr, sect, "Life", CONF_DFLT_TAG_LIFE_QUICK_MODE, 0,
556			    1);
557	      }
558  return;
559}
560
561void
562conf_init (void)
563{
564  unsigned int i;
565
566  for (i = 0; i < sizeof conf_bindings / sizeof conf_bindings[0]; i++)
567    LIST_INIT (&conf_bindings[i]);
568  TAILQ_INIT (&conf_trans_queue);
569  conf_reinit ();
570}
571
572/* Open the config file and map it into our address space, then parse it.  */
573void
574conf_reinit (void)
575{
576  struct conf_binding *cb = 0;
577  int fd, trans;
578  unsigned int i;
579  size_t sz;
580  char *new_conf_addr = 0;
581  struct stat sb;
582
583  if ((stat (conf_path, &sb) == 0) || (errno != ENOENT))
584    {
585      if (check_file_secrecy (conf_path, &sz))
586	return;
587
588      fd = monitor_open (conf_path, O_RDONLY, 0);
589      if (fd == -1)
590        {
591	  log_error ("conf_reinit: open (\"%s\", O_RDONLY) failed", conf_path);
592	  return;
593	}
594
595      new_conf_addr = malloc (sz);
596      if (!new_conf_addr)
597        {
598	  log_error ("conf_reinit: malloc (%lu) failed", (unsigned long)sz);
599	  goto fail;
600	}
601
602      /* XXX I assume short reads won't happen here.  */
603      if (read (fd, new_conf_addr, sz) != (int)sz)
604        {
605	    log_error ("conf_reinit: read (%d, %p, %lu) failed",
606		       fd, new_conf_addr, (unsigned long)sz);
607	    goto fail;
608	}
609      close (fd);
610
611      trans = conf_begin ();
612
613      /* XXX Should we not care about errors and rollback?  */
614      conf_parse (trans, new_conf_addr, sz);
615    }
616  else
617    trans = conf_begin ();
618
619  /* Load default configuration values.  */
620  conf_load_defaults (trans);
621
622  /* Free potential existing configuration.  */
623  if (conf_addr)
624    {
625      for (i = 0; i < sizeof conf_bindings / sizeof conf_bindings[0]; i++)
626	for (cb = LIST_FIRST (&conf_bindings[i]); cb;
627	     cb = LIST_FIRST (&conf_bindings[i]))
628	  conf_remove_now (cb->section, cb->tag);
629      free (conf_addr);
630    }
631
632  conf_end (trans, 1);
633  conf_addr = new_conf_addr;
634  return;
635
636 fail:
637  if (new_conf_addr)
638    free (new_conf_addr);
639  close (fd);
640}
641
642/*
643 * Return the numeric value denoted by TAG in section SECTION or DEF
644 * if that tag does not exist.
645 */
646int
647conf_get_num (char *section, char *tag, int def)
648{
649  char *value = conf_get_str (section, tag);
650
651  if (value)
652      return atoi (value);
653  return def;
654}
655
656/*
657 * Return the socket endpoint address denoted by TAG in SECTION as a
658 * struct sockaddr.  It is the callers responsibility to deallocate
659 * this structure when it is finished with it.
660 */
661struct sockaddr *
662conf_get_address (char *section, char *tag)
663{
664  char *value = conf_get_str (section, tag);
665  struct sockaddr *sa;
666
667  if (!value)
668    return 0;
669  if (text2sockaddr (value, 0, &sa) == -1)
670    return 0;
671  return sa;
672}
673
674/* Validate X according to the range denoted by TAG in section SECTION.  */
675int
676conf_match_num (char *section, char *tag, int x)
677{
678  char *value = conf_get_str (section, tag);
679  int val, min, max, n;
680
681  if (!value)
682    return 0;
683  n = sscanf (value, "%d,%d:%d", &val, &min, &max);
684  switch (n)
685    {
686    case 1:
687      LOG_DBG ((LOG_MISC, 90, "conf_match_num: %s:%s %d==%d?", section, tag,
688		val, x));
689      return x == val;
690    case 3:
691      LOG_DBG ((LOG_MISC, 90, "conf_match_num: %s:%s %d<=%d<=%d?", section,
692		tag, min, x, max));
693      return min <= x && max >= x;
694    default:
695      log_error ("conf_match_num: section %s tag %s: invalid number spec %s",
696		 section, tag, value);
697    }
698  return 0;
699}
700
701/* Return the string value denoted by TAG in section SECTION.  */
702char *
703conf_get_str (char *section, char *tag)
704{
705  struct conf_binding *cb;
706
707  for (cb = LIST_FIRST (&conf_bindings[conf_hash (section)]); cb;
708       cb = LIST_NEXT (cb, link))
709    if (strcasecmp (section, cb->section) == 0
710	&& strcasecmp (tag, cb->tag) == 0)
711      {
712	LOG_DBG ((LOG_MISC, 95, "conf_get_str: [%s]:%s->%s", section,
713		  tag, cb->value));
714	return cb->value;
715      }
716  LOG_DBG ((LOG_MISC, 95,
717	    "conf_get_str: configuration value not found [%s]:%s", section,
718	    tag));
719  return 0;
720}
721
722/*
723 * Build a list of string values out of the comma separated value denoted by
724 * TAG in SECTION.
725 */
726struct conf_list *
727conf_get_list (char *section, char *tag)
728{
729  char *liststr = 0, *p, *field, *t;
730  struct conf_list *list = 0;
731  struct conf_list_node *node;
732
733  list = malloc (sizeof *list);
734  if (!list)
735    goto cleanup;
736  TAILQ_INIT (&list->fields);
737  list->cnt = 0;
738  liststr = conf_get_str (section, tag);
739  if (!liststr)
740    goto cleanup;
741  liststr = strdup (liststr);
742  if (!liststr)
743    goto cleanup;
744  p = liststr;
745  while ((field = strsep (&p, ",")) != NULL)
746    {
747      /* Skip leading whitespace */
748      while (isspace (*field))
749	field++;
750      /* Skip trailing whitespace */
751      if (p)
752	for (t = p - 1; t > field && isspace (*t); t--)
753	  *t = '\0';
754      if (*field == '\0')
755	{
756	  log_print ("conf_get_list: empty field, ignoring...");
757	  continue;
758	}
759      list->cnt++;
760      node = calloc (1, sizeof *node);
761      if (!node)
762	goto cleanup;
763      node->field = strdup (field);
764      if (!node->field)
765	goto cleanup;
766      TAILQ_INSERT_TAIL (&list->fields, node, link);
767    }
768  free (liststr);
769  return list;
770
771 cleanup:
772  if (list)
773    conf_free_list (list);
774  if (liststr)
775    free (liststr);
776  return 0;
777}
778
779struct conf_list *
780conf_get_tag_list (char *section)
781{
782  struct conf_list *list = 0;
783  struct conf_list_node *node;
784  struct conf_binding *cb;
785
786  list = malloc (sizeof *list);
787  if (!list)
788    goto cleanup;
789  TAILQ_INIT (&list->fields);
790  list->cnt = 0;
791  for (cb = LIST_FIRST (&conf_bindings[conf_hash (section)]); cb;
792       cb = LIST_NEXT (cb, link))
793    if (strcasecmp (section, cb->section) == 0)
794      {
795	list->cnt++;
796	node = calloc (1, sizeof *node);
797	if (!node)
798	  goto cleanup;
799	node->field = strdup (cb->tag);
800	if (!node->field)
801	  goto cleanup;
802	TAILQ_INSERT_TAIL (&list->fields, node, link);
803      }
804  return list;
805
806 cleanup:
807  if (list)
808    conf_free_list (list);
809  return 0;
810}
811
812/* Decode a PEM encoded buffer.  */
813int
814conf_decode_base64 (u_int8_t *out, u_int32_t *len, u_char *buf)
815{
816  u_int32_t c = 0;
817  u_int8_t c1, c2, c3, c4;
818
819  while (*buf)
820    {
821      if (*buf > 127 || (c1 = asc2bin[*buf]) == 255)
822	return 0;
823      buf++;
824
825      if (*buf > 127 || (c2 = asc2bin[*buf]) == 255)
826	return 0;
827      buf++;
828
829      if (*buf == '=')
830	{
831	  c3 = c4 = 0;
832	  c++;
833
834	  /* Check last four bit */
835	  if (c2 & 0xF)
836	    return 0;
837
838	  if (strcmp ((char *)buf, "==") == 0)
839	    buf++;
840	  else
841	    return 0;
842	}
843      else if (*buf > 127 || (c3 = asc2bin[*buf]) == 255)
844	return 0;
845      else
846	{
847	  if (*++buf == '=')
848	    {
849	      c4 = 0;
850	      c += 2;
851
852	      /* Check last two bit */
853	      if (c3 & 3)
854		return 0;
855
856	      if (strcmp ((char *)buf, "="))
857		return 0;
858
859	    }
860	  else if (*buf > 127 || (c4 = asc2bin[*buf]) == 255)
861	      return 0;
862	  else
863	      c += 3;
864	}
865
866      buf++;
867      *out++ = (c1 << 2) | (c2 >> 4);
868      *out++ = (c2 << 4) | (c3 >> 2);
869      *out++ = (c3 << 6) | c4;
870    }
871
872  *len = c;
873  return 1;
874
875}
876
877void
878conf_free_list (struct conf_list *list)
879{
880  struct conf_list_node *node = TAILQ_FIRST (&list->fields);
881
882  while (node)
883    {
884      TAILQ_REMOVE (&list->fields, node, link);
885      if (node->field)
886	free (node->field);
887      free (node);
888      node = TAILQ_FIRST (&list->fields);
889    }
890  free (list);
891}
892
893int
894conf_begin (void)
895{
896  static int seq = 0;
897
898  return ++seq;
899}
900
901static struct conf_trans *
902conf_trans_node (int transaction, enum conf_op op)
903{
904  struct conf_trans *node;
905
906  node = calloc (1, sizeof *node);
907  if (!node)
908    {
909      log_error ("conf_trans_node: calloc (1, %lu) failed",
910	(unsigned long)sizeof *node);
911      return 0;
912    }
913  node->trans = transaction;
914  node->op = op;
915  TAILQ_INSERT_TAIL (&conf_trans_queue, node, link);
916  return node;
917}
918
919/* Queue a set operation.  */
920int
921conf_set (int transaction, char *section, char *tag, char *value, int override,
922	  int is_default)
923{
924  struct conf_trans *node;
925
926  node = conf_trans_node (transaction, CONF_SET);
927  if (!node)
928    return 1;
929  node->section = strdup (section);
930  if (!node->section)
931    {
932      log_error ("conf_set: strdup (\"%s\") failed", section);
933      goto fail;
934    }
935  node->tag = strdup (tag);
936  if (!node->tag)
937    {
938      log_error ("conf_set: strdup (\"%s\") failed", tag);
939      goto fail;
940    }
941  node->value = strdup (value);
942  if (!node->value)
943    {
944      log_error ("conf_set: strdup (\"%s\") failed", value);
945      goto fail;
946    }
947  node->override = override;
948  node->is_default = is_default;
949  return 0;
950
951 fail:
952  if (node->tag)
953    free (node->tag);
954  if (node->section)
955    free (node->section);
956  if (node)
957    free (node);
958  return 1;
959}
960
961/* Queue a remove operation.  */
962int
963conf_remove (int transaction, char *section, char *tag)
964{
965  struct conf_trans *node;
966
967  node = conf_trans_node (transaction, CONF_REMOVE);
968  if (!node)
969    goto fail;
970  node->section = strdup (section);
971  if (!node->section)
972    {
973      log_error ("conf_remove: strdup (\"%s\") failed", section);
974      goto fail;
975    }
976  node->tag = strdup (tag);
977  if (!node->tag)
978    {
979      log_error ("conf_remove: strdup (\"%s\") failed", tag);
980      goto fail;
981    }
982  return 0;
983
984 fail:
985  if (node->section)
986    free (node->section);
987  if (node)
988    free (node);
989  return 1;
990}
991
992/* Queue a remove section operation.  */
993int
994conf_remove_section (int transaction, char *section)
995{
996  struct conf_trans *node;
997
998  node = conf_trans_node (transaction, CONF_REMOVE_SECTION);
999  if (!node)
1000    goto fail;
1001  node->section = strdup (section);
1002  if (!node->section)
1003    {
1004      log_error ("conf_remove_section: strdup (\"%s\") failed", section);
1005      goto fail;
1006    }
1007  return 0;
1008
1009 fail:
1010  if (node)
1011    free (node);
1012  return 1;
1013}
1014
1015/* Execute all queued operations for this transaction.  Cleanup.  */
1016int
1017conf_end (int transaction, int commit)
1018{
1019  struct conf_trans *node, *next;
1020
1021  for (node = TAILQ_FIRST (&conf_trans_queue); node; node = next)
1022    {
1023      next = TAILQ_NEXT (node, link);
1024      if (node->trans == transaction)
1025	{
1026	  if (commit)
1027	    switch (node->op)
1028	      {
1029	      case CONF_SET:
1030		conf_set_now (node->section, node->tag, node->value,
1031			      node->override, node->is_default);
1032		break;
1033	      case CONF_REMOVE:
1034		conf_remove_now (node->section, node->tag);
1035		break;
1036	      case CONF_REMOVE_SECTION:
1037		conf_remove_section_now (node->section);
1038		break;
1039	      default:
1040		log_print ("conf_end: unknown operation: %d", node->op);
1041	      }
1042	  TAILQ_REMOVE (&conf_trans_queue, node, link);
1043	  if (node->section)
1044	    free (node->section);
1045	  if (node->tag)
1046	    free (node->tag);
1047	  if (node->value)
1048	    free (node->value);
1049	  free (node);
1050	}
1051    }
1052  return 0;
1053}
1054
1055/*
1056 * Dump running configuration upon SIGUSR1.
1057 * Configuration is "stored in reverse order", so reverse it again.
1058 */
1059struct dumper {
1060  char *s, *v;
1061  struct dumper *next;
1062};
1063
1064static void
1065conf_report_dump (struct dumper *node)
1066{
1067  /* Recursive, cleanup when we're done.  */
1068
1069  if (node->next)
1070    conf_report_dump (node->next);
1071
1072  if (node->v)
1073    LOG_DBG ((LOG_REPORT, 0, "%s=\t%s", node->s, node->v));
1074  else if (node->s)
1075    {
1076      LOG_DBG ((LOG_REPORT, 0, "%s", node->s));
1077      if (strlen (node->s) > 0)
1078	free (node->s);
1079    }
1080
1081  free (node);
1082}
1083
1084void
1085conf_report (void)
1086{
1087  struct conf_binding *cb, *last = 0;
1088  unsigned int i, len;
1089  char *current_section = (char *)0;
1090  struct dumper *dumper, *dnode;
1091
1092  dumper = dnode = (struct dumper *)calloc (1, sizeof *dumper);
1093  if (!dumper)
1094    goto mem_fail;
1095
1096  LOG_DBG ((LOG_REPORT, 0, "conf_report: dumping running configuration"));
1097
1098  for (i = 0; i < sizeof conf_bindings / sizeof conf_bindings[0]; i++)
1099    for (cb = LIST_FIRST (&conf_bindings[i]); cb;
1100	 cb = LIST_NEXT (cb, link))
1101      {
1102	if (!cb->is_default)
1103	  {
1104	    /* Dump this entry.  */
1105	    if (!current_section || strcmp (cb->section, current_section))
1106	      {
1107		if (current_section)
1108		  {
1109		    len = strlen (current_section) + 3;
1110		    dnode->s = malloc (len);
1111		    if (!dnode->s)
1112		      goto mem_fail;
1113
1114		    snprintf (dnode->s, len, "[%s]", current_section);
1115		    dnode->next
1116		      = (struct dumper *)calloc (1, sizeof (struct dumper));
1117		    dnode = dnode->next;
1118		    if (!dnode)
1119		      goto mem_fail;
1120
1121		    dnode->s = "";
1122		    dnode->next
1123		      = (struct dumper *)calloc (1, sizeof (struct dumper));
1124		    dnode = dnode->next;
1125		    if (!dnode)
1126		      goto mem_fail;
1127		  }
1128		current_section = cb->section;
1129	      }
1130	    dnode->s = cb->tag;
1131	    dnode->v = cb->value;
1132	    dnode->next = (struct dumper *)calloc (1, sizeof (struct dumper));
1133	    dnode = dnode->next;
1134	    if (!dnode)
1135	      goto mem_fail;
1136	    last = cb;
1137	  }
1138      }
1139
1140  if (last)
1141    {
1142      len = strlen (last->section) + 3;
1143      dnode->s = malloc (len);
1144      if (!dnode->s)
1145	goto mem_fail;
1146      snprintf (dnode->s, len, "[%s]", last->section);
1147    }
1148
1149  conf_report_dump (dumper);
1150
1151  return;
1152
1153 mem_fail:
1154  log_error ("conf_report: malloc/calloc failed");
1155  while ((dnode = dumper) != 0)
1156    {
1157      dumper = dumper->next;
1158      if (dnode->s)
1159	free (dnode->s);
1160      free (dnode);
1161    }
1162  return;
1163}
1164