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