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