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