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