1/* 2 * Copyright (C) 2004-2014 Internet Systems Consortium, Inc. ("ISC") 3 * Copyright (C) 2000-2003 Internet Software Consortium. 4 * 5 * Permission to use, copy, modify, and/or distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 10 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 11 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 12 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 13 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 14 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 15 * PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18/* $Id$ */ 19 20/*! \file */ 21 22#include <config.h> 23 24#include <isc/buffer.h> 25#include <isc/dir.h> 26#include <isc/formatcheck.h> 27#include <isc/lex.h> 28#include <isc/log.h> 29#include <isc/mem.h> 30#include <isc/net.h> 31#include <isc/netaddr.h> 32#include <isc/netscope.h> 33#include <isc/print.h> 34#include <isc/string.h> 35#include <isc/sockaddr.h> 36#include <isc/symtab.h> 37#include <isc/util.h> 38 39#include <isccfg/cfg.h> 40#include <isccfg/grammar.h> 41#include <isccfg/log.h> 42 43/* Shorthand */ 44#define CAT CFG_LOGCATEGORY_CONFIG 45#define MOD CFG_LOGMODULE_PARSER 46 47#define MAP_SYM 1 /* Unique type for isc_symtab */ 48 49#define TOKEN_STRING(pctx) (pctx->token.value.as_textregion.base) 50 51/* Check a return value. */ 52#define CHECK(op) \ 53 do { result = (op); \ 54 if (result != ISC_R_SUCCESS) goto cleanup; \ 55 } while (0) 56 57/* Clean up a configuration object if non-NULL. */ 58#define CLEANUP_OBJ(obj) \ 59 do { if ((obj) != NULL) cfg_obj_destroy(pctx, &(obj)); } while (0) 60 61 62/* 63 * Forward declarations of static functions. 64 */ 65 66static void 67free_tuple(cfg_parser_t *pctx, cfg_obj_t *obj); 68 69static isc_result_t 70parse_list(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret); 71 72static void 73print_list(cfg_printer_t *pctx, const cfg_obj_t *obj); 74 75static void 76free_list(cfg_parser_t *pctx, cfg_obj_t *obj); 77 78static isc_result_t 79create_listelt(cfg_parser_t *pctx, cfg_listelt_t **eltp); 80 81static isc_result_t 82create_string(cfg_parser_t *pctx, const char *contents, const cfg_type_t *type, 83 cfg_obj_t **ret); 84 85static void 86free_string(cfg_parser_t *pctx, cfg_obj_t *obj); 87 88static isc_result_t 89create_map(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **objp); 90 91static void 92free_map(cfg_parser_t *pctx, cfg_obj_t *obj); 93 94static isc_result_t 95parse_symtab_elt(cfg_parser_t *pctx, const char *name, 96 cfg_type_t *elttype, isc_symtab_t *symtab, 97 isc_boolean_t callback); 98 99static void 100free_noop(cfg_parser_t *pctx, cfg_obj_t *obj); 101 102static isc_result_t 103cfg_getstringtoken(cfg_parser_t *pctx); 104 105static void 106parser_complain(cfg_parser_t *pctx, isc_boolean_t is_warning, 107 unsigned int flags, const char *format, va_list args); 108 109/* 110 * Data representations. These correspond to members of the 111 * "value" union in struct cfg_obj (except "void", which does 112 * not need a union member). 113 */ 114 115cfg_rep_t cfg_rep_uint32 = { "uint32", free_noop }; 116cfg_rep_t cfg_rep_uint64 = { "uint64", free_noop }; 117cfg_rep_t cfg_rep_string = { "string", free_string }; 118cfg_rep_t cfg_rep_boolean = { "boolean", free_noop }; 119cfg_rep_t cfg_rep_map = { "map", free_map }; 120cfg_rep_t cfg_rep_list = { "list", free_list }; 121cfg_rep_t cfg_rep_tuple = { "tuple", free_tuple }; 122cfg_rep_t cfg_rep_sockaddr = { "sockaddr", free_noop }; 123cfg_rep_t cfg_rep_netprefix = { "netprefix", free_noop }; 124cfg_rep_t cfg_rep_void = { "void", free_noop }; 125 126/* 127 * Configuration type definitions. 128 */ 129 130/*% 131 * An implicit list. These are formed by clauses that occur multiple times. 132 */ 133static cfg_type_t cfg_type_implicitlist = { 134 "implicitlist", NULL, print_list, NULL, &cfg_rep_list, NULL }; 135 136/* Functions. */ 137 138void 139cfg_print_obj(cfg_printer_t *pctx, const cfg_obj_t *obj) { 140 obj->type->print(pctx, obj); 141} 142 143void 144cfg_print_chars(cfg_printer_t *pctx, const char *text, int len) { 145 pctx->f(pctx->closure, text, len); 146} 147 148static void 149print_open(cfg_printer_t *pctx) { 150 cfg_print_chars(pctx, "{\n", 2); 151 pctx->indent++; 152} 153 154static void 155print_indent(cfg_printer_t *pctx) { 156 int indent = pctx->indent; 157 while (indent > 0) { 158 cfg_print_chars(pctx, "\t", 1); 159 indent--; 160 } 161} 162 163static void 164print_close(cfg_printer_t *pctx) { 165 pctx->indent--; 166 print_indent(pctx); 167 cfg_print_chars(pctx, "}", 1); 168} 169 170isc_result_t 171cfg_parse_obj(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { 172 isc_result_t result; 173 INSIST(ret != NULL && *ret == NULL); 174 result = type->parse(pctx, type, ret); 175 if (result != ISC_R_SUCCESS) 176 return (result); 177 INSIST(*ret != NULL); 178 return (ISC_R_SUCCESS); 179} 180 181void 182cfg_print(const cfg_obj_t *obj, 183 void (*f)(void *closure, const char *text, int textlen), 184 void *closure) 185{ 186 cfg_printx(obj, 0, f, closure); 187} 188 189void 190cfg_printx(const cfg_obj_t *obj, unsigned int flags, 191 void (*f)(void *closure, const char *text, int textlen), 192 void *closure) 193{ 194 cfg_printer_t pctx; 195 pctx.f = f; 196 pctx.closure = closure; 197 pctx.indent = 0; 198 pctx.flags = flags; 199 obj->type->print(&pctx, obj); 200} 201 202/* Tuples. */ 203 204isc_result_t 205cfg_create_tuple(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { 206 isc_result_t result; 207 const cfg_tuplefielddef_t *fields = type->of; 208 const cfg_tuplefielddef_t *f; 209 cfg_obj_t *obj = NULL; 210 unsigned int nfields = 0; 211 int i; 212 213 for (f = fields; f->name != NULL; f++) 214 nfields++; 215 216 CHECK(cfg_create_obj(pctx, type, &obj)); 217 obj->value.tuple = isc_mem_get(pctx->mctx, 218 nfields * sizeof(cfg_obj_t *)); 219 if (obj->value.tuple == NULL) { 220 result = ISC_R_NOMEMORY; 221 goto cleanup; 222 } 223 for (f = fields, i = 0; f->name != NULL; f++, i++) 224 obj->value.tuple[i] = NULL; 225 *ret = obj; 226 return (ISC_R_SUCCESS); 227 228 cleanup: 229 if (obj != NULL) 230 isc_mem_put(pctx->mctx, obj, sizeof(*obj)); 231 return (result); 232} 233 234isc_result_t 235cfg_parse_tuple(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) 236{ 237 isc_result_t result; 238 const cfg_tuplefielddef_t *fields = type->of; 239 const cfg_tuplefielddef_t *f; 240 cfg_obj_t *obj = NULL; 241 unsigned int i; 242 243 CHECK(cfg_create_tuple(pctx, type, &obj)); 244 for (f = fields, i = 0; f->name != NULL; f++, i++) 245 CHECK(cfg_parse_obj(pctx, f->type, &obj->value.tuple[i])); 246 247 *ret = obj; 248 return (ISC_R_SUCCESS); 249 250 cleanup: 251 CLEANUP_OBJ(obj); 252 return (result); 253} 254 255void 256cfg_print_tuple(cfg_printer_t *pctx, const cfg_obj_t *obj) { 257 unsigned int i; 258 const cfg_tuplefielddef_t *fields = obj->type->of; 259 const cfg_tuplefielddef_t *f; 260 isc_boolean_t need_space = ISC_FALSE; 261 262 for (f = fields, i = 0; f->name != NULL; f++, i++) { 263 const cfg_obj_t *fieldobj = obj->value.tuple[i]; 264 if (need_space) 265 cfg_print_chars(pctx, " ", 1); 266 cfg_print_obj(pctx, fieldobj); 267 need_space = ISC_TF(fieldobj->type->print != cfg_print_void); 268 } 269} 270 271void 272cfg_doc_tuple(cfg_printer_t *pctx, const cfg_type_t *type) { 273 const cfg_tuplefielddef_t *fields = type->of; 274 const cfg_tuplefielddef_t *f; 275 isc_boolean_t need_space = ISC_FALSE; 276 277 for (f = fields; f->name != NULL; f++) { 278 if (need_space) 279 cfg_print_chars(pctx, " ", 1); 280 cfg_doc_obj(pctx, f->type); 281 need_space = ISC_TF(f->type->print != cfg_print_void); 282 } 283} 284 285static void 286free_tuple(cfg_parser_t *pctx, cfg_obj_t *obj) { 287 unsigned int i; 288 const cfg_tuplefielddef_t *fields = obj->type->of; 289 const cfg_tuplefielddef_t *f; 290 unsigned int nfields = 0; 291 292 if (obj->value.tuple == NULL) 293 return; 294 295 for (f = fields, i = 0; f->name != NULL; f++, i++) { 296 CLEANUP_OBJ(obj->value.tuple[i]); 297 nfields++; 298 } 299 isc_mem_put(pctx->mctx, obj->value.tuple, 300 nfields * sizeof(cfg_obj_t *)); 301} 302 303isc_boolean_t 304cfg_obj_istuple(const cfg_obj_t *obj) { 305 REQUIRE(obj != NULL); 306 return (ISC_TF(obj->type->rep == &cfg_rep_tuple)); 307} 308 309const cfg_obj_t * 310cfg_tuple_get(const cfg_obj_t *tupleobj, const char* name) { 311 unsigned int i; 312 const cfg_tuplefielddef_t *fields; 313 const cfg_tuplefielddef_t *f; 314 315 REQUIRE(tupleobj != NULL && tupleobj->type->rep == &cfg_rep_tuple); 316 317 fields = tupleobj->type->of; 318 for (f = fields, i = 0; f->name != NULL; f++, i++) { 319 if (strcmp(f->name, name) == 0) 320 return (tupleobj->value.tuple[i]); 321 } 322 INSIST(0); 323 return (NULL); 324} 325 326isc_result_t 327cfg_parse_special(cfg_parser_t *pctx, int special) { 328 isc_result_t result; 329 CHECK(cfg_gettoken(pctx, 0)); 330 if (pctx->token.type == isc_tokentype_special && 331 pctx->token.value.as_char == special) 332 return (ISC_R_SUCCESS); 333 334 cfg_parser_error(pctx, CFG_LOG_NEAR, "'%c' expected", special); 335 return (ISC_R_UNEXPECTEDTOKEN); 336 cleanup: 337 return (result); 338} 339 340/* 341 * Parse a required semicolon. If it is not there, log 342 * an error and increment the error count but continue 343 * parsing. Since the next token is pushed back, 344 * care must be taken to make sure it is eventually 345 * consumed or an infinite loop may result. 346 */ 347static isc_result_t 348parse_semicolon(cfg_parser_t *pctx) { 349 isc_result_t result; 350 CHECK(cfg_gettoken(pctx, 0)); 351 if (pctx->token.type == isc_tokentype_special && 352 pctx->token.value.as_char == ';') 353 return (ISC_R_SUCCESS); 354 355 cfg_parser_error(pctx, CFG_LOG_BEFORE, "missing ';'"); 356 cfg_ungettoken(pctx); 357 cleanup: 358 return (result); 359} 360 361/* 362 * Parse EOF, logging and returning an error if not there. 363 */ 364static isc_result_t 365parse_eof(cfg_parser_t *pctx) { 366 isc_result_t result; 367 CHECK(cfg_gettoken(pctx, 0)); 368 369 if (pctx->token.type == isc_tokentype_eof) 370 return (ISC_R_SUCCESS); 371 372 cfg_parser_error(pctx, CFG_LOG_NEAR, "syntax error"); 373 return (ISC_R_UNEXPECTEDTOKEN); 374 cleanup: 375 return (result); 376} 377 378/* A list of files, used internally for pctx->files. */ 379 380static cfg_type_t cfg_type_filelist = { 381 "filelist", NULL, print_list, NULL, &cfg_rep_list, 382 &cfg_type_qstring 383}; 384 385isc_result_t 386cfg_parser_create(isc_mem_t *mctx, isc_log_t *lctx, cfg_parser_t **ret) { 387 isc_result_t result; 388 cfg_parser_t *pctx; 389 isc_lexspecials_t specials; 390 391 REQUIRE(mctx != NULL); 392 REQUIRE(ret != NULL && *ret == NULL); 393 394 pctx = isc_mem_get(mctx, sizeof(*pctx)); 395 if (pctx == NULL) 396 return (ISC_R_NOMEMORY); 397 398 pctx->mctx = NULL; 399 isc_mem_attach(mctx, &pctx->mctx); 400 401 result = isc_refcount_init(&pctx->references, 1); 402 if (result != ISC_R_SUCCESS) { 403 isc_mem_putanddetach(&pctx->mctx, pctx, sizeof(*pctx)); 404 return (result); 405 } 406 407 pctx->lctx = lctx; 408 pctx->lexer = NULL; 409 pctx->seen_eof = ISC_FALSE; 410 pctx->ungotten = ISC_FALSE; 411 pctx->errors = 0; 412 pctx->warnings = 0; 413 pctx->open_files = NULL; 414 pctx->closed_files = NULL; 415 pctx->line = 0; 416 pctx->callback = NULL; 417 pctx->callbackarg = NULL; 418 pctx->token.type = isc_tokentype_unknown; 419 pctx->flags = 0; 420 421 memset(specials, 0, sizeof(specials)); 422 specials['{'] = 1; 423 specials['}'] = 1; 424 specials[';'] = 1; 425 specials['/'] = 1; 426 specials['"'] = 1; 427 specials['!'] = 1; 428 429 CHECK(isc_lex_create(pctx->mctx, 1024, &pctx->lexer)); 430 431 isc_lex_setspecials(pctx->lexer, specials); 432 isc_lex_setcomments(pctx->lexer, (ISC_LEXCOMMENT_C | 433 ISC_LEXCOMMENT_CPLUSPLUS | 434 ISC_LEXCOMMENT_SHELL)); 435 436 CHECK(cfg_create_list(pctx, &cfg_type_filelist, &pctx->open_files)); 437 CHECK(cfg_create_list(pctx, &cfg_type_filelist, &pctx->closed_files)); 438 439 *ret = pctx; 440 return (ISC_R_SUCCESS); 441 442 cleanup: 443 if (pctx->lexer != NULL) 444 isc_lex_destroy(&pctx->lexer); 445 CLEANUP_OBJ(pctx->open_files); 446 CLEANUP_OBJ(pctx->closed_files); 447 isc_mem_putanddetach(&pctx->mctx, pctx, sizeof(*pctx)); 448 return (result); 449} 450 451static isc_result_t 452parser_openfile(cfg_parser_t *pctx, const char *filename) { 453 isc_result_t result; 454 cfg_listelt_t *elt = NULL; 455 cfg_obj_t *stringobj = NULL; 456 457 result = isc_lex_openfile(pctx->lexer, filename); 458 if (result != ISC_R_SUCCESS) { 459 cfg_parser_error(pctx, 0, "open: %s: %s", 460 filename, isc_result_totext(result)); 461 goto cleanup; 462 } 463 464 CHECK(create_string(pctx, filename, &cfg_type_qstring, &stringobj)); 465 CHECK(create_listelt(pctx, &elt)); 466 elt->obj = stringobj; 467 ISC_LIST_APPEND(pctx->open_files->value.list, elt, link); 468 469 return (ISC_R_SUCCESS); 470 cleanup: 471 CLEANUP_OBJ(stringobj); 472 return (result); 473} 474 475void 476cfg_parser_setcallback(cfg_parser_t *pctx, 477 cfg_parsecallback_t callback, 478 void *arg) 479{ 480 pctx->callback = callback; 481 pctx->callbackarg = arg; 482} 483 484/* 485 * Parse a configuration using a pctx where a lexer has already 486 * been set up with a source. 487 */ 488static isc_result_t 489parse2(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { 490 isc_result_t result; 491 cfg_obj_t *obj = NULL; 492 493 result = cfg_parse_obj(pctx, type, &obj); 494 495 if (pctx->errors != 0) { 496 /* Errors have been logged. */ 497 if (result == ISC_R_SUCCESS) 498 result = ISC_R_FAILURE; 499 goto cleanup; 500 } 501 502 if (result != ISC_R_SUCCESS) { 503 /* Parsing failed but no errors have been logged. */ 504 cfg_parser_error(pctx, 0, "parsing failed"); 505 goto cleanup; 506 } 507 508 CHECK(parse_eof(pctx)); 509 510 *ret = obj; 511 return (ISC_R_SUCCESS); 512 513 cleanup: 514 CLEANUP_OBJ(obj); 515 return (result); 516} 517 518isc_result_t 519cfg_parse_file(cfg_parser_t *pctx, const char *filename, 520 const cfg_type_t *type, cfg_obj_t **ret) 521{ 522 isc_result_t result; 523 524 REQUIRE(filename != NULL); 525 526 CHECK(parser_openfile(pctx, filename)); 527 CHECK(parse2(pctx, type, ret)); 528 cleanup: 529 return (result); 530} 531 532 533isc_result_t 534cfg_parse_buffer(cfg_parser_t *pctx, isc_buffer_t *buffer, 535 const cfg_type_t *type, cfg_obj_t **ret) 536{ 537 isc_result_t result; 538 REQUIRE(buffer != NULL); 539 CHECK(isc_lex_openbuffer(pctx->lexer, buffer)); 540 CHECK(parse2(pctx, type, ret)); 541 cleanup: 542 return (result); 543} 544 545void 546cfg_parser_attach(cfg_parser_t *src, cfg_parser_t **dest) { 547 REQUIRE(src != NULL); 548 REQUIRE(dest != NULL && *dest == NULL); 549 isc_refcount_increment(&src->references, NULL); 550 *dest = src; 551} 552 553void 554cfg_parser_destroy(cfg_parser_t **pctxp) { 555 cfg_parser_t *pctx = *pctxp; 556 unsigned int refs; 557 558 isc_refcount_decrement(&pctx->references, &refs); 559 if (refs == 0) { 560 isc_lex_destroy(&pctx->lexer); 561 /* 562 * Cleaning up open_files does not 563 * close the files; that was already done 564 * by closing the lexer. 565 */ 566 CLEANUP_OBJ(pctx->open_files); 567 CLEANUP_OBJ(pctx->closed_files); 568 isc_mem_putanddetach(&pctx->mctx, pctx, sizeof(*pctx)); 569 } 570 *pctxp = NULL; 571} 572 573/* 574 * void 575 */ 576isc_result_t 577cfg_parse_void(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { 578 UNUSED(type); 579 return (cfg_create_obj(pctx, &cfg_type_void, ret)); 580} 581 582void 583cfg_print_void(cfg_printer_t *pctx, const cfg_obj_t *obj) { 584 UNUSED(pctx); 585 UNUSED(obj); 586} 587 588void 589cfg_doc_void(cfg_printer_t *pctx, const cfg_type_t *type) { 590 UNUSED(pctx); 591 UNUSED(type); 592} 593 594isc_boolean_t 595cfg_obj_isvoid(const cfg_obj_t *obj) { 596 REQUIRE(obj != NULL); 597 return (ISC_TF(obj->type->rep == &cfg_rep_void)); 598} 599 600cfg_type_t cfg_type_void = { 601 "void", cfg_parse_void, cfg_print_void, cfg_doc_void, &cfg_rep_void, 602 NULL }; 603 604 605/* 606 * uint32 607 */ 608isc_result_t 609cfg_parse_uint32(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { 610 isc_result_t result; 611 cfg_obj_t *obj = NULL; 612 UNUSED(type); 613 614 CHECK(cfg_gettoken(pctx, ISC_LEXOPT_NUMBER | ISC_LEXOPT_CNUMBER)); 615 if (pctx->token.type != isc_tokentype_number) { 616 cfg_parser_error(pctx, CFG_LOG_NEAR, "expected number"); 617 return (ISC_R_UNEXPECTEDTOKEN); 618 } 619 620 CHECK(cfg_create_obj(pctx, &cfg_type_uint32, &obj)); 621 622 obj->value.uint32 = pctx->token.value.as_ulong; 623 *ret = obj; 624 cleanup: 625 return (result); 626} 627 628void 629cfg_print_cstr(cfg_printer_t *pctx, const char *s) { 630 cfg_print_chars(pctx, s, strlen(s)); 631} 632 633void 634cfg_print_rawuint(cfg_printer_t *pctx, unsigned int u) { 635 char buf[32]; 636 snprintf(buf, sizeof(buf), "%u", u); 637 cfg_print_cstr(pctx, buf); 638} 639 640void 641cfg_print_uint32(cfg_printer_t *pctx, const cfg_obj_t *obj) { 642 cfg_print_rawuint(pctx, obj->value.uint32); 643} 644 645isc_boolean_t 646cfg_obj_isuint32(const cfg_obj_t *obj) { 647 REQUIRE(obj != NULL); 648 return (ISC_TF(obj->type->rep == &cfg_rep_uint32)); 649} 650 651isc_uint32_t 652cfg_obj_asuint32(const cfg_obj_t *obj) { 653 REQUIRE(obj != NULL && obj->type->rep == &cfg_rep_uint32); 654 return (obj->value.uint32); 655} 656 657cfg_type_t cfg_type_uint32 = { 658 "integer", cfg_parse_uint32, cfg_print_uint32, cfg_doc_terminal, 659 &cfg_rep_uint32, NULL 660}; 661 662 663/* 664 * uint64 665 */ 666isc_boolean_t 667cfg_obj_isuint64(const cfg_obj_t *obj) { 668 REQUIRE(obj != NULL); 669 return (ISC_TF(obj->type->rep == &cfg_rep_uint64)); 670} 671 672isc_uint64_t 673cfg_obj_asuint64(const cfg_obj_t *obj) { 674 REQUIRE(obj != NULL && obj->type->rep == &cfg_rep_uint64); 675 return (obj->value.uint64); 676} 677 678void 679cfg_print_uint64(cfg_printer_t *pctx, const cfg_obj_t *obj) { 680 char buf[32]; 681 snprintf(buf, sizeof(buf), "%" ISC_PRINT_QUADFORMAT "u", 682 obj->value.uint64); 683 cfg_print_cstr(pctx, buf); 684} 685 686cfg_type_t cfg_type_uint64 = { 687 "64_bit_integer", NULL, cfg_print_uint64, cfg_doc_terminal, 688 &cfg_rep_uint64, NULL 689}; 690 691/* 692 * qstring (quoted string), ustring (unquoted string), astring 693 * (any string) 694 */ 695 696/* Create a string object from a null-terminated C string. */ 697static isc_result_t 698create_string(cfg_parser_t *pctx, const char *contents, const cfg_type_t *type, 699 cfg_obj_t **ret) 700{ 701 isc_result_t result; 702 cfg_obj_t *obj = NULL; 703 int len; 704 705 CHECK(cfg_create_obj(pctx, type, &obj)); 706 len = strlen(contents); 707 obj->value.string.length = len; 708 obj->value.string.base = isc_mem_get(pctx->mctx, len + 1); 709 if (obj->value.string.base == 0) { 710 isc_mem_put(pctx->mctx, obj, sizeof(*obj)); 711 return (ISC_R_NOMEMORY); 712 } 713 memmove(obj->value.string.base, contents, len); 714 obj->value.string.base[len] = '\0'; 715 716 *ret = obj; 717 cleanup: 718 return (result); 719} 720 721isc_result_t 722cfg_parse_qstring(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { 723 isc_result_t result; 724 UNUSED(type); 725 726 CHECK(cfg_gettoken(pctx, CFG_LEXOPT_QSTRING)); 727 if (pctx->token.type != isc_tokentype_qstring) { 728 cfg_parser_error(pctx, CFG_LOG_NEAR, "expected quoted string"); 729 return (ISC_R_UNEXPECTEDTOKEN); 730 } 731 return (create_string(pctx, 732 TOKEN_STRING(pctx), 733 &cfg_type_qstring, 734 ret)); 735 cleanup: 736 return (result); 737} 738 739static isc_result_t 740parse_ustring(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { 741 isc_result_t result; 742 UNUSED(type); 743 744 CHECK(cfg_gettoken(pctx, 0)); 745 if (pctx->token.type != isc_tokentype_string) { 746 cfg_parser_error(pctx, CFG_LOG_NEAR, "expected unquoted string"); 747 return (ISC_R_UNEXPECTEDTOKEN); 748 } 749 return (create_string(pctx, 750 TOKEN_STRING(pctx), 751 &cfg_type_ustring, 752 ret)); 753 cleanup: 754 return (result); 755} 756 757isc_result_t 758cfg_parse_astring(cfg_parser_t *pctx, const cfg_type_t *type, 759 cfg_obj_t **ret) 760{ 761 isc_result_t result; 762 UNUSED(type); 763 764 CHECK(cfg_getstringtoken(pctx)); 765 return (create_string(pctx, 766 TOKEN_STRING(pctx), 767 &cfg_type_qstring, 768 ret)); 769 cleanup: 770 return (result); 771} 772 773isc_result_t 774cfg_parse_sstring(cfg_parser_t *pctx, const cfg_type_t *type, 775 cfg_obj_t **ret) 776{ 777 isc_result_t result; 778 UNUSED(type); 779 780 CHECK(cfg_getstringtoken(pctx)); 781 return (create_string(pctx, 782 TOKEN_STRING(pctx), 783 &cfg_type_sstring, 784 ret)); 785 cleanup: 786 return (result); 787} 788 789isc_boolean_t 790cfg_is_enum(const char *s, const char *const *enums) { 791 const char * const *p; 792 for (p = enums; *p != NULL; p++) { 793 if (strcasecmp(*p, s) == 0) 794 return (ISC_TRUE); 795 } 796 return (ISC_FALSE); 797} 798 799static isc_result_t 800check_enum(cfg_parser_t *pctx, cfg_obj_t *obj, const char *const *enums) { 801 const char *s = obj->value.string.base; 802 if (cfg_is_enum(s, enums)) 803 return (ISC_R_SUCCESS); 804 cfg_parser_error(pctx, 0, "'%s' unexpected", s); 805 return (ISC_R_UNEXPECTEDTOKEN); 806} 807 808isc_result_t 809cfg_parse_enum(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { 810 isc_result_t result; 811 cfg_obj_t *obj = NULL; 812 CHECK(parse_ustring(pctx, NULL, &obj)); 813 CHECK(check_enum(pctx, obj, type->of)); 814 *ret = obj; 815 return (ISC_R_SUCCESS); 816 cleanup: 817 CLEANUP_OBJ(obj); 818 return (result); 819} 820 821void 822cfg_doc_enum(cfg_printer_t *pctx, const cfg_type_t *type) { 823 const char * const *p; 824 cfg_print_chars(pctx, "( ", 2); 825 for (p = type->of; *p != NULL; p++) { 826 cfg_print_cstr(pctx, *p); 827 if (p[1] != NULL) 828 cfg_print_chars(pctx, " | ", 3); 829 } 830 cfg_print_chars(pctx, " )", 2); 831} 832 833void 834cfg_print_ustring(cfg_printer_t *pctx, const cfg_obj_t *obj) { 835 cfg_print_chars(pctx, obj->value.string.base, obj->value.string.length); 836} 837 838static void 839print_qstring(cfg_printer_t *pctx, const cfg_obj_t *obj) { 840 cfg_print_chars(pctx, "\"", 1); 841 cfg_print_ustring(pctx, obj); 842 cfg_print_chars(pctx, "\"", 1); 843} 844 845static void 846print_sstring(cfg_printer_t *pctx, const cfg_obj_t *obj) { 847 cfg_print_chars(pctx, "\"", 1); 848 if ((pctx->flags & CFG_PRINTER_XKEY) != 0) { 849 unsigned int len = obj->value.string.length; 850 while (len-- > 0) 851 cfg_print_chars(pctx, "?", 1); 852 } else 853 cfg_print_ustring(pctx, obj); 854 cfg_print_chars(pctx, "\"", 1); 855} 856 857static void 858free_string(cfg_parser_t *pctx, cfg_obj_t *obj) { 859 isc_mem_put(pctx->mctx, obj->value.string.base, 860 obj->value.string.length + 1); 861} 862 863isc_boolean_t 864cfg_obj_isstring(const cfg_obj_t *obj) { 865 REQUIRE(obj != NULL); 866 return (ISC_TF(obj->type->rep == &cfg_rep_string)); 867} 868 869const char * 870cfg_obj_asstring(const cfg_obj_t *obj) { 871 REQUIRE(obj != NULL && obj->type->rep == &cfg_rep_string); 872 return (obj->value.string.base); 873} 874 875/* Quoted string only */ 876cfg_type_t cfg_type_qstring = { 877 "quoted_string", cfg_parse_qstring, print_qstring, cfg_doc_terminal, 878 &cfg_rep_string, NULL 879}; 880 881/* Unquoted string only */ 882cfg_type_t cfg_type_ustring = { 883 "string", parse_ustring, cfg_print_ustring, cfg_doc_terminal, 884 &cfg_rep_string, NULL 885}; 886 887/* Any string (quoted or unquoted); printed with quotes */ 888cfg_type_t cfg_type_astring = { 889 "string", cfg_parse_astring, print_qstring, cfg_doc_terminal, 890 &cfg_rep_string, NULL 891}; 892 893/* 894 * Any string (quoted or unquoted); printed with quotes. 895 * If CFG_PRINTER_XKEY is set when printing the string will be '?' out. 896 */ 897cfg_type_t cfg_type_sstring = { 898 "string", cfg_parse_sstring, print_sstring, cfg_doc_terminal, 899 &cfg_rep_string, NULL 900}; 901 902/* 903 * Booleans 904 */ 905 906isc_boolean_t 907cfg_obj_isboolean(const cfg_obj_t *obj) { 908 REQUIRE(obj != NULL); 909 return (ISC_TF(obj->type->rep == &cfg_rep_boolean)); 910} 911 912isc_boolean_t 913cfg_obj_asboolean(const cfg_obj_t *obj) { 914 REQUIRE(obj != NULL && obj->type->rep == &cfg_rep_boolean); 915 return (obj->value.boolean); 916} 917 918isc_result_t 919cfg_parse_boolean(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) 920{ 921 isc_result_t result; 922 isc_boolean_t value; 923 cfg_obj_t *obj = NULL; 924 UNUSED(type); 925 926 result = cfg_gettoken(pctx, 0); 927 if (result != ISC_R_SUCCESS) 928 return (result); 929 930 if (pctx->token.type != isc_tokentype_string) 931 goto bad_boolean; 932 933 if ((strcasecmp(TOKEN_STRING(pctx), "true") == 0) || 934 (strcasecmp(TOKEN_STRING(pctx), "yes") == 0) || 935 (strcmp(TOKEN_STRING(pctx), "1") == 0)) { 936 value = ISC_TRUE; 937 } else if ((strcasecmp(TOKEN_STRING(pctx), "false") == 0) || 938 (strcasecmp(TOKEN_STRING(pctx), "no") == 0) || 939 (strcmp(TOKEN_STRING(pctx), "0") == 0)) { 940 value = ISC_FALSE; 941 } else { 942 goto bad_boolean; 943 } 944 945 CHECK(cfg_create_obj(pctx, &cfg_type_boolean, &obj)); 946 obj->value.boolean = value; 947 *ret = obj; 948 return (result); 949 950 bad_boolean: 951 cfg_parser_error(pctx, CFG_LOG_NEAR, "boolean expected"); 952 return (ISC_R_UNEXPECTEDTOKEN); 953 954 cleanup: 955 return (result); 956} 957 958void 959cfg_print_boolean(cfg_printer_t *pctx, const cfg_obj_t *obj) { 960 if (obj->value.boolean) 961 cfg_print_chars(pctx, "yes", 3); 962 else 963 cfg_print_chars(pctx, "no", 2); 964} 965 966cfg_type_t cfg_type_boolean = { 967 "boolean", cfg_parse_boolean, cfg_print_boolean, cfg_doc_terminal, 968 &cfg_rep_boolean, NULL 969}; 970 971/* 972 * Lists. 973 */ 974 975isc_result_t 976cfg_create_list(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **obj) { 977 isc_result_t result; 978 CHECK(cfg_create_obj(pctx, type, obj)); 979 ISC_LIST_INIT((*obj)->value.list); 980 cleanup: 981 return (result); 982} 983 984static isc_result_t 985create_listelt(cfg_parser_t *pctx, cfg_listelt_t **eltp) { 986 cfg_listelt_t *elt; 987 elt = isc_mem_get(pctx->mctx, sizeof(*elt)); 988 if (elt == NULL) 989 return (ISC_R_NOMEMORY); 990 elt->obj = NULL; 991 ISC_LINK_INIT(elt, link); 992 *eltp = elt; 993 return (ISC_R_SUCCESS); 994} 995 996static void 997free_list_elt(cfg_parser_t *pctx, cfg_listelt_t *elt) { 998 cfg_obj_destroy(pctx, &elt->obj); 999 isc_mem_put(pctx->mctx, elt, sizeof(*elt)); 1000} 1001 1002static void 1003free_list(cfg_parser_t *pctx, cfg_obj_t *obj) { 1004 cfg_listelt_t *elt, *next; 1005 for (elt = ISC_LIST_HEAD(obj->value.list); 1006 elt != NULL; 1007 elt = next) 1008 { 1009 next = ISC_LIST_NEXT(elt, link); 1010 free_list_elt(pctx, elt); 1011 } 1012} 1013 1014isc_result_t 1015cfg_parse_listelt(cfg_parser_t *pctx, const cfg_type_t *elttype, 1016 cfg_listelt_t **ret) 1017{ 1018 isc_result_t result; 1019 cfg_listelt_t *elt = NULL; 1020 cfg_obj_t *value = NULL; 1021 1022 CHECK(create_listelt(pctx, &elt)); 1023 1024 result = cfg_parse_obj(pctx, elttype, &value); 1025 if (result != ISC_R_SUCCESS) 1026 goto cleanup; 1027 1028 elt->obj = value; 1029 1030 *ret = elt; 1031 return (ISC_R_SUCCESS); 1032 1033 cleanup: 1034 isc_mem_put(pctx->mctx, elt, sizeof(*elt)); 1035 return (result); 1036} 1037 1038/* 1039 * Parse a homogeneous list whose elements are of type 'elttype' 1040 * and where each element is terminated by a semicolon. 1041 */ 1042static isc_result_t 1043parse_list(cfg_parser_t *pctx, const cfg_type_t *listtype, cfg_obj_t **ret) 1044{ 1045 cfg_obj_t *listobj = NULL; 1046 const cfg_type_t *listof = listtype->of; 1047 isc_result_t result; 1048 cfg_listelt_t *elt = NULL; 1049 1050 CHECK(cfg_create_list(pctx, listtype, &listobj)); 1051 1052 for (;;) { 1053 CHECK(cfg_peektoken(pctx, 0)); 1054 if (pctx->token.type == isc_tokentype_special && 1055 pctx->token.value.as_char == /*{*/ '}') 1056 break; 1057 CHECK(cfg_parse_listelt(pctx, listof, &elt)); 1058 CHECK(parse_semicolon(pctx)); 1059 ISC_LIST_APPEND(listobj->value.list, elt, link); 1060 elt = NULL; 1061 } 1062 *ret = listobj; 1063 return (ISC_R_SUCCESS); 1064 1065 cleanup: 1066 if (elt != NULL) 1067 free_list_elt(pctx, elt); 1068 CLEANUP_OBJ(listobj); 1069 return (result); 1070} 1071 1072static void 1073print_list(cfg_printer_t *pctx, const cfg_obj_t *obj) { 1074 const cfg_list_t *list = &obj->value.list; 1075 const cfg_listelt_t *elt; 1076 1077 for (elt = ISC_LIST_HEAD(*list); 1078 elt != NULL; 1079 elt = ISC_LIST_NEXT(elt, link)) { 1080 print_indent(pctx); 1081 cfg_print_obj(pctx, elt->obj); 1082 cfg_print_chars(pctx, ";\n", 2); 1083 } 1084} 1085 1086isc_result_t 1087cfg_parse_bracketed_list(cfg_parser_t *pctx, const cfg_type_t *type, 1088 cfg_obj_t **ret) 1089{ 1090 isc_result_t result; 1091 CHECK(cfg_parse_special(pctx, '{')); 1092 CHECK(parse_list(pctx, type, ret)); 1093 CHECK(cfg_parse_special(pctx, '}')); 1094 cleanup: 1095 return (result); 1096} 1097 1098void 1099cfg_print_bracketed_list(cfg_printer_t *pctx, const cfg_obj_t *obj) { 1100 print_open(pctx); 1101 print_list(pctx, obj); 1102 print_close(pctx); 1103} 1104 1105void 1106cfg_doc_bracketed_list(cfg_printer_t *pctx, const cfg_type_t *type) { 1107 cfg_print_chars(pctx, "{ ", 2); 1108 cfg_doc_obj(pctx, type->of); 1109 cfg_print_chars(pctx, "; ... }", 7); 1110} 1111 1112/* 1113 * Parse a homogeneous list whose elements are of type 'elttype' 1114 * and where elements are separated by space. The list ends 1115 * before the first semicolon. 1116 */ 1117isc_result_t 1118cfg_parse_spacelist(cfg_parser_t *pctx, const cfg_type_t *listtype, 1119 cfg_obj_t **ret) 1120{ 1121 cfg_obj_t *listobj = NULL; 1122 const cfg_type_t *listof = listtype->of; 1123 isc_result_t result; 1124 1125 CHECK(cfg_create_list(pctx, listtype, &listobj)); 1126 1127 for (;;) { 1128 cfg_listelt_t *elt = NULL; 1129 1130 CHECK(cfg_peektoken(pctx, 0)); 1131 if (pctx->token.type == isc_tokentype_special && 1132 pctx->token.value.as_char == ';') 1133 break; 1134 CHECK(cfg_parse_listelt(pctx, listof, &elt)); 1135 ISC_LIST_APPEND(listobj->value.list, elt, link); 1136 } 1137 *ret = listobj; 1138 return (ISC_R_SUCCESS); 1139 1140 cleanup: 1141 CLEANUP_OBJ(listobj); 1142 return (result); 1143} 1144 1145void 1146cfg_print_spacelist(cfg_printer_t *pctx, const cfg_obj_t *obj) { 1147 const cfg_list_t *list = &obj->value.list; 1148 const cfg_listelt_t *elt; 1149 1150 for (elt = ISC_LIST_HEAD(*list); 1151 elt != NULL; 1152 elt = ISC_LIST_NEXT(elt, link)) { 1153 cfg_print_obj(pctx, elt->obj); 1154 if (ISC_LIST_NEXT(elt, link) != NULL) 1155 cfg_print_chars(pctx, " ", 1); 1156 } 1157} 1158 1159isc_boolean_t 1160cfg_obj_islist(const cfg_obj_t *obj) { 1161 REQUIRE(obj != NULL); 1162 return (ISC_TF(obj->type->rep == &cfg_rep_list)); 1163} 1164 1165const cfg_listelt_t * 1166cfg_list_first(const cfg_obj_t *obj) { 1167 REQUIRE(obj == NULL || obj->type->rep == &cfg_rep_list); 1168 if (obj == NULL) 1169 return (NULL); 1170 return (ISC_LIST_HEAD(obj->value.list)); 1171} 1172 1173const cfg_listelt_t * 1174cfg_list_next(const cfg_listelt_t *elt) { 1175 REQUIRE(elt != NULL); 1176 return (ISC_LIST_NEXT(elt, link)); 1177} 1178 1179/* 1180 * Return the length of a list object. If obj is NULL or is not 1181 * a list, return 0. 1182 */ 1183unsigned int 1184cfg_list_length(const cfg_obj_t *obj, isc_boolean_t recurse) { 1185 const cfg_listelt_t *elt; 1186 unsigned int count = 0; 1187 1188 if (obj == NULL || !cfg_obj_islist(obj)) 1189 return (0U); 1190 for (elt = cfg_list_first(obj); 1191 elt != NULL; 1192 elt = cfg_list_next(elt)) { 1193 if (recurse && cfg_obj_islist(elt->obj)) { 1194 count += cfg_list_length(elt->obj, recurse); 1195 } else { 1196 count++; 1197 } 1198 } 1199 return (count); 1200} 1201 1202cfg_obj_t * 1203cfg_listelt_value(const cfg_listelt_t *elt) { 1204 REQUIRE(elt != NULL); 1205 return (elt->obj); 1206} 1207 1208/* 1209 * Maps. 1210 */ 1211 1212/* 1213 * Parse a map body. That's something like 1214 * 1215 * "foo 1; bar { glub; }; zap true; zap false;" 1216 * 1217 * i.e., a sequence of option names followed by values and 1218 * terminated by semicolons. Used for the top level of 1219 * the named.conf syntax, as well as for the body of the 1220 * options, view, zone, and other statements. 1221 */ 1222isc_result_t 1223cfg_parse_mapbody(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) 1224{ 1225 const cfg_clausedef_t * const *clausesets = type->of; 1226 isc_result_t result; 1227 const cfg_clausedef_t * const *clauseset; 1228 const cfg_clausedef_t *clause; 1229 cfg_obj_t *value = NULL; 1230 cfg_obj_t *obj = NULL; 1231 cfg_obj_t *eltobj = NULL; 1232 cfg_obj_t *includename = NULL; 1233 isc_symvalue_t symval; 1234 cfg_list_t *list = NULL; 1235 1236 CHECK(create_map(pctx, type, &obj)); 1237 1238 obj->value.map.clausesets = clausesets; 1239 1240 for (;;) { 1241 cfg_listelt_t *elt; 1242 1243 redo: 1244 /* 1245 * Parse the option name and see if it is known. 1246 */ 1247 CHECK(cfg_gettoken(pctx, 0)); 1248 1249 if (pctx->token.type != isc_tokentype_string) { 1250 cfg_ungettoken(pctx); 1251 break; 1252 } 1253 1254 /* 1255 * We accept "include" statements wherever a map body 1256 * clause can occur. 1257 */ 1258 if (strcasecmp(TOKEN_STRING(pctx), "include") == 0) { 1259 /* 1260 * Turn the file name into a temporary configuration 1261 * object just so that it is not overwritten by the 1262 * semicolon token. 1263 */ 1264 CHECK(cfg_parse_obj(pctx, &cfg_type_qstring, &includename)); 1265 CHECK(parse_semicolon(pctx)); 1266 CHECK(parser_openfile(pctx, includename-> 1267 value.string.base)); 1268 cfg_obj_destroy(pctx, &includename); 1269 goto redo; 1270 } 1271 1272 clause = NULL; 1273 for (clauseset = clausesets; *clauseset != NULL; clauseset++) { 1274 for (clause = *clauseset; 1275 clause->name != NULL; 1276 clause++) { 1277 if (strcasecmp(TOKEN_STRING(pctx), 1278 clause->name) == 0) 1279 goto done; 1280 } 1281 } 1282 done: 1283 if (clause == NULL || clause->name == NULL) { 1284 cfg_parser_error(pctx, CFG_LOG_NOPREP, "unknown option"); 1285 /* 1286 * Try to recover by parsing this option as an unknown 1287 * option and discarding it. 1288 */ 1289 CHECK(cfg_parse_obj(pctx, &cfg_type_unsupported, &eltobj)); 1290 cfg_obj_destroy(pctx, &eltobj); 1291 CHECK(parse_semicolon(pctx)); 1292 continue; 1293 } 1294 1295 /* Clause is known. */ 1296 1297 /* Issue warnings if appropriate */ 1298 if ((clause->flags & CFG_CLAUSEFLAG_OBSOLETE) != 0) 1299 cfg_parser_warning(pctx, 0, "option '%s' is obsolete", 1300 clause->name); 1301 if ((clause->flags & CFG_CLAUSEFLAG_NOTIMP) != 0) 1302 cfg_parser_warning(pctx, 0, "option '%s' is " 1303 "not implemented", clause->name); 1304 if ((clause->flags & CFG_CLAUSEFLAG_NYI) != 0) 1305 cfg_parser_warning(pctx, 0, "option '%s' is " 1306 "not implemented", clause->name); 1307 1308 if ((clause->flags & CFG_CLAUSEFLAG_NOTCONFIGURED) != 0) { 1309 cfg_parser_warning(pctx, 0, "option '%s' is not " 1310 "configured", clause->name); 1311 result = ISC_R_FAILURE; 1312 goto cleanup; 1313 } 1314 1315 /* 1316 * Don't log options with CFG_CLAUSEFLAG_NEWDEFAULT 1317 * set here - we need to log the *lack* of such an option, 1318 * not its presence. 1319 */ 1320 1321 /* See if the clause already has a value; if not create one. */ 1322 result = isc_symtab_lookup(obj->value.map.symtab, 1323 clause->name, 0, &symval); 1324 1325 if ((clause->flags & CFG_CLAUSEFLAG_MULTI) != 0) { 1326 /* Multivalued clause */ 1327 cfg_obj_t *listobj = NULL; 1328 if (result == ISC_R_NOTFOUND) { 1329 CHECK(cfg_create_list(pctx, 1330 &cfg_type_implicitlist, 1331 &listobj)); 1332 symval.as_pointer = listobj; 1333 result = isc_symtab_define(obj->value. 1334 map.symtab, 1335 clause->name, 1336 1, symval, 1337 isc_symexists_reject); 1338 if (result != ISC_R_SUCCESS) { 1339 cfg_parser_error(pctx, CFG_LOG_NEAR, 1340 "isc_symtab_define(%s) " 1341 "failed", clause->name); 1342 isc_mem_put(pctx->mctx, list, 1343 sizeof(cfg_list_t)); 1344 goto cleanup; 1345 } 1346 } else { 1347 INSIST(result == ISC_R_SUCCESS); 1348 listobj = symval.as_pointer; 1349 } 1350 1351 elt = NULL; 1352 CHECK(cfg_parse_listelt(pctx, clause->type, &elt)); 1353 CHECK(parse_semicolon(pctx)); 1354 1355 ISC_LIST_APPEND(listobj->value.list, elt, link); 1356 } else { 1357 /* Single-valued clause */ 1358 if (result == ISC_R_NOTFOUND) { 1359 isc_boolean_t callback = 1360 ISC_TF((clause->flags & 1361 CFG_CLAUSEFLAG_CALLBACK) != 0); 1362 CHECK(parse_symtab_elt(pctx, clause->name, 1363 clause->type, 1364 obj->value.map.symtab, 1365 callback)); 1366 CHECK(parse_semicolon(pctx)); 1367 } else if (result == ISC_R_SUCCESS) { 1368 cfg_parser_error(pctx, CFG_LOG_NEAR, "'%s' redefined", 1369 clause->name); 1370 result = ISC_R_EXISTS; 1371 goto cleanup; 1372 } else { 1373 cfg_parser_error(pctx, CFG_LOG_NEAR, 1374 "isc_symtab_define() failed"); 1375 goto cleanup; 1376 } 1377 } 1378 } 1379 1380 1381 *ret = obj; 1382 return (ISC_R_SUCCESS); 1383 1384 cleanup: 1385 CLEANUP_OBJ(value); 1386 CLEANUP_OBJ(obj); 1387 CLEANUP_OBJ(eltobj); 1388 CLEANUP_OBJ(includename); 1389 return (result); 1390} 1391 1392static isc_result_t 1393parse_symtab_elt(cfg_parser_t *pctx, const char *name, 1394 cfg_type_t *elttype, isc_symtab_t *symtab, 1395 isc_boolean_t callback) 1396{ 1397 isc_result_t result; 1398 cfg_obj_t *obj = NULL; 1399 isc_symvalue_t symval; 1400 1401 CHECK(cfg_parse_obj(pctx, elttype, &obj)); 1402 1403 if (callback && pctx->callback != NULL) 1404 CHECK(pctx->callback(name, obj, pctx->callbackarg)); 1405 1406 symval.as_pointer = obj; 1407 CHECK(isc_symtab_define(symtab, name, 1408 1, symval, 1409 isc_symexists_reject)); 1410 return (ISC_R_SUCCESS); 1411 1412 cleanup: 1413 CLEANUP_OBJ(obj); 1414 return (result); 1415} 1416 1417/* 1418 * Parse a map; e.g., "{ foo 1; bar { glub; }; zap true; zap false; }" 1419 */ 1420isc_result_t 1421cfg_parse_map(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { 1422 isc_result_t result; 1423 CHECK(cfg_parse_special(pctx, '{')); 1424 CHECK(cfg_parse_mapbody(pctx, type, ret)); 1425 CHECK(cfg_parse_special(pctx, '}')); 1426 cleanup: 1427 return (result); 1428} 1429 1430/* 1431 * Subroutine for cfg_parse_named_map() and cfg_parse_addressed_map(). 1432 */ 1433static isc_result_t 1434parse_any_named_map(cfg_parser_t *pctx, cfg_type_t *nametype, const cfg_type_t *type, 1435 cfg_obj_t **ret) 1436{ 1437 isc_result_t result; 1438 cfg_obj_t *idobj = NULL; 1439 cfg_obj_t *mapobj = NULL; 1440 1441 CHECK(cfg_parse_obj(pctx, nametype, &idobj)); 1442 CHECK(cfg_parse_map(pctx, type, &mapobj)); 1443 mapobj->value.map.id = idobj; 1444 idobj = NULL; 1445 *ret = mapobj; 1446 cleanup: 1447 CLEANUP_OBJ(idobj); 1448 return (result); 1449} 1450 1451/* 1452 * Parse a map identified by a string name. E.g., "name { foo 1; }". 1453 * Used for the "key" and "channel" statements. 1454 */ 1455isc_result_t 1456cfg_parse_named_map(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { 1457 return (parse_any_named_map(pctx, &cfg_type_astring, type, ret)); 1458} 1459 1460/* 1461 * Parse a map identified by a network address. 1462 * Used to be used for the "server" statement. 1463 */ 1464isc_result_t 1465cfg_parse_addressed_map(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { 1466 return (parse_any_named_map(pctx, &cfg_type_netaddr, type, ret)); 1467} 1468 1469/* 1470 * Parse a map identified by a network prefix. 1471 * Used for the "server" statement. 1472 */ 1473isc_result_t 1474cfg_parse_netprefix_map(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { 1475 return (parse_any_named_map(pctx, &cfg_type_netprefix, type, ret)); 1476} 1477 1478void 1479cfg_print_mapbody(cfg_printer_t *pctx, const cfg_obj_t *obj) { 1480 isc_result_t result = ISC_R_SUCCESS; 1481 1482 const cfg_clausedef_t * const *clauseset; 1483 1484 for (clauseset = obj->value.map.clausesets; 1485 *clauseset != NULL; 1486 clauseset++) 1487 { 1488 isc_symvalue_t symval; 1489 const cfg_clausedef_t *clause; 1490 1491 for (clause = *clauseset; 1492 clause->name != NULL; 1493 clause++) { 1494 result = isc_symtab_lookup(obj->value.map.symtab, 1495 clause->name, 0, &symval); 1496 if (result == ISC_R_SUCCESS) { 1497 cfg_obj_t *obj = symval.as_pointer; 1498 if (obj->type == &cfg_type_implicitlist) { 1499 /* Multivalued. */ 1500 cfg_list_t *list = &obj->value.list; 1501 cfg_listelt_t *elt; 1502 for (elt = ISC_LIST_HEAD(*list); 1503 elt != NULL; 1504 elt = ISC_LIST_NEXT(elt, link)) { 1505 print_indent(pctx); 1506 cfg_print_cstr(pctx, clause->name); 1507 cfg_print_chars(pctx, " ", 1); 1508 cfg_print_obj(pctx, elt->obj); 1509 cfg_print_chars(pctx, ";\n", 2); 1510 } 1511 } else { 1512 /* Single-valued. */ 1513 print_indent(pctx); 1514 cfg_print_cstr(pctx, clause->name); 1515 cfg_print_chars(pctx, " ", 1); 1516 cfg_print_obj(pctx, obj); 1517 cfg_print_chars(pctx, ";\n", 2); 1518 } 1519 } else if (result == ISC_R_NOTFOUND) { 1520 ; /* do nothing */ 1521 } else { 1522 INSIST(0); 1523 } 1524 } 1525 } 1526} 1527 1528void 1529cfg_doc_mapbody(cfg_printer_t *pctx, const cfg_type_t *type) { 1530 const cfg_clausedef_t * const *clauseset; 1531 const cfg_clausedef_t *clause; 1532 1533 for (clauseset = type->of; *clauseset != NULL; clauseset++) { 1534 for (clause = *clauseset; 1535 clause->name != NULL; 1536 clause++) { 1537 cfg_print_cstr(pctx, clause->name); 1538 cfg_print_chars(pctx, " ", 1); 1539 cfg_doc_obj(pctx, clause->type); 1540 cfg_print_chars(pctx, ";", 1); 1541 /* XXX print flags here? */ 1542 cfg_print_chars(pctx, "\n\n", 2); 1543 } 1544 } 1545} 1546 1547static struct flagtext { 1548 unsigned int flag; 1549 const char *text; 1550} flagtexts[] = { 1551 { CFG_CLAUSEFLAG_NOTIMP, "not implemented" }, 1552 { CFG_CLAUSEFLAG_NYI, "not yet implemented" }, 1553 { CFG_CLAUSEFLAG_OBSOLETE, "obsolete" }, 1554 { CFG_CLAUSEFLAG_NEWDEFAULT, "default changed" }, 1555 { CFG_CLAUSEFLAG_TESTONLY, "test only" }, 1556 { CFG_CLAUSEFLAG_NOTCONFIGURED, "not configured" }, 1557 { 0, NULL } 1558}; 1559 1560void 1561cfg_print_map(cfg_printer_t *pctx, const cfg_obj_t *obj) { 1562 if (obj->value.map.id != NULL) { 1563 cfg_print_obj(pctx, obj->value.map.id); 1564 cfg_print_chars(pctx, " ", 1); 1565 } 1566 print_open(pctx); 1567 cfg_print_mapbody(pctx, obj); 1568 print_close(pctx); 1569} 1570 1571static void 1572print_clause_flags(cfg_printer_t *pctx, unsigned int flags) { 1573 struct flagtext *p; 1574 isc_boolean_t first = ISC_TRUE; 1575 for (p = flagtexts; p->flag != 0; p++) { 1576 if ((flags & p->flag) != 0) { 1577 if (first) 1578 cfg_print_chars(pctx, " // ", 4); 1579 else 1580 cfg_print_chars(pctx, ", ", 2); 1581 cfg_print_cstr(pctx, p->text); 1582 first = ISC_FALSE; 1583 } 1584 } 1585} 1586 1587void 1588cfg_doc_map(cfg_printer_t *pctx, const cfg_type_t *type) { 1589 const cfg_clausedef_t * const *clauseset; 1590 const cfg_clausedef_t *clause; 1591 1592 if (type->parse == cfg_parse_named_map) { 1593 cfg_doc_obj(pctx, &cfg_type_astring); 1594 cfg_print_chars(pctx, " ", 1); 1595 } else if (type->parse == cfg_parse_addressed_map) { 1596 cfg_doc_obj(pctx, &cfg_type_netaddr); 1597 cfg_print_chars(pctx, " ", 1); 1598 } else if (type->parse == cfg_parse_netprefix_map) { 1599 cfg_doc_obj(pctx, &cfg_type_netprefix); 1600 cfg_print_chars(pctx, " ", 1); 1601 } 1602 1603 print_open(pctx); 1604 1605 for (clauseset = type->of; *clauseset != NULL; clauseset++) { 1606 for (clause = *clauseset; 1607 clause->name != NULL; 1608 clause++) { 1609 print_indent(pctx); 1610 cfg_print_cstr(pctx, clause->name); 1611 if (clause->type->print != cfg_print_void) 1612 cfg_print_chars(pctx, " ", 1); 1613 cfg_doc_obj(pctx, clause->type); 1614 cfg_print_chars(pctx, ";", 1); 1615 print_clause_flags(pctx, clause->flags); 1616 cfg_print_chars(pctx, "\n", 1); 1617 } 1618 } 1619 print_close(pctx); 1620} 1621 1622isc_boolean_t 1623cfg_obj_ismap(const cfg_obj_t *obj) { 1624 REQUIRE(obj != NULL); 1625 return (ISC_TF(obj->type->rep == &cfg_rep_map)); 1626} 1627 1628isc_result_t 1629cfg_map_get(const cfg_obj_t *mapobj, const char* name, const cfg_obj_t **obj) { 1630 isc_result_t result; 1631 isc_symvalue_t val; 1632 const cfg_map_t *map; 1633 1634 REQUIRE(mapobj != NULL && mapobj->type->rep == &cfg_rep_map); 1635 REQUIRE(name != NULL); 1636 REQUIRE(obj != NULL && *obj == NULL); 1637 1638 map = &mapobj->value.map; 1639 1640 result = isc_symtab_lookup(map->symtab, name, MAP_SYM, &val); 1641 if (result != ISC_R_SUCCESS) 1642 return (result); 1643 *obj = val.as_pointer; 1644 return (ISC_R_SUCCESS); 1645} 1646 1647const cfg_obj_t * 1648cfg_map_getname(const cfg_obj_t *mapobj) { 1649 REQUIRE(mapobj != NULL && mapobj->type->rep == &cfg_rep_map); 1650 return (mapobj->value.map.id); 1651} 1652 1653 1654/* Parse an arbitrary token, storing its raw text representation. */ 1655static isc_result_t 1656parse_token(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { 1657 cfg_obj_t *obj = NULL; 1658 isc_result_t result; 1659 isc_region_t r; 1660 1661 UNUSED(type); 1662 1663 CHECK(cfg_create_obj(pctx, &cfg_type_token, &obj)); 1664 CHECK(cfg_gettoken(pctx, CFG_LEXOPT_QSTRING)); 1665 if (pctx->token.type == isc_tokentype_eof) { 1666 cfg_ungettoken(pctx); 1667 result = ISC_R_EOF; 1668 goto cleanup; 1669 } 1670 1671 isc_lex_getlasttokentext(pctx->lexer, &pctx->token, &r); 1672 1673 obj->value.string.base = isc_mem_get(pctx->mctx, r.length + 1); 1674 if (obj->value.string.base == NULL) { 1675 result = ISC_R_NOMEMORY; 1676 goto cleanup; 1677 } 1678 obj->value.string.length = r.length; 1679 memmove(obj->value.string.base, r.base, r.length); 1680 obj->value.string.base[r.length] = '\0'; 1681 *ret = obj; 1682 return (result); 1683 1684 cleanup: 1685 if (obj != NULL) 1686 isc_mem_put(pctx->mctx, obj, sizeof(*obj)); 1687 return (result); 1688} 1689 1690cfg_type_t cfg_type_token = { 1691 "token", parse_token, cfg_print_ustring, cfg_doc_terminal, 1692 &cfg_rep_string, NULL 1693}; 1694 1695/* 1696 * An unsupported option. This is just a list of tokens with balanced braces 1697 * ending in a semicolon. 1698 */ 1699 1700static isc_result_t 1701parse_unsupported(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { 1702 cfg_obj_t *listobj = NULL; 1703 isc_result_t result; 1704 int braces = 0; 1705 1706 CHECK(cfg_create_list(pctx, type, &listobj)); 1707 1708 for (;;) { 1709 cfg_listelt_t *elt = NULL; 1710 1711 CHECK(cfg_peektoken(pctx, 0)); 1712 if (pctx->token.type == isc_tokentype_special) { 1713 if (pctx->token.value.as_char == '{') 1714 braces++; 1715 else if (pctx->token.value.as_char == '}') 1716 braces--; 1717 else if (pctx->token.value.as_char == ';') 1718 if (braces == 0) 1719 break; 1720 } 1721 if (pctx->token.type == isc_tokentype_eof || braces < 0) { 1722 cfg_parser_error(pctx, CFG_LOG_NEAR, "unexpected token"); 1723 result = ISC_R_UNEXPECTEDTOKEN; 1724 goto cleanup; 1725 } 1726 1727 CHECK(cfg_parse_listelt(pctx, &cfg_type_token, &elt)); 1728 ISC_LIST_APPEND(listobj->value.list, elt, link); 1729 } 1730 INSIST(braces == 0); 1731 *ret = listobj; 1732 return (ISC_R_SUCCESS); 1733 1734 cleanup: 1735 CLEANUP_OBJ(listobj); 1736 return (result); 1737} 1738 1739cfg_type_t cfg_type_unsupported = { 1740 "unsupported", parse_unsupported, cfg_print_spacelist, cfg_doc_terminal, 1741 &cfg_rep_list, NULL 1742}; 1743 1744/* 1745 * Try interpreting the current token as a network address. 1746 * 1747 * If CFG_ADDR_WILDOK is set in flags, "*" can be used as a wildcard 1748 * and at least one of CFG_ADDR_V4OK and CFG_ADDR_V6OK must also be set. The 1749 * "*" is interpreted as the IPv4 wildcard address if CFG_ADDR_V4OK is 1750 * set (including the case where CFG_ADDR_V4OK and CFG_ADDR_V6OK are both set), 1751 * and the IPv6 wildcard address otherwise. 1752 */ 1753static isc_result_t 1754token_addr(cfg_parser_t *pctx, unsigned int flags, isc_netaddr_t *na) { 1755 char *s; 1756 struct in_addr in4a; 1757 struct in6_addr in6a; 1758 1759 if (pctx->token.type != isc_tokentype_string) 1760 return (ISC_R_UNEXPECTEDTOKEN); 1761 1762 s = TOKEN_STRING(pctx); 1763 if ((flags & CFG_ADDR_WILDOK) != 0 && strcmp(s, "*") == 0) { 1764 if ((flags & CFG_ADDR_V4OK) != 0) { 1765 isc_netaddr_any(na); 1766 return (ISC_R_SUCCESS); 1767 } else if ((flags & CFG_ADDR_V6OK) != 0) { 1768 isc_netaddr_any6(na); 1769 return (ISC_R_SUCCESS); 1770 } else { 1771 INSIST(0); 1772 } 1773 } else { 1774 if ((flags & (CFG_ADDR_V4OK | CFG_ADDR_V4PREFIXOK)) != 0) { 1775 if (inet_pton(AF_INET, s, &in4a) == 1) { 1776 isc_netaddr_fromin(na, &in4a); 1777 return (ISC_R_SUCCESS); 1778 } 1779 } 1780 if ((flags & CFG_ADDR_V4PREFIXOK) != 0 && 1781 strlen(s) <= 15U) { 1782 char buf[64]; 1783 int i; 1784 1785 strcpy(buf, s); 1786 for (i = 0; i < 3; i++) { 1787 strcat(buf, ".0"); 1788 if (inet_pton(AF_INET, buf, &in4a) == 1) { 1789 isc_netaddr_fromin(na, &in4a); 1790 return (ISC_R_SUCCESS); 1791 } 1792 } 1793 } 1794 if ((flags & CFG_ADDR_V6OK) != 0 && 1795 strlen(s) <= 127U) { 1796 char buf[128]; /* see lib/bind9/getaddresses.c */ 1797 char *d; /* zone delimiter */ 1798 isc_uint32_t zone = 0; /* scope zone ID */ 1799 1800 strcpy(buf, s); 1801 d = strchr(buf, '%'); 1802 if (d != NULL) 1803 *d = '\0'; 1804 1805 if (inet_pton(AF_INET6, buf, &in6a) == 1) { 1806 if (d != NULL) { 1807#ifdef ISC_PLATFORM_HAVESCOPEID 1808 isc_result_t result; 1809 1810 result = isc_netscope_pton(AF_INET6, 1811 d + 1, 1812 &in6a, 1813 &zone); 1814 if (result != ISC_R_SUCCESS) 1815 return (result); 1816#else 1817 return (ISC_R_BADADDRESSFORM); 1818#endif 1819 } 1820 1821 isc_netaddr_fromin6(na, &in6a); 1822 isc_netaddr_setzone(na, zone); 1823 return (ISC_R_SUCCESS); 1824 } 1825 } 1826 } 1827 return (ISC_R_UNEXPECTEDTOKEN); 1828} 1829 1830isc_result_t 1831cfg_parse_rawaddr(cfg_parser_t *pctx, unsigned int flags, isc_netaddr_t *na) { 1832 isc_result_t result; 1833 const char *wild = ""; 1834 const char *prefix = ""; 1835 1836 CHECK(cfg_gettoken(pctx, 0)); 1837 result = token_addr(pctx, flags, na); 1838 if (result == ISC_R_UNEXPECTEDTOKEN) { 1839 if ((flags & CFG_ADDR_WILDOK) != 0) 1840 wild = " or '*'"; 1841 if ((flags & CFG_ADDR_V4PREFIXOK) != 0) 1842 wild = " or IPv4 prefix"; 1843 if ((flags & CFG_ADDR_MASK) == CFG_ADDR_V4OK) 1844 cfg_parser_error(pctx, CFG_LOG_NEAR, 1845 "expected IPv4 address%s%s", 1846 prefix, wild); 1847 else if ((flags & CFG_ADDR_MASK) == CFG_ADDR_V6OK) 1848 cfg_parser_error(pctx, CFG_LOG_NEAR, 1849 "expected IPv6 address%s%s", 1850 prefix, wild); 1851 else 1852 cfg_parser_error(pctx, CFG_LOG_NEAR, 1853 "expected IP address%s%s", 1854 prefix, wild); 1855 } 1856 cleanup: 1857 return (result); 1858} 1859 1860isc_boolean_t 1861cfg_lookingat_netaddr(cfg_parser_t *pctx, unsigned int flags) { 1862 isc_result_t result; 1863 isc_netaddr_t na_dummy; 1864 result = token_addr(pctx, flags, &na_dummy); 1865 return (ISC_TF(result == ISC_R_SUCCESS)); 1866} 1867 1868isc_result_t 1869cfg_parse_rawport(cfg_parser_t *pctx, unsigned int flags, in_port_t *port) { 1870 isc_result_t result; 1871 1872 CHECK(cfg_gettoken(pctx, ISC_LEXOPT_NUMBER)); 1873 1874 if ((flags & CFG_ADDR_WILDOK) != 0 && 1875 pctx->token.type == isc_tokentype_string && 1876 strcmp(TOKEN_STRING(pctx), "*") == 0) { 1877 *port = 0; 1878 return (ISC_R_SUCCESS); 1879 } 1880 if (pctx->token.type != isc_tokentype_number) { 1881 cfg_parser_error(pctx, CFG_LOG_NEAR, 1882 "expected port number or '*'"); 1883 return (ISC_R_UNEXPECTEDTOKEN); 1884 } 1885 if (pctx->token.value.as_ulong >= 65536U) { 1886 cfg_parser_error(pctx, CFG_LOG_NEAR, 1887 "port number out of range"); 1888 return (ISC_R_UNEXPECTEDTOKEN); 1889 } 1890 *port = (in_port_t)(pctx->token.value.as_ulong); 1891 return (ISC_R_SUCCESS); 1892 cleanup: 1893 return (result); 1894} 1895 1896void 1897cfg_print_rawaddr(cfg_printer_t *pctx, const isc_netaddr_t *na) { 1898 isc_result_t result; 1899 char text[128]; 1900 isc_buffer_t buf; 1901 1902 isc_buffer_init(&buf, text, sizeof(text)); 1903 result = isc_netaddr_totext(na, &buf); 1904 RUNTIME_CHECK(result == ISC_R_SUCCESS); 1905 cfg_print_chars(pctx, isc_buffer_base(&buf), isc_buffer_usedlength(&buf)); 1906} 1907 1908/* netaddr */ 1909 1910static unsigned int netaddr_flags = CFG_ADDR_V4OK | CFG_ADDR_V6OK; 1911static unsigned int netaddr4_flags = CFG_ADDR_V4OK; 1912static unsigned int netaddr4wild_flags = CFG_ADDR_V4OK | CFG_ADDR_WILDOK; 1913static unsigned int netaddr6_flags = CFG_ADDR_V6OK; 1914static unsigned int netaddr6wild_flags = CFG_ADDR_V6OK | CFG_ADDR_WILDOK; 1915 1916static isc_result_t 1917parse_netaddr(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { 1918 isc_result_t result; 1919 cfg_obj_t *obj = NULL; 1920 isc_netaddr_t netaddr; 1921 unsigned int flags = *(const unsigned int *)type->of; 1922 1923 CHECK(cfg_create_obj(pctx, type, &obj)); 1924 CHECK(cfg_parse_rawaddr(pctx, flags, &netaddr)); 1925 isc_sockaddr_fromnetaddr(&obj->value.sockaddr, &netaddr, 0); 1926 *ret = obj; 1927 return (ISC_R_SUCCESS); 1928 cleanup: 1929 CLEANUP_OBJ(obj); 1930 return (result); 1931} 1932 1933static void 1934cfg_doc_netaddr(cfg_printer_t *pctx, const cfg_type_t *type) { 1935 const unsigned int *flagp = type->of; 1936 int n = 0; 1937 if (*flagp != CFG_ADDR_V4OK && *flagp != CFG_ADDR_V6OK) 1938 cfg_print_chars(pctx, "( ", 2); 1939 if (*flagp & CFG_ADDR_V4OK) { 1940 cfg_print_cstr(pctx, "<ipv4_address>"); 1941 n++; 1942 } 1943 if (*flagp & CFG_ADDR_V6OK) { 1944 if (n != 0) 1945 cfg_print_chars(pctx, " | ", 3); 1946 cfg_print_cstr(pctx, "<ipv6_address>"); 1947 n++; 1948 } 1949 if (*flagp & CFG_ADDR_WILDOK) { 1950 if (n != 0) 1951 cfg_print_chars(pctx, " | ", 3); 1952 cfg_print_chars(pctx, "*", 1); 1953 n++; 1954 POST(n); 1955 } 1956 if (*flagp != CFG_ADDR_V4OK && *flagp != CFG_ADDR_V6OK) 1957 cfg_print_chars(pctx, " )", 2); 1958} 1959 1960cfg_type_t cfg_type_netaddr = { 1961 "netaddr", parse_netaddr, cfg_print_sockaddr, cfg_doc_netaddr, 1962 &cfg_rep_sockaddr, &netaddr_flags 1963}; 1964 1965cfg_type_t cfg_type_netaddr4 = { 1966 "netaddr4", parse_netaddr, cfg_print_sockaddr, cfg_doc_netaddr, 1967 &cfg_rep_sockaddr, &netaddr4_flags 1968}; 1969 1970cfg_type_t cfg_type_netaddr4wild = { 1971 "netaddr4wild", parse_netaddr, cfg_print_sockaddr, cfg_doc_netaddr, 1972 &cfg_rep_sockaddr, &netaddr4wild_flags 1973}; 1974 1975cfg_type_t cfg_type_netaddr6 = { 1976 "netaddr6", parse_netaddr, cfg_print_sockaddr, cfg_doc_netaddr, 1977 &cfg_rep_sockaddr, &netaddr6_flags 1978}; 1979 1980cfg_type_t cfg_type_netaddr6wild = { 1981 "netaddr6wild", parse_netaddr, cfg_print_sockaddr, cfg_doc_netaddr, 1982 &cfg_rep_sockaddr, &netaddr6wild_flags 1983}; 1984 1985/* netprefix */ 1986 1987isc_result_t 1988cfg_parse_netprefix(cfg_parser_t *pctx, const cfg_type_t *type, 1989 cfg_obj_t **ret) 1990{ 1991 cfg_obj_t *obj = NULL; 1992 isc_result_t result; 1993 isc_netaddr_t netaddr; 1994 unsigned int addrlen = 0, prefixlen; 1995 UNUSED(type); 1996 1997 CHECK(cfg_parse_rawaddr(pctx, CFG_ADDR_V4OK | CFG_ADDR_V4PREFIXOK | 1998 CFG_ADDR_V6OK, &netaddr)); 1999 switch (netaddr.family) { 2000 case AF_INET: 2001 addrlen = 32; 2002 break; 2003 case AF_INET6: 2004 addrlen = 128; 2005 break; 2006 default: 2007 INSIST(0); 2008 break; 2009 } 2010 CHECK(cfg_peektoken(pctx, 0)); 2011 if (pctx->token.type == isc_tokentype_special && 2012 pctx->token.value.as_char == '/') { 2013 CHECK(cfg_gettoken(pctx, 0)); /* read "/" */ 2014 CHECK(cfg_gettoken(pctx, ISC_LEXOPT_NUMBER)); 2015 if (pctx->token.type != isc_tokentype_number) { 2016 cfg_parser_error(pctx, CFG_LOG_NEAR, 2017 "expected prefix length"); 2018 return (ISC_R_UNEXPECTEDTOKEN); 2019 } 2020 prefixlen = pctx->token.value.as_ulong; 2021 if (prefixlen > addrlen) { 2022 cfg_parser_error(pctx, CFG_LOG_NOPREP, 2023 "invalid prefix length"); 2024 return (ISC_R_RANGE); 2025 } 2026 } else { 2027 prefixlen = addrlen; 2028 } 2029 CHECK(cfg_create_obj(pctx, &cfg_type_netprefix, &obj)); 2030 obj->value.netprefix.address = netaddr; 2031 obj->value.netprefix.prefixlen = prefixlen; 2032 *ret = obj; 2033 return (ISC_R_SUCCESS); 2034 cleanup: 2035 cfg_parser_error(pctx, CFG_LOG_NEAR, "expected network prefix"); 2036 return (result); 2037} 2038 2039static void 2040print_netprefix(cfg_printer_t *pctx, const cfg_obj_t *obj) { 2041 const cfg_netprefix_t *p = &obj->value.netprefix; 2042 2043 cfg_print_rawaddr(pctx, &p->address); 2044 cfg_print_chars(pctx, "/", 1); 2045 cfg_print_rawuint(pctx, p->prefixlen); 2046} 2047 2048isc_boolean_t 2049cfg_obj_isnetprefix(const cfg_obj_t *obj) { 2050 REQUIRE(obj != NULL); 2051 return (ISC_TF(obj->type->rep == &cfg_rep_netprefix)); 2052} 2053 2054void 2055cfg_obj_asnetprefix(const cfg_obj_t *obj, isc_netaddr_t *netaddr, 2056 unsigned int *prefixlen) 2057{ 2058 REQUIRE(obj != NULL && obj->type->rep == &cfg_rep_netprefix); 2059 REQUIRE(netaddr != NULL); 2060 REQUIRE(prefixlen != NULL); 2061 2062 *netaddr = obj->value.netprefix.address; 2063 *prefixlen = obj->value.netprefix.prefixlen; 2064} 2065 2066cfg_type_t cfg_type_netprefix = { 2067 "netprefix", cfg_parse_netprefix, print_netprefix, cfg_doc_terminal, 2068 &cfg_rep_netprefix, NULL 2069}; 2070 2071static isc_result_t 2072parse_sockaddrsub(cfg_parser_t *pctx, const cfg_type_t *type, 2073 int flags, cfg_obj_t **ret) 2074{ 2075 isc_result_t result; 2076 isc_netaddr_t netaddr; 2077 in_port_t port = 0; 2078 cfg_obj_t *obj = NULL; 2079 2080 CHECK(cfg_create_obj(pctx, type, &obj)); 2081 CHECK(cfg_parse_rawaddr(pctx, flags, &netaddr)); 2082 CHECK(cfg_peektoken(pctx, 0)); 2083 if (pctx->token.type == isc_tokentype_string && 2084 strcasecmp(TOKEN_STRING(pctx), "port") == 0) { 2085 CHECK(cfg_gettoken(pctx, 0)); /* read "port" */ 2086 CHECK(cfg_parse_rawport(pctx, flags, &port)); 2087 } 2088 isc_sockaddr_fromnetaddr(&obj->value.sockaddr, &netaddr, port); 2089 *ret = obj; 2090 return (ISC_R_SUCCESS); 2091 2092 cleanup: 2093 CLEANUP_OBJ(obj); 2094 return (result); 2095} 2096 2097static unsigned int sockaddr_flags = CFG_ADDR_V4OK | CFG_ADDR_V6OK; 2098cfg_type_t cfg_type_sockaddr = { 2099 "sockaddr", cfg_parse_sockaddr, cfg_print_sockaddr, cfg_doc_sockaddr, 2100 &cfg_rep_sockaddr, &sockaddr_flags 2101}; 2102 2103isc_result_t 2104cfg_parse_sockaddr(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { 2105 const unsigned int *flagp = type->of; 2106 return (parse_sockaddrsub(pctx, &cfg_type_sockaddr, *flagp, ret)); 2107} 2108 2109void 2110cfg_print_sockaddr(cfg_printer_t *pctx, const cfg_obj_t *obj) { 2111 isc_netaddr_t netaddr; 2112 in_port_t port; 2113 char buf[ISC_NETADDR_FORMATSIZE]; 2114 2115 isc_netaddr_fromsockaddr(&netaddr, &obj->value.sockaddr); 2116 isc_netaddr_format(&netaddr, buf, sizeof(buf)); 2117 cfg_print_cstr(pctx, buf); 2118 port = isc_sockaddr_getport(&obj->value.sockaddr); 2119 if (port != 0) { 2120 cfg_print_chars(pctx, " port ", 6); 2121 cfg_print_rawuint(pctx, port); 2122 } 2123} 2124 2125void 2126cfg_doc_sockaddr(cfg_printer_t *pctx, const cfg_type_t *type) { 2127 const unsigned int *flagp = type->of; 2128 int n = 0; 2129 cfg_print_chars(pctx, "( ", 2); 2130 if (*flagp & CFG_ADDR_V4OK) { 2131 cfg_print_cstr(pctx, "<ipv4_address>"); 2132 n++; 2133 } 2134 if (*flagp & CFG_ADDR_V6OK) { 2135 if (n != 0) 2136 cfg_print_chars(pctx, " | ", 3); 2137 cfg_print_cstr(pctx, "<ipv6_address>"); 2138 n++; 2139 } 2140 if (*flagp & CFG_ADDR_WILDOK) { 2141 if (n != 0) 2142 cfg_print_chars(pctx, " | ", 3); 2143 cfg_print_chars(pctx, "*", 1); 2144 n++; 2145 POST(n); 2146 } 2147 cfg_print_chars(pctx, " ) ", 3); 2148 if (*flagp & CFG_ADDR_WILDOK) { 2149 cfg_print_cstr(pctx, "[ port ( <integer> | * ) ]"); 2150 } else { 2151 cfg_print_cstr(pctx, "[ port <integer> ]"); 2152 } 2153} 2154 2155isc_boolean_t 2156cfg_obj_issockaddr(const cfg_obj_t *obj) { 2157 REQUIRE(obj != NULL); 2158 return (ISC_TF(obj->type->rep == &cfg_rep_sockaddr)); 2159} 2160 2161const isc_sockaddr_t * 2162cfg_obj_assockaddr(const cfg_obj_t *obj) { 2163 REQUIRE(obj != NULL && obj->type->rep == &cfg_rep_sockaddr); 2164 return (&obj->value.sockaddr); 2165} 2166 2167isc_result_t 2168cfg_gettoken(cfg_parser_t *pctx, int options) { 2169 isc_result_t result; 2170 2171 if (pctx->seen_eof) 2172 return (ISC_R_SUCCESS); 2173 2174 options |= (ISC_LEXOPT_EOF | ISC_LEXOPT_NOMORE); 2175 2176 redo: 2177 pctx->token.type = isc_tokentype_unknown; 2178 result = isc_lex_gettoken(pctx->lexer, options, &pctx->token); 2179 pctx->ungotten = ISC_FALSE; 2180 pctx->line = isc_lex_getsourceline(pctx->lexer); 2181 2182 switch (result) { 2183 case ISC_R_SUCCESS: 2184 if (pctx->token.type == isc_tokentype_eof) { 2185 result = isc_lex_close(pctx->lexer); 2186 INSIST(result == ISC_R_NOMORE || 2187 result == ISC_R_SUCCESS); 2188 2189 if (isc_lex_getsourcename(pctx->lexer) != NULL) { 2190 /* 2191 * Closed an included file, not the main file. 2192 */ 2193 cfg_listelt_t *elt; 2194 elt = ISC_LIST_TAIL(pctx->open_files-> 2195 value.list); 2196 INSIST(elt != NULL); 2197 ISC_LIST_UNLINK(pctx->open_files-> 2198 value.list, elt, link); 2199 ISC_LIST_APPEND(pctx->closed_files-> 2200 value.list, elt, link); 2201 goto redo; 2202 } 2203 pctx->seen_eof = ISC_TRUE; 2204 } 2205 break; 2206 2207 case ISC_R_NOSPACE: 2208 /* More understandable than "ran out of space". */ 2209 cfg_parser_error(pctx, CFG_LOG_NEAR, "token too big"); 2210 break; 2211 2212 case ISC_R_IOERROR: 2213 cfg_parser_error(pctx, 0, "%s", 2214 isc_result_totext(result)); 2215 break; 2216 2217 default: 2218 cfg_parser_error(pctx, CFG_LOG_NEAR, "%s", 2219 isc_result_totext(result)); 2220 break; 2221 } 2222 return (result); 2223} 2224 2225void 2226cfg_ungettoken(cfg_parser_t *pctx) { 2227 if (pctx->seen_eof) 2228 return; 2229 isc_lex_ungettoken(pctx->lexer, &pctx->token); 2230 pctx->ungotten = ISC_TRUE; 2231} 2232 2233isc_result_t 2234cfg_peektoken(cfg_parser_t *pctx, int options) { 2235 isc_result_t result; 2236 CHECK(cfg_gettoken(pctx, options)); 2237 cfg_ungettoken(pctx); 2238 cleanup: 2239 return (result); 2240} 2241 2242/* 2243 * Get a string token, accepting both the quoted and the unquoted form. 2244 * Log an error if the next token is not a string. 2245 */ 2246static isc_result_t 2247cfg_getstringtoken(cfg_parser_t *pctx) { 2248 isc_result_t result; 2249 2250 result = cfg_gettoken(pctx, CFG_LEXOPT_QSTRING); 2251 if (result != ISC_R_SUCCESS) 2252 return (result); 2253 2254 if (pctx->token.type != isc_tokentype_string && 2255 pctx->token.type != isc_tokentype_qstring) { 2256 cfg_parser_error(pctx, CFG_LOG_NEAR, "expected string"); 2257 return (ISC_R_UNEXPECTEDTOKEN); 2258 } 2259 return (ISC_R_SUCCESS); 2260} 2261 2262void 2263cfg_parser_error(cfg_parser_t *pctx, unsigned int flags, const char *fmt, ...) { 2264 va_list args; 2265 va_start(args, fmt); 2266 parser_complain(pctx, ISC_FALSE, flags, fmt, args); 2267 va_end(args); 2268 pctx->errors++; 2269} 2270 2271void 2272cfg_parser_warning(cfg_parser_t *pctx, unsigned int flags, const char *fmt, ...) { 2273 va_list args; 2274 va_start(args, fmt); 2275 parser_complain(pctx, ISC_TRUE, flags, fmt, args); 2276 va_end(args); 2277 pctx->warnings++; 2278} 2279 2280#define MAX_LOG_TOKEN 30 /* How much of a token to quote in log messages. */ 2281 2282static isc_boolean_t 2283have_current_file(cfg_parser_t *pctx) { 2284 cfg_listelt_t *elt; 2285 if (pctx->open_files == NULL) 2286 return (ISC_FALSE); 2287 2288 elt = ISC_LIST_TAIL(pctx->open_files->value.list); 2289 if (elt == NULL) 2290 return (ISC_FALSE); 2291 2292 return (ISC_TRUE); 2293} 2294 2295static char * 2296current_file(cfg_parser_t *pctx) { 2297 static char none[] = "none"; 2298 cfg_listelt_t *elt; 2299 cfg_obj_t *fileobj; 2300 2301 if (!have_current_file(pctx)) 2302 return (none); 2303 2304 elt = ISC_LIST_TAIL(pctx->open_files->value.list); 2305 if (elt == NULL) /* shouldn't be possible, but... */ 2306 return (none); 2307 2308 fileobj = elt->obj; 2309 INSIST(fileobj->type == &cfg_type_qstring); 2310 return (fileobj->value.string.base); 2311} 2312 2313static void 2314parser_complain(cfg_parser_t *pctx, isc_boolean_t is_warning, 2315 unsigned int flags, const char *format, 2316 va_list args) 2317{ 2318 char tokenbuf[MAX_LOG_TOKEN + 10]; 2319 static char where[ISC_DIR_PATHMAX + 100]; 2320 static char message[2048]; 2321 int level = ISC_LOG_ERROR; 2322 const char *prep = ""; 2323 size_t len; 2324 2325 if (is_warning) 2326 level = ISC_LOG_WARNING; 2327 2328 where[0] = '\0'; 2329 if (have_current_file(pctx)) 2330 snprintf(where, sizeof(where), "%s:%u: ", 2331 current_file(pctx), pctx->line); 2332 2333 len = vsnprintf(message, sizeof(message), format, args); 2334 if (len >= sizeof(message)) 2335 FATAL_ERROR(__FILE__, __LINE__, 2336 "error message would overflow"); 2337 2338 if ((flags & (CFG_LOG_NEAR|CFG_LOG_BEFORE|CFG_LOG_NOPREP)) != 0) { 2339 isc_region_t r; 2340 2341 if (pctx->ungotten) 2342 (void)cfg_gettoken(pctx, 0); 2343 2344 if (pctx->token.type == isc_tokentype_eof) { 2345 snprintf(tokenbuf, sizeof(tokenbuf), "end of file"); 2346 } else if (pctx->token.type == isc_tokentype_unknown) { 2347 flags = 0; 2348 tokenbuf[0] = '\0'; 2349 } else { 2350 isc_lex_getlasttokentext(pctx->lexer, 2351 &pctx->token, &r); 2352 if (r.length > MAX_LOG_TOKEN) 2353 snprintf(tokenbuf, sizeof(tokenbuf), 2354 "'%.*s...'", MAX_LOG_TOKEN, r.base); 2355 else 2356 snprintf(tokenbuf, sizeof(tokenbuf), 2357 "'%.*s'", (int)r.length, r.base); 2358 } 2359 2360 /* Choose a preposition. */ 2361 if (flags & CFG_LOG_NEAR) 2362 prep = " near "; 2363 else if (flags & CFG_LOG_BEFORE) 2364 prep = " before "; 2365 else 2366 prep = " "; 2367 } else { 2368 tokenbuf[0] = '\0'; 2369 } 2370 isc_log_write(pctx->lctx, CAT, MOD, level, 2371 "%s%s%s%s", where, message, prep, tokenbuf); 2372} 2373 2374void 2375cfg_obj_log(const cfg_obj_t *obj, isc_log_t *lctx, int level, 2376 const char *fmt, ...) { 2377 va_list ap; 2378 char msgbuf[2048]; 2379 2380 if (! isc_log_wouldlog(lctx, level)) 2381 return; 2382 2383 va_start(ap, fmt); 2384 2385 vsnprintf(msgbuf, sizeof(msgbuf), fmt, ap); 2386 isc_log_write(lctx, CAT, MOD, level, 2387 "%s:%u: %s", 2388 obj->file == NULL ? "<unknown file>" : obj->file, 2389 obj->line, msgbuf); 2390 va_end(ap); 2391} 2392 2393const char * 2394cfg_obj_file(const cfg_obj_t *obj) { 2395 return (obj->file); 2396} 2397 2398unsigned int 2399cfg_obj_line(const cfg_obj_t *obj) { 2400 return (obj->line); 2401} 2402 2403isc_result_t 2404cfg_create_obj(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { 2405 isc_result_t result; 2406 cfg_obj_t *obj; 2407 2408 obj = isc_mem_get(pctx->mctx, sizeof(cfg_obj_t)); 2409 if (obj == NULL) 2410 return (ISC_R_NOMEMORY); 2411 obj->type = type; 2412 obj->file = current_file(pctx); 2413 obj->line = pctx->line; 2414 result = isc_refcount_init(&obj->references, 1); 2415 if (result != ISC_R_SUCCESS) { 2416 isc_mem_put(pctx->mctx, obj, sizeof(cfg_obj_t)); 2417 return (result); 2418 } 2419 *ret = obj; 2420 return (ISC_R_SUCCESS); 2421} 2422 2423 2424static void 2425map_symtabitem_destroy(char *key, unsigned int type, 2426 isc_symvalue_t symval, void *userarg) 2427{ 2428 cfg_obj_t *obj = symval.as_pointer; 2429 cfg_parser_t *pctx = (cfg_parser_t *)userarg; 2430 2431 UNUSED(key); 2432 UNUSED(type); 2433 2434 cfg_obj_destroy(pctx, &obj); 2435} 2436 2437 2438static isc_result_t 2439create_map(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { 2440 isc_result_t result; 2441 isc_symtab_t *symtab = NULL; 2442 cfg_obj_t *obj = NULL; 2443 2444 CHECK(cfg_create_obj(pctx, type, &obj)); 2445 CHECK(isc_symtab_create(pctx->mctx, 5, /* XXX */ 2446 map_symtabitem_destroy, 2447 pctx, ISC_FALSE, &symtab)); 2448 obj->value.map.symtab = symtab; 2449 obj->value.map.id = NULL; 2450 2451 *ret = obj; 2452 return (ISC_R_SUCCESS); 2453 2454 cleanup: 2455 if (obj != NULL) 2456 isc_mem_put(pctx->mctx, obj, sizeof(*obj)); 2457 return (result); 2458} 2459 2460static void 2461free_map(cfg_parser_t *pctx, cfg_obj_t *obj) { 2462 CLEANUP_OBJ(obj->value.map.id); 2463 isc_symtab_destroy(&obj->value.map.symtab); 2464} 2465 2466isc_boolean_t 2467cfg_obj_istype(const cfg_obj_t *obj, const cfg_type_t *type) { 2468 return (ISC_TF(obj->type == type)); 2469} 2470 2471/* 2472 * Destroy 'obj', a configuration object created in 'pctx'. 2473 */ 2474void 2475cfg_obj_destroy(cfg_parser_t *pctx, cfg_obj_t **objp) { 2476 cfg_obj_t *obj; 2477 unsigned int refs; 2478 2479 REQUIRE(objp != NULL && *objp != NULL); 2480 REQUIRE(pctx != NULL); 2481 2482 obj = *objp; 2483 2484 isc_refcount_decrement(&obj->references, &refs); 2485 if (refs == 0) { 2486 obj->type->rep->free(pctx, obj); 2487 isc_refcount_destroy(&obj->references); 2488 isc_mem_put(pctx->mctx, obj, sizeof(cfg_obj_t)); 2489 } 2490 *objp = NULL; 2491} 2492 2493void 2494cfg_obj_attach(cfg_obj_t *src, cfg_obj_t **dest) { 2495 REQUIRE(src != NULL); 2496 REQUIRE(dest != NULL && *dest == NULL); 2497 isc_refcount_increment(&src->references, NULL); 2498 *dest = src; 2499} 2500 2501static void 2502free_noop(cfg_parser_t *pctx, cfg_obj_t *obj) { 2503 UNUSED(pctx); 2504 UNUSED(obj); 2505} 2506 2507void 2508cfg_doc_obj(cfg_printer_t *pctx, const cfg_type_t *type) { 2509 type->doc(pctx, type); 2510} 2511 2512void 2513cfg_doc_terminal(cfg_printer_t *pctx, const cfg_type_t *type) { 2514 cfg_print_chars(pctx, "<", 1); 2515 cfg_print_cstr(pctx, type->name); 2516 cfg_print_chars(pctx, ">", 1); 2517} 2518 2519void 2520cfg_print_grammar(const cfg_type_t *type, 2521 void (*f)(void *closure, const char *text, int textlen), 2522 void *closure) 2523{ 2524 cfg_printer_t pctx; 2525 pctx.f = f; 2526 pctx.closure = closure; 2527 pctx.indent = 0; 2528 pctx.flags = 0; 2529 cfg_doc_obj(&pctx, type); 2530} 2531