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