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