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