parser.c revision 170222
1264790Sbapt/* 2264790Sbapt * Copyright (C) 2004-2006 Internet Systems Consortium, Inc. ("ISC") 3264790Sbapt * Copyright (C) 2000-2003 Internet Software Consortium. 4264790Sbapt * 5264790Sbapt * Permission to use, copy, modify, and distribute this software for any 6264790Sbapt * purpose with or without fee is hereby granted, provided that the above 7264790Sbapt * copyright notice and this permission notice appear in all copies. 8264790Sbapt * 9264790Sbapt * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 10264790Sbapt * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 11264790Sbapt * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 12264790Sbapt * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 13264790Sbapt * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 14264790Sbapt * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 15264790Sbapt * PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18/* $Id: parser.c,v 1.112.18.11 2006/02/28 03:10:49 marka 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 1112const cfg_obj_t * 1113cfg_listelt_value(const cfg_listelt_t *elt) { 1114 REQUIRE(elt != NULL); 1115 return (elt->obj); 1116} 1117 1118/* 1119 * Maps. 1120 */ 1121 1122/* 1123 * Parse a map body. That's something like 1124 * 1125 * "foo 1; bar { glub; }; zap true; zap false;" 1126 * 1127 * i.e., a sequence of option names followed by values and 1128 * terminated by semicolons. Used for the top level of 1129 * the named.conf syntax, as well as for the body of the 1130 * options, view, zone, and other statements. 1131 */ 1132isc_result_t 1133cfg_parse_mapbody(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) 1134{ 1135 const cfg_clausedef_t * const *clausesets = type->of; 1136 isc_result_t result; 1137 const cfg_clausedef_t * const *clauseset; 1138 const cfg_clausedef_t *clause; 1139 cfg_obj_t *value = NULL; 1140 cfg_obj_t *obj = NULL; 1141 cfg_obj_t *eltobj = NULL; 1142 cfg_obj_t *includename = NULL; 1143 isc_symvalue_t symval; 1144 cfg_list_t *list = NULL; 1145 1146 CHECK(create_map(pctx, type, &obj)); 1147 1148 obj->value.map.clausesets = clausesets; 1149 1150 for (;;) { 1151 cfg_listelt_t *elt; 1152 1153 redo: 1154 /* 1155 * Parse the option name and see if it is known. 1156 */ 1157 CHECK(cfg_gettoken(pctx, 0)); 1158 1159 if (pctx->token.type != isc_tokentype_string) { 1160 cfg_ungettoken(pctx); 1161 break; 1162 } 1163 1164 /* 1165 * We accept "include" statements wherever a map body 1166 * clause can occur. 1167 */ 1168 if (strcasecmp(TOKEN_STRING(pctx), "include") == 0) { 1169 /* 1170 * Turn the file name into a temporary configuration 1171 * object just so that it is not overwritten by the 1172 * semicolon token. 1173 */ 1174 CHECK(cfg_parse_obj(pctx, &cfg_type_qstring, &includename)); 1175 CHECK(parse_semicolon(pctx)); 1176 CHECK(parser_openfile(pctx, includename-> 1177 value.string.base)); 1178 cfg_obj_destroy(pctx, &includename); 1179 goto redo; 1180 } 1181 1182 clause = NULL; 1183 for (clauseset = clausesets; *clauseset != NULL; clauseset++) { 1184 for (clause = *clauseset; 1185 clause->name != NULL; 1186 clause++) { 1187 if (strcasecmp(TOKEN_STRING(pctx), 1188 clause->name) == 0) 1189 goto done; 1190 } 1191 } 1192 done: 1193 if (clause == NULL || clause->name == NULL) { 1194 cfg_parser_error(pctx, CFG_LOG_NOPREP, "unknown option"); 1195 /* 1196 * Try to recover by parsing this option as an unknown 1197 * option and discarding it. 1198 */ 1199 CHECK(cfg_parse_obj(pctx, &cfg_type_unsupported, &eltobj)); 1200 cfg_obj_destroy(pctx, &eltobj); 1201 CHECK(parse_semicolon(pctx)); 1202 continue; 1203 } 1204 1205 /* Clause is known. */ 1206 1207 /* Issue warnings if appropriate */ 1208 if ((clause->flags & CFG_CLAUSEFLAG_OBSOLETE) != 0) 1209 cfg_parser_warning(pctx, 0, "option '%s' is obsolete", 1210 clause->name); 1211 if ((clause->flags & CFG_CLAUSEFLAG_NOTIMP) != 0) 1212 cfg_parser_warning(pctx, 0, "option '%s' is " 1213 "not implemented", clause->name); 1214 if ((clause->flags & CFG_CLAUSEFLAG_NYI) != 0) 1215 cfg_parser_warning(pctx, 0, "option '%s' is " 1216 "not implemented", clause->name); 1217 /* 1218 * Don't log options with CFG_CLAUSEFLAG_NEWDEFAULT 1219 * set here - we need to log the *lack* of such an option, 1220 * not its presence. 1221 */ 1222 1223 /* See if the clause already has a value; if not create one. */ 1224 result = isc_symtab_lookup(obj->value.map.symtab, 1225 clause->name, 0, &symval); 1226 1227 if ((clause->flags & CFG_CLAUSEFLAG_MULTI) != 0) { 1228 /* Multivalued clause */ 1229 cfg_obj_t *listobj = NULL; 1230 if (result == ISC_R_NOTFOUND) { 1231 CHECK(cfg_create_list(pctx, 1232 &cfg_type_implicitlist, 1233 &listobj)); 1234 symval.as_pointer = listobj; 1235 result = isc_symtab_define(obj->value. 1236 map.symtab, 1237 clause->name, 1238 1, symval, 1239 isc_symexists_reject); 1240 if (result != ISC_R_SUCCESS) { 1241 cfg_parser_error(pctx, CFG_LOG_NEAR, 1242 "isc_symtab_define(%s) " 1243 "failed", clause->name); 1244 isc_mem_put(pctx->mctx, list, 1245 sizeof(cfg_list_t)); 1246 goto cleanup; 1247 } 1248 } else { 1249 INSIST(result == ISC_R_SUCCESS); 1250 listobj = symval.as_pointer; 1251 } 1252 1253 elt = NULL; 1254 CHECK(cfg_parse_listelt(pctx, clause->type, &elt)); 1255 CHECK(parse_semicolon(pctx)); 1256 1257 ISC_LIST_APPEND(listobj->value.list, elt, link); 1258 } else { 1259 /* Single-valued clause */ 1260 if (result == ISC_R_NOTFOUND) { 1261 isc_boolean_t callback = 1262 ISC_TF((clause->flags & 1263 CFG_CLAUSEFLAG_CALLBACK) != 0); 1264 CHECK(parse_symtab_elt(pctx, clause->name, 1265 clause->type, 1266 obj->value.map.symtab, 1267 callback)); 1268 CHECK(parse_semicolon(pctx)); 1269 } else if (result == ISC_R_SUCCESS) { 1270 cfg_parser_error(pctx, CFG_LOG_NEAR, "'%s' redefined", 1271 clause->name); 1272 result = ISC_R_EXISTS; 1273 goto cleanup; 1274 } else { 1275 cfg_parser_error(pctx, CFG_LOG_NEAR, 1276 "isc_symtab_define() failed"); 1277 goto cleanup; 1278 } 1279 } 1280 } 1281 1282 1283 *ret = obj; 1284 return (ISC_R_SUCCESS); 1285 1286 cleanup: 1287 CLEANUP_OBJ(value); 1288 CLEANUP_OBJ(obj); 1289 CLEANUP_OBJ(eltobj); 1290 CLEANUP_OBJ(includename); 1291 return (result); 1292} 1293 1294static isc_result_t 1295parse_symtab_elt(cfg_parser_t *pctx, const char *name, 1296 cfg_type_t *elttype, isc_symtab_t *symtab, 1297 isc_boolean_t callback) 1298{ 1299 isc_result_t result; 1300 cfg_obj_t *obj = NULL; 1301 isc_symvalue_t symval; 1302 1303 CHECK(cfg_parse_obj(pctx, elttype, &obj)); 1304 1305 if (callback && pctx->callback != NULL) 1306 CHECK(pctx->callback(name, obj, pctx->callbackarg)); 1307 1308 symval.as_pointer = obj; 1309 CHECK(isc_symtab_define(symtab, name, 1310 1, symval, 1311 isc_symexists_reject)); 1312 return (ISC_R_SUCCESS); 1313 1314 cleanup: 1315 CLEANUP_OBJ(obj); 1316 return (result); 1317} 1318 1319/* 1320 * Parse a map; e.g., "{ foo 1; bar { glub; }; zap true; zap false; }" 1321 */ 1322isc_result_t 1323cfg_parse_map(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { 1324 isc_result_t result; 1325 CHECK(cfg_parse_special(pctx, '{')); 1326 CHECK(cfg_parse_mapbody(pctx, type, ret)); 1327 CHECK(cfg_parse_special(pctx, '}')); 1328 cleanup: 1329 return (result); 1330} 1331 1332/* 1333 * Subroutine for cfg_parse_named_map() and cfg_parse_addressed_map(). 1334 */ 1335static isc_result_t 1336parse_any_named_map(cfg_parser_t *pctx, cfg_type_t *nametype, const cfg_type_t *type, 1337 cfg_obj_t **ret) 1338{ 1339 isc_result_t result; 1340 cfg_obj_t *idobj = NULL; 1341 cfg_obj_t *mapobj = NULL; 1342 1343 CHECK(cfg_parse_obj(pctx, nametype, &idobj)); 1344 CHECK(cfg_parse_map(pctx, type, &mapobj)); 1345 mapobj->value.map.id = idobj; 1346 idobj = NULL; 1347 *ret = mapobj; 1348 cleanup: 1349 CLEANUP_OBJ(idobj); 1350 return (result); 1351} 1352 1353/* 1354 * Parse a map identified by a string name. E.g., "name { foo 1; }". 1355 * Used for the "key" and "channel" statements. 1356 */ 1357isc_result_t 1358cfg_parse_named_map(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { 1359 return (parse_any_named_map(pctx, &cfg_type_astring, type, ret)); 1360} 1361 1362/* 1363 * Parse a map identified by a network address. 1364 * Used to be used for the "server" statement. 1365 */ 1366isc_result_t 1367cfg_parse_addressed_map(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { 1368 return (parse_any_named_map(pctx, &cfg_type_netaddr, type, ret)); 1369} 1370 1371/* 1372 * Parse a map identified by a network prefix. 1373 * Used for the "server" statement. 1374 */ 1375isc_result_t 1376cfg_parse_netprefix_map(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { 1377 return (parse_any_named_map(pctx, &cfg_type_netprefix, type, ret)); 1378} 1379 1380void 1381cfg_print_mapbody(cfg_printer_t *pctx, const cfg_obj_t *obj) { 1382 isc_result_t result = ISC_R_SUCCESS; 1383 1384 const cfg_clausedef_t * const *clauseset; 1385 1386 for (clauseset = obj->value.map.clausesets; 1387 *clauseset != NULL; 1388 clauseset++) 1389 { 1390 isc_symvalue_t symval; 1391 const cfg_clausedef_t *clause; 1392 1393 for (clause = *clauseset; 1394 clause->name != NULL; 1395 clause++) { 1396 result = isc_symtab_lookup(obj->value.map.symtab, 1397 clause->name, 0, &symval); 1398 if (result == ISC_R_SUCCESS) { 1399 cfg_obj_t *obj = symval.as_pointer; 1400 if (obj->type == &cfg_type_implicitlist) { 1401 /* Multivalued. */ 1402 cfg_list_t *list = &obj->value.list; 1403 cfg_listelt_t *elt; 1404 for (elt = ISC_LIST_HEAD(*list); 1405 elt != NULL; 1406 elt = ISC_LIST_NEXT(elt, link)) { 1407 print_indent(pctx); 1408 cfg_print_cstr(pctx, clause->name); 1409 cfg_print_chars(pctx, " ", 1); 1410 cfg_print_obj(pctx, elt->obj); 1411 cfg_print_chars(pctx, ";\n", 2); 1412 } 1413 } else { 1414 /* Single-valued. */ 1415 print_indent(pctx); 1416 cfg_print_cstr(pctx, clause->name); 1417 cfg_print_chars(pctx, " ", 1); 1418 cfg_print_obj(pctx, obj); 1419 cfg_print_chars(pctx, ";\n", 2); 1420 } 1421 } else if (result == ISC_R_NOTFOUND) { 1422 ; /* do nothing */ 1423 } else { 1424 INSIST(0); 1425 } 1426 } 1427 } 1428} 1429 1430void 1431cfg_doc_mapbody(cfg_printer_t *pctx, const cfg_type_t *type) { 1432 const cfg_clausedef_t * const *clauseset; 1433 const cfg_clausedef_t *clause; 1434 1435 for (clauseset = type->of; *clauseset != NULL; clauseset++) { 1436 for (clause = *clauseset; 1437 clause->name != NULL; 1438 clause++) { 1439 cfg_print_cstr(pctx, clause->name); 1440 cfg_print_chars(pctx, " ", 1); 1441 cfg_doc_obj(pctx, clause->type); 1442 cfg_print_chars(pctx, ";", 1); 1443 /* XXX print flags here? */ 1444 cfg_print_chars(pctx, "\n\n", 2); 1445 } 1446 } 1447} 1448 1449static struct flagtext { 1450 unsigned int flag; 1451 const char *text; 1452} flagtexts[] = { 1453 { CFG_CLAUSEFLAG_NOTIMP, "not implemented" }, 1454 { CFG_CLAUSEFLAG_NYI, "not yet implemented" }, 1455 { CFG_CLAUSEFLAG_OBSOLETE, "obsolete" }, 1456 { CFG_CLAUSEFLAG_NEWDEFAULT, "default changed" }, 1457 { 0, NULL } 1458}; 1459 1460void 1461cfg_print_map(cfg_printer_t *pctx, const cfg_obj_t *obj) { 1462 if (obj->value.map.id != NULL) { 1463 cfg_print_obj(pctx, obj->value.map.id); 1464 cfg_print_chars(pctx, " ", 1); 1465 } 1466 print_open(pctx); 1467 cfg_print_mapbody(pctx, obj); 1468 print_close(pctx); 1469} 1470 1471static void 1472print_clause_flags(cfg_printer_t *pctx, unsigned int flags) { 1473 struct flagtext *p; 1474 isc_boolean_t first = ISC_TRUE; 1475 for (p = flagtexts; p->flag != 0; p++) { 1476 if ((flags & p->flag) != 0) { 1477 if (first) 1478 cfg_print_chars(pctx, " // ", 4); 1479 else 1480 cfg_print_chars(pctx, ", ", 2); 1481 cfg_print_cstr(pctx, p->text); 1482 first = ISC_FALSE; 1483 } 1484 } 1485} 1486 1487void 1488cfg_doc_map(cfg_printer_t *pctx, const cfg_type_t *type) { 1489 const cfg_clausedef_t * const *clauseset; 1490 const cfg_clausedef_t *clause; 1491 1492 if (type->parse == cfg_parse_named_map) { 1493 cfg_doc_obj(pctx, &cfg_type_astring); 1494 cfg_print_chars(pctx, " ", 1); 1495 } else if (type->parse == cfg_parse_addressed_map) { 1496 cfg_doc_obj(pctx, &cfg_type_netaddr); 1497 cfg_print_chars(pctx, " ", 1); 1498 } else if (type->parse == cfg_parse_netprefix_map) { 1499 cfg_doc_obj(pctx, &cfg_type_netprefix); 1500 cfg_print_chars(pctx, " ", 1); 1501 } 1502 1503 print_open(pctx); 1504 1505 for (clauseset = type->of; *clauseset != NULL; clauseset++) { 1506 for (clause = *clauseset; 1507 clause->name != NULL; 1508 clause++) { 1509 print_indent(pctx); 1510 cfg_print_cstr(pctx, clause->name); 1511 if (clause->type->print != cfg_print_void) 1512 cfg_print_chars(pctx, " ", 1); 1513 cfg_doc_obj(pctx, clause->type); 1514 cfg_print_chars(pctx, ";", 1); 1515 print_clause_flags(pctx, clause->flags); 1516 cfg_print_chars(pctx, "\n", 1); 1517 } 1518 } 1519 print_close(pctx); 1520} 1521 1522isc_boolean_t 1523cfg_obj_ismap(const cfg_obj_t *obj) { 1524 REQUIRE(obj != NULL); 1525 return (ISC_TF(obj->type->rep == &cfg_rep_map)); 1526} 1527 1528isc_result_t 1529cfg_map_get(const cfg_obj_t *mapobj, const char* name, const cfg_obj_t **obj) { 1530 isc_result_t result; 1531 isc_symvalue_t val; 1532 const cfg_map_t *map; 1533 1534 REQUIRE(mapobj != NULL && mapobj->type->rep == &cfg_rep_map); 1535 REQUIRE(name != NULL); 1536 REQUIRE(obj != NULL && *obj == NULL); 1537 1538 map = &mapobj->value.map; 1539 1540 result = isc_symtab_lookup(map->symtab, name, MAP_SYM, &val); 1541 if (result != ISC_R_SUCCESS) 1542 return (result); 1543 *obj = val.as_pointer; 1544 return (ISC_R_SUCCESS); 1545} 1546 1547const cfg_obj_t * 1548cfg_map_getname(const cfg_obj_t *mapobj) { 1549 REQUIRE(mapobj != NULL && mapobj->type->rep == &cfg_rep_map); 1550 return (mapobj->value.map.id); 1551} 1552 1553 1554/* Parse an arbitrary token, storing its raw text representation. */ 1555static isc_result_t 1556parse_token(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { 1557 cfg_obj_t *obj = NULL; 1558 isc_result_t result; 1559 isc_region_t r; 1560 1561 UNUSED(type); 1562 1563 CHECK(cfg_create_obj(pctx, &cfg_type_token, &obj)); 1564 CHECK(cfg_gettoken(pctx, CFG_LEXOPT_QSTRING)); 1565 if (pctx->token.type == isc_tokentype_eof) { 1566 cfg_ungettoken(pctx); 1567 result = ISC_R_EOF; 1568 goto cleanup; 1569 } 1570 1571 isc_lex_getlasttokentext(pctx->lexer, &pctx->token, &r); 1572 1573 obj->value.string.base = isc_mem_get(pctx->mctx, r.length + 1); 1574 if (obj->value.string.base == NULL) { 1575 result = ISC_R_NOMEMORY; 1576 goto cleanup; 1577 } 1578 obj->value.string.length = r.length; 1579 memcpy(obj->value.string.base, r.base, r.length); 1580 obj->value.string.base[r.length] = '\0'; 1581 *ret = obj; 1582 return (result); 1583 1584 cleanup: 1585 if (obj != NULL) 1586 isc_mem_put(pctx->mctx, obj, sizeof(*obj)); 1587 return (result); 1588} 1589 1590cfg_type_t cfg_type_token = { 1591 "token", parse_token, cfg_print_ustring, cfg_doc_terminal, 1592 &cfg_rep_string, NULL 1593}; 1594 1595/* 1596 * An unsupported option. This is just a list of tokens with balanced braces 1597 * ending in a semicolon. 1598 */ 1599 1600static isc_result_t 1601parse_unsupported(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { 1602 cfg_obj_t *listobj = NULL; 1603 isc_result_t result; 1604 int braces = 0; 1605 1606 CHECK(cfg_create_list(pctx, type, &listobj)); 1607 1608 for (;;) { 1609 cfg_listelt_t *elt = NULL; 1610 1611 CHECK(cfg_peektoken(pctx, 0)); 1612 if (pctx->token.type == isc_tokentype_special) { 1613 if (pctx->token.value.as_char == '{') 1614 braces++; 1615 else if (pctx->token.value.as_char == '}') 1616 braces--; 1617 else if (pctx->token.value.as_char == ';') 1618 if (braces == 0) 1619 break; 1620 } 1621 if (pctx->token.type == isc_tokentype_eof || braces < 0) { 1622 cfg_parser_error(pctx, CFG_LOG_NEAR, "unexpected token"); 1623 result = ISC_R_UNEXPECTEDTOKEN; 1624 goto cleanup; 1625 } 1626 1627 CHECK(cfg_parse_listelt(pctx, &cfg_type_token, &elt)); 1628 ISC_LIST_APPEND(listobj->value.list, elt, link); 1629 } 1630 INSIST(braces == 0); 1631 *ret = listobj; 1632 return (ISC_R_SUCCESS); 1633 1634 cleanup: 1635 CLEANUP_OBJ(listobj); 1636 return (result); 1637} 1638 1639cfg_type_t cfg_type_unsupported = { 1640 "unsupported", parse_unsupported, cfg_print_spacelist, cfg_doc_terminal, 1641 &cfg_rep_list, NULL 1642}; 1643 1644/* 1645 * Try interpreting the current token as a network address. 1646 * 1647 * If CFG_ADDR_WILDOK is set in flags, "*" can be used as a wildcard 1648 * and at least one of CFG_ADDR_V4OK and CFG_ADDR_V6OK must also be set. The 1649 * "*" is interpreted as the IPv4 wildcard address if CFG_ADDR_V4OK is 1650 * set (including the case where CFG_ADDR_V4OK and CFG_ADDR_V6OK are both set), 1651 * and the IPv6 wildcard address otherwise. 1652 */ 1653static isc_result_t 1654token_addr(cfg_parser_t *pctx, unsigned int flags, isc_netaddr_t *na) { 1655 char *s; 1656 struct in_addr in4a; 1657 struct in6_addr in6a; 1658 1659 if (pctx->token.type != isc_tokentype_string) 1660 return (ISC_R_UNEXPECTEDTOKEN); 1661 1662 s = TOKEN_STRING(pctx); 1663 if ((flags & CFG_ADDR_WILDOK) != 0 && strcmp(s, "*") == 0) { 1664 if ((flags & CFG_ADDR_V4OK) != 0) { 1665 isc_netaddr_any(na); 1666 return (ISC_R_SUCCESS); 1667 } else if ((flags & CFG_ADDR_V6OK) != 0) { 1668 isc_netaddr_any6(na); 1669 return (ISC_R_SUCCESS); 1670 } else { 1671 INSIST(0); 1672 } 1673 } else { 1674 if ((flags & (CFG_ADDR_V4OK | CFG_ADDR_V4PREFIXOK)) != 0) { 1675 if (inet_pton(AF_INET, s, &in4a) == 1) { 1676 isc_netaddr_fromin(na, &in4a); 1677 return (ISC_R_SUCCESS); 1678 } 1679 } 1680 if ((flags & CFG_ADDR_V4PREFIXOK) != 0 && 1681 strlen(s) <= 15U) { 1682 char buf[64]; 1683 int i; 1684 1685 strcpy(buf, s); 1686 for (i = 0; i < 3; i++) { 1687 strcat(buf, ".0"); 1688 if (inet_pton(AF_INET, buf, &in4a) == 1) { 1689 isc_netaddr_fromin(na, &in4a); 1690 return (ISC_R_SUCCESS); 1691 } 1692 } 1693 } 1694 if ((flags & CFG_ADDR_V6OK) != 0 && 1695 strlen(s) <= 127U) { 1696 char buf[128]; /* see lib/bind9/getaddresses.c */ 1697 char *d; /* zone delimiter */ 1698 isc_uint32_t zone = 0; /* scope zone ID */ 1699 1700 strcpy(buf, s); 1701 d = strchr(buf, '%'); 1702 if (d != NULL) 1703 *d = '\0'; 1704 1705 if (inet_pton(AF_INET6, buf, &in6a) == 1) { 1706 if (d != NULL) { 1707#ifdef ISC_PLATFORM_HAVESCOPEID 1708 isc_result_t result; 1709 1710 result = isc_netscope_pton(AF_INET6, 1711 d + 1, 1712 &in6a, 1713 &zone); 1714 if (result != ISC_R_SUCCESS) 1715 return (result); 1716#else 1717 return (ISC_R_BADADDRESSFORM); 1718#endif 1719 } 1720 1721 isc_netaddr_fromin6(na, &in6a); 1722 isc_netaddr_setzone(na, zone); 1723 return (ISC_R_SUCCESS); 1724 } 1725 } 1726 } 1727 return (ISC_R_UNEXPECTEDTOKEN); 1728} 1729 1730isc_result_t 1731cfg_parse_rawaddr(cfg_parser_t *pctx, unsigned int flags, isc_netaddr_t *na) { 1732 isc_result_t result; 1733 const char *wild = ""; 1734 const char *prefix = ""; 1735 1736 CHECK(cfg_gettoken(pctx, 0)); 1737 result = token_addr(pctx, flags, na); 1738 if (result == ISC_R_UNEXPECTEDTOKEN) { 1739 if ((flags & CFG_ADDR_WILDOK) != 0) 1740 wild = " or '*'"; 1741 if ((flags & CFG_ADDR_V4PREFIXOK) != 0) 1742 wild = " or IPv4 prefix"; 1743 if ((flags & CFG_ADDR_MASK) == CFG_ADDR_V4OK) 1744 cfg_parser_error(pctx, CFG_LOG_NEAR, 1745 "expected IPv4 address%s%s", 1746 prefix, wild); 1747 else if ((flags & CFG_ADDR_MASK) == CFG_ADDR_V6OK) 1748 cfg_parser_error(pctx, CFG_LOG_NEAR, 1749 "expected IPv6 address%s%s", 1750 prefix, wild); 1751 else 1752 cfg_parser_error(pctx, CFG_LOG_NEAR, 1753 "expected IP address%s%s", 1754 prefix, wild); 1755 } 1756 cleanup: 1757 return (result); 1758} 1759 1760isc_boolean_t 1761cfg_lookingat_netaddr(cfg_parser_t *pctx, unsigned int flags) { 1762 isc_result_t result; 1763 isc_netaddr_t na_dummy; 1764 result = token_addr(pctx, flags, &na_dummy); 1765 return (ISC_TF(result == ISC_R_SUCCESS)); 1766} 1767 1768isc_result_t 1769cfg_parse_rawport(cfg_parser_t *pctx, unsigned int flags, in_port_t *port) { 1770 isc_result_t result; 1771 1772 CHECK(cfg_gettoken(pctx, ISC_LEXOPT_NUMBER)); 1773 1774 if ((flags & CFG_ADDR_WILDOK) != 0 && 1775 pctx->token.type == isc_tokentype_string && 1776 strcmp(TOKEN_STRING(pctx), "*") == 0) { 1777 *port = 0; 1778 return (ISC_R_SUCCESS); 1779 } 1780 if (pctx->token.type != isc_tokentype_number) { 1781 cfg_parser_error(pctx, CFG_LOG_NEAR, 1782 "expected port number or '*'"); 1783 return (ISC_R_UNEXPECTEDTOKEN); 1784 } 1785 if (pctx->token.value.as_ulong >= 65536U) { 1786 cfg_parser_error(pctx, CFG_LOG_NEAR, 1787 "port number out of range"); 1788 return (ISC_R_UNEXPECTEDTOKEN); 1789 } 1790 *port = (in_port_t)(pctx->token.value.as_ulong); 1791 return (ISC_R_SUCCESS); 1792 cleanup: 1793 return (result); 1794} 1795 1796void 1797cfg_print_rawaddr(cfg_printer_t *pctx, const isc_netaddr_t *na) { 1798 isc_result_t result; 1799 char text[128]; 1800 isc_buffer_t buf; 1801 1802 isc_buffer_init(&buf, text, sizeof(text)); 1803 result = isc_netaddr_totext(na, &buf); 1804 RUNTIME_CHECK(result == ISC_R_SUCCESS); 1805 cfg_print_chars(pctx, isc_buffer_base(&buf), isc_buffer_usedlength(&buf)); 1806} 1807 1808/* netaddr */ 1809 1810static unsigned int netaddr_flags = CFG_ADDR_V4OK | CFG_ADDR_V6OK; 1811static unsigned int netaddr4_flags = CFG_ADDR_V4OK; 1812static unsigned int netaddr4wild_flags = CFG_ADDR_V4OK | CFG_ADDR_WILDOK; 1813static unsigned int netaddr6_flags = CFG_ADDR_V6OK; 1814static unsigned int netaddr6wild_flags = CFG_ADDR_V6OK | CFG_ADDR_WILDOK; 1815 1816static isc_result_t 1817parse_netaddr(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { 1818 isc_result_t result; 1819 cfg_obj_t *obj = NULL; 1820 isc_netaddr_t netaddr; 1821 unsigned int flags = *(const unsigned int *)type->of; 1822 1823 CHECK(cfg_create_obj(pctx, type, &obj)); 1824 CHECK(cfg_parse_rawaddr(pctx, flags, &netaddr)); 1825 isc_sockaddr_fromnetaddr(&obj->value.sockaddr, &netaddr, 0); 1826 *ret = obj; 1827 return (ISC_R_SUCCESS); 1828 cleanup: 1829 CLEANUP_OBJ(obj); 1830 return (result); 1831} 1832 1833static void 1834cfg_doc_netaddr(cfg_printer_t *pctx, const cfg_type_t *type) { 1835 const unsigned int *flagp = type->of; 1836 int n = 0; 1837 if (*flagp != CFG_ADDR_V4OK && *flagp != CFG_ADDR_V6OK) 1838 cfg_print_chars(pctx, "( ", 2); 1839 if (*flagp & CFG_ADDR_V4OK) { 1840 cfg_print_cstr(pctx, "<ipv4_address>"); 1841 n++; 1842 } 1843 if (*flagp & CFG_ADDR_V6OK) { 1844 if (n != 0) 1845 cfg_print_chars(pctx, " | ", 3); 1846 cfg_print_cstr(pctx, "<ipv6_address>"); 1847 n++; 1848 } 1849 if (*flagp & CFG_ADDR_WILDOK) { 1850 if (n != 0) 1851 cfg_print_chars(pctx, " | ", 3); 1852 cfg_print_chars(pctx, "*", 1); 1853 n++; 1854 } 1855 if (*flagp != CFG_ADDR_V4OK && *flagp != CFG_ADDR_V6OK) 1856 cfg_print_chars(pctx, " )", 2); 1857} 1858 1859cfg_type_t cfg_type_netaddr = { 1860 "netaddr", parse_netaddr, cfg_print_sockaddr, cfg_doc_netaddr, 1861 &cfg_rep_sockaddr, &netaddr_flags 1862}; 1863 1864cfg_type_t cfg_type_netaddr4 = { 1865 "netaddr4", parse_netaddr, cfg_print_sockaddr, cfg_doc_netaddr, 1866 &cfg_rep_sockaddr, &netaddr4_flags 1867}; 1868 1869cfg_type_t cfg_type_netaddr4wild = { 1870 "netaddr4wild", parse_netaddr, cfg_print_sockaddr, cfg_doc_netaddr, 1871 &cfg_rep_sockaddr, &netaddr4wild_flags 1872}; 1873 1874cfg_type_t cfg_type_netaddr6 = { 1875 "netaddr6", parse_netaddr, cfg_print_sockaddr, cfg_doc_netaddr, 1876 &cfg_rep_sockaddr, &netaddr6_flags 1877}; 1878 1879cfg_type_t cfg_type_netaddr6wild = { 1880 "netaddr6wild", parse_netaddr, cfg_print_sockaddr, cfg_doc_netaddr, 1881 &cfg_rep_sockaddr, &netaddr6wild_flags 1882}; 1883 1884/* netprefix */ 1885 1886isc_result_t 1887cfg_parse_netprefix(cfg_parser_t *pctx, const cfg_type_t *type, 1888 cfg_obj_t **ret) 1889{ 1890 cfg_obj_t *obj = NULL; 1891 isc_result_t result; 1892 isc_netaddr_t netaddr; 1893 unsigned int addrlen, prefixlen; 1894 UNUSED(type); 1895 1896 CHECK(cfg_parse_rawaddr(pctx, CFG_ADDR_V4OK | CFG_ADDR_V4PREFIXOK | 1897 CFG_ADDR_V6OK, &netaddr)); 1898 switch (netaddr.family) { 1899 case AF_INET: 1900 addrlen = 32; 1901 break; 1902 case AF_INET6: 1903 addrlen = 128; 1904 break; 1905 default: 1906 addrlen = 0; 1907 INSIST(0); 1908 break; 1909 } 1910 CHECK(cfg_peektoken(pctx, 0)); 1911 if (pctx->token.type == isc_tokentype_special && 1912 pctx->token.value.as_char == '/') { 1913 CHECK(cfg_gettoken(pctx, 0)); /* read "/" */ 1914 CHECK(cfg_gettoken(pctx, ISC_LEXOPT_NUMBER)); 1915 if (pctx->token.type != isc_tokentype_number) { 1916 cfg_parser_error(pctx, CFG_LOG_NEAR, 1917 "expected prefix length"); 1918 return (ISC_R_UNEXPECTEDTOKEN); 1919 } 1920 prefixlen = pctx->token.value.as_ulong; 1921 if (prefixlen > addrlen) { 1922 cfg_parser_error(pctx, CFG_LOG_NOPREP, 1923 "invalid prefix length"); 1924 return (ISC_R_RANGE); 1925 } 1926 } else { 1927 prefixlen = addrlen; 1928 } 1929 CHECK(cfg_create_obj(pctx, &cfg_type_netprefix, &obj)); 1930 obj->value.netprefix.address = netaddr; 1931 obj->value.netprefix.prefixlen = prefixlen; 1932 *ret = obj; 1933 return (ISC_R_SUCCESS); 1934 cleanup: 1935 cfg_parser_error(pctx, CFG_LOG_NEAR, "expected network prefix"); 1936 return (result); 1937} 1938 1939static void 1940print_netprefix(cfg_printer_t *pctx, const cfg_obj_t *obj) { 1941 const cfg_netprefix_t *p = &obj->value.netprefix; 1942 1943 cfg_print_rawaddr(pctx, &p->address); 1944 cfg_print_chars(pctx, "/", 1); 1945 cfg_print_rawuint(pctx, p->prefixlen); 1946} 1947 1948isc_boolean_t 1949cfg_obj_isnetprefix(const cfg_obj_t *obj) { 1950 REQUIRE(obj != NULL); 1951 return (ISC_TF(obj->type->rep == &cfg_rep_netprefix)); 1952} 1953 1954void 1955cfg_obj_asnetprefix(const cfg_obj_t *obj, isc_netaddr_t *netaddr, 1956 unsigned int *prefixlen) { 1957 REQUIRE(obj != NULL && obj->type->rep == &cfg_rep_netprefix); 1958 *netaddr = obj->value.netprefix.address; 1959 *prefixlen = obj->value.netprefix.prefixlen; 1960} 1961 1962cfg_type_t cfg_type_netprefix = { 1963 "netprefix", cfg_parse_netprefix, print_netprefix, cfg_doc_terminal, 1964 &cfg_rep_netprefix, NULL 1965}; 1966 1967static isc_result_t 1968parse_sockaddrsub(cfg_parser_t *pctx, const cfg_type_t *type, 1969 int flags, cfg_obj_t **ret) 1970{ 1971 isc_result_t result; 1972 isc_netaddr_t netaddr; 1973 in_port_t port = 0; 1974 cfg_obj_t *obj = NULL; 1975 1976 CHECK(cfg_create_obj(pctx, type, &obj)); 1977 CHECK(cfg_parse_rawaddr(pctx, flags, &netaddr)); 1978 CHECK(cfg_peektoken(pctx, 0)); 1979 if (pctx->token.type == isc_tokentype_string && 1980 strcasecmp(TOKEN_STRING(pctx), "port") == 0) { 1981 CHECK(cfg_gettoken(pctx, 0)); /* read "port" */ 1982 CHECK(cfg_parse_rawport(pctx, flags, &port)); 1983 } 1984 isc_sockaddr_fromnetaddr(&obj->value.sockaddr, &netaddr, port); 1985 *ret = obj; 1986 return (ISC_R_SUCCESS); 1987 1988 cleanup: 1989 CLEANUP_OBJ(obj); 1990 return (result); 1991} 1992 1993static unsigned int sockaddr_flags = CFG_ADDR_V4OK | CFG_ADDR_V6OK; 1994cfg_type_t cfg_type_sockaddr = { 1995 "sockaddr", cfg_parse_sockaddr, cfg_print_sockaddr, cfg_doc_sockaddr, 1996 &cfg_rep_sockaddr, &sockaddr_flags 1997}; 1998 1999isc_result_t 2000cfg_parse_sockaddr(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { 2001 const unsigned int *flagp = type->of; 2002 return (parse_sockaddrsub(pctx, &cfg_type_sockaddr, *flagp, ret)); 2003} 2004 2005void 2006cfg_print_sockaddr(cfg_printer_t *pctx, const cfg_obj_t *obj) { 2007 isc_netaddr_t netaddr; 2008 in_port_t port; 2009 char buf[ISC_NETADDR_FORMATSIZE]; 2010 2011 isc_netaddr_fromsockaddr(&netaddr, &obj->value.sockaddr); 2012 isc_netaddr_format(&netaddr, buf, sizeof(buf)); 2013 cfg_print_cstr(pctx, buf); 2014 port = isc_sockaddr_getport(&obj->value.sockaddr); 2015 if (port != 0) { 2016 cfg_print_chars(pctx, " port ", 6); 2017 cfg_print_rawuint(pctx, port); 2018 } 2019} 2020 2021void 2022cfg_doc_sockaddr(cfg_printer_t *pctx, const cfg_type_t *type) { 2023 const unsigned int *flagp = type->of; 2024 int n = 0; 2025 cfg_print_chars(pctx, "( ", 2); 2026 if (*flagp & CFG_ADDR_V4OK) { 2027 cfg_print_cstr(pctx, "<ipv4_address>"); 2028 n++; 2029 } 2030 if (*flagp & CFG_ADDR_V6OK) { 2031 if (n != 0) 2032 cfg_print_chars(pctx, " | ", 3); 2033 cfg_print_cstr(pctx, "<ipv6_address>"); 2034 n++; 2035 } 2036 if (*flagp & CFG_ADDR_WILDOK) { 2037 if (n != 0) 2038 cfg_print_chars(pctx, " | ", 3); 2039 cfg_print_chars(pctx, "*", 1); 2040 n++; 2041 } 2042 cfg_print_chars(pctx, " ) ", 3); 2043 if (*flagp & CFG_ADDR_WILDOK) { 2044 cfg_print_cstr(pctx, "[ port ( <integer> | * ) ]"); 2045 } else { 2046 cfg_print_cstr(pctx, "[ port <integer> ]"); 2047 } 2048} 2049 2050isc_boolean_t 2051cfg_obj_issockaddr(const cfg_obj_t *obj) { 2052 REQUIRE(obj != NULL); 2053 return (ISC_TF(obj->type->rep == &cfg_rep_sockaddr)); 2054} 2055 2056const isc_sockaddr_t * 2057cfg_obj_assockaddr(const cfg_obj_t *obj) { 2058 REQUIRE(obj != NULL && obj->type->rep == &cfg_rep_sockaddr); 2059 return (&obj->value.sockaddr); 2060} 2061 2062isc_result_t 2063cfg_gettoken(cfg_parser_t *pctx, int options) { 2064 isc_result_t result; 2065 2066 if (pctx->seen_eof) 2067 return (ISC_R_SUCCESS); 2068 2069 options |= (ISC_LEXOPT_EOF | ISC_LEXOPT_NOMORE); 2070 2071 redo: 2072 pctx->token.type = isc_tokentype_unknown; 2073 result = isc_lex_gettoken(pctx->lexer, options, &pctx->token); 2074 pctx->ungotten = ISC_FALSE; 2075 pctx->line = isc_lex_getsourceline(pctx->lexer); 2076 2077 switch (result) { 2078 case ISC_R_SUCCESS: 2079 if (pctx->token.type == isc_tokentype_eof) { 2080 result = isc_lex_close(pctx->lexer); 2081 INSIST(result == ISC_R_NOMORE || 2082 result == ISC_R_SUCCESS); 2083 2084 if (isc_lex_getsourcename(pctx->lexer) != NULL) { 2085 /* 2086 * Closed an included file, not the main file. 2087 */ 2088 cfg_listelt_t *elt; 2089 elt = ISC_LIST_TAIL(pctx->open_files-> 2090 value.list); 2091 INSIST(elt != NULL); 2092 ISC_LIST_UNLINK(pctx->open_files-> 2093 value.list, elt, link); 2094 ISC_LIST_APPEND(pctx->closed_files-> 2095 value.list, elt, link); 2096 goto redo; 2097 } 2098 pctx->seen_eof = ISC_TRUE; 2099 } 2100 break; 2101 2102 case ISC_R_NOSPACE: 2103 /* More understandable than "ran out of space". */ 2104 cfg_parser_error(pctx, CFG_LOG_NEAR, "token too big"); 2105 break; 2106 2107 case ISC_R_IOERROR: 2108 cfg_parser_error(pctx, 0, "%s", 2109 isc_result_totext(result)); 2110 break; 2111 2112 default: 2113 cfg_parser_error(pctx, CFG_LOG_NEAR, "%s", 2114 isc_result_totext(result)); 2115 break; 2116 } 2117 return (result); 2118} 2119 2120void 2121cfg_ungettoken(cfg_parser_t *pctx) { 2122 if (pctx->seen_eof) 2123 return; 2124 isc_lex_ungettoken(pctx->lexer, &pctx->token); 2125 pctx->ungotten = ISC_TRUE; 2126} 2127 2128isc_result_t 2129cfg_peektoken(cfg_parser_t *pctx, int options) { 2130 isc_result_t result; 2131 CHECK(cfg_gettoken(pctx, options)); 2132 cfg_ungettoken(pctx); 2133 cleanup: 2134 return (result); 2135} 2136 2137/* 2138 * Get a string token, accepting both the quoted and the unquoted form. 2139 * Log an error if the next token is not a string. 2140 */ 2141static isc_result_t 2142cfg_getstringtoken(cfg_parser_t *pctx) { 2143 isc_result_t result; 2144 2145 result = cfg_gettoken(pctx, CFG_LEXOPT_QSTRING); 2146 if (result != ISC_R_SUCCESS) 2147 return (result); 2148 2149 if (pctx->token.type != isc_tokentype_string && 2150 pctx->token.type != isc_tokentype_qstring) { 2151 cfg_parser_error(pctx, CFG_LOG_NEAR, "expected string"); 2152 return (ISC_R_UNEXPECTEDTOKEN); 2153 } 2154 return (ISC_R_SUCCESS); 2155} 2156 2157void 2158cfg_parser_error(cfg_parser_t *pctx, unsigned int flags, const char *fmt, ...) { 2159 va_list args; 2160 va_start(args, fmt); 2161 parser_complain(pctx, ISC_FALSE, flags, fmt, args); 2162 va_end(args); 2163 pctx->errors++; 2164} 2165 2166void 2167cfg_parser_warning(cfg_parser_t *pctx, unsigned int flags, const char *fmt, ...) { 2168 va_list args; 2169 va_start(args, fmt); 2170 parser_complain(pctx, ISC_TRUE, flags, fmt, args); 2171 va_end(args); 2172 pctx->warnings++; 2173} 2174 2175#define MAX_LOG_TOKEN 30 /* How much of a token to quote in log messages. */ 2176 2177static char * 2178current_file(cfg_parser_t *pctx) { 2179 static char none[] = "none"; 2180 cfg_listelt_t *elt; 2181 cfg_obj_t *fileobj; 2182 2183 if (pctx->open_files == NULL) 2184 return (none); 2185 elt = ISC_LIST_TAIL(pctx->open_files->value.list); 2186 if (elt == NULL) 2187 return (none); 2188 2189 fileobj = elt->obj; 2190 INSIST(fileobj->type == &cfg_type_qstring); 2191 return (fileobj->value.string.base); 2192} 2193 2194static void 2195parser_complain(cfg_parser_t *pctx, isc_boolean_t is_warning, 2196 unsigned int flags, const char *format, 2197 va_list args) 2198{ 2199 char tokenbuf[MAX_LOG_TOKEN + 10]; 2200 static char where[ISC_DIR_PATHMAX + 100]; 2201 static char message[2048]; 2202 int level = ISC_LOG_ERROR; 2203 const char *prep = ""; 2204 size_t len; 2205 2206 if (is_warning) 2207 level = ISC_LOG_WARNING; 2208 2209 snprintf(where, sizeof(where), "%s:%u: ", 2210 current_file(pctx), pctx->line); 2211 2212 len = vsnprintf(message, sizeof(message), format, args); 2213 if (len >= sizeof(message)) 2214 FATAL_ERROR(__FILE__, __LINE__, 2215 "error message would overflow"); 2216 2217 if ((flags & (CFG_LOG_NEAR|CFG_LOG_BEFORE|CFG_LOG_NOPREP)) != 0) { 2218 isc_region_t r; 2219 2220 if (pctx->ungotten) 2221 (void)cfg_gettoken(pctx, 0); 2222 2223 if (pctx->token.type == isc_tokentype_eof) { 2224 snprintf(tokenbuf, sizeof(tokenbuf), "end of file"); 2225 } else if (pctx->token.type == isc_tokentype_unknown) { 2226 flags = 0; 2227 tokenbuf[0] = '\0'; 2228 } else { 2229 isc_lex_getlasttokentext(pctx->lexer, 2230 &pctx->token, &r); 2231 if (r.length > MAX_LOG_TOKEN) 2232 snprintf(tokenbuf, sizeof(tokenbuf), 2233 "'%.*s...'", MAX_LOG_TOKEN, r.base); 2234 else 2235 snprintf(tokenbuf, sizeof(tokenbuf), 2236 "'%.*s'", (int)r.length, r.base); 2237 } 2238 2239 /* Choose a preposition. */ 2240 if (flags & CFG_LOG_NEAR) 2241 prep = " near "; 2242 else if (flags & CFG_LOG_BEFORE) 2243 prep = " before "; 2244 else 2245 prep = " "; 2246 } else { 2247 tokenbuf[0] = '\0'; 2248 } 2249 isc_log_write(pctx->lctx, CAT, MOD, level, 2250 "%s%s%s%s", where, message, prep, tokenbuf); 2251} 2252 2253void 2254cfg_obj_log(const cfg_obj_t *obj, isc_log_t *lctx, int level, 2255 const char *fmt, ...) { 2256 va_list ap; 2257 char msgbuf[2048]; 2258 2259 if (! isc_log_wouldlog(lctx, level)) 2260 return; 2261 2262 va_start(ap, fmt); 2263 2264 vsnprintf(msgbuf, sizeof(msgbuf), fmt, ap); 2265 isc_log_write(lctx, CAT, MOD, level, 2266 "%s:%u: %s", 2267 obj->file == NULL ? "<unknown file>" : obj->file, 2268 obj->line, msgbuf); 2269 va_end(ap); 2270} 2271 2272const char * 2273cfg_obj_file(const cfg_obj_t *obj) { 2274 return (obj->file); 2275} 2276 2277unsigned int 2278cfg_obj_line(const cfg_obj_t *obj) { 2279 return (obj->line); 2280} 2281 2282isc_result_t 2283cfg_create_obj(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { 2284 cfg_obj_t *obj; 2285 2286 obj = isc_mem_get(pctx->mctx, sizeof(cfg_obj_t)); 2287 if (obj == NULL) 2288 return (ISC_R_NOMEMORY); 2289 obj->type = type; 2290 obj->file = current_file(pctx); 2291 obj->line = pctx->line; 2292 *ret = obj; 2293 return (ISC_R_SUCCESS); 2294} 2295 2296static void 2297map_symtabitem_destroy(char *key, unsigned int type, 2298 isc_symvalue_t symval, void *userarg) 2299{ 2300 cfg_obj_t *obj = symval.as_pointer; 2301 cfg_parser_t *pctx = (cfg_parser_t *)userarg; 2302 2303 UNUSED(key); 2304 UNUSED(type); 2305 2306 cfg_obj_destroy(pctx, &obj); 2307} 2308 2309 2310static isc_result_t 2311create_map(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { 2312 isc_result_t result; 2313 isc_symtab_t *symtab = NULL; 2314 cfg_obj_t *obj = NULL; 2315 2316 CHECK(cfg_create_obj(pctx, type, &obj)); 2317 CHECK(isc_symtab_create(pctx->mctx, 5, /* XXX */ 2318 map_symtabitem_destroy, 2319 pctx, ISC_FALSE, &symtab)); 2320 obj->value.map.symtab = symtab; 2321 obj->value.map.id = NULL; 2322 2323 *ret = obj; 2324 return (ISC_R_SUCCESS); 2325 2326 cleanup: 2327 if (obj != NULL) 2328 isc_mem_put(pctx->mctx, obj, sizeof(*obj)); 2329 return (result); 2330} 2331 2332static void 2333free_map(cfg_parser_t *pctx, cfg_obj_t *obj) { 2334 CLEANUP_OBJ(obj->value.map.id); 2335 isc_symtab_destroy(&obj->value.map.symtab); 2336} 2337 2338isc_boolean_t 2339cfg_obj_istype(const cfg_obj_t *obj, const cfg_type_t *type) { 2340 return (ISC_TF(obj->type == type)); 2341} 2342 2343/* 2344 * Destroy 'obj', a configuration object created in 'pctx'. 2345 */ 2346void 2347cfg_obj_destroy(cfg_parser_t *pctx, cfg_obj_t **objp) { 2348 cfg_obj_t *obj = *objp; 2349 obj->type->rep->free(pctx, obj); 2350 isc_mem_put(pctx->mctx, obj, sizeof(cfg_obj_t)); 2351 *objp = NULL; 2352} 2353 2354static void 2355free_noop(cfg_parser_t *pctx, cfg_obj_t *obj) { 2356 UNUSED(pctx); 2357 UNUSED(obj); 2358} 2359 2360void 2361cfg_doc_obj(cfg_printer_t *pctx, const cfg_type_t *type) { 2362 type->doc(pctx, type); 2363} 2364 2365void 2366cfg_doc_terminal(cfg_printer_t *pctx, const cfg_type_t *type) { 2367 cfg_print_chars(pctx, "<", 1); 2368 cfg_print_cstr(pctx, type->name); 2369 cfg_print_chars(pctx, ">", 1); 2370} 2371 2372void 2373cfg_print_grammar(const cfg_type_t *type, 2374 void (*f)(void *closure, const char *text, int textlen), 2375 void *closure) 2376{ 2377 cfg_printer_t pctx; 2378 pctx.f = f; 2379 pctx.closure = closure; 2380 pctx.indent = 0; 2381 cfg_doc_obj(&pctx, type); 2382} 2383