xref: /openbsd/sbin/isakmpd/conf.c (revision 78b63d65)
1 /*	$OpenBSD: conf.c,v 1.34 2001/10/05 05:59:06 ho Exp $	*/
2 /*	$EOM: conf.c,v 1.48 2000/12/04 02:04:29 angelos Exp $	*/
3 
4 /*
5  * Copyright (c) 1998, 1999, 2000, 2001 Niklas Hallqvist.  All rights reserved.
6  * Copyright (c) 2000, 2001 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 
60 static char *conf_get_trans_str (int, char *, char *);
61 static void conf_load_defaults (int);
62 #if 0
63 static int conf_find_trans_xf (int, char *);
64 #endif
65 
66 struct 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 
77 TAILQ_HEAD (conf_trans_head, conf_trans) conf_trans_queue;
78 
79 /*
80  * Radix-64 Encoding.
81  */
82 const u_int8_t bin2asc[]
83   = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
84 
85 const 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 
105 struct conf_binding {
106   LIST_ENTRY (conf_binding) link;
107   char *section;
108   char *tag;
109   char *value;
110   int is_default;
111 };
112 
113 char *conf_path = CONFIG_FILE;
114 LIST_HEAD (conf_bindings, conf_binding) conf_bindings[256];
115 
116 static char *conf_addr;
117 
118 static __inline__ u_int8_t
119 conf_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  */
134 static int
135 conf_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 
158 static int
159 conf_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  */
186 static int
187 conf_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, %d) failed", 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  */
223 static void
224 conf_parse_line (int trans, char *line, size_t sz)
225 {
226   char *cp = line;
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 (i == sz)
244 	{
245 	  log_print ("conf_parse_line: %d:"
246 		     "non-matched ']', ignoring until next section", ln);
247 	  section = 0;
248 	  return;
249 	}
250       if (section)
251 	free (section);
252       section = malloc (i);
253       strncpy (section, line + 1, i - 1);
254       section[i - 1] = '\0';
255       return;
256     }
257 
258   /* Deal with assignments.  */
259   for (i = 0; i < sz; i++)
260     if (cp[i] == '=')
261       {
262 	/* If no section, we are ignoring the lines.  */
263 	if (!section)
264 	  {
265 	    log_print ("conf_parse_line: %d: ignoring line due to no section",
266 		       ln);
267 	    return;
268 	  }
269 	line[strcspn (line, " \t=")] = '\0';
270 	/* XXX Perhaps should we not ignore errors?  */
271 	conf_set (trans, section, line,
272 		  line + i + 1 + strspn (line + i + 1, " \t"), 0, 0);
273 	return;
274       }
275 
276   /* Other non-empty lines are wierd.  */
277   i = strspn (line, " \t");
278   if (line[i])
279     log_print ("conf_parse_line: %d: syntax error", ln);
280 
281   return;
282 }
283 
284 /* Parse the mapped configuration file.  */
285 static void
286 conf_parse (int trans, char *buf, size_t sz)
287 {
288   char *cp = buf;
289   char *bufend = buf + sz;
290   char *line;
291 
292   line = cp;
293   while (cp < bufend)
294     {
295       if (*cp == '\n')
296 	{
297 	  /* Check for escaped newlines.  */
298 	  if (cp > buf && *(cp - 1) == '\\')
299 	    *(cp - 1) = *cp = ' ';
300 	  else
301 	    {
302 	      *cp = '\0';
303 	      conf_parse_line (trans, line, cp - line);
304 	      line = cp + 1;
305 	    }
306 	}
307       cp++;
308     }
309   if (cp != line)
310     log_print ("conf_parse: last line non-terminated, ignored.");
311 }
312 
313 /*
314  * Auto-generate default configuration values for the transforms and
315  * suites the user wants.
316  *
317  * Resulting section names can be:
318  *  For main mode:
319  *     {DES,BLF,3DES,CAST}-{MD5,SHA}[-{DSS,RSA_SIG}]
320  *  For quick mode:
321  *     QM-{ESP,AH}[-TRP]-{DES,3DES,CAST,BLF,AES}[-{MD5,SHA,RIPEMD}][-PFS]-SUITE
322  * DH groups; currently always MODP_768 for MD5, and MODP_1024 for SHA.
323  *
324  * XXX We may want to support USE_BLOWFISH, USE_TRIPLEDES, etc...
325  * XXX No EC2N DH support here yet.
326  */
327 
328 /* Find the value for a section+tag in the transaction list.  */
329 static char *
330 conf_get_trans_str (int trans, char *section, char *tag)
331 {
332   struct conf_trans *node, *nf = 0;
333 
334   for (node = TAILQ_FIRST (&conf_trans_queue); node;
335        node = TAILQ_NEXT (node, link))
336     if (node->trans == trans && strcmp (section, node->section) == 0
337 	&& strcmp (tag, node->tag) == 0)
338       {
339 	if (!nf)
340 	  nf = node;
341 	else if (node->override)
342 	  nf = node;
343       }
344   return nf ? nf->value : 0;
345 }
346 
347 #if 0
348 /* XXX Currently unused.  */
349 static int
350 conf_find_trans_xf (int phase, char *xf)
351 {
352   struct conf_trans *node;
353   char *p;
354 
355   /* Find the relevant transforms and suites, if any.  */
356   for (node = TAILQ_FIRST (&conf_trans_queue); node;
357        node = TAILQ_NEXT (node, link))
358     if ((phase == 1 && strcmp ("Transforms", node->tag) == 0) ||
359 	(phase == 2 && strcmp ("Suites", node->tag) == 0))
360       {
361 	p = node->value;
362 	while ((p = strstr (p, xf)) != NULL)
363 	  if (*(p + strlen (p)) && *(p + strlen (p)) != ',')
364 	    p += strlen (p);
365 	  else
366 	    return 1;
367       }
368   return 0;
369 }
370 #endif
371 
372 static void
373 conf_load_defaults (int tr)
374 {
375   int enc, auth, hash, proto, mode, pfs;
376   char sect[256], *dflt;
377 
378   char *mm_auth[]   = { "PRE_SHARED", "DSS", "RSA_SIG", 0 };
379   char *mm_hash[]   = { "MD5", "SHA", 0 };
380   char *mm_enc[]    = { "DES_CBC", "BLOWFISH_CBC", "3DES_CBC",
381 			"CAST_CBC", 0 };
382   char *dh_group[]  = { "MODP_768", "MODP_1024", "MODP_1536", 0 };
383   char *qm_enc[]    = { "DES", "3DES", "CAST", "BLOWFISH", "AES", 0 };
384   char *qm_hash[]   = { "HMAC_MD5", "HMAC_SHA", "HMAC_RIPEMD", "NONE", 0 };
385 
386   /* Abbreviations to make section names a bit shorter.  */
387   char *mm_auth_p[] = { "", "-DSS", "-RSA_SIG", 0 };
388   char *mm_enc_p[]  = { "DES", "BLF", "3DES", "CAST", 0 };
389   char *qm_enc_p[]  = { "-DES", "-3DES", "-CAST", "-BLF", "-AES", 0 };
390   char *qm_hash_p[] = { "-MD5", "-SHA", "-RIPEMD", "", 0 };
391 
392   /* Helper #defines, incl abbreviations.  */
393 #define PROTO(x)  ((x) ? "AH" : "ESP")
394 #define PFS(x)    ((x) ? "-PFS" : "")
395 #define MODE(x)   ((x) ? "TRANSPORT" : "TUNNEL")
396 #define MODE_p(x) ((x) ? "-TRP" : "")
397 
398   /* General and X509 defaults */
399   conf_set (tr, "General", "Retransmits", CONF_DFLT_RETRANSMITS, 0, 1);
400   conf_set (tr, "General", "Exchange-max-time", CONF_DFLT_EXCH_MAX_TIME, 0, 1);
401   conf_set (tr, "General", "Policy-file", CONF_DFLT_POLICY_FILE, 0, 1);
402 
403 #ifdef USE_X509
404   conf_set (tr, "X509-certificates", "CA-directory", CONF_DFLT_X509_CA_DIR, 0,
405 	    1);
406   conf_set (tr, "X509-certificates", "Cert-directory", CONF_DFLT_X509_CERT_DIR,
407 	    0, 1);
408   conf_set (tr, "X509-certificates", "Private-key", CONF_DFLT_X509_PRIVATE_KEY,
409 	    0, 1);
410 #endif
411 
412 #ifdef USE_KEYNOTE
413   conf_set (tr, "KeyNote", "Credential-directory", CONF_DFLT_KEYNOTE_CRED_DIR,
414 	    0, 1);
415 #endif
416 
417   /* Lifetimes. XXX p1/p2 vs main/quick mode may be unclear.  */
418   dflt = conf_get_trans_str (tr, "General", "Default-phase-1-lifetime");
419   conf_set (tr, CONF_DFLT_TAG_LIFE_MAIN_MODE, "LIFE_TYPE",
420 	    CONF_DFLT_TYPE_LIFE_MAIN_MODE, 0, 1);
421   conf_set (tr, CONF_DFLT_TAG_LIFE_MAIN_MODE, "LIFE_DURATION",
422 	    (dflt ? dflt : CONF_DFLT_VAL_LIFE_MAIN_MODE), 0, 1);
423 
424   dflt = conf_get_trans_str (tr, "General", "Default-phase-2-lifetime");
425   conf_set (tr, CONF_DFLT_TAG_LIFE_QUICK_MODE, "LIFE_TYPE",
426 	    CONF_DFLT_TYPE_LIFE_QUICK_MODE, 0, 1);
427   conf_set (tr, CONF_DFLT_TAG_LIFE_QUICK_MODE, "LIFE_DURATION",
428 	    (dflt ? dflt : CONF_DFLT_VAL_LIFE_QUICK_MODE), 0, 1);
429 
430   /* Main modes */
431   for (enc = 0; mm_enc[enc]; enc ++)
432     for (hash = 0; mm_hash[hash]; hash ++)
433       for (auth = 0; mm_auth[auth]; auth ++)
434 	{
435 	  sprintf (sect, "%s-%s%s", mm_enc_p[enc], mm_hash[hash],
436 		   mm_auth_p[auth]);
437 
438 #if 0
439 	  if (!conf_find_trans_xf (1, sect))
440 	    continue;
441 #endif
442 
443 	  LOG_DBG ((LOG_MISC, 90, "conf_load_defaults : main mode %s", sect));
444 
445 	  conf_set (tr, sect, "ENCRYPTION_ALGORITHM", mm_enc[enc], 0, 1);
446 	  if (strcmp (mm_enc[enc], "BLOWFISH_CBC") == 0)
447 	    conf_set (tr, sect, "KEY_LENGTH", CONF_DFLT_VAL_BLF_KEYLEN, 0, 1);
448 
449 	  conf_set (tr, sect, "HASH_ALGORITHM", mm_hash[hash], 0, 1);
450 	  conf_set (tr, sect, "AUTHENTICATION_METHOD", mm_auth[auth], 0, 1);
451 
452 	  /* XXX Assumes md5 -> modp768 and sha -> modp1024 */
453 	  conf_set (tr, sect, "GROUP_DESCRIPTION", dh_group[hash], 0, 1);
454 
455 	  conf_set (tr, sect, "Life", CONF_DFLT_TAG_LIFE_MAIN_MODE, 0, 1);
456 	}
457 
458   /* Setup a default Phase 1 entry */
459   conf_set (tr, "Phase 1", "Default", "Default-phase-1", 0, 1);
460 
461   conf_set (tr, "Default-phase-1", "Phase", "1", 0, 1);
462   conf_set (tr, "Default-phase-1", "Configuration",
463             "Default-phase-1-configuration", 0, 1);
464   dflt = conf_get_trans_str (tr, "General", "Default-phase-1-ID");
465   if (dflt)
466     conf_set (tr, "Default-phase-1", "ID", dflt, 0, 1);
467 
468   conf_set (tr, "Default-phase-1-configuration",
469             "EXCHANGE_TYPE", "ID_PROT", 0, 1);
470   conf_set (tr, "Default-phase-1-configuration", "Transforms",
471             "3DES-SHA-RSA_SIG", 0, 1);
472 
473    /* Quick modes */
474   for (enc = 0; qm_enc[enc]; enc ++)
475     for (proto = 0; proto < 2; proto ++)
476       for (mode = 0; mode < 2; mode ++)
477 	for (pfs = 0; pfs < 2; pfs ++)
478 	  for (hash = 0; qm_hash[hash]; hash ++)
479 	    if ((proto == 1 && strcmp (qm_hash[hash], "NONE") == 0)) /* AH */
480 	      continue;
481 	    else
482 	      {
483 		char tmp[256];
484 
485 		sprintf (tmp, "QM-%s%s%s%s%s", PROTO (proto), MODE_p (mode),
486 			 qm_enc_p[enc], qm_hash_p[hash], PFS (pfs));
487 
488 		strcpy (sect, tmp);
489 		strcat (sect, "-SUITE");
490 
491 #if 0
492 		if (!conf_find_trans_xf (2, sect))
493 		  continue;
494 #endif
495 
496 		LOG_DBG ((LOG_MISC, 90, "conf_load_defaults : quick mode %s",
497 			  sect));
498 
499 		conf_set (tr, sect, "Protocols", tmp, 0, 1);
500 
501 		sprintf (sect, "IPSEC_%s", PROTO (proto));
502 		conf_set (tr, tmp, "PROTOCOL_ID", sect, 0, 1);
503 
504 		strcpy (sect, tmp);
505 		strcat (sect, "-XF");
506 		conf_set (tr, tmp, "Transforms", sect, 0, 1);
507 
508                 /* XXX For now, defaults contain just one xf per protocol.  */
509 
510 		conf_set (tr, sect, "TRANSFORM_ID", qm_enc[enc], 0, 1);
511 
512                 if (strcmp (qm_enc[enc], "BLOWFISH") == 0)
513 		  conf_set (tr, sect, "KEY_LENGTH", CONF_DFLT_VAL_BLF_KEYLEN,
514 			    0, 1);
515 
516 		conf_set (tr, sect, "ENCAPSULATION_MODE", MODE (mode), 0, 1);
517 
518                 if (strcmp (qm_hash[hash], "NONE"))
519                 {
520 		  conf_set (tr, sect, "AUTHENTICATION_ALGORITHM",
521 			    qm_hash[hash], 0, 1);
522 
523                   /* XXX Another shortcut -- to keep length down.  */
524                   if (pfs)
525 		    conf_set (tr, sect, "GROUP_DESCRIPTION",
526 			      dh_group[ ((hash<2) ? hash : 1) ], 0, 1);
527                 }
528 
529                 /* XXX Lifetimes depending on enc/auth strength?  */
530 		conf_set (tr, sect, "Life", CONF_DFLT_TAG_LIFE_QUICK_MODE, 0,
531 			  1);
532 	      }
533   return;
534 }
535 
536 void
537 conf_init (void)
538 {
539   int i;
540 
541   for (i = 0; i < sizeof conf_bindings / sizeof conf_bindings[0]; i++)
542     LIST_INIT (&conf_bindings[i]);
543   TAILQ_INIT (&conf_trans_queue);
544   conf_reinit ();
545 }
546 
547 /* Open the config file and map it into our address space, then parse it.  */
548 void
549 conf_reinit (void)
550 {
551   struct conf_binding *cb = 0;
552   int fd, i, trans;
553   off_t sz;
554   char *new_conf_addr = 0;
555   struct stat sb;
556 
557   if ((stat (conf_path, &sb) == 0) || (errno != ENOENT))
558     {
559       if (check_file_secrecy (conf_path, &sz))
560 	return;
561 
562       fd = open (conf_path, O_RDONLY);
563       if (fd == -1)
564         {
565 	  log_error ("conf_reinit: open (\"%s\", O_RDONLY) failed", conf_path);
566 	  return;
567 	}
568 
569       new_conf_addr = malloc (sz);
570       if (!new_conf_addr)
571         {
572 	  log_error ("conf_reinit: malloc (%d) failed", sz);
573 	  goto fail;
574 	}
575 
576       /* XXX I assume short reads won't happen here.  */
577       if (read (fd, new_conf_addr, sz) != sz)
578         {
579 	    log_error ("conf_reinit: read (%d, %p, %d) failed",
580 		       fd, new_conf_addr, sz);
581 	    goto fail;
582 	}
583       close (fd);
584 
585       trans = conf_begin ();
586 
587       /* XXX Should we not care about errors and rollback?  */
588       conf_parse (trans, new_conf_addr, sz);
589     }
590   else
591     trans = conf_begin ();
592 
593   /* Load default configuration values.  */
594   conf_load_defaults (trans);
595 
596   /* Free potential existing configuration.  */
597   if (conf_addr)
598     {
599       for (i = 0; i < sizeof conf_bindings / sizeof conf_bindings[0]; i++)
600 	for (cb = LIST_FIRST (&conf_bindings[i]); cb;
601 	     cb = LIST_FIRST (&conf_bindings[i]))
602 	  conf_remove_now (cb->section, cb->tag);
603       free (conf_addr);
604     }
605 
606   conf_end (trans, 1);
607   conf_addr = new_conf_addr;
608   return;
609 
610  fail:
611   if (new_conf_addr)
612     free (new_conf_addr);
613   close (fd);
614 }
615 
616 /*
617  * Return the numeric value denoted by TAG in section SECTION or DEF
618  * if that tag does not exist.
619  */
620 int
621 conf_get_num (char *section, char *tag, int def)
622 {
623   char *value = conf_get_str (section, tag);
624 
625   if (value)
626       return atoi (value);
627   return def;
628 }
629 
630 /*
631  * Return the socket endpoint address denoted by TAG in SECTION as a
632  * struct sockaddr.  It is the callers responsibility to deallocate
633  * this structure when it is finished with it.
634  */
635 struct sockaddr *
636 conf_get_address (char *section, char *tag)
637 {
638   char *value = conf_get_str (section, tag);
639   struct sockaddr *sa;
640 
641   if (!value)
642     return 0;
643   if (text2sockaddr (value, 0, &sa) == -1)
644     return 0;
645   return sa;
646 }
647 
648 /* Validate X according to the range denoted by TAG in section SECTION.  */
649 int
650 conf_match_num (char *section, char *tag, int x)
651 {
652   char *value = conf_get_str (section, tag);
653   int val, min, max, n;
654 
655   if (!value)
656     return 0;
657   n = sscanf (value, "%d,%d:%d", &val, &min, &max);
658   switch (n)
659     {
660     case 1:
661       LOG_DBG ((LOG_MISC, 90, "conf_match_num: %s:%s %d==%d?", section, tag,
662 		val, x));
663       return x == val;
664     case 3:
665       LOG_DBG ((LOG_MISC, 90, "conf_match_num: %s:%s %d<=%d<=%d?", section,
666 		tag, min, x, max));
667       return min <= x && max >= x;
668     default:
669       log_error ("conf_match_num: section %s tag %s: invalid number spec %s",
670 		 section, tag, value);
671     }
672   return 0;
673 }
674 
675 /* Return the string value denoted by TAG in section SECTION.  */
676 char *
677 conf_get_str (char *section, char *tag)
678 {
679   struct conf_binding *cb;
680 
681   for (cb = LIST_FIRST (&conf_bindings[conf_hash (section)]); cb;
682        cb = LIST_NEXT (cb, link))
683     if (strcasecmp (section, cb->section) == 0
684 	&& strcasecmp (tag, cb->tag) == 0)
685       {
686 	LOG_DBG ((LOG_MISC, 95, "conf_get_str: [%s]:%s->%s", section,
687 		  tag, cb->value));
688 	return cb->value;
689       }
690   LOG_DBG ((LOG_MISC, 95,
691 	    "conf_get_str: configuration value not found [%s]:%s", section,
692 	    tag));
693   return 0;
694 }
695 
696 /*
697  * Build a list of string values out of the comma separated value denoted by
698  * TAG in SECTION.
699  */
700 struct conf_list *
701 conf_get_list (char *section, char *tag)
702 {
703   char *liststr = 0, *p, *field;
704   struct conf_list *list = 0;
705   struct conf_list_node *node;
706 
707   list = malloc (sizeof *list);
708   if (!list)
709     goto cleanup;
710   TAILQ_INIT (&list->fields);
711   list->cnt = 0;
712   liststr = conf_get_str (section, tag);
713   if (!liststr)
714     goto cleanup;
715   liststr = strdup (liststr);
716   if (!liststr)
717     goto cleanup;
718   p = liststr;
719   while ((field = strsep (&p, ", \t")) != NULL)
720     {
721       if (*field == '\0')
722 	{
723 	  log_print ("conf_get_list: empty field, ignoring...");
724 	  continue;
725 	}
726       list->cnt++;
727       node = calloc (1, sizeof *node);
728       if (!node)
729 	goto cleanup;
730       node->field = strdup (field);
731       if (!node->field)
732 	goto cleanup;
733       TAILQ_INSERT_TAIL (&list->fields, node, link);
734     }
735   free (liststr);
736   return list;
737 
738  cleanup:
739   if (list)
740     conf_free_list (list);
741   if (liststr)
742     free (liststr);
743   return 0;
744 }
745 
746 struct conf_list *
747 conf_get_tag_list (char *section)
748 {
749   struct conf_list *list = 0;
750   struct conf_list_node *node;
751   struct conf_binding *cb;
752 
753   list = malloc (sizeof *list);
754   if (!list)
755     goto cleanup;
756   TAILQ_INIT (&list->fields);
757   list->cnt = 0;
758   for (cb = LIST_FIRST (&conf_bindings[conf_hash (section)]); cb;
759        cb = LIST_NEXT (cb, link))
760     if (strcasecmp (section, cb->section) == 0)
761       {
762 	list->cnt++;
763 	node = calloc (1, sizeof *node);
764 	if (!node)
765 	  goto cleanup;
766 	node->field = strdup (cb->tag);
767 	if (!node->field)
768 	  goto cleanup;
769 	TAILQ_INSERT_TAIL (&list->fields, node, link);
770       }
771   return list;
772 
773  cleanup:
774   if (list)
775     conf_free_list (list);
776   return 0;
777 }
778 
779 /* Decode a PEM encoded buffer.  */
780 int
781 conf_decode_base64 (u_int8_t *out, u_int32_t *len, u_char *buf)
782 {
783   u_int32_t c = 0;
784   u_int8_t c1, c2, c3, c4;
785 
786   while (*buf)
787     {
788       if (*buf > 127 || (c1 = asc2bin[*buf]) == 255)
789 	return 0;
790       buf++;
791 
792       if (*buf > 127 || (c2 = asc2bin[*buf]) == 255)
793 	return 0;
794       buf++;
795 
796       if (*buf == '=')
797 	{
798 	  c3 = c4 = 0;
799 	  c++;
800 
801 	  /* Check last four bit */
802 	  if (c2 & 0xF)
803 	    return 0;
804 
805 	  if (strcmp (buf, "==") == 0)
806 	    buf++;
807 	  else
808 	    return 0;
809 	}
810       else if (*buf > 127 || (c3 = asc2bin[*buf]) == 255)
811 	return 0;
812       else
813 	{
814 	  if (*++buf == '=')
815 	    {
816 	      c4 = 0;
817 	      c += 2;
818 
819 	      /* Check last two bit */
820 	      if (c3 & 3)
821 		return 0;
822 
823 	      if (strcmp (buf, "="))
824 		return 0;
825 
826 	    }
827 	  else if (*buf > 127 || (c4 = asc2bin[*buf]) == 255)
828 	      return 0;
829 	  else
830 	      c += 3;
831 	}
832 
833       buf++;
834       *out++ = (c1 << 2) | (c2 >> 4);
835       *out++ = (c2 << 4) | (c3 >> 2);
836       *out++ = (c3 << 6) | c4;
837     }
838 
839   *len = c;
840   return 1;
841 
842 }
843 
844 /* Read a line from a stream to the buffer.  */
845 int
846 conf_get_line (FILE *stream, char *buf, u_int32_t len)
847 {
848   int c;
849 
850   while (len-- > 1)
851     {
852       c = fgetc (stream);
853       if (c == '\n')
854 	{
855 	  *buf = 0;
856 	  return 1;
857 	}
858       else if (c == EOF)
859 	break;
860 
861       *buf++ = c;
862     }
863 
864   *buf = 0;
865   return 0;
866 }
867 
868 void
869 conf_free_list (struct conf_list *list)
870 {
871   struct conf_list_node *node = TAILQ_FIRST (&list->fields);
872 
873   while (node)
874     {
875       TAILQ_REMOVE (&list->fields, node, link);
876       if (node->field)
877 	free (node->field);
878       free (node);
879       node = TAILQ_FIRST (&list->fields);
880     }
881   free (list);
882 }
883 
884 int
885 conf_begin (void)
886 {
887   static int seq = 0;
888 
889   return ++seq;
890 }
891 
892 static struct conf_trans *
893 conf_trans_node (int transaction, enum conf_op op)
894 {
895   struct conf_trans *node;
896 
897   node = calloc (1, sizeof *node);
898   if (!node)
899     {
900       log_error ("conf_trans_node: calloc (1, %d) failed", sizeof *node);
901       return 0;
902     }
903   node->trans = transaction;
904   node->op = op;
905   TAILQ_INSERT_TAIL (&conf_trans_queue, node, link);
906   return node;
907 }
908 
909 /* Queue a set operation.  */
910 int
911 conf_set (int transaction, char *section, char *tag, char *value, int override,
912 	  int is_default)
913 {
914   struct conf_trans *node;
915 
916   node = conf_trans_node (transaction, CONF_SET);
917   if (!node)
918     return 1;
919   node->section = strdup (section);
920   if (!node->section)
921     {
922       log_error ("conf_set: strdup (\"%s\") failed", section);
923       goto fail;
924     }
925   node->tag = strdup (tag);
926   if (!node->tag)
927     {
928       log_error ("conf_set: strdup (\"%s\") failed", tag);
929       goto fail;
930     }
931   node->value = strdup (value);
932   if (!node->value)
933     {
934       log_error ("conf_set: strdup (\"%s\") failed", value);
935       goto fail;
936     }
937   node->override = override;
938   node->is_default = is_default;
939   return 0;
940 
941  fail:
942   if (node->tag)
943     free (node->tag);
944   if (node->section)
945     free (node->section);
946   if (node)
947     free (node);
948   return 1;
949 }
950 
951 /* Queue a remove operation.  */
952 int
953 conf_remove (int transaction, char *section, char *tag)
954 {
955   struct conf_trans *node;
956 
957   node = conf_trans_node (transaction, CONF_REMOVE);
958   if (!node)
959     goto fail;
960   node->section = strdup (section);
961   if (!node->section)
962     {
963       log_error ("conf_remove: strdup (\"%s\") failed", section);
964       goto fail;
965     }
966   node->tag = strdup (tag);
967   if (!node->tag)
968     {
969       log_error ("conf_remove: strdup (\"%s\") failed", tag);
970       goto fail;
971     }
972   return 0;
973 
974  fail:
975   if (node->section)
976     free (node->section);
977   if (node)
978     free (node);
979   return 1;
980 }
981 
982 /* Queue a remove section operation.  */
983 int
984 conf_remove_section (int transaction, char *section)
985 {
986   struct conf_trans *node;
987 
988   node = conf_trans_node (transaction, CONF_REMOVE_SECTION);
989   if (!node)
990     goto fail;
991   node->section = strdup (section);
992   if (!node->section)
993     {
994       log_error ("conf_remove_section: strdup (\"%s\") failed", section);
995       goto fail;
996     }
997   return 0;
998 
999  fail:
1000   if (node)
1001     free (node);
1002   return 1;
1003 }
1004 
1005 /* Execute all queued operations for this transaction.  Cleanup.  */
1006 int
1007 conf_end (int transaction, int commit)
1008 {
1009   struct conf_trans *node, *next;
1010 
1011   for (node = TAILQ_FIRST (&conf_trans_queue); node; node = next)
1012     {
1013       next = TAILQ_NEXT (node, link);
1014       if (node->trans == transaction)
1015 	{
1016 	  if (commit)
1017 	    switch (node->op)
1018 	      {
1019 	      case CONF_SET:
1020 		conf_set_now (node->section, node->tag, node->value,
1021 			      node->override, node->is_default);
1022 		break;
1023 	      case CONF_REMOVE:
1024 		conf_remove_now (node->section, node->tag);
1025 		break;
1026 	      case CONF_REMOVE_SECTION:
1027 		conf_remove_section_now (node->section);
1028 		break;
1029 	      default:
1030 		log_print ("conf_end: unknown operation: %d", node->op);
1031 	      }
1032 	  TAILQ_REMOVE (&conf_trans_queue, node, link);
1033 	  if (node->section)
1034 	    free (node->section);
1035 	  if (node->tag)
1036 	    free (node->tag);
1037 	  if (node->value)
1038 	    free (node->value);
1039 	  free (node);
1040 	}
1041     }
1042   return 0;
1043 }
1044 
1045 /*
1046  * Dump running configuration upon SIGUSR1.
1047  * Configuration is "stored in reverse order", so reverse it again.
1048  */
1049 struct dumper {
1050   char *s, *v;
1051   struct dumper *next;
1052 };
1053 
1054 static void
1055 conf_report_dump (struct dumper *node)
1056 {
1057   /* Recursive, cleanup when we're done.  */
1058 
1059   if (node->next)
1060     conf_report_dump (node->next);
1061 
1062   if (node->v)
1063     LOG_DBG ((LOG_REPORT, 0, "%s=\t%s", node->s, node->v));
1064   else if (node->s)
1065     {
1066       LOG_DBG ((LOG_REPORT, 0, "%s", node->s));
1067       if (strlen (node->s) > 0)
1068 	free (node->s);
1069     }
1070 
1071   free (node);
1072 }
1073 
1074 void
1075 conf_report (void)
1076 {
1077   struct conf_binding *cb, *last = 0;
1078   int i;
1079   char *current_section = (char *)0;
1080   struct dumper *dumper, *dnode;
1081 
1082   dumper = dnode = (struct dumper *)calloc (1, sizeof *dumper);
1083   if (!dumper)
1084     goto mem_fail;
1085 
1086   LOG_DBG ((LOG_REPORT, 0, "conf_report: dumping running configuration"));
1087 
1088   for (i = 0; i < sizeof conf_bindings / sizeof conf_bindings[0]; i++)
1089     for (cb = LIST_FIRST (&conf_bindings[i]); cb;
1090 	 cb = LIST_NEXT (cb, link))
1091       {
1092 	if (!cb->is_default)
1093 	  {
1094 	    /* Dump this entry.  */
1095 	    if (!current_section || strcmp (cb->section, current_section))
1096 	      {
1097 		if (current_section)
1098 		  {
1099 		    dnode->s = malloc (strlen (current_section) + 3);
1100 		    if (!dnode->s)
1101 		      goto mem_fail;
1102 
1103 		    sprintf (dnode->s, "[%s]", current_section);
1104 		    dnode->next
1105 		      = (struct dumper *)calloc (1, sizeof (struct dumper));
1106 		    dnode = dnode->next;
1107 		    if (!dnode)
1108 		      goto mem_fail;
1109 
1110 		    dnode->s = "";
1111 		    dnode->next
1112 		      = (struct dumper *)calloc (1, sizeof (struct dumper));
1113 		    dnode = dnode->next;
1114 		    if (!dnode)
1115 		      goto mem_fail;
1116 		  }
1117 		current_section = cb->section;
1118 	      }
1119 	    dnode->s = cb->tag;
1120 	    dnode->v = cb->value;
1121 	    dnode->next = (struct dumper *)calloc (1, sizeof (struct dumper));
1122 	    dnode = dnode->next;
1123 	    if (!dnode)
1124 	      goto mem_fail;
1125 	    last = cb;
1126 	  }
1127       }
1128 
1129   if (last)
1130     {
1131       dnode->s = malloc (strlen (last->section) + 3);
1132       if (!dnode->s)
1133 	goto mem_fail;
1134       sprintf (dnode->s, "[%s]", last->section);
1135     }
1136 
1137   conf_report_dump (dumper);
1138 
1139   return;
1140 
1141  mem_fail:
1142   log_error ("conf_report: malloc/calloc failed");
1143   while ((dnode = dumper) != 0)
1144     {
1145       dumper = dumper->next;
1146       if (dnode->s)
1147 	free (dnode->s);
1148       free (dnode);
1149     }
1150   return;
1151 }
1152