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