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