diff options
| author | 2019-12-16 16:16:22 +0000 | |
|---|---|---|
| committer | 2019-12-16 16:16:22 +0000 | |
| commit | 2fc5abb04c862f358e234358caea4444e15db068 (patch) | |
| tree | 1c77d5b577fef0399be14245b2108ca9c1a8819d /usr.sbin/bind/lib/isccfg/parser.c | |
| parent | Need to include message size in the maximum buffer calculation. (diff) | |
| download | wireguard-openbsd-2fc5abb04c862f358e234358caea4444e15db068.tar.xz wireguard-openbsd-2fc5abb04c862f358e234358caea4444e15db068.zip | |
Update to bind-9.10.5-P3, which appears to have been the last ISC version.
We only use this tree to build dig and nslookup. Our previous version
predated edns0 support in those tools, and we want that. This is the worst
code I've looked at in years, with layers and layers of spaghetti abstraction
clearly unfit for reuse, but then reused anyways, and the old ones remain
behind. So this is a 8MB diff.
florian, sthen, and otto tried this merge before but failed.
Diffstat (limited to 'usr.sbin/bind/lib/isccfg/parser.c')
| -rw-r--r-- | usr.sbin/bind/lib/isccfg/parser.c | 851 |
1 files changed, 698 insertions, 153 deletions
diff --git a/usr.sbin/bind/lib/isccfg/parser.c b/usr.sbin/bind/lib/isccfg/parser.c index 5ddbed7868b..f82b3d91dd2 100644 --- a/usr.sbin/bind/lib/isccfg/parser.c +++ b/usr.sbin/bind/lib/isccfg/parser.c @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004-2006 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2016 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 2000-2003 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * @@ -15,12 +15,12 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $ISC: parser.c,v 1.112.18.11 2006/02/28 03:10:49 marka Exp $ */ - /*! \file */ #include <config.h> +#include <stdlib.h> + #include <isc/buffer.h> #include <isc/dir.h> #include <isc/formatcheck.h> @@ -29,12 +29,12 @@ #include <isc/mem.h> #include <isc/net.h> #include <isc/netaddr.h> +#include <isc/netscope.h> #include <isc/print.h> #include <isc/string.h> #include <isc/sockaddr.h> -#include <isc/netscope.h> -#include <isc/util.h> #include <isc/symtab.h> +#include <isc/util.h> #include <isccfg/cfg.h> #include <isccfg/grammar.h> @@ -50,7 +50,7 @@ /* Check a return value. */ #define CHECK(op) \ - do { result = (op); \ + do { result = (op); \ if (result != ISC_R_SUCCESS) goto cleanup; \ } while (0) @@ -112,16 +112,17 @@ parser_complain(cfg_parser_t *pctx, isc_boolean_t is_warning, * not need a union member). */ -cfg_rep_t cfg_rep_uint32 = { "uint32", free_noop }; -cfg_rep_t cfg_rep_uint64 = { "uint64", free_noop }; -cfg_rep_t cfg_rep_string = { "string", free_string }; -cfg_rep_t cfg_rep_boolean = { "boolean", free_noop }; -cfg_rep_t cfg_rep_map = { "map", free_map }; -cfg_rep_t cfg_rep_list = { "list", free_list }; -cfg_rep_t cfg_rep_tuple = { "tuple", free_tuple }; -cfg_rep_t cfg_rep_sockaddr = { "sockaddr", free_noop }; -cfg_rep_t cfg_rep_netprefix = { "netprefix", free_noop }; -cfg_rep_t cfg_rep_void = { "void", free_noop }; +LIBISCCFG_EXTERNAL_DATA cfg_rep_t cfg_rep_uint32 = { "uint32", free_noop }; +LIBISCCFG_EXTERNAL_DATA cfg_rep_t cfg_rep_uint64 = { "uint64", free_noop }; +LIBISCCFG_EXTERNAL_DATA cfg_rep_t cfg_rep_string = { "string", free_string }; +LIBISCCFG_EXTERNAL_DATA cfg_rep_t cfg_rep_boolean = { "boolean", free_noop }; +LIBISCCFG_EXTERNAL_DATA cfg_rep_t cfg_rep_map = { "map", free_map }; +LIBISCCFG_EXTERNAL_DATA cfg_rep_t cfg_rep_list = { "list", free_list }; +LIBISCCFG_EXTERNAL_DATA cfg_rep_t cfg_rep_tuple = { "tuple", free_tuple }; +LIBISCCFG_EXTERNAL_DATA cfg_rep_t cfg_rep_sockaddr = { "sockaddr", free_noop }; +LIBISCCFG_EXTERNAL_DATA cfg_rep_t cfg_rep_netprefix = { "netprefix", free_noop }; +LIBISCCFG_EXTERNAL_DATA cfg_rep_t cfg_rep_void = { "void", free_noop }; +LIBISCCFG_EXTERNAL_DATA cfg_rep_t cfg_rep_fixedpoint = { "fixedpoint", free_noop }; /* * Configuration type definitions. @@ -137,11 +138,17 @@ static cfg_type_t cfg_type_implicitlist = { void cfg_print_obj(cfg_printer_t *pctx, const cfg_obj_t *obj) { + REQUIRE(pctx != NULL); + REQUIRE(obj != NULL); + obj->type->print(pctx, obj); } void cfg_print_chars(cfg_printer_t *pctx, const char *text, int len) { + REQUIRE(pctx != NULL); + REQUIRE(text != NULL); + pctx->f(pctx->closure, text, len); } @@ -170,11 +177,15 @@ print_close(cfg_printer_t *pctx) { isc_result_t cfg_parse_obj(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { isc_result_t result; - INSIST(ret != NULL && *ret == NULL); + + REQUIRE(pctx != NULL); + REQUIRE(type != NULL); + REQUIRE(ret != NULL && *ret == NULL); + result = type->parse(pctx, type, ret); if (result != ISC_R_SUCCESS) return (result); - INSIST(*ret != NULL); + ENSURE(*ret != NULL); return (ISC_R_SUCCESS); } @@ -183,16 +194,31 @@ cfg_print(const cfg_obj_t *obj, void (*f)(void *closure, const char *text, int textlen), void *closure) { + REQUIRE(obj != NULL); + REQUIRE(f != NULL); + + cfg_printx(obj, 0, f, closure); +} + +void +cfg_printx(const cfg_obj_t *obj, unsigned int flags, + void (*f)(void *closure, const char *text, int textlen), + void *closure) +{ cfg_printer_t pctx; + + REQUIRE(obj != NULL); + REQUIRE(f != NULL); + pctx.f = f; pctx.closure = closure; pctx.indent = 0; + pctx.flags = flags; obj->type->print(&pctx, obj); } - /* Tuples. */ - + isc_result_t cfg_create_tuple(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { isc_result_t result; @@ -202,6 +228,10 @@ cfg_create_tuple(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { unsigned int nfields = 0; int i; + REQUIRE(pctx != NULL); + REQUIRE(type != NULL); + REQUIRE(ret != NULL && *ret == NULL); + for (f = fields; f->name != NULL; f++) nfields++; @@ -232,6 +262,10 @@ cfg_parse_tuple(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) cfg_obj_t *obj = NULL; unsigned int i; + REQUIRE(pctx != NULL); + REQUIRE(type != NULL); + REQUIRE(ret != NULL && *ret == NULL); + CHECK(cfg_create_tuple(pctx, type, &obj)); for (f = fields, i = 0; f->name != NULL; f++, i++) CHECK(cfg_parse_obj(pctx, f->type, &obj->value.tuple[i])); @@ -247,16 +281,22 @@ cfg_parse_tuple(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) void cfg_print_tuple(cfg_printer_t *pctx, const cfg_obj_t *obj) { unsigned int i; - const cfg_tuplefielddef_t *fields = obj->type->of; + const cfg_tuplefielddef_t *fields; const cfg_tuplefielddef_t *f; isc_boolean_t need_space = ISC_FALSE; + REQUIRE(pctx != NULL); + REQUIRE(obj != NULL); + + fields = obj->type->of; + for (f = fields, i = 0; f->name != NULL; f++, i++) { const cfg_obj_t *fieldobj = obj->value.tuple[i]; - if (need_space) - cfg_print_chars(pctx, " ", 1); + if (need_space && fieldobj->type->rep != &cfg_rep_void) + cfg_print_cstr(pctx, " "); cfg_print_obj(pctx, fieldobj); - need_space = ISC_TF(fieldobj->type->print != cfg_print_void); + need_space = ISC_TF(need_space || + fieldobj->type->print != cfg_print_void); } } @@ -266,9 +306,14 @@ cfg_doc_tuple(cfg_printer_t *pctx, const cfg_type_t *type) { const cfg_tuplefielddef_t *f; isc_boolean_t need_space = ISC_FALSE; + REQUIRE(pctx != NULL); + REQUIRE(type != NULL); + + fields = type->of; + for (f = fields; f->name != NULL; f++) { if (need_space) - cfg_print_chars(pctx, " ", 1); + cfg_print_cstr(pctx, " "); cfg_doc_obj(pctx, f->type); need_space = ISC_TF(f->type->print != cfg_print_void); } @@ -303,8 +348,9 @@ cfg_tuple_get(const cfg_obj_t *tupleobj, const char* name) { unsigned int i; const cfg_tuplefielddef_t *fields; const cfg_tuplefielddef_t *f; - + REQUIRE(tupleobj != NULL && tupleobj->type->rep == &cfg_rep_tuple); + REQUIRE(name != NULL); fields = tupleobj->type->of; for (f = fields, i = 0; f->name != NULL; f++, i++) { @@ -317,7 +363,10 @@ cfg_tuple_get(const cfg_obj_t *tupleobj, const char* name) { isc_result_t cfg_parse_special(cfg_parser_t *pctx, int special) { - isc_result_t result; + isc_result_t result; + + REQUIRE(pctx != NULL); + CHECK(cfg_gettoken(pctx, 0)); if (pctx->token.type == isc_tokentype_special && pctx->token.value.as_char == special) @@ -338,7 +387,8 @@ cfg_parse_special(cfg_parser_t *pctx, int special) { */ static isc_result_t parse_semicolon(cfg_parser_t *pctx) { - isc_result_t result; + isc_result_t result; + CHECK(cfg_gettoken(pctx, 0)); if (pctx->token.type == isc_tokentype_special && pctx->token.value.as_char == ';') @@ -355,7 +405,8 @@ parse_semicolon(cfg_parser_t *pctx) { */ static isc_result_t parse_eof(cfg_parser_t *pctx) { - isc_result_t result; + isc_result_t result; + CHECK(cfg_gettoken(pctx, 0)); if (pctx->token.type == isc_tokentype_eof) @@ -387,7 +438,15 @@ cfg_parser_create(isc_mem_t *mctx, isc_log_t *lctx, cfg_parser_t **ret) { if (pctx == NULL) return (ISC_R_NOMEMORY); - pctx->mctx = mctx; + pctx->mctx = NULL; + isc_mem_attach(mctx, &pctx->mctx); + + result = isc_refcount_init(&pctx->references, 1); + if (result != ISC_R_SUCCESS) { + isc_mem_putanddetach(&pctx->mctx, pctx, sizeof(*pctx)); + return (result); + } + pctx->lctx = lctx; pctx->lexer = NULL; pctx->seen_eof = ISC_FALSE; @@ -400,6 +459,7 @@ cfg_parser_create(isc_mem_t *mctx, isc_log_t *lctx, cfg_parser_t **ret) { pctx->callback = NULL; pctx->callbackarg = NULL; pctx->token.type = isc_tokentype_unknown; + pctx->flags = 0; memset(specials, 0, sizeof(specials)); specials['{'] = 1; @@ -427,7 +487,7 @@ cfg_parser_create(isc_mem_t *mctx, isc_log_t *lctx, cfg_parser_t **ret) { isc_lex_destroy(&pctx->lexer); CLEANUP_OBJ(pctx->open_files); CLEANUP_OBJ(pctx->closed_files); - isc_mem_put(mctx, pctx, sizeof(*pctx)); + isc_mem_putanddetach(&pctx->mctx, pctx, sizeof(*pctx)); return (result); } @@ -460,6 +520,8 @@ cfg_parser_setcallback(cfg_parser_t *pctx, cfg_parsecallback_t callback, void *arg) { + REQUIRE(pctx != NULL); + pctx->callback = callback; pctx->callbackarg = arg; } @@ -504,7 +566,10 @@ cfg_parse_file(cfg_parser_t *pctx, const char *filename, { isc_result_t result; + REQUIRE(pctx != NULL); REQUIRE(filename != NULL); + REQUIRE(type != NULL); + REQUIRE(ret != NULL && *ret == NULL); CHECK(parser_openfile(pctx, filename)); CHECK(parse2(pctx, type, ret)); @@ -518,26 +583,48 @@ cfg_parse_buffer(cfg_parser_t *pctx, isc_buffer_t *buffer, const cfg_type_t *type, cfg_obj_t **ret) { isc_result_t result; + REQUIRE(pctx != NULL); + REQUIRE(type != NULL); REQUIRE(buffer != NULL); - CHECK(isc_lex_openbuffer(pctx->lexer, buffer)); + REQUIRE(ret != NULL && *ret == NULL); + + CHECK(isc_lex_openbuffer(pctx->lexer, buffer)); CHECK(parse2(pctx, type, ret)); cleanup: return (result); } void +cfg_parser_attach(cfg_parser_t *src, cfg_parser_t **dest) { + REQUIRE(src != NULL); + REQUIRE(dest != NULL && *dest == NULL); + + isc_refcount_increment(&src->references, NULL); + *dest = src; +} + +void cfg_parser_destroy(cfg_parser_t **pctxp) { - cfg_parser_t *pctx = *pctxp; - isc_lex_destroy(&pctx->lexer); - /* - * Cleaning up open_files does not - * close the files; that was already done - * by closing the lexer. - */ - CLEANUP_OBJ(pctx->open_files); - CLEANUP_OBJ(pctx->closed_files); - isc_mem_put(pctx->mctx, pctx, sizeof(*pctx)); + cfg_parser_t *pctx; + unsigned int refs; + + REQUIRE(pctxp != NULL && *pctxp != NULL); + + pctx = *pctxp; *pctxp = NULL; + + isc_refcount_decrement(&pctx->references, &refs); + if (refs == 0) { + isc_lex_destroy(&pctx->lexer); + /* + * Cleaning up open_files does not + * close the files; that was already done + * by closing the lexer. + */ + CLEANUP_OBJ(pctx->open_files); + CLEANUP_OBJ(pctx->closed_files); + isc_mem_putanddetach(&pctx->mctx, pctx, sizeof(*pctx)); + } } /* @@ -545,18 +632,30 @@ cfg_parser_destroy(cfg_parser_t **pctxp) { */ isc_result_t cfg_parse_void(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { + REQUIRE(pctx != NULL); + REQUIRE(ret != NULL && *ret == NULL); + UNUSED(type); + return (cfg_create_obj(pctx, &cfg_type_void, ret)); } void cfg_print_void(cfg_printer_t *pctx, const cfg_obj_t *obj) { + + REQUIRE(pctx != NULL); + REQUIRE(obj != NULL); + UNUSED(pctx); UNUSED(obj); } void cfg_doc_void(cfg_printer_t *pctx, const cfg_type_t *type) { + + REQUIRE(pctx != NULL); + REQUIRE(type != NULL); + UNUSED(pctx); UNUSED(type); } @@ -567,18 +666,101 @@ cfg_obj_isvoid(const cfg_obj_t *obj) { return (ISC_TF(obj->type->rep == &cfg_rep_void)); } -cfg_type_t cfg_type_void = { +LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_void = { "void", cfg_parse_void, cfg_print_void, cfg_doc_void, &cfg_rep_void, NULL }; +/* + * Fixed point + */ +isc_result_t +cfg_parse_fixedpoint(cfg_parser_t *pctx, const cfg_type_t *type, + cfg_obj_t **ret) +{ + isc_result_t result; + cfg_obj_t *obj = NULL; + size_t n1, n2, n3, l; + const char *p; + + REQUIRE(pctx != NULL); + REQUIRE(ret != NULL && *ret == NULL); + + UNUSED(type); + + CHECK(cfg_gettoken(pctx, 0)); + if (pctx->token.type != isc_tokentype_string) { + cfg_parser_error(pctx, CFG_LOG_NEAR, + "expected fixed point number"); + return (ISC_R_UNEXPECTEDTOKEN); + } + + + p = TOKEN_STRING(pctx); + l = strlen(p); + n1 = strspn(p, "0123456789"); + n2 = strspn(p + n1, "."); + n3 = strspn(p + n1 + n2, "0123456789"); + + if ((n1 + n2 + n3 != l) || (n1 + n3 == 0) || + n1 > 5 || n2 > 1 || n3 > 2) { + cfg_parser_error(pctx, CFG_LOG_NEAR, + "expected fixed point number"); + return (ISC_R_UNEXPECTEDTOKEN); + } + + CHECK(cfg_create_obj(pctx, &cfg_type_fixedpoint, &obj)); + + obj->value.uint32 = strtoul(p, NULL, 10) * 100; + switch (n3) { + case 2: + obj->value.uint32 += strtoul(p + n1 + n2, NULL, 10); + break; + case 1: + obj->value.uint32 += strtoul(p + n1 + n2, NULL, 10) * 10; + break; + } + *ret = obj; + + cleanup: + return (result); +} + +void +cfg_print_fixedpoint(cfg_printer_t *pctx, const cfg_obj_t *obj) { + char buf[64]; + int n; + + REQUIRE(pctx != NULL); + REQUIRE(obj != NULL); + + n = snprintf(buf, sizeof(buf), "%u.%02u", + obj->value.uint32/100, obj->value.uint32%100); + INSIST(n > 0 && (size_t)n < sizeof(buf)); + cfg_print_chars(pctx, buf, strlen(buf)); +} + +isc_uint32_t +cfg_obj_asfixedpoint(const cfg_obj_t *obj) { + REQUIRE(obj != NULL && obj->type->rep == &cfg_rep_fixedpoint); + return (obj->value.uint32); +} + +LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_fixedpoint = { + "fixedpoint", cfg_parse_fixedpoint, cfg_print_fixedpoint, + cfg_doc_terminal, &cfg_rep_fixedpoint, NULL +}; /* * uint32 */ isc_result_t cfg_parse_uint32(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { - isc_result_t result; + isc_result_t result; cfg_obj_t *obj = NULL; + + REQUIRE(pctx != NULL); + REQUIRE(ret != NULL && *ret == NULL); + UNUSED(type); CHECK(cfg_gettoken(pctx, ISC_LEXOPT_NUMBER | ISC_LEXOPT_CNUMBER)); @@ -603,6 +785,7 @@ cfg_print_cstr(cfg_printer_t *pctx, const char *s) { void cfg_print_rawuint(cfg_printer_t *pctx, unsigned int u) { char buf[32]; + snprintf(buf, sizeof(buf), "%u", u); cfg_print_cstr(pctx, buf); } @@ -624,7 +807,7 @@ cfg_obj_asuint32(const cfg_obj_t *obj) { return (obj->value.uint32); } -cfg_type_t cfg_type_uint32 = { +LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_uint32 = { "integer", cfg_parse_uint32, cfg_print_uint32, cfg_doc_terminal, &cfg_rep_uint32, NULL }; @@ -648,12 +831,13 @@ cfg_obj_asuint64(const cfg_obj_t *obj) { void cfg_print_uint64(cfg_printer_t *pctx, const cfg_obj_t *obj) { char buf[32]; + snprintf(buf, sizeof(buf), "%" ISC_PRINT_QUADFORMAT "u", obj->value.uint64); cfg_print_cstr(pctx, buf); } -cfg_type_t cfg_type_uint64 = { +LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_uint64 = { "64_bit_integer", NULL, cfg_print_uint64, cfg_doc_terminal, &cfg_rep_uint64, NULL }; @@ -680,7 +864,7 @@ create_string(cfg_parser_t *pctx, const char *contents, const cfg_type_t *type, isc_mem_put(pctx->mctx, obj, sizeof(*obj)); return (ISC_R_NOMEMORY); } - memcpy(obj->value.string.base, contents, len); + memmove(obj->value.string.base, contents, len); obj->value.string.base[len] = '\0'; *ret = obj; @@ -690,7 +874,11 @@ create_string(cfg_parser_t *pctx, const char *contents, const cfg_type_t *type, isc_result_t cfg_parse_qstring(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { - isc_result_t result; + isc_result_t result; + + REQUIRE(pctx != NULL); + REQUIRE(ret != NULL && *ret == NULL); + UNUSED(type); CHECK(cfg_gettoken(pctx, CFG_LEXOPT_QSTRING)); @@ -698,17 +886,16 @@ cfg_parse_qstring(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { cfg_parser_error(pctx, CFG_LOG_NEAR, "expected quoted string"); return (ISC_R_UNEXPECTEDTOKEN); } - return (create_string(pctx, - TOKEN_STRING(pctx), - &cfg_type_qstring, - ret)); + return (create_string(pctx, TOKEN_STRING(pctx), + &cfg_type_qstring, ret)); cleanup: return (result); } static isc_result_t parse_ustring(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { - isc_result_t result; + isc_result_t result; + UNUSED(type); CHECK(cfg_gettoken(pctx, 0)); @@ -728,7 +915,11 @@ isc_result_t cfg_parse_astring(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { - isc_result_t result; + isc_result_t result; + + REQUIRE(pctx != NULL); + REQUIRE(ret != NULL && *ret == NULL); + UNUSED(type); CHECK(cfg_getstringtoken(pctx)); @@ -740,9 +931,33 @@ cfg_parse_astring(cfg_parser_t *pctx, const cfg_type_t *type, return (result); } +isc_result_t +cfg_parse_sstring(cfg_parser_t *pctx, const cfg_type_t *type, + cfg_obj_t **ret) +{ + isc_result_t result; + + REQUIRE(pctx != NULL); + REQUIRE(ret != NULL && *ret == NULL); + + UNUSED(type); + + CHECK(cfg_getstringtoken(pctx)); + return (create_string(pctx, + TOKEN_STRING(pctx), + &cfg_type_sstring, + ret)); + cleanup: + return (result); +} + isc_boolean_t cfg_is_enum(const char *s, const char *const *enums) { const char * const *p; + + REQUIRE(s != NULL); + REQUIRE(enums != NULL); + for (p = enums; *p != NULL; p++) { if (strcasecmp(*p, s) == 0) return (ISC_TRUE); @@ -753,6 +968,7 @@ cfg_is_enum(const char *s, const char *const *enums) { static isc_result_t check_enum(cfg_parser_t *pctx, cfg_obj_t *obj, const char *const *enums) { const char *s = obj->value.string.base; + if (cfg_is_enum(s, enums)) return (ISC_R_SUCCESS); cfg_parser_error(pctx, 0, "'%s' unexpected", s); @@ -761,20 +977,28 @@ check_enum(cfg_parser_t *pctx, cfg_obj_t *obj, const char *const *enums) { isc_result_t cfg_parse_enum(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { - isc_result_t result; + isc_result_t result; cfg_obj_t *obj = NULL; + + REQUIRE(pctx != NULL); + REQUIRE(type != NULL); + REQUIRE(ret != NULL && *ret == NULL); + CHECK(parse_ustring(pctx, NULL, &obj)); CHECK(check_enum(pctx, obj, type->of)); *ret = obj; return (ISC_R_SUCCESS); cleanup: - CLEANUP_OBJ(obj); + CLEANUP_OBJ(obj); return (result); } void cfg_doc_enum(cfg_printer_t *pctx, const cfg_type_t *type) { const char * const *p; + REQUIRE(pctx != NULL); + REQUIRE(type != NULL); + cfg_print_chars(pctx, "( ", 2); for (p = type->of; *p != NULL; p++) { cfg_print_cstr(pctx, *p); @@ -786,6 +1010,9 @@ cfg_doc_enum(cfg_printer_t *pctx, const cfg_type_t *type) { void cfg_print_ustring(cfg_printer_t *pctx, const cfg_obj_t *obj) { + REQUIRE(pctx != NULL); + REQUIRE(obj != NULL); + cfg_print_chars(pctx, obj->value.string.base, obj->value.string.length); } @@ -797,6 +1024,18 @@ print_qstring(cfg_printer_t *pctx, const cfg_obj_t *obj) { } static void +print_sstring(cfg_printer_t *pctx, const cfg_obj_t *obj) { + cfg_print_chars(pctx, "\"", 1); + if ((pctx->flags & CFG_PRINTER_XKEY) != 0) { + unsigned int len = obj->value.string.length; + while (len-- > 0) + cfg_print_chars(pctx, "?", 1); + } else + cfg_print_ustring(pctx, obj); + cfg_print_chars(pctx, "\"", 1); +} + +static void free_string(cfg_parser_t *pctx, cfg_obj_t *obj) { isc_mem_put(pctx->mctx, obj->value.string.base, obj->value.string.length + 1); @@ -815,24 +1054,33 @@ cfg_obj_asstring(const cfg_obj_t *obj) { } /* Quoted string only */ -cfg_type_t cfg_type_qstring = { +LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_qstring = { "quoted_string", cfg_parse_qstring, print_qstring, cfg_doc_terminal, &cfg_rep_string, NULL }; /* Unquoted string only */ -cfg_type_t cfg_type_ustring = { +LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_ustring = { "string", parse_ustring, cfg_print_ustring, cfg_doc_terminal, &cfg_rep_string, NULL }; /* Any string (quoted or unquoted); printed with quotes */ -cfg_type_t cfg_type_astring = { +LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_astring = { "string", cfg_parse_astring, print_qstring, cfg_doc_terminal, &cfg_rep_string, NULL }; /* + * Any string (quoted or unquoted); printed with quotes. + * If CFG_PRINTER_XKEY is set when printing the string will be '?' out. + */ +LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_sstring = { + "string", cfg_parse_sstring, print_sstring, cfg_doc_terminal, + &cfg_rep_string, NULL +}; + +/* * Booleans */ @@ -848,12 +1096,16 @@ cfg_obj_asboolean(const cfg_obj_t *obj) { return (obj->value.boolean); } -static isc_result_t -parse_boolean(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) +isc_result_t +cfg_parse_boolean(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { - isc_result_t result; + isc_result_t result; isc_boolean_t value; cfg_obj_t *obj = NULL; + + REQUIRE(pctx != NULL); + REQUIRE(ret != NULL && ret != NULL); + UNUSED(type); result = cfg_gettoken(pctx, 0); @@ -888,16 +1140,19 @@ parse_boolean(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) return (result); } -static void -print_boolean(cfg_printer_t *pctx, const cfg_obj_t *obj) { +void +cfg_print_boolean(cfg_printer_t *pctx, const cfg_obj_t *obj) { + REQUIRE(pctx != NULL); + REQUIRE(obj != NULL); + if (obj->value.boolean) cfg_print_chars(pctx, "yes", 3); else cfg_print_chars(pctx, "no", 2); } -cfg_type_t cfg_type_boolean = { - "boolean", parse_boolean, print_boolean, cfg_doc_terminal, +LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_boolean = { + "boolean", cfg_parse_boolean, cfg_print_boolean, cfg_doc_terminal, &cfg_rep_boolean, NULL }; @@ -908,6 +1163,11 @@ cfg_type_t cfg_type_boolean = { isc_result_t cfg_create_list(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **obj) { isc_result_t result; + + REQUIRE(pctx != NULL); + REQUIRE(type != NULL); + REQUIRE(obj != NULL && *obj == NULL); + CHECK(cfg_create_obj(pctx, type, obj)); ISC_LIST_INIT((*obj)->value.list); cleanup: @@ -917,6 +1177,7 @@ cfg_create_list(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **obj) { static isc_result_t create_listelt(cfg_parser_t *pctx, cfg_listelt_t **eltp) { cfg_listelt_t *elt; + elt = isc_mem_get(pctx->mctx, sizeof(*elt)); if (elt == NULL) return (ISC_R_NOMEMORY); @@ -952,6 +1213,10 @@ cfg_parse_listelt(cfg_parser_t *pctx, const cfg_type_t *elttype, cfg_listelt_t *elt = NULL; cfg_obj_t *value = NULL; + REQUIRE(pctx != NULL); + REQUIRE(elttype != NULL); + REQUIRE(ret != NULL && *ret == NULL); + CHECK(create_listelt(pctx, &elt)); result = cfg_parse_obj(pctx, elttype, &value); @@ -1021,6 +1286,11 @@ cfg_parse_bracketed_list(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { isc_result_t result; + + REQUIRE(pctx != NULL); + REQUIRE(type != NULL); + REQUIRE(ret != NULL && *ret == NULL); + CHECK(cfg_parse_special(pctx, '{')); CHECK(parse_list(pctx, type, ret)); CHECK(cfg_parse_special(pctx, '}')); @@ -1030,6 +1300,9 @@ cfg_parse_bracketed_list(cfg_parser_t *pctx, const cfg_type_t *type, void cfg_print_bracketed_list(cfg_printer_t *pctx, const cfg_obj_t *obj) { + REQUIRE(pctx != NULL); + REQUIRE(obj != NULL); + print_open(pctx); print_list(pctx, obj); print_close(pctx); @@ -1037,6 +1310,9 @@ cfg_print_bracketed_list(cfg_printer_t *pctx, const cfg_obj_t *obj) { void cfg_doc_bracketed_list(cfg_printer_t *pctx, const cfg_type_t *type) { + REQUIRE(pctx != NULL); + REQUIRE(type != NULL); + cfg_print_chars(pctx, "{ ", 2); cfg_doc_obj(pctx, type->of); cfg_print_chars(pctx, "; ... }", 7); @@ -1055,6 +1331,10 @@ cfg_parse_spacelist(cfg_parser_t *pctx, const cfg_type_t *listtype, const cfg_type_t *listof = listtype->of; isc_result_t result; + REQUIRE(pctx != NULL); + REQUIRE(listtype != NULL); + REQUIRE(ret != NULL && *ret == NULL); + CHECK(cfg_create_list(pctx, listtype, &listobj)); for (;;) { @@ -1080,6 +1360,9 @@ cfg_print_spacelist(cfg_printer_t *pctx, const cfg_obj_t *obj) { const cfg_list_t *list = &obj->value.list; const cfg_listelt_t *elt; + REQUIRE(pctx != NULL); + REQUIRE(obj != NULL); + for (elt = ISC_LIST_HEAD(*list); elt != NULL; elt = ISC_LIST_NEXT(elt, link)) { @@ -1109,7 +1392,30 @@ cfg_list_next(const cfg_listelt_t *elt) { return (ISC_LIST_NEXT(elt, link)); } -const cfg_obj_t * +/* + * Return the length of a list object. If obj is NULL or is not + * a list, return 0. + */ +unsigned int +cfg_list_length(const cfg_obj_t *obj, isc_boolean_t recurse) { + const cfg_listelt_t *elt; + unsigned int count = 0; + + if (obj == NULL || !cfg_obj_islist(obj)) + return (0U); + for (elt = cfg_list_first(obj); + elt != NULL; + elt = cfg_list_next(elt)) { + if (recurse && cfg_obj_islist(elt->obj)) { + count += cfg_list_length(elt->obj, recurse); + } else { + count++; + } + } + return (count); +} + +cfg_obj_t * cfg_listelt_value(const cfg_listelt_t *elt) { REQUIRE(elt != NULL); return (elt->obj); @@ -1143,6 +1449,10 @@ cfg_parse_mapbody(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) isc_symvalue_t symval; cfg_list_t *list = NULL; + REQUIRE(pctx != NULL); + REQUIRE(type != NULL); + REQUIRE(ret != NULL && *ret == NULL); + CHECK(create_map(pctx, type, &obj)); obj->value.map.clausesets = clausesets; @@ -1214,6 +1524,15 @@ cfg_parse_mapbody(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) if ((clause->flags & CFG_CLAUSEFLAG_NYI) != 0) cfg_parser_warning(pctx, 0, "option '%s' is " "not implemented", clause->name); + + if ((clause->flags & CFG_CLAUSEFLAG_NOTCONFIGURED) != 0) { + cfg_parser_warning(pctx, 0, "option '%s' was not " + "enabled at compile time", + clause->name); + result = ISC_R_FAILURE; + goto cleanup; + } + /* * Don't log options with CFG_CLAUSEFLAG_NEWDEFAULT * set here - we need to log the *lack* of such an option, @@ -1304,7 +1623,7 @@ parse_symtab_elt(cfg_parser_t *pctx, const char *name, if (callback && pctx->callback != NULL) CHECK(pctx->callback(name, obj, pctx->callbackarg)); - + symval.as_pointer = obj; CHECK(isc_symtab_define(symtab, name, 1, symval, @@ -1322,6 +1641,11 @@ parse_symtab_elt(cfg_parser_t *pctx, const char *name, isc_result_t cfg_parse_map(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { isc_result_t result; + + REQUIRE(pctx != NULL); + REQUIRE(type != NULL); + REQUIRE(ret != NULL && *ret == NULL); + CHECK(cfg_parse_special(pctx, '{')); CHECK(cfg_parse_mapbody(pctx, type, ret)); CHECK(cfg_parse_special(pctx, '}')); @@ -1333,25 +1657,31 @@ cfg_parse_map(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { * Subroutine for cfg_parse_named_map() and cfg_parse_addressed_map(). */ static isc_result_t -parse_any_named_map(cfg_parser_t *pctx, cfg_type_t *nametype, const cfg_type_t *type, - cfg_obj_t **ret) +parse_any_named_map(cfg_parser_t *pctx, cfg_type_t *nametype, + const cfg_type_t *type, cfg_obj_t **ret) { isc_result_t result; cfg_obj_t *idobj = NULL; cfg_obj_t *mapobj = NULL; + REQUIRE(pctx != NULL); + REQUIRE(nametype != NULL); + REQUIRE(type != NULL); + REQUIRE(ret != NULL && *ret == NULL); + CHECK(cfg_parse_obj(pctx, nametype, &idobj)); CHECK(cfg_parse_map(pctx, type, &mapobj)); mapobj->value.map.id = idobj; - idobj = NULL; *ret = mapobj; + return (result); cleanup: CLEANUP_OBJ(idobj); + CLEANUP_OBJ(mapobj); return (result); } /* - * Parse a map identified by a string name. E.g., "name { foo 1; }". + * Parse a map identified by a string name. E.g., "name { foo 1; }". * Used for the "key" and "channel" statements. */ isc_result_t @@ -1383,6 +1713,9 @@ cfg_print_mapbody(cfg_printer_t *pctx, const cfg_obj_t *obj) { const cfg_clausedef_t * const *clauseset; + REQUIRE(pctx != NULL); + REQUIRE(obj != NULL); + for (clauseset = obj->value.map.clausesets; *clauseset != NULL; clauseset++) @@ -1396,10 +1729,10 @@ cfg_print_mapbody(cfg_printer_t *pctx, const cfg_obj_t *obj) { result = isc_symtab_lookup(obj->value.map.symtab, clause->name, 0, &symval); if (result == ISC_R_SUCCESS) { - cfg_obj_t *obj = symval.as_pointer; - if (obj->type == &cfg_type_implicitlist) { + cfg_obj_t *symobj = symval.as_pointer; + if (symobj->type == &cfg_type_implicitlist) { /* Multivalued. */ - cfg_list_t *list = &obj->value.list; + cfg_list_t *list = &symobj->value.list; cfg_listelt_t *elt; for (elt = ISC_LIST_HEAD(*list); elt != NULL; @@ -1415,7 +1748,7 @@ cfg_print_mapbody(cfg_printer_t *pctx, const cfg_obj_t *obj) { print_indent(pctx); cfg_print_cstr(pctx, clause->name); cfg_print_chars(pctx, " ", 1); - cfg_print_obj(pctx, obj); + cfg_print_obj(pctx, symobj); cfg_print_chars(pctx, ";\n", 2); } } else if (result == ISC_R_NOTFOUND) { @@ -1427,11 +1760,45 @@ cfg_print_mapbody(cfg_printer_t *pctx, const cfg_obj_t *obj) { } } +static struct flagtext { + unsigned int flag; + const char *text; +} flagtexts[] = { + { CFG_CLAUSEFLAG_NOTIMP, "not implemented" }, + { CFG_CLAUSEFLAG_NYI, "not yet implemented" }, + { CFG_CLAUSEFLAG_OBSOLETE, "obsolete" }, + { CFG_CLAUSEFLAG_NEWDEFAULT, "default changed" }, + { CFG_CLAUSEFLAG_TESTONLY, "test only" }, + { CFG_CLAUSEFLAG_NOTCONFIGURED, "not configured" }, + { CFG_CLAUSEFLAG_MULTI, "may occur multiple times" }, + { CFG_CLAUSEFLAG_EXPERIMENTAL, "experimental" }, + { 0, NULL } +}; + +static void +print_clause_flags(cfg_printer_t *pctx, unsigned int flags) { + struct flagtext *p; + isc_boolean_t first = ISC_TRUE; + for (p = flagtexts; p->flag != 0; p++) { + if ((flags & p->flag) != 0) { + if (first) + cfg_print_cstr(pctx, " // "); + else + cfg_print_cstr(pctx, ", "); + cfg_print_cstr(pctx, p->text); + first = ISC_FALSE; + } + } +} + void cfg_doc_mapbody(cfg_printer_t *pctx, const cfg_type_t *type) { const cfg_clausedef_t * const *clauseset; const cfg_clausedef_t *clause; - + + REQUIRE(pctx != NULL); + REQUIRE(type != NULL); + for (clauseset = type->of; *clauseset != NULL; clauseset++) { for (clause = *clauseset; clause->name != NULL; @@ -1439,26 +1806,18 @@ cfg_doc_mapbody(cfg_printer_t *pctx, const cfg_type_t *type) { cfg_print_cstr(pctx, clause->name); cfg_print_chars(pctx, " ", 1); cfg_doc_obj(pctx, clause->type); - cfg_print_chars(pctx, ";", 1); - /* XXX print flags here? */ - cfg_print_chars(pctx, "\n\n", 2); + cfg_print_cstr(pctx, ";"); + print_clause_flags(pctx, clause->flags); + cfg_print_cstr(pctx, "\n\n"); } } } -static struct flagtext { - unsigned int flag; - const char *text; -} flagtexts[] = { - { CFG_CLAUSEFLAG_NOTIMP, "not implemented" }, - { CFG_CLAUSEFLAG_NYI, "not yet implemented" }, - { CFG_CLAUSEFLAG_OBSOLETE, "obsolete" }, - { CFG_CLAUSEFLAG_NEWDEFAULT, "default changed" }, - { 0, NULL } -}; - void cfg_print_map(cfg_printer_t *pctx, const cfg_obj_t *obj) { + REQUIRE(pctx != NULL); + REQUIRE(obj != NULL); + if (obj->value.map.id != NULL) { cfg_print_obj(pctx, obj->value.map.id); cfg_print_chars(pctx, " ", 1); @@ -1468,27 +1827,14 @@ cfg_print_map(cfg_printer_t *pctx, const cfg_obj_t *obj) { print_close(pctx); } -static void -print_clause_flags(cfg_printer_t *pctx, unsigned int flags) { - struct flagtext *p; - isc_boolean_t first = ISC_TRUE; - for (p = flagtexts; p->flag != 0; p++) { - if ((flags & p->flag) != 0) { - if (first) - cfg_print_chars(pctx, " // ", 4); - else - cfg_print_chars(pctx, ", ", 2); - cfg_print_cstr(pctx, p->text); - first = ISC_FALSE; - } - } -} - void cfg_doc_map(cfg_printer_t *pctx, const cfg_type_t *type) { const cfg_clausedef_t * const *clauseset; const cfg_clausedef_t *clause; - + + REQUIRE(pctx != NULL); + REQUIRE(type != NULL); + if (type->parse == cfg_parse_named_map) { cfg_doc_obj(pctx, &cfg_type_astring); cfg_print_chars(pctx, " ", 1); @@ -1499,9 +1845,9 @@ cfg_doc_map(cfg_printer_t *pctx, const cfg_type_t *type) { cfg_doc_obj(pctx, &cfg_type_netprefix); cfg_print_chars(pctx, " ", 1); } - + print_open(pctx); - + for (clauseset = type->of; *clauseset != NULL; clauseset++) { for (clause = *clauseset; clause->name != NULL; @@ -1530,13 +1876,13 @@ cfg_map_get(const cfg_obj_t *mapobj, const char* name, const cfg_obj_t **obj) { isc_result_t result; isc_symvalue_t val; const cfg_map_t *map; - + REQUIRE(mapobj != NULL && mapobj->type->rep == &cfg_rep_map); REQUIRE(name != NULL); REQUIRE(obj != NULL && *obj == NULL); map = &mapobj->value.map; - + result = isc_symtab_lookup(map->symtab, name, MAP_SYM, &val); if (result != ISC_R_SUCCESS) return (result); @@ -1550,12 +1896,21 @@ cfg_map_getname(const cfg_obj_t *mapobj) { return (mapobj->value.map.id); } +unsigned int +cfg_map_count(const cfg_obj_t *mapobj) { + const cfg_map_t *map; + + REQUIRE(mapobj != NULL && mapobj->type->rep == &cfg_rep_map); + + map = &mapobj->value.map; + return (isc_symtab_count(map->symtab)); +} /* Parse an arbitrary token, storing its raw text representation. */ static isc_result_t parse_token(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { cfg_obj_t *obj = NULL; - isc_result_t result; + isc_result_t result; isc_region_t r; UNUSED(type); @@ -1576,7 +1931,7 @@ parse_token(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { goto cleanup; } obj->value.string.length = r.length; - memcpy(obj->value.string.base, r.base, r.length); + memmove(obj->value.string.base, r.base, r.length); obj->value.string.base[r.length] = '\0'; *ret = obj; return (result); @@ -1587,7 +1942,7 @@ parse_token(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { return (result); } -cfg_type_t cfg_type_token = { +LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_token = { "token", parse_token, cfg_print_ustring, cfg_doc_terminal, &cfg_rep_string, NULL }; @@ -1636,7 +1991,7 @@ parse_unsupported(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { return (result); } -cfg_type_t cfg_type_unsupported = { +LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_unsupported = { "unsupported", parse_unsupported, cfg_print_spacelist, cfg_doc_terminal, &cfg_rep_list, NULL }; @@ -1646,7 +2001,7 @@ cfg_type_t cfg_type_unsupported = { * * If CFG_ADDR_WILDOK is set in flags, "*" can be used as a wildcard * and at least one of CFG_ADDR_V4OK and CFG_ADDR_V6OK must also be set. The - * "*" is interpreted as the IPv4 wildcard address if CFG_ADDR_V4OK is + * "*" is interpreted as the IPv4 wildcard address if CFG_ADDR_V4OK is * set (including the case where CFG_ADDR_V4OK and CFG_ADDR_V6OK are both set), * and the IPv6 wildcard address otherwise. */ @@ -1682,9 +2037,9 @@ token_addr(cfg_parser_t *pctx, unsigned int flags, isc_netaddr_t *na) { char buf[64]; int i; - strlcpy(buf, s, sizeof(buf)); + strcpy(buf, s); for (i = 0; i < 3; i++) { - strlcat(buf, ".0", sizeof(buf)); + strcat(buf, ".0"); if (inet_pton(AF_INET, buf, &in4a) == 1) { isc_netaddr_fromin(na, &in4a); return (ISC_R_SUCCESS); @@ -1697,7 +2052,7 @@ token_addr(cfg_parser_t *pctx, unsigned int flags, isc_netaddr_t *na) { char *d; /* zone delimiter */ isc_uint32_t zone = 0; /* scope zone ID */ - strlcpy(buf, s, sizeof(buf)); + strcpy(buf, s); d = strchr(buf, '%'); if (d != NULL) *d = '\0'; @@ -1733,6 +2088,9 @@ cfg_parse_rawaddr(cfg_parser_t *pctx, unsigned int flags, isc_netaddr_t *na) { const char *wild = ""; const char *prefix = ""; + REQUIRE(pctx != NULL); + REQUIRE(na != NULL); + CHECK(cfg_gettoken(pctx, 0)); result = token_addr(pctx, flags, na); if (result == ISC_R_UNEXPECTEDTOKEN) { @@ -1761,6 +2119,9 @@ isc_boolean_t cfg_lookingat_netaddr(cfg_parser_t *pctx, unsigned int flags) { isc_result_t result; isc_netaddr_t na_dummy; + + REQUIRE(pctx != NULL); + result = token_addr(pctx, flags, &na_dummy); return (ISC_TF(result == ISC_R_SUCCESS)); } @@ -1769,6 +2130,9 @@ isc_result_t cfg_parse_rawport(cfg_parser_t *pctx, unsigned int flags, in_port_t *port) { isc_result_t result; + REQUIRE(pctx != NULL); + REQUIRE(port != NULL); + CHECK(cfg_gettoken(pctx, ISC_LEXOPT_NUMBER)); if ((flags & CFG_ADDR_WILDOK) != 0 && @@ -1799,12 +2163,40 @@ cfg_print_rawaddr(cfg_printer_t *pctx, const isc_netaddr_t *na) { char text[128]; isc_buffer_t buf; + REQUIRE(pctx != NULL); + REQUIRE(na != NULL); + isc_buffer_init(&buf, text, sizeof(text)); result = isc_netaddr_totext(na, &buf); RUNTIME_CHECK(result == ISC_R_SUCCESS); cfg_print_chars(pctx, isc_buffer_base(&buf), isc_buffer_usedlength(&buf)); } +isc_result_t +cfg_parse_dscp(cfg_parser_t *pctx, isc_dscp_t *dscp) { + isc_result_t result; + + REQUIRE(pctx != NULL); + REQUIRE(dscp != NULL); + + CHECK(cfg_gettoken(pctx, ISC_LEXOPT_NUMBER | ISC_LEXOPT_CNUMBER)); + + if (pctx->token.type != isc_tokentype_number) { + cfg_parser_error(pctx, CFG_LOG_NEAR, + "expected number"); + return (ISC_R_UNEXPECTEDTOKEN); + } + if (pctx->token.value.as_ulong > 63U) { + cfg_parser_error(pctx, CFG_LOG_NEAR, + "dscp out of range"); + return (ISC_R_RANGE); + } + *dscp = (isc_dscp_t)(pctx->token.value.as_ulong); + return (ISC_R_SUCCESS); + cleanup: + return (result); +} + /* netaddr */ static unsigned int netaddr_flags = CFG_ADDR_V4OK | CFG_ADDR_V6OK; @@ -1844,39 +2236,40 @@ cfg_doc_netaddr(cfg_printer_t *pctx, const cfg_type_t *type) { if (n != 0) cfg_print_chars(pctx, " | ", 3); cfg_print_cstr(pctx, "<ipv6_address>"); - n++; + n++; } if (*flagp & CFG_ADDR_WILDOK) { if (n != 0) cfg_print_chars(pctx, " | ", 3); cfg_print_chars(pctx, "*", 1); n++; + POST(n); } if (*flagp != CFG_ADDR_V4OK && *flagp != CFG_ADDR_V6OK) cfg_print_chars(pctx, " )", 2); } -cfg_type_t cfg_type_netaddr = { +LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_netaddr = { "netaddr", parse_netaddr, cfg_print_sockaddr, cfg_doc_netaddr, &cfg_rep_sockaddr, &netaddr_flags }; -cfg_type_t cfg_type_netaddr4 = { +LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_netaddr4 = { "netaddr4", parse_netaddr, cfg_print_sockaddr, cfg_doc_netaddr, &cfg_rep_sockaddr, &netaddr4_flags }; -cfg_type_t cfg_type_netaddr4wild = { +LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_netaddr4wild = { "netaddr4wild", parse_netaddr, cfg_print_sockaddr, cfg_doc_netaddr, &cfg_rep_sockaddr, &netaddr4wild_flags }; -cfg_type_t cfg_type_netaddr6 = { +LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_netaddr6 = { "netaddr6", parse_netaddr, cfg_print_sockaddr, cfg_doc_netaddr, &cfg_rep_sockaddr, &netaddr6_flags }; -cfg_type_t cfg_type_netaddr6wild = { +LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_netaddr6wild = { "netaddr6wild", parse_netaddr, cfg_print_sockaddr, cfg_doc_netaddr, &cfg_rep_sockaddr, &netaddr6wild_flags }; @@ -1890,7 +2283,11 @@ cfg_parse_netprefix(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t *obj = NULL; isc_result_t result; isc_netaddr_t netaddr; - unsigned int addrlen, prefixlen; + unsigned int addrlen = 0, prefixlen; + + REQUIRE(pctx != NULL); + REQUIRE(ret != NULL && *ret == NULL); + UNUSED(type); CHECK(cfg_parse_rawaddr(pctx, CFG_ADDR_V4OK | CFG_ADDR_V4PREFIXOK | @@ -1903,7 +2300,6 @@ cfg_parse_netprefix(cfg_parser_t *pctx, const cfg_type_t *type, addrlen = 128; break; default: - addrlen = 0; INSIST(0); break; } @@ -1953,13 +2349,17 @@ cfg_obj_isnetprefix(const cfg_obj_t *obj) { void cfg_obj_asnetprefix(const cfg_obj_t *obj, isc_netaddr_t *netaddr, - unsigned int *prefixlen) { + unsigned int *prefixlen) +{ REQUIRE(obj != NULL && obj->type->rep == &cfg_rep_netprefix); + REQUIRE(netaddr != NULL); + REQUIRE(prefixlen != NULL); + *netaddr = obj->value.netprefix.address; *prefixlen = obj->value.netprefix.prefixlen; } -cfg_type_t cfg_type_netprefix = { +LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_netprefix = { "netprefix", cfg_parse_netprefix, print_netprefix, cfg_doc_terminal, &cfg_rep_netprefix, NULL }; @@ -1971,17 +2371,43 @@ parse_sockaddrsub(cfg_parser_t *pctx, const cfg_type_t *type, isc_result_t result; isc_netaddr_t netaddr; in_port_t port = 0; + isc_dscp_t dscp = -1; cfg_obj_t *obj = NULL; + int have_port = 0, have_dscp = 0; CHECK(cfg_create_obj(pctx, type, &obj)); CHECK(cfg_parse_rawaddr(pctx, flags, &netaddr)); - CHECK(cfg_peektoken(pctx, 0)); - if (pctx->token.type == isc_tokentype_string && - strcasecmp(TOKEN_STRING(pctx), "port") == 0) { - CHECK(cfg_gettoken(pctx, 0)); /* read "port" */ - CHECK(cfg_parse_rawport(pctx, flags, &port)); + for (;;) { + CHECK(cfg_peektoken(pctx, 0)); + if (pctx->token.type == isc_tokentype_string) { + if (strcasecmp(TOKEN_STRING(pctx), "port") == 0) { + CHECK(cfg_gettoken(pctx, 0)); /* read "port" */ + CHECK(cfg_parse_rawport(pctx, flags, &port)); + ++have_port; + } else if ((flags & CFG_ADDR_DSCPOK) != 0 && + strcasecmp(TOKEN_STRING(pctx), "dscp") == 0) + { + CHECK(cfg_gettoken(pctx, 0)); /* read "dscp" */ + CHECK(cfg_parse_dscp(pctx, &dscp)); + ++have_dscp; + } else + break; + } else + break; + } + if (have_port > 1) { + cfg_parser_error(pctx, 0, "expected at most one port"); + result = ISC_R_UNEXPECTEDTOKEN; + goto cleanup; + } + + if (have_dscp > 1) { + cfg_parser_error(pctx, 0, "expected at most one dscp"); + result = ISC_R_UNEXPECTEDTOKEN; + goto cleanup; } isc_sockaddr_fromnetaddr(&obj->value.sockaddr, &netaddr, port); + obj->value.sockaddrdscp.dscp = dscp; *ret = obj; return (ISC_R_SUCCESS); @@ -1991,14 +2417,28 @@ parse_sockaddrsub(cfg_parser_t *pctx, const cfg_type_t *type, } static unsigned int sockaddr_flags = CFG_ADDR_V4OK | CFG_ADDR_V6OK; -cfg_type_t cfg_type_sockaddr = { +LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_sockaddr = { "sockaddr", cfg_parse_sockaddr, cfg_print_sockaddr, cfg_doc_sockaddr, &cfg_rep_sockaddr, &sockaddr_flags }; +static unsigned int sockaddrdscp_flags = CFG_ADDR_V4OK | CFG_ADDR_V6OK | + CFG_ADDR_DSCPOK; +LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_sockaddrdscp = { + "sockaddr", cfg_parse_sockaddr, cfg_print_sockaddr, cfg_doc_sockaddr, + &cfg_rep_sockaddr, &sockaddrdscp_flags +}; + isc_result_t cfg_parse_sockaddr(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { - const unsigned int *flagp = type->of; + const unsigned int *flagp; + + REQUIRE(pctx != NULL); + REQUIRE(type != NULL); + REQUIRE(ret != NULL && *ret == NULL); + + flagp = type->of; + return (parse_sockaddrsub(pctx, &cfg_type_sockaddr, *flagp, ret)); } @@ -2008,6 +2448,9 @@ cfg_print_sockaddr(cfg_printer_t *pctx, const cfg_obj_t *obj) { in_port_t port; char buf[ISC_NETADDR_FORMATSIZE]; + REQUIRE(pctx != NULL); + REQUIRE(obj != NULL); + isc_netaddr_fromsockaddr(&netaddr, &obj->value.sockaddr); isc_netaddr_format(&netaddr, buf, sizeof(buf)); cfg_print_cstr(pctx, buf); @@ -2016,12 +2459,20 @@ cfg_print_sockaddr(cfg_printer_t *pctx, const cfg_obj_t *obj) { cfg_print_chars(pctx, " port ", 6); cfg_print_rawuint(pctx, port); } + if (obj->value.sockaddrdscp.dscp != -1) { + cfg_print_chars(pctx, " dscp ", 6); + cfg_print_rawuint(pctx, obj->value.sockaddrdscp.dscp); + } } void cfg_doc_sockaddr(cfg_printer_t *pctx, const cfg_type_t *type) { const unsigned int *flagp = type->of; int n = 0; + + REQUIRE(pctx != NULL); + REQUIRE(type != NULL); + cfg_print_chars(pctx, "( ", 2); if (*flagp & CFG_ADDR_V4OK) { cfg_print_cstr(pctx, "<ipv4_address>"); @@ -2031,13 +2482,14 @@ cfg_doc_sockaddr(cfg_printer_t *pctx, const cfg_type_t *type) { if (n != 0) cfg_print_chars(pctx, " | ", 3); cfg_print_cstr(pctx, "<ipv6_address>"); - n++; + n++; } if (*flagp & CFG_ADDR_WILDOK) { if (n != 0) cfg_print_chars(pctx, " | ", 3); cfg_print_chars(pctx, "*", 1); n++; + POST(n); } cfg_print_chars(pctx, " ) ", 3); if (*flagp & CFG_ADDR_WILDOK) { @@ -2045,6 +2497,9 @@ cfg_doc_sockaddr(cfg_printer_t *pctx, const cfg_type_t *type) { } else { cfg_print_cstr(pctx, "[ port <integer> ]"); } + if ((*flagp & CFG_ADDR_DSCPOK) != 0) { + cfg_print_cstr(pctx, " [ dscp <integer> ]"); + } } isc_boolean_t @@ -2059,10 +2514,18 @@ cfg_obj_assockaddr(const cfg_obj_t *obj) { return (&obj->value.sockaddr); } +isc_dscp_t +cfg_obj_getdscp(const cfg_obj_t *obj) { + REQUIRE(obj != NULL && obj->type->rep == &cfg_rep_sockaddr); + return (obj->value.sockaddrdscp.dscp); +} + isc_result_t cfg_gettoken(cfg_parser_t *pctx, int options) { isc_result_t result; + REQUIRE(pctx != NULL); + if (pctx->seen_eof) return (ISC_R_SUCCESS); @@ -2119,6 +2582,8 @@ cfg_gettoken(cfg_parser_t *pctx, int options) { void cfg_ungettoken(cfg_parser_t *pctx) { + REQUIRE(pctx != NULL); + if (pctx->seen_eof) return; isc_lex_ungettoken(pctx->lexer, &pctx->token); @@ -2128,6 +2593,9 @@ cfg_ungettoken(cfg_parser_t *pctx) { isc_result_t cfg_peektoken(cfg_parser_t *pctx, int options) { isc_result_t result; + + REQUIRE(pctx != NULL); + CHECK(cfg_gettoken(pctx, options)); cfg_ungettoken(pctx); cleanup: @@ -2157,6 +2625,10 @@ cfg_getstringtoken(cfg_parser_t *pctx) { void cfg_parser_error(cfg_parser_t *pctx, unsigned int flags, const char *fmt, ...) { va_list args; + + REQUIRE(pctx != NULL); + REQUIRE(fmt != NULL); + va_start(args, fmt); parser_complain(pctx, ISC_FALSE, flags, fmt, args); va_end(args); @@ -2166,6 +2638,10 @@ cfg_parser_error(cfg_parser_t *pctx, unsigned int flags, const char *fmt, ...) { void cfg_parser_warning(cfg_parser_t *pctx, unsigned int flags, const char *fmt, ...) { va_list args; + + REQUIRE(pctx != NULL); + REQUIRE(fmt != NULL); + va_start(args, fmt); parser_complain(pctx, ISC_TRUE, flags, fmt, args); va_end(args); @@ -2174,16 +2650,30 @@ cfg_parser_warning(cfg_parser_t *pctx, unsigned int flags, const char *fmt, ...) #define MAX_LOG_TOKEN 30 /* How much of a token to quote in log messages. */ +static isc_boolean_t +have_current_file(cfg_parser_t *pctx) { + cfg_listelt_t *elt; + if (pctx->open_files == NULL) + return (ISC_FALSE); + + elt = ISC_LIST_TAIL(pctx->open_files->value.list); + if (elt == NULL) + return (ISC_FALSE); + + return (ISC_TRUE); +} + static char * current_file(cfg_parser_t *pctx) { static char none[] = "none"; cfg_listelt_t *elt; cfg_obj_t *fileobj; - if (pctx->open_files == NULL) + if (!have_current_file(pctx)) return (none); + elt = ISC_LIST_TAIL(pctx->open_files->value.list); - if (elt == NULL) + if (elt == NULL) /* shouldn't be possible, but... */ return (none); fileobj = elt->obj; @@ -2206,13 +2696,16 @@ parser_complain(cfg_parser_t *pctx, isc_boolean_t is_warning, if (is_warning) level = ISC_LOG_WARNING; - snprintf(where, sizeof(where), "%s:%u: ", - current_file(pctx), pctx->line); + where[0] = '\0'; + if (have_current_file(pctx)) + snprintf(where, sizeof(where), "%s:%u: ", + current_file(pctx), pctx->line); len = vsnprintf(message, sizeof(message), format, args); - if (len == -1 || len >= sizeof(message)) - FATAL_ERROR(__FILE__, __LINE__, - "error message would overflow"); +#define ELIPSIS " ... " + if (len >= sizeof(message)) + strcpy(message + sizeof(message) - sizeof(ELIPSIS) - 1, + ELIPSIS); if ((flags & (CFG_LOG_NEAR|CFG_LOG_BEFORE|CFG_LOG_NOPREP)) != 0) { isc_region_t r; @@ -2256,43 +2749,63 @@ cfg_obj_log(const cfg_obj_t *obj, isc_log_t *lctx, int level, va_list ap; char msgbuf[2048]; + REQUIRE(obj != NULL); + REQUIRE(fmt != NULL); + if (! isc_log_wouldlog(lctx, level)) return; va_start(ap, fmt); vsnprintf(msgbuf, sizeof(msgbuf), fmt, ap); - isc_log_write(lctx, CAT, MOD, level, - "%s:%u: %s", - obj->file == NULL ? "<unknown file>" : obj->file, - obj->line, msgbuf); va_end(ap); + if (obj->file != NULL) { + isc_log_write(lctx, CAT, MOD, level, + "%s:%u: %s", obj->file, obj->line, msgbuf); + } else { + isc_log_write(lctx, CAT, MOD, level, "%s", msgbuf); + } } const char * cfg_obj_file(const cfg_obj_t *obj) { + REQUIRE(obj != NULL); + return (obj->file); } unsigned int cfg_obj_line(const cfg_obj_t *obj) { + REQUIRE(obj != NULL); + return (obj->line); } isc_result_t cfg_create_obj(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { + isc_result_t result; cfg_obj_t *obj; + REQUIRE(pctx != NULL); + REQUIRE(type != NULL); + REQUIRE(ret != NULL && *ret == NULL); + obj = isc_mem_get(pctx->mctx, sizeof(cfg_obj_t)); if (obj == NULL) return (ISC_R_NOMEMORY); obj->type = type; obj->file = current_file(pctx); obj->line = pctx->line; + result = isc_refcount_init(&obj->references, 1); + if (result != ISC_R_SUCCESS) { + isc_mem_put(pctx->mctx, obj, sizeof(cfg_obj_t)); + return (result); + } *ret = obj; return (ISC_R_SUCCESS); } + static void map_symtabitem_destroy(char *key, unsigned int type, isc_symvalue_t symval, void *userarg) @@ -2337,6 +2850,10 @@ free_map(cfg_parser_t *pctx, cfg_obj_t *obj) { isc_boolean_t cfg_obj_istype(const cfg_obj_t *obj, const cfg_type_t *type) { + + REQUIRE(obj != NULL); + REQUIRE(type != NULL); + return (ISC_TF(obj->type == type)); } @@ -2345,12 +2862,32 @@ cfg_obj_istype(const cfg_obj_t *obj, const cfg_type_t *type) { */ void cfg_obj_destroy(cfg_parser_t *pctx, cfg_obj_t **objp) { - cfg_obj_t *obj = *objp; - obj->type->rep->free(pctx, obj); - isc_mem_put(pctx->mctx, obj, sizeof(cfg_obj_t)); + cfg_obj_t *obj; + unsigned int refs; + + REQUIRE(objp != NULL && *objp != NULL); + REQUIRE(pctx != NULL); + + obj = *objp; + + isc_refcount_decrement(&obj->references, &refs); + if (refs == 0) { + obj->type->rep->free(pctx, obj); + isc_refcount_destroy(&obj->references); + isc_mem_put(pctx->mctx, obj, sizeof(cfg_obj_t)); + } *objp = NULL; } +void +cfg_obj_attach(cfg_obj_t *src, cfg_obj_t **dest) { + REQUIRE(src != NULL); + REQUIRE(dest != NULL && *dest == NULL); + + isc_refcount_increment(&src->references, NULL); + *dest = src; +} + static void free_noop(cfg_parser_t *pctx, cfg_obj_t *obj) { UNUSED(pctx); @@ -2359,11 +2896,17 @@ free_noop(cfg_parser_t *pctx, cfg_obj_t *obj) { void cfg_doc_obj(cfg_printer_t *pctx, const cfg_type_t *type) { + REQUIRE(pctx != NULL); + REQUIRE(type != NULL); + type->doc(pctx, type); } void cfg_doc_terminal(cfg_printer_t *pctx, const cfg_type_t *type) { + REQUIRE(pctx != NULL); + REQUIRE(type != NULL); + cfg_print_chars(pctx, "<", 1); cfg_print_cstr(pctx, type->name); cfg_print_chars(pctx, ">", 1); @@ -2375,8 +2918,10 @@ cfg_print_grammar(const cfg_type_t *type, void *closure) { cfg_printer_t pctx; + pctx.f = f; pctx.closure = closure; pctx.indent = 0; + pctx.flags = 0; cfg_doc_obj(&pctx, type); } |
