2001-02-15 04:14:15 +00:00
|
|
|
/*
|
2011-01-04 23:47:14 +00:00
|
|
|
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
|
2001-02-15 04:14:15 +00:00
|
|
|
*
|
|
|
|
* SPDX-License-Identifier: MPL-2.0 AND BSD-2-Clause
|
2021-06-03 08:37:05 +02:00
|
|
|
*
|
2001-02-15 04:14:15 +00:00
|
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
|
* file, you can obtain one at https://mozilla.org/MPL/2.0/.
|
2018-02-23 09:53:12 +01:00
|
|
|
*
|
2001-02-15 04:14:15 +00:00
|
|
|
* See the COPYRIGHT file distributed with this work for additional
|
2016-11-29 15:28:28 +11:00
|
|
|
* information regarding copyright ownership.
|
2001-02-15 04:14:15 +00:00
|
|
|
*/
|
|
|
|
|
2021-06-03 08:37:05 +02:00
|
|
|
/*
|
2019-09-02 15:46:28 +02:00
|
|
|
* Copyright (c) 2009-2018 NLNet Labs.
|
|
|
|
* All rights reserved.
|
2021-06-03 08:37:05 +02:00
|
|
|
*
|
2019-09-02 15:46:28 +02:00
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
|
* modification, are permitted provided that the following conditions
|
|
|
|
* are met:
|
|
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer.
|
|
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
|
|
* documentation and/or other materials provided with the distribution.
|
2021-06-03 08:37:05 +02:00
|
|
|
*
|
2019-09-02 15:46:28 +02:00
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
|
|
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
|
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
|
|
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
|
|
|
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
|
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
|
|
|
|
* IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
|
|
|
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
|
|
|
|
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
2021-06-03 08:37:05 +02:00
|
|
|
*/
|
|
|
|
|
2005-04-27 04:57:32 +00:00
|
|
|
/*! \file */
|
2001-02-15 04:14:15 +00:00
|
|
|
|
2020-02-06 12:51:24 -08:00
|
|
|
#include <ctype.h>
|
2019-09-13 12:08:56 -03:00
|
|
|
#include <errno.h>
|
2018-03-28 14:56:40 +02:00
|
|
|
#include <inttypes.h>
|
2018-04-17 08:29:14 -07:00
|
|
|
#include <stdbool.h>
|
2018-03-28 14:19:37 +02:00
|
|
|
#include <stdlib.h>
|
2019-09-13 12:08:56 -03:00
|
|
|
#include <string.h>
|
2015-07-08 22:53:39 -07:00
|
|
|
|
2001-02-15 04:14:15 +00:00
|
|
|
#include <isc/buffer.h>
|
|
|
|
#include <isc/dir.h>
|
2019-09-13 12:08:56 -03:00
|
|
|
#include <isc/errno.h>
|
2001-07-02 17:05:46 +00:00
|
|
|
#include <isc/formatcheck.h>
|
2019-10-23 16:25:06 -03:00
|
|
|
#include <isc/glob.h>
|
2001-02-15 04:14:15 +00:00
|
|
|
#include <isc/lex.h>
|
|
|
|
#include <isc/log.h>
|
|
|
|
#include <isc/mem.h>
|
|
|
|
#include <isc/net.h>
|
|
|
|
#include <isc/netaddr.h>
|
2021-05-19 18:03:11 +03:00
|
|
|
#include <isc/netmgr.h>
|
2009-09-02 23:43:54 +00:00
|
|
|
#include <isc/netscope.h>
|
2001-02-17 00:46:58 +00:00
|
|
|
#include <isc/print.h>
|
2001-02-15 04:14:15 +00:00
|
|
|
#include <isc/sockaddr.h>
|
|
|
|
#include <isc/string.h>
|
|
|
|
#include <isc/symtab.h>
|
2009-09-02 23:43:54 +00:00
|
|
|
#include <isc/util.h>
|
2001-02-15 04:14:15 +00:00
|
|
|
|
2019-09-02 15:46:28 +02:00
|
|
|
#include <dns/ttl.h>
|
2020-02-12 13:59:18 +01:00
|
|
|
|
2001-02-15 04:14:15 +00:00
|
|
|
#include <isccfg/cfg.h>
|
2002-01-04 02:32:16 +00:00
|
|
|
#include <isccfg/grammar.h>
|
2001-02-22 02:39:24 +00:00
|
|
|
#include <isccfg/log.h>
|
2001-02-15 04:14:15 +00:00
|
|
|
|
2001-02-22 02:39:24 +00:00
|
|
|
/* Shorthand */
|
2001-03-13 03:04:09 +00:00
|
|
|
#define CAT CFG_LOGCATEGORY_CONFIG
|
|
|
|
#define MOD CFG_LOGMODULE_PARSER
|
2001-02-15 04:14:15 +00:00
|
|
|
|
|
|
|
#define MAP_SYM 1 /* Unique type for isc_symtab */
|
|
|
|
|
2002-01-22 19:31:57 +00:00
|
|
|
#define TOKEN_STRING(pctx) (pctx->token.value.as_textregion.base)
|
|
|
|
|
2001-02-15 04:14:15 +00:00
|
|
|
/* Check a return value. */
|
|
|
|
#define CHECK(op) \
|
2008-09-25 04:02:39 +00:00
|
|
|
do { \
|
|
|
|
result = (op); \
|
2001-02-15 04:14:15 +00:00
|
|
|
if (result != ISC_R_SUCCESS) \
|
|
|
|
goto cleanup; \
|
|
|
|
} while (0)
|
|
|
|
|
|
|
|
/* Clean up a configuration object if non-NULL. */
|
|
|
|
#define CLEANUP_OBJ(obj) \
|
|
|
|
do { \
|
|
|
|
if ((obj) != NULL) \
|
|
|
|
cfg_obj_destroy(pctx, &(obj)); \
|
|
|
|
} while (0)
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Forward declarations of static functions.
|
|
|
|
*/
|
|
|
|
|
2002-01-04 02:32:16 +00:00
|
|
|
static void
|
|
|
|
free_tuple(cfg_parser_t *pctx, cfg_obj_t *obj);
|
2001-02-27 01:31:56 +00:00
|
|
|
|
2001-07-23 00:23:30 +00:00
|
|
|
static isc_result_t
|
|
|
|
parse_list(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret);
|
2001-02-15 04:14:15 +00:00
|
|
|
|
2006-02-28 02:39:52 +00:00
|
|
|
static void
|
|
|
|
print_list(cfg_printer_t *pctx, const cfg_obj_t *obj);
|
2001-02-15 04:14:15 +00:00
|
|
|
|
2002-01-04 02:32:16 +00:00
|
|
|
static void
|
|
|
|
free_list(cfg_parser_t *pctx, cfg_obj_t *obj);
|
2001-02-27 01:31:56 +00:00
|
|
|
|
2002-01-04 02:32:16 +00:00
|
|
|
static isc_result_t
|
|
|
|
create_listelt(cfg_parser_t *pctx, cfg_listelt_t **eltp);
|
2001-02-15 04:14:15 +00:00
|
|
|
|
2002-01-04 02:32:16 +00:00
|
|
|
static isc_result_t
|
|
|
|
create_string(cfg_parser_t *pctx, const char *contents, const cfg_type_t *type,
|
|
|
|
cfg_obj_t **ret);
|
2001-02-15 04:14:15 +00:00
|
|
|
|
2002-01-04 02:32:16 +00:00
|
|
|
static void
|
|
|
|
free_string(cfg_parser_t *pctx, cfg_obj_t *obj);
|
2001-02-26 22:37:34 +00:00
|
|
|
|
2002-01-04 02:32:16 +00:00
|
|
|
static isc_result_t
|
|
|
|
create_map(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **objp);
|
2001-02-15 04:14:15 +00:00
|
|
|
|
2002-01-04 02:32:16 +00:00
|
|
|
static void
|
|
|
|
free_map(cfg_parser_t *pctx, cfg_obj_t *obj);
|
2001-02-15 04:14:15 +00:00
|
|
|
|
|
|
|
static isc_result_t
|
|
|
|
parse_symtab_elt(cfg_parser_t *pctx, const char *name, cfg_type_t *elttype,
|
2001-02-22 00:23:31 +00:00
|
|
|
isc_symtab_t *symtab, bool callback);
|
2001-02-15 04:14:15 +00:00
|
|
|
|
|
|
|
static void
|
|
|
|
free_noop(cfg_parser_t *pctx, cfg_obj_t *obj);
|
|
|
|
|
|
|
|
static isc_result_t
|
|
|
|
cfg_getstringtoken(cfg_parser_t *pctx);
|
|
|
|
|
2018-04-17 08:29:14 -07:00
|
|
|
static void
|
|
|
|
parser_complain(cfg_parser_t *pctx, bool is_warning, unsigned int flags,
|
2001-02-15 04:14:15 +00:00
|
|
|
const char *format, va_list args);
|
|
|
|
|
2019-06-27 21:08:20 -07:00
|
|
|
#if defined(HAVE_GEOIP2)
|
2018-12-07 12:50:03 +11:00
|
|
|
static isc_result_t
|
|
|
|
parse_geoip(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret);
|
|
|
|
|
|
|
|
static void
|
|
|
|
print_geoip(cfg_printer_t *pctx, const cfg_obj_t *obj);
|
|
|
|
|
|
|
|
static void
|
|
|
|
doc_geoip(cfg_printer_t *pctx, const cfg_type_t *type);
|
2019-06-27 21:08:20 -07:00
|
|
|
#endif /* HAVE_GEOIP2 */
|
2018-12-07 12:50:03 +11:00
|
|
|
|
2001-02-15 04:14:15 +00:00
|
|
|
/*
|
|
|
|
* Data representations. These correspond to members of the
|
|
|
|
* "value" union in struct cfg_obj (except "void", which does
|
|
|
|
* not need a union member).
|
|
|
|
*/
|
2001-05-09 03:17:02 +00:00
|
|
|
|
2021-06-10 08:06:48 +02:00
|
|
|
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 };
|
|
|
|
cfg_rep_t cfg_rep_fixedpoint = { "fixedpoint", free_noop };
|
|
|
|
cfg_rep_t cfg_rep_percentage = { "percentage", free_noop };
|
|
|
|
cfg_rep_t cfg_rep_duration = { "duration", free_noop };
|
2001-02-15 04:14:15 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Configuration type definitions.
|
|
|
|
*/
|
|
|
|
|
2005-04-27 04:57:32 +00:00
|
|
|
/*%
|
2001-02-15 04:14:15 +00:00
|
|
|
* An implicit list. These are formed by clauses that occur multiple times.
|
|
|
|
*/
|
|
|
|
static cfg_type_t cfg_type_implicitlist = { "implicitlist", NULL,
|
2002-01-04 02:32:16 +00:00
|
|
|
print_list, NULL,
|
|
|
|
&cfg_rep_list, NULL };
|
2001-02-15 04:14:15 +00:00
|
|
|
|
|
|
|
/* Functions. */
|
|
|
|
|
2002-01-04 02:32:16 +00:00
|
|
|
void
|
2006-02-28 02:39:52 +00:00
|
|
|
cfg_print_obj(cfg_printer_t *pctx, const cfg_obj_t *obj) {
|
2016-10-10 17:11:21 -07:00
|
|
|
REQUIRE(pctx != NULL);
|
|
|
|
REQUIRE(obj != NULL);
|
|
|
|
|
2001-02-15 04:14:15 +00:00
|
|
|
obj->type->print(pctx, obj);
|
|
|
|
}
|
|
|
|
|
2002-01-04 02:32:16 +00:00
|
|
|
void
|
|
|
|
cfg_print_chars(cfg_printer_t *pctx, const char *text, int len) {
|
2016-10-10 17:11:21 -07:00
|
|
|
REQUIRE(pctx != NULL);
|
|
|
|
REQUIRE(text != NULL);
|
|
|
|
|
2001-02-15 04:14:15 +00:00
|
|
|
pctx->f(pctx->closure, text, len);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
print_open(cfg_printer_t *pctx) {
|
2015-01-06 22:57:57 -08:00
|
|
|
if ((pctx->flags & CFG_PRINTER_ONELINE) != 0) {
|
|
|
|
cfg_print_cstr(pctx, "{ ");
|
|
|
|
} else {
|
|
|
|
cfg_print_cstr(pctx, "{\n");
|
|
|
|
pctx->indent++;
|
|
|
|
}
|
2001-02-15 04:14:15 +00:00
|
|
|
}
|
|
|
|
|
2018-01-22 11:00:45 -08:00
|
|
|
void
|
|
|
|
cfg_print_indent(cfg_printer_t *pctx) {
|
2001-02-15 04:14:15 +00:00
|
|
|
int indent = pctx->indent;
|
2015-01-06 22:57:57 -08:00
|
|
|
if ((pctx->flags & CFG_PRINTER_ONELINE) != 0) {
|
|
|
|
cfg_print_cstr(pctx, " ");
|
|
|
|
return;
|
|
|
|
}
|
2001-02-15 04:14:15 +00:00
|
|
|
while (indent > 0) {
|
2015-01-06 22:57:57 -08:00
|
|
|
cfg_print_cstr(pctx, "\t");
|
2001-02-15 04:14:15 +00:00
|
|
|
indent--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
print_close(cfg_printer_t *pctx) {
|
2015-01-06 22:57:57 -08:00
|
|
|
if ((pctx->flags & CFG_PRINTER_ONELINE) == 0) {
|
|
|
|
pctx->indent--;
|
2018-01-22 11:00:45 -08:00
|
|
|
cfg_print_indent(pctx);
|
2015-01-06 22:57:57 -08:00
|
|
|
}
|
|
|
|
cfg_print_cstr(pctx, "}");
|
2001-02-15 04:14:15 +00:00
|
|
|
}
|
|
|
|
|
2002-01-04 02:32:16 +00:00
|
|
|
isc_result_t
|
|
|
|
cfg_parse_obj(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
|
2001-03-02 01:10:51 +00:00
|
|
|
isc_result_t result;
|
2016-10-10 17:11:21 -07:00
|
|
|
|
|
|
|
REQUIRE(pctx != NULL);
|
|
|
|
REQUIRE(type != NULL);
|
|
|
|
REQUIRE(ret != NULL && *ret == NULL);
|
|
|
|
|
2001-03-02 01:10:51 +00:00
|
|
|
result = type->parse(pctx, type, ret);
|
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
return (result);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2016-10-10 17:11:21 -07:00
|
|
|
ENSURE(*ret != NULL);
|
2001-03-02 01:10:51 +00:00
|
|
|
return (ISC_R_SUCCESS);
|
2001-02-15 04:14:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2006-02-28 02:39:52 +00:00
|
|
|
cfg_print(const cfg_obj_t *obj,
|
2001-02-15 04:14:15 +00:00
|
|
|
void (*f)(void *closure, const char *text, int textlen),
|
|
|
|
void *closure) {
|
2016-10-10 17:11:21 -07:00
|
|
|
REQUIRE(obj != NULL);
|
|
|
|
REQUIRE(f != NULL);
|
|
|
|
|
2014-01-10 16:56:36 +11:00
|
|
|
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) {
|
2001-02-15 04:14:15 +00:00
|
|
|
cfg_printer_t pctx;
|
2016-10-10 17:11:21 -07:00
|
|
|
|
|
|
|
REQUIRE(obj != NULL);
|
|
|
|
REQUIRE(f != NULL);
|
|
|
|
|
2001-02-15 04:14:15 +00:00
|
|
|
pctx.f = f;
|
|
|
|
pctx.closure = closure;
|
|
|
|
pctx.indent = 0;
|
2014-01-10 16:56:36 +11:00
|
|
|
pctx.flags = flags;
|
2001-02-15 04:14:15 +00:00
|
|
|
obj->type->print(&pctx, obj);
|
|
|
|
}
|
|
|
|
|
2001-03-02 20:00:17 +00:00
|
|
|
/* Tuples. */
|
2008-09-25 04:02:39 +00:00
|
|
|
|
2002-01-04 02:32:16 +00:00
|
|
|
isc_result_t
|
|
|
|
cfg_create_tuple(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
|
2001-02-15 04:14:15 +00:00
|
|
|
isc_result_t result;
|
2019-09-27 12:07:32 +02:00
|
|
|
const cfg_tuplefielddef_t *fields;
|
2001-07-23 00:23:30 +00:00
|
|
|
const cfg_tuplefielddef_t *f;
|
2001-03-02 20:00:17 +00:00
|
|
|
cfg_obj_t *obj = NULL;
|
|
|
|
unsigned int nfields = 0;
|
|
|
|
int i;
|
2001-02-15 04:14:15 +00:00
|
|
|
|
2016-10-10 17:11:21 -07:00
|
|
|
REQUIRE(pctx != NULL);
|
|
|
|
REQUIRE(type != NULL);
|
|
|
|
REQUIRE(ret != NULL && *ret == NULL);
|
|
|
|
|
2019-09-27 12:07:32 +02:00
|
|
|
fields = type->of;
|
|
|
|
|
2001-02-22 03:13:08 +00:00
|
|
|
for (f = fields; f->name != NULL; f++) {
|
2001-02-15 04:14:15 +00:00
|
|
|
nfields++;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2001-02-15 04:14:15 +00:00
|
|
|
|
2002-01-04 02:32:16 +00:00
|
|
|
CHECK(cfg_create_obj(pctx, type, &obj));
|
2001-02-15 04:14:15 +00:00
|
|
|
obj->value.tuple = isc_mem_get(pctx->mctx,
|
|
|
|
nfields * sizeof(cfg_obj_t *));
|
2001-02-22 03:13:08 +00:00
|
|
|
for (f = fields, i = 0; f->name != NULL; f++, i++) {
|
2001-02-15 04:14:15 +00:00
|
|
|
obj->value.tuple[i] = NULL;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2001-03-02 20:00:17 +00:00
|
|
|
*ret = obj;
|
|
|
|
return (ISC_R_SUCCESS);
|
|
|
|
|
|
|
|
cleanup:
|
2003-07-03 01:50:25 +00:00
|
|
|
if (obj != NULL) {
|
|
|
|
isc_mem_put(pctx->mctx, obj, sizeof(*obj));
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2001-03-02 20:00:17 +00:00
|
|
|
return (result);
|
|
|
|
}
|
|
|
|
|
2002-01-04 02:32:16 +00:00
|
|
|
isc_result_t
|
|
|
|
cfg_parse_tuple(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
|
2001-03-02 20:00:17 +00:00
|
|
|
isc_result_t result;
|
2019-09-27 12:07:32 +02:00
|
|
|
const cfg_tuplefielddef_t *fields;
|
2001-07-23 00:23:30 +00:00
|
|
|
const cfg_tuplefielddef_t *f;
|
2001-03-02 20:00:17 +00:00
|
|
|
cfg_obj_t *obj = NULL;
|
|
|
|
unsigned int i;
|
2001-02-15 04:14:15 +00:00
|
|
|
|
2016-10-10 17:11:21 -07:00
|
|
|
REQUIRE(pctx != NULL);
|
|
|
|
REQUIRE(type != NULL);
|
|
|
|
REQUIRE(ret != NULL && *ret == NULL);
|
|
|
|
|
2019-09-27 12:07:32 +02:00
|
|
|
fields = type->of;
|
|
|
|
|
2002-01-04 02:32:16 +00:00
|
|
|
CHECK(cfg_create_tuple(pctx, type, &obj));
|
2001-02-22 03:13:08 +00:00
|
|
|
for (f = fields, i = 0; f->name != NULL; f++, i++) {
|
2002-01-04 02:32:16 +00:00
|
|
|
CHECK(cfg_parse_obj(pctx, f->type, &obj->value.tuple[i]));
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2001-02-15 04:14:15 +00:00
|
|
|
|
|
|
|
*ret = obj;
|
|
|
|
return (ISC_R_SUCCESS);
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
CLEANUP_OBJ(obj);
|
|
|
|
return (result);
|
|
|
|
}
|
|
|
|
|
2002-01-04 02:32:16 +00:00
|
|
|
void
|
2006-02-28 02:39:52 +00:00
|
|
|
cfg_print_tuple(cfg_printer_t *pctx, const cfg_obj_t *obj) {
|
2001-02-15 04:14:15 +00:00
|
|
|
unsigned int i;
|
2016-10-10 17:11:21 -07:00
|
|
|
const cfg_tuplefielddef_t *fields;
|
2001-07-23 00:23:30 +00:00
|
|
|
const cfg_tuplefielddef_t *f;
|
2018-04-17 08:29:14 -07:00
|
|
|
bool need_space = false;
|
2001-02-15 04:14:15 +00:00
|
|
|
|
2016-10-10 17:11:21 -07:00
|
|
|
REQUIRE(pctx != NULL);
|
|
|
|
REQUIRE(obj != NULL);
|
|
|
|
|
|
|
|
fields = obj->type->of;
|
|
|
|
|
2001-02-22 03:13:08 +00:00
|
|
|
for (f = fields, i = 0; f->name != NULL; f++, i++) {
|
2006-02-28 02:39:52 +00:00
|
|
|
const cfg_obj_t *fieldobj = obj->value.tuple[i];
|
2015-09-14 08:50:17 -07:00
|
|
|
if (need_space && fieldobj->type->rep != &cfg_rep_void) {
|
2015-01-06 22:57:57 -08:00
|
|
|
cfg_print_cstr(pctx, " ");
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2002-01-04 02:32:16 +00:00
|
|
|
cfg_print_obj(pctx, fieldobj);
|
2018-04-17 08:29:14 -07:00
|
|
|
need_space = (need_space ||
|
|
|
|
fieldobj->type->print != cfg_print_void);
|
2002-01-04 02:32:16 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
cfg_doc_tuple(cfg_printer_t *pctx, const cfg_type_t *type) {
|
2017-09-27 10:27:09 +10:00
|
|
|
const cfg_tuplefielddef_t *fields;
|
2002-01-04 02:32:16 +00:00
|
|
|
const cfg_tuplefielddef_t *f;
|
2018-04-17 08:29:14 -07:00
|
|
|
bool need_space = false;
|
2002-01-04 02:32:16 +00:00
|
|
|
|
2016-10-10 17:11:21 -07:00
|
|
|
REQUIRE(pctx != NULL);
|
|
|
|
REQUIRE(type != NULL);
|
|
|
|
|
|
|
|
fields = type->of;
|
|
|
|
|
2002-01-04 02:32:16 +00:00
|
|
|
for (f = fields; f->name != NULL; f++) {
|
|
|
|
if (need_space) {
|
2015-01-06 22:57:57 -08:00
|
|
|
cfg_print_cstr(pctx, " ");
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2002-01-04 02:32:16 +00:00
|
|
|
cfg_doc_obj(pctx, f->type);
|
2018-04-17 08:29:14 -07:00
|
|
|
need_space = (f->type->print != cfg_print_void);
|
2001-02-15 04:14:15 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
free_tuple(cfg_parser_t *pctx, cfg_obj_t *obj) {
|
|
|
|
unsigned int i;
|
2001-07-23 00:23:30 +00:00
|
|
|
const cfg_tuplefielddef_t *fields = obj->type->of;
|
|
|
|
const cfg_tuplefielddef_t *f;
|
2001-02-15 04:14:15 +00:00
|
|
|
unsigned int nfields = 0;
|
|
|
|
|
2001-03-02 20:00:17 +00:00
|
|
|
if (obj->value.tuple == NULL) {
|
|
|
|
return;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2001-03-02 20:00:17 +00:00
|
|
|
|
2001-02-22 03:13:08 +00:00
|
|
|
for (f = fields, i = 0; f->name != NULL; f++, i++) {
|
2001-02-15 04:14:15 +00:00
|
|
|
CLEANUP_OBJ(obj->value.tuple[i]);
|
|
|
|
nfields++;
|
|
|
|
}
|
|
|
|
isc_mem_put(pctx->mctx, obj->value.tuple,
|
|
|
|
nfields * sizeof(cfg_obj_t *));
|
|
|
|
}
|
|
|
|
|
2018-04-17 08:29:14 -07:00
|
|
|
bool
|
2006-02-28 02:39:52 +00:00
|
|
|
cfg_obj_istuple(const cfg_obj_t *obj) {
|
2001-02-23 00:15:55 +00:00
|
|
|
REQUIRE(obj != NULL);
|
2018-04-17 08:29:14 -07:00
|
|
|
return (obj->type->rep == &cfg_rep_tuple);
|
2001-02-23 00:15:55 +00:00
|
|
|
}
|
|
|
|
|
2006-02-28 02:39:52 +00:00
|
|
|
const cfg_obj_t *
|
|
|
|
cfg_tuple_get(const cfg_obj_t *tupleobj, const char *name) {
|
2001-02-22 04:17:37 +00:00
|
|
|
unsigned int i;
|
2001-07-23 00:23:30 +00:00
|
|
|
const cfg_tuplefielddef_t *fields;
|
|
|
|
const cfg_tuplefielddef_t *f;
|
2008-09-25 04:02:39 +00:00
|
|
|
|
2001-02-22 04:17:37 +00:00
|
|
|
REQUIRE(tupleobj != NULL && tupleobj->type->rep == &cfg_rep_tuple);
|
2016-10-10 17:11:21 -07:00
|
|
|
REQUIRE(name != NULL);
|
2001-02-22 04:17:37 +00:00
|
|
|
|
|
|
|
fields = tupleobj->type->of;
|
|
|
|
for (f = fields, i = 0; f->name != NULL; f++, i++) {
|
|
|
|
if (strcmp(f->name, name) == 0) {
|
|
|
|
return (tupleobj->value.tuple[i]);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2001-02-22 04:17:37 +00:00
|
|
|
}
|
2021-10-11 12:50:17 +02:00
|
|
|
UNREACHABLE();
|
2001-02-22 04:17:37 +00:00
|
|
|
}
|
|
|
|
|
2002-01-04 02:32:16 +00:00
|
|
|
isc_result_t
|
|
|
|
cfg_parse_special(cfg_parser_t *pctx, int special) {
|
2008-09-25 04:02:39 +00:00
|
|
|
isc_result_t result;
|
2016-10-10 17:11:21 -07:00
|
|
|
|
|
|
|
REQUIRE(pctx != NULL);
|
|
|
|
|
2001-02-15 04:14:15 +00:00
|
|
|
CHECK(cfg_gettoken(pctx, 0));
|
|
|
|
if (pctx->token.type == isc_tokentype_special &&
|
|
|
|
pctx->token.value.as_char == special)
|
|
|
|
{
|
|
|
|
return (ISC_R_SUCCESS);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2001-02-15 04:14:15 +00:00
|
|
|
|
2002-01-04 02:32:16 +00:00
|
|
|
cfg_parser_error(pctx, CFG_LOG_NEAR, "'%c' expected", special);
|
2001-02-15 04:14:15 +00:00
|
|
|
return (ISC_R_UNEXPECTEDTOKEN);
|
|
|
|
cleanup:
|
|
|
|
return (result);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Parse a required semicolon. If it is not there, log
|
|
|
|
* an error and increment the error count but continue
|
|
|
|
* parsing. Since the next token is pushed back,
|
|
|
|
* care must be taken to make sure it is eventually
|
|
|
|
* consumed or an infinite loop may result.
|
|
|
|
*/
|
|
|
|
static isc_result_t
|
|
|
|
parse_semicolon(cfg_parser_t *pctx) {
|
2008-09-25 04:02:39 +00:00
|
|
|
isc_result_t result;
|
2016-10-10 17:11:21 -07:00
|
|
|
|
2001-02-15 04:14:15 +00:00
|
|
|
CHECK(cfg_gettoken(pctx, 0));
|
|
|
|
if (pctx->token.type == isc_tokentype_special &&
|
|
|
|
pctx->token.value.as_char == ';')
|
|
|
|
{
|
|
|
|
return (ISC_R_SUCCESS);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2001-02-15 04:14:15 +00:00
|
|
|
|
2002-01-04 02:32:16 +00:00
|
|
|
cfg_parser_error(pctx, CFG_LOG_BEFORE, "missing ';'");
|
2001-02-15 04:14:15 +00:00
|
|
|
cfg_ungettoken(pctx);
|
|
|
|
cleanup:
|
|
|
|
return (result);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Parse EOF, logging and returning an error if not there.
|
|
|
|
*/
|
|
|
|
static isc_result_t
|
|
|
|
parse_eof(cfg_parser_t *pctx) {
|
2008-09-25 04:02:39 +00:00
|
|
|
isc_result_t result;
|
2016-10-10 17:11:21 -07:00
|
|
|
|
2001-02-15 04:14:15 +00:00
|
|
|
CHECK(cfg_gettoken(pctx, 0));
|
|
|
|
|
|
|
|
if (pctx->token.type == isc_tokentype_eof) {
|
|
|
|
return (ISC_R_SUCCESS);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2001-02-15 04:14:15 +00:00
|
|
|
|
2002-01-04 02:32:16 +00:00
|
|
|
cfg_parser_error(pctx, CFG_LOG_NEAR, "syntax error");
|
2001-02-15 04:14:15 +00:00
|
|
|
return (ISC_R_UNEXPECTEDTOKEN);
|
|
|
|
cleanup:
|
2002-02-01 02:33:26 +00:00
|
|
|
return (result);
|
2001-02-15 04:14:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* A list of files, used internally for pctx->files. */
|
2001-05-09 03:17:02 +00:00
|
|
|
|
2001-02-15 04:14:15 +00:00
|
|
|
static cfg_type_t cfg_type_filelist = { "filelist", NULL,
|
2002-01-04 02:32:16 +00:00
|
|
|
print_list, NULL,
|
2001-02-15 04:14:15 +00:00
|
|
|
&cfg_rep_list, &cfg_type_qstring };
|
|
|
|
|
|
|
|
isc_result_t
|
2002-01-04 02:32:16 +00:00
|
|
|
cfg_parser_create(isc_mem_t *mctx, isc_log_t *lctx, cfg_parser_t **ret) {
|
2001-02-15 04:14:15 +00:00
|
|
|
isc_result_t result;
|
|
|
|
cfg_parser_t *pctx;
|
|
|
|
isc_lexspecials_t specials;
|
|
|
|
|
|
|
|
REQUIRE(mctx != NULL);
|
|
|
|
REQUIRE(ret != NULL && *ret == NULL);
|
|
|
|
|
|
|
|
pctx = isc_mem_get(mctx, sizeof(*pctx));
|
|
|
|
|
2013-03-08 14:38:03 +11:00
|
|
|
pctx->mctx = NULL;
|
|
|
|
isc_mem_attach(mctx, &pctx->mctx);
|
|
|
|
|
2018-08-01 11:46:11 +02:00
|
|
|
isc_refcount_init(&pctx->references, 1);
|
2010-08-11 18:14:20 +00:00
|
|
|
|
2001-02-15 04:14:15 +00:00
|
|
|
pctx->lctx = lctx;
|
|
|
|
pctx->lexer = NULL;
|
2018-04-17 08:29:14 -07:00
|
|
|
pctx->seen_eof = false;
|
|
|
|
pctx->ungotten = false;
|
2001-02-15 04:14:15 +00:00
|
|
|
pctx->errors = 0;
|
2002-01-04 06:19:20 +00:00
|
|
|
pctx->warnings = 0;
|
2001-06-07 01:58:49 +00:00
|
|
|
pctx->open_files = NULL;
|
|
|
|
pctx->closed_files = NULL;
|
2001-02-15 04:14:15 +00:00
|
|
|
pctx->line = 0;
|
2001-02-22 00:23:31 +00:00
|
|
|
pctx->callback = NULL;
|
|
|
|
pctx->callbackarg = NULL;
|
2002-01-04 06:19:20 +00:00
|
|
|
pctx->token.type = isc_tokentype_unknown;
|
2009-06-11 23:47:56 +00:00
|
|
|
pctx->flags = 0;
|
2015-05-21 23:04:29 -07:00
|
|
|
pctx->buf_name = NULL;
|
2001-02-15 04:14:15 +00:00
|
|
|
|
|
|
|
memset(specials, 0, sizeof(specials));
|
|
|
|
specials['{'] = 1;
|
|
|
|
specials['}'] = 1;
|
|
|
|
specials[';'] = 1;
|
|
|
|
specials['/'] = 1;
|
|
|
|
specials['"'] = 1;
|
|
|
|
specials['!'] = 1;
|
|
|
|
|
2022-10-26 12:35:41 +02:00
|
|
|
isc_lex_create(pctx->mctx, 1024, &pctx->lexer);
|
2001-02-15 04:14:15 +00:00
|
|
|
|
|
|
|
isc_lex_setspecials(pctx->lexer, specials);
|
|
|
|
isc_lex_setcomments(pctx->lexer,
|
|
|
|
(ISC_LEXCOMMENT_C | ISC_LEXCOMMENT_CPLUSPLUS |
|
|
|
|
ISC_LEXCOMMENT_SHELL));
|
|
|
|
|
2002-01-04 02:32:16 +00:00
|
|
|
CHECK(cfg_create_list(pctx, &cfg_type_filelist, &pctx->open_files));
|
|
|
|
CHECK(cfg_create_list(pctx, &cfg_type_filelist, &pctx->closed_files));
|
2001-02-15 04:14:15 +00:00
|
|
|
|
|
|
|
*ret = pctx;
|
|
|
|
return (ISC_R_SUCCESS);
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
if (pctx->lexer != NULL) {
|
|
|
|
isc_lex_destroy(&pctx->lexer);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2001-06-07 01:58:49 +00:00
|
|
|
CLEANUP_OBJ(pctx->open_files);
|
|
|
|
CLEANUP_OBJ(pctx->closed_files);
|
2013-03-08 14:38:03 +11:00
|
|
|
isc_mem_putanddetach(&pctx->mctx, pctx, sizeof(*pctx));
|
2001-02-15 04:14:15 +00:00
|
|
|
return (result);
|
|
|
|
}
|
|
|
|
|
2019-06-25 09:41:51 +02:00
|
|
|
void
|
|
|
|
cfg_parser_setflags(cfg_parser_t *pctx, unsigned int flags, bool turn_on) {
|
|
|
|
REQUIRE(pctx != NULL);
|
|
|
|
|
|
|
|
if (turn_on) {
|
|
|
|
pctx->flags |= flags;
|
|
|
|
} else {
|
|
|
|
pctx->flags &= ~flags;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2001-02-15 04:14:15 +00:00
|
|
|
static isc_result_t
|
2001-02-17 00:15:22 +00:00
|
|
|
parser_openfile(cfg_parser_t *pctx, const char *filename) {
|
2001-02-15 04:14:15 +00:00
|
|
|
isc_result_t result;
|
|
|
|
cfg_listelt_t *elt = NULL;
|
|
|
|
cfg_obj_t *stringobj = NULL;
|
|
|
|
|
|
|
|
result = isc_lex_openfile(pctx->lexer, filename);
|
|
|
|
if (result != ISC_R_SUCCESS) {
|
2002-01-04 02:32:16 +00:00
|
|
|
cfg_parser_error(pctx, 0, "open: %s: %s", filename,
|
2001-02-15 04:14:15 +00:00
|
|
|
isc_result_totext(result));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
CHECK(create_string(pctx, filename, &cfg_type_qstring, &stringobj));
|
|
|
|
CHECK(create_listelt(pctx, &elt));
|
|
|
|
elt->obj = stringobj;
|
2001-06-07 01:58:49 +00:00
|
|
|
ISC_LIST_APPEND(pctx->open_files->value.list, elt, link);
|
2001-02-15 04:14:15 +00:00
|
|
|
|
|
|
|
return (ISC_R_SUCCESS);
|
|
|
|
cleanup:
|
|
|
|
CLEANUP_OBJ(stringobj);
|
|
|
|
return (result);
|
|
|
|
}
|
|
|
|
|
2001-02-22 00:23:31 +00:00
|
|
|
void
|
|
|
|
cfg_parser_setcallback(cfg_parser_t *pctx, cfg_parsecallback_t callback,
|
|
|
|
void *arg) {
|
2016-10-10 17:11:21 -07:00
|
|
|
REQUIRE(pctx != NULL);
|
|
|
|
|
2001-02-22 00:23:31 +00:00
|
|
|
pctx->callback = callback;
|
|
|
|
pctx->callbackarg = arg;
|
|
|
|
}
|
|
|
|
|
2015-01-06 22:57:57 -08:00
|
|
|
void
|
|
|
|
cfg_parser_reset(cfg_parser_t *pctx) {
|
|
|
|
REQUIRE(pctx != NULL);
|
|
|
|
|
|
|
|
if (pctx->lexer != NULL) {
|
|
|
|
isc_lex_close(pctx->lexer);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2015-01-06 22:57:57 -08:00
|
|
|
|
2018-04-17 08:29:14 -07:00
|
|
|
pctx->seen_eof = false;
|
|
|
|
pctx->ungotten = false;
|
2015-01-06 22:57:57 -08:00
|
|
|
pctx->errors = 0;
|
|
|
|
pctx->warnings = 0;
|
|
|
|
pctx->line = 0;
|
|
|
|
}
|
|
|
|
|
2001-02-17 00:15:22 +00:00
|
|
|
/*
|
|
|
|
* Parse a configuration using a pctx where a lexer has already
|
|
|
|
* been set up with a source.
|
|
|
|
*/
|
|
|
|
static isc_result_t
|
2001-07-23 00:23:30 +00:00
|
|
|
parse2(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
|
2001-02-15 04:14:15 +00:00
|
|
|
isc_result_t result;
|
|
|
|
cfg_obj_t *obj = NULL;
|
|
|
|
|
2002-01-04 02:32:16 +00:00
|
|
|
result = cfg_parse_obj(pctx, type, &obj);
|
2001-02-15 04:14:15 +00:00
|
|
|
|
|
|
|
if (pctx->errors != 0) {
|
|
|
|
/* Errors have been logged. */
|
|
|
|
if (result == ISC_R_SUCCESS) {
|
|
|
|
result = ISC_R_FAILURE;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2001-02-15 04:14:15 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
/* Parsing failed but no errors have been logged. */
|
2017-10-10 18:28:34 -07:00
|
|
|
cfg_parser_error(pctx, 0, "parsing failed: %s",
|
|
|
|
isc_result_totext(result));
|
2001-02-15 04:14:15 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
CHECK(parse_eof(pctx));
|
|
|
|
|
|
|
|
*ret = obj;
|
|
|
|
return (ISC_R_SUCCESS);
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
CLEANUP_OBJ(obj);
|
|
|
|
return (result);
|
|
|
|
}
|
|
|
|
|
2001-02-17 00:15:22 +00:00
|
|
|
isc_result_t
|
|
|
|
cfg_parse_file(cfg_parser_t *pctx, const char *filename, const cfg_type_t *type,
|
2001-07-23 00:23:30 +00:00
|
|
|
cfg_obj_t **ret) {
|
2001-02-17 00:15:22 +00:00
|
|
|
isc_result_t result;
|
2015-05-21 23:04:29 -07:00
|
|
|
cfg_listelt_t *elt;
|
2001-02-17 00:15:22 +00:00
|
|
|
|
2016-10-10 17:11:21 -07:00
|
|
|
REQUIRE(pctx != NULL);
|
2001-02-17 00:15:22 +00:00
|
|
|
REQUIRE(filename != NULL);
|
2016-10-10 17:11:21 -07:00
|
|
|
REQUIRE(type != NULL);
|
|
|
|
REQUIRE(ret != NULL && *ret == NULL);
|
2001-02-17 00:15:22 +00:00
|
|
|
|
|
|
|
CHECK(parser_openfile(pctx, filename));
|
2015-05-21 23:04:29 -07:00
|
|
|
|
|
|
|
result = parse2(pctx, type, ret);
|
|
|
|
|
|
|
|
/* Clean up the opened file */
|
|
|
|
elt = ISC_LIST_TAIL(pctx->open_files->value.list);
|
|
|
|
INSIST(elt != NULL);
|
|
|
|
ISC_LIST_UNLINK(pctx->open_files->value.list, elt, link);
|
|
|
|
ISC_LIST_APPEND(pctx->closed_files->value.list, elt, link);
|
|
|
|
|
2001-02-17 00:15:22 +00:00
|
|
|
cleanup:
|
|
|
|
return (result);
|
|
|
|
}
|
|
|
|
|
|
|
|
isc_result_t
|
|
|
|
cfg_parse_buffer(cfg_parser_t *pctx, isc_buffer_t *buffer, const char *file,
|
2019-01-21 20:03:45 -08:00
|
|
|
unsigned int line, const cfg_type_t *type, unsigned int flags,
|
|
|
|
cfg_obj_t **ret) {
|
2001-02-17 00:15:22 +00:00
|
|
|
isc_result_t result;
|
2015-01-06 22:57:57 -08:00
|
|
|
|
2016-10-10 17:11:21 -07:00
|
|
|
REQUIRE(pctx != NULL);
|
|
|
|
REQUIRE(type != NULL);
|
2001-02-17 00:15:22 +00:00
|
|
|
REQUIRE(buffer != NULL);
|
2016-10-10 17:11:21 -07:00
|
|
|
REQUIRE(ret != NULL && *ret == NULL);
|
2018-06-08 11:04:21 +10:00
|
|
|
REQUIRE((flags & ~(CFG_PCTX_NODEPRECATED)) == 0);
|
2015-01-06 22:57:57 -08:00
|
|
|
|
2008-09-25 04:02:39 +00:00
|
|
|
CHECK(isc_lex_openbuffer(pctx->lexer, buffer));
|
2016-10-10 17:11:21 -07:00
|
|
|
|
|
|
|
pctx->buf_name = file;
|
2018-06-08 11:04:21 +10:00
|
|
|
pctx->flags = flags;
|
2016-10-10 17:11:21 -07:00
|
|
|
|
|
|
|
if (line != 0U) {
|
|
|
|
CHECK(isc_lex_setsourceline(pctx->lexer, line));
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2016-10-10 17:11:21 -07:00
|
|
|
|
2001-02-17 00:15:22 +00:00
|
|
|
CHECK(parse2(pctx, type, ret));
|
2015-05-21 23:04:29 -07:00
|
|
|
pctx->buf_name = NULL;
|
2015-01-06 22:57:57 -08:00
|
|
|
|
2001-02-17 00:15:22 +00:00
|
|
|
cleanup:
|
|
|
|
return (result);
|
|
|
|
}
|
|
|
|
|
2010-08-11 18:14:20 +00:00
|
|
|
void
|
|
|
|
cfg_parser_attach(cfg_parser_t *src, cfg_parser_t **dest) {
|
|
|
|
REQUIRE(src != NULL);
|
|
|
|
REQUIRE(dest != NULL && *dest == NULL);
|
2016-10-10 17:11:21 -07:00
|
|
|
|
2018-08-17 15:16:59 +02:00
|
|
|
isc_refcount_increment(&src->references);
|
2010-08-11 18:14:20 +00:00
|
|
|
*dest = src;
|
|
|
|
}
|
|
|
|
|
2001-02-15 04:14:15 +00:00
|
|
|
void
|
|
|
|
cfg_parser_destroy(cfg_parser_t **pctxp) {
|
2016-10-10 17:11:21 -07:00
|
|
|
cfg_parser_t *pctx;
|
2010-08-11 18:14:20 +00:00
|
|
|
|
2016-10-10 17:11:21 -07:00
|
|
|
REQUIRE(pctxp != NULL && *pctxp != NULL);
|
|
|
|
pctx = *pctxp;
|
|
|
|
*pctxp = NULL;
|
|
|
|
|
2018-08-17 15:16:59 +02:00
|
|
|
if (isc_refcount_decrement(&pctx->references) == 1) {
|
2010-08-11 18:14:20 +00:00
|
|
|
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);
|
2013-03-08 14:38:03 +11:00
|
|
|
isc_mem_putanddetach(&pctx->mctx, pctx, sizeof(*pctx));
|
2010-08-11 18:14:20 +00:00
|
|
|
}
|
2001-02-15 04:14:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* void
|
|
|
|
*/
|
2002-01-04 02:32:16 +00:00
|
|
|
isc_result_t
|
|
|
|
cfg_parse_void(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
|
2016-10-10 17:11:21 -07:00
|
|
|
REQUIRE(pctx != NULL);
|
|
|
|
REQUIRE(ret != NULL && *ret == NULL);
|
|
|
|
|
2001-02-15 04:14:15 +00:00
|
|
|
UNUSED(type);
|
2016-10-10 17:11:21 -07:00
|
|
|
|
2002-01-04 02:32:16 +00:00
|
|
|
return (cfg_create_obj(pctx, &cfg_type_void, ret));
|
2001-02-15 04:14:15 +00:00
|
|
|
}
|
|
|
|
|
2002-01-04 02:32:16 +00:00
|
|
|
void
|
2006-02-28 02:39:52 +00:00
|
|
|
cfg_print_void(cfg_printer_t *pctx, const cfg_obj_t *obj) {
|
2016-10-10 17:11:21 -07:00
|
|
|
REQUIRE(pctx != NULL);
|
|
|
|
REQUIRE(obj != NULL);
|
|
|
|
|
2001-02-15 04:14:15 +00:00
|
|
|
UNUSED(pctx);
|
|
|
|
UNUSED(obj);
|
|
|
|
}
|
2001-02-23 00:15:55 +00:00
|
|
|
|
2002-01-04 02:32:16 +00:00
|
|
|
void
|
|
|
|
cfg_doc_void(cfg_printer_t *pctx, const cfg_type_t *type) {
|
2016-10-10 17:11:21 -07:00
|
|
|
REQUIRE(pctx != NULL);
|
|
|
|
REQUIRE(type != NULL);
|
|
|
|
|
2002-01-04 02:32:16 +00:00
|
|
|
UNUSED(pctx);
|
|
|
|
UNUSED(type);
|
|
|
|
}
|
|
|
|
|
2018-04-17 08:29:14 -07:00
|
|
|
bool
|
2006-02-28 02:39:52 +00:00
|
|
|
cfg_obj_isvoid(const cfg_obj_t *obj) {
|
2001-02-23 00:15:55 +00:00
|
|
|
REQUIRE(obj != NULL);
|
2018-04-17 08:29:14 -07:00
|
|
|
return (obj->type->rep == &cfg_rep_void);
|
2001-02-23 00:15:55 +00:00
|
|
|
}
|
|
|
|
|
2021-06-10 08:06:48 +02:00
|
|
|
cfg_type_t cfg_type_void = { "void", cfg_parse_void, cfg_print_void,
|
|
|
|
cfg_doc_void, &cfg_rep_void, NULL };
|
2001-02-15 04:14:15 +00:00
|
|
|
|
2015-09-28 11:08:50 +02:00
|
|
|
/*
|
|
|
|
* percentage
|
|
|
|
*/
|
|
|
|
isc_result_t
|
|
|
|
cfg_parse_percentage(cfg_parser_t *pctx, const cfg_type_t *type,
|
|
|
|
cfg_obj_t **ret) {
|
|
|
|
char *endp;
|
|
|
|
isc_result_t result;
|
|
|
|
cfg_obj_t *obj = NULL;
|
2018-03-28 14:19:37 +02:00
|
|
|
uint64_t percent;
|
2015-09-28 11:08:50 +02:00
|
|
|
|
2016-10-10 17:11:21 -07:00
|
|
|
REQUIRE(pctx != NULL);
|
|
|
|
REQUIRE(ret != NULL && *ret == NULL);
|
|
|
|
|
2015-09-28 11:08:50 +02:00
|
|
|
UNUSED(type);
|
|
|
|
|
|
|
|
CHECK(cfg_gettoken(pctx, 0));
|
|
|
|
if (pctx->token.type != isc_tokentype_string) {
|
|
|
|
cfg_parser_error(pctx, CFG_LOG_NEAR, "expected percentage");
|
|
|
|
return (ISC_R_UNEXPECTEDTOKEN);
|
|
|
|
}
|
|
|
|
|
2018-03-21 16:09:08 +00:00
|
|
|
percent = strtoull(TOKEN_STRING(pctx), &endp, 10);
|
2015-09-28 11:08:50 +02:00
|
|
|
if (*endp != '%' || *(endp + 1) != 0) {
|
|
|
|
cfg_parser_error(pctx, CFG_LOG_NEAR, "expected percentage");
|
|
|
|
return (ISC_R_UNEXPECTEDTOKEN);
|
|
|
|
}
|
|
|
|
|
|
|
|
CHECK(cfg_create_obj(pctx, &cfg_type_percentage, &obj));
|
2018-03-28 14:19:37 +02:00
|
|
|
obj->value.uint32 = (uint32_t)percent;
|
2015-09-28 11:08:50 +02:00
|
|
|
*ret = obj;
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
return (result);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
cfg_print_percentage(cfg_printer_t *pctx, const cfg_obj_t *obj) {
|
|
|
|
char buf[64];
|
|
|
|
int n;
|
|
|
|
|
2016-10-10 17:11:21 -07:00
|
|
|
REQUIRE(pctx != NULL);
|
|
|
|
REQUIRE(obj != NULL);
|
|
|
|
|
2015-09-28 11:08:50 +02:00
|
|
|
n = snprintf(buf, sizeof(buf), "%u%%", obj->value.uint32);
|
|
|
|
INSIST(n > 0 && (size_t)n < sizeof(buf));
|
|
|
|
cfg_print_chars(pctx, buf, strlen(buf));
|
|
|
|
}
|
|
|
|
|
2018-03-28 14:19:37 +02:00
|
|
|
uint32_t
|
2015-09-28 11:08:50 +02:00
|
|
|
cfg_obj_aspercentage(const cfg_obj_t *obj) {
|
|
|
|
REQUIRE(obj != NULL && obj->type->rep == &cfg_rep_percentage);
|
|
|
|
return (obj->value.uint32);
|
|
|
|
}
|
|
|
|
|
2021-06-10 08:06:48 +02:00
|
|
|
cfg_type_t cfg_type_percentage = { "percentage", cfg_parse_percentage,
|
|
|
|
cfg_print_percentage, cfg_doc_terminal,
|
|
|
|
&cfg_rep_percentage, NULL };
|
2015-09-28 11:08:50 +02:00
|
|
|
|
2018-04-17 08:29:14 -07:00
|
|
|
bool
|
2015-09-28 11:08:50 +02:00
|
|
|
cfg_obj_ispercentage(const cfg_obj_t *obj) {
|
|
|
|
REQUIRE(obj != NULL);
|
2018-04-17 08:29:14 -07:00
|
|
|
return (obj->type->rep == &cfg_rep_percentage);
|
2015-09-28 11:08:50 +02:00
|
|
|
}
|
|
|
|
|
2015-07-08 22:53:39 -07:00
|
|
|
/*
|
|
|
|
* 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;
|
|
|
|
|
2016-10-10 17:11:21 -07:00
|
|
|
REQUIRE(pctx != NULL);
|
|
|
|
REQUIRE(ret != NULL && *ret == NULL);
|
|
|
|
|
2015-07-08 22:53:39 -07:00
|
|
|
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;
|
|
|
|
|
2016-10-10 17:11:21 -07:00
|
|
|
REQUIRE(pctx != NULL);
|
|
|
|
REQUIRE(obj != NULL);
|
|
|
|
|
2015-07-08 22:53:39 -07:00
|
|
|
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));
|
|
|
|
}
|
|
|
|
|
2018-03-28 14:19:37 +02:00
|
|
|
uint32_t
|
2015-07-08 22:53:39 -07:00
|
|
|
cfg_obj_asfixedpoint(const cfg_obj_t *obj) {
|
|
|
|
REQUIRE(obj != NULL && obj->type->rep == &cfg_rep_fixedpoint);
|
|
|
|
return (obj->value.uint32);
|
|
|
|
}
|
|
|
|
|
2021-06-10 08:06:48 +02:00
|
|
|
cfg_type_t cfg_type_fixedpoint = { "fixedpoint", cfg_parse_fixedpoint,
|
|
|
|
cfg_print_fixedpoint, cfg_doc_terminal,
|
|
|
|
&cfg_rep_fixedpoint, NULL };
|
2001-02-15 04:14:15 +00:00
|
|
|
|
2018-04-17 08:29:14 -07:00
|
|
|
bool
|
2015-09-28 11:08:50 +02:00
|
|
|
cfg_obj_isfixedpoint(const cfg_obj_t *obj) {
|
|
|
|
REQUIRE(obj != NULL);
|
2018-04-17 08:29:14 -07:00
|
|
|
return (obj->type->rep == &cfg_rep_fixedpoint);
|
2015-09-28 11:08:50 +02:00
|
|
|
}
|
|
|
|
|
2001-02-15 04:14:15 +00:00
|
|
|
/*
|
|
|
|
* uint32
|
|
|
|
*/
|
2002-01-04 02:32:16 +00:00
|
|
|
isc_result_t
|
|
|
|
cfg_parse_uint32(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
|
2008-09-25 04:02:39 +00:00
|
|
|
isc_result_t result;
|
2001-02-15 04:14:15 +00:00
|
|
|
cfg_obj_t *obj = NULL;
|
2016-10-10 17:11:21 -07:00
|
|
|
|
|
|
|
REQUIRE(pctx != NULL);
|
|
|
|
REQUIRE(ret != NULL && *ret == NULL);
|
|
|
|
|
2001-02-15 04:14:15 +00:00
|
|
|
UNUSED(type);
|
|
|
|
|
2001-03-03 02:18:13 +00:00
|
|
|
CHECK(cfg_gettoken(pctx, ISC_LEXOPT_NUMBER | ISC_LEXOPT_CNUMBER));
|
2001-02-15 04:14:15 +00:00
|
|
|
if (pctx->token.type != isc_tokentype_number) {
|
2002-01-04 02:32:16 +00:00
|
|
|
cfg_parser_error(pctx, CFG_LOG_NEAR, "expected number");
|
2001-02-15 04:14:15 +00:00
|
|
|
return (ISC_R_UNEXPECTEDTOKEN);
|
|
|
|
}
|
|
|
|
|
2002-01-04 02:32:16 +00:00
|
|
|
CHECK(cfg_create_obj(pctx, &cfg_type_uint32, &obj));
|
2001-02-15 04:14:15 +00:00
|
|
|
|
|
|
|
obj->value.uint32 = pctx->token.value.as_ulong;
|
|
|
|
*ret = obj;
|
|
|
|
cleanup:
|
|
|
|
return (result);
|
|
|
|
}
|
|
|
|
|
2002-01-04 02:32:16 +00:00
|
|
|
void
|
|
|
|
cfg_print_cstr(cfg_printer_t *pctx, const char *s) {
|
|
|
|
cfg_print_chars(pctx, s, strlen(s));
|
2001-07-31 20:07:48 +00:00
|
|
|
}
|
|
|
|
|
2002-01-04 02:32:16 +00:00
|
|
|
void
|
|
|
|
cfg_print_rawuint(cfg_printer_t *pctx, unsigned int u) {
|
2001-02-15 04:14:15 +00:00
|
|
|
char buf[32];
|
2016-10-10 17:11:21 -07:00
|
|
|
|
2001-03-03 02:18:13 +00:00
|
|
|
snprintf(buf, sizeof(buf), "%u", u);
|
2002-01-04 02:32:16 +00:00
|
|
|
cfg_print_cstr(pctx, buf);
|
2001-02-15 04:14:15 +00:00
|
|
|
}
|
|
|
|
|
2002-01-04 02:32:16 +00:00
|
|
|
void
|
2006-02-28 02:39:52 +00:00
|
|
|
cfg_print_uint32(cfg_printer_t *pctx, const cfg_obj_t *obj) {
|
2002-01-04 02:32:16 +00:00
|
|
|
cfg_print_rawuint(pctx, obj->value.uint32);
|
2001-02-15 04:14:15 +00:00
|
|
|
}
|
|
|
|
|
2018-04-17 08:29:14 -07:00
|
|
|
bool
|
2006-02-28 02:39:52 +00:00
|
|
|
cfg_obj_isuint32(const cfg_obj_t *obj) {
|
2001-02-23 00:15:55 +00:00
|
|
|
REQUIRE(obj != NULL);
|
2018-04-17 08:29:14 -07:00
|
|
|
return (obj->type->rep == &cfg_rep_uint32);
|
2001-02-23 00:15:55 +00:00
|
|
|
}
|
|
|
|
|
2018-03-28 14:19:37 +02:00
|
|
|
uint32_t
|
2006-02-28 02:39:52 +00:00
|
|
|
cfg_obj_asuint32(const cfg_obj_t *obj) {
|
2001-02-15 04:14:15 +00:00
|
|
|
REQUIRE(obj != NULL && obj->type->rep == &cfg_rep_uint32);
|
|
|
|
return (obj->value.uint32);
|
|
|
|
}
|
|
|
|
|
2021-06-10 08:06:48 +02:00
|
|
|
cfg_type_t cfg_type_uint32 = { "integer", cfg_parse_uint32,
|
|
|
|
cfg_print_uint32, cfg_doc_terminal,
|
|
|
|
&cfg_rep_uint32, NULL };
|
2001-02-15 04:14:15 +00:00
|
|
|
|
2001-03-03 02:18:13 +00:00
|
|
|
/*
|
|
|
|
* uint64
|
|
|
|
*/
|
2018-04-17 08:29:14 -07:00
|
|
|
bool
|
2006-02-28 02:39:52 +00:00
|
|
|
cfg_obj_isuint64(const cfg_obj_t *obj) {
|
2001-03-03 02:18:13 +00:00
|
|
|
REQUIRE(obj != NULL);
|
2018-04-17 08:29:14 -07:00
|
|
|
return (obj->type->rep == &cfg_rep_uint64);
|
2001-03-03 02:18:13 +00:00
|
|
|
}
|
|
|
|
|
2018-03-28 14:19:37 +02:00
|
|
|
uint64_t
|
2006-02-28 02:39:52 +00:00
|
|
|
cfg_obj_asuint64(const cfg_obj_t *obj) {
|
2001-03-03 02:18:13 +00:00
|
|
|
REQUIRE(obj != NULL && obj->type->rep == &cfg_rep_uint64);
|
|
|
|
return (obj->value.uint64);
|
|
|
|
}
|
|
|
|
|
2002-01-04 02:32:16 +00:00
|
|
|
void
|
2006-02-28 02:39:52 +00:00
|
|
|
cfg_print_uint64(cfg_printer_t *pctx, const cfg_obj_t *obj) {
|
2001-03-03 02:18:13 +00:00
|
|
|
char buf[32];
|
2016-10-10 17:11:21 -07:00
|
|
|
|
2018-03-28 14:56:40 +02:00
|
|
|
snprintf(buf, sizeof(buf), "%" PRIu64, obj->value.uint64);
|
2002-01-04 02:32:16 +00:00
|
|
|
cfg_print_cstr(pctx, buf);
|
2001-03-03 02:18:13 +00:00
|
|
|
}
|
|
|
|
|
2021-06-10 08:06:48 +02:00
|
|
|
cfg_type_t cfg_type_uint64 = { "64_bit_integer", NULL,
|
|
|
|
cfg_print_uint64, cfg_doc_terminal,
|
|
|
|
&cfg_rep_uint64, NULL };
|
2001-03-03 02:18:13 +00:00
|
|
|
|
2019-09-02 15:46:28 +02:00
|
|
|
/*
|
|
|
|
* Get the number of digits in a number.
|
|
|
|
*/
|
|
|
|
static size_t
|
2019-10-30 17:40:08 +01:00
|
|
|
numlen(uint32_t num) {
|
|
|
|
uint32_t period = num;
|
2019-09-02 15:46:28 +02:00
|
|
|
size_t count = 0;
|
|
|
|
|
|
|
|
if (period == 0) {
|
2020-02-06 10:28:53 -08:00
|
|
|
return (1);
|
2019-09-02 15:46:28 +02:00
|
|
|
}
|
|
|
|
while (period > 0) {
|
|
|
|
count++;
|
|
|
|
period /= 10;
|
|
|
|
}
|
|
|
|
return (count);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* duration
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
cfg_print_duration(cfg_printer_t *pctx, const cfg_obj_t *obj) {
|
Handle large numbers when parsing/printing a duration
The isccfg_duration_fromtext() function is truncating large numbers
to 32 bits instead of capping or rejecting them, i.e. 64424509445,
which is 0xf00000005, gets parsed as 32-bit value 5 (0x00000005).
Fail parsing a duration if any of its components is bigger than
32 bits. Using those kind of big numbers has no practical use case
for a duration.
The isccfg_duration_toseconds() function can overflow the 32 bit
seconds variable when calculating the duration from its component
parts.
To avoid that, use 64-bit calculation and return UINT32_MAX if the
calculated value is bigger than UINT32_MAX. Again, a number this big
has no practical use case anyway.
The buffer for the generated duration string is limited to 64 bytes,
which, in theory, is smaller than the longest possible generated
duration string.
Use 80 bytes instead, calculated by the '7 x (10 + 1) + 3' formula,
where '7' is the count of the duration's parts (year, month, etc.), '10'
is their maximum length when printed as a decimal number, '1' is their
indicator character (Y, M, etc.), and 3 is two more indicators (P and T)
and the terminating NUL character.
2022-10-17 08:45:45 +00:00
|
|
|
char buf[CFG_DURATION_MAXLEN];
|
2019-09-02 15:46:28 +02:00
|
|
|
char *str;
|
|
|
|
const char *indicators = "YMWDHMS";
|
|
|
|
int count, i;
|
Fix a logical bug in cfg_print_duration()
The cfg_print_duration() function prints a ISO 8601 duration value
converted from an array of integers, where the parts of the date and
time are stored.
durationlen[6], which holds the "seconds" part of the duration, has
a special case in cfg_print_duration() to ensure that when there are
no values in the duration, the result still can be printed as "PT0S",
instead of just "P", so it can be a valid ISO 8601 duration value.
There is a logical error in one of the two special case code paths,
when it checks that no value from the "date" part is defined, and no
"hour" or "minute" from the "time" part are defined.
Because of the error, durationlen[6] can be used uninitialized, in
which case the second parameter passed to snprintf() (which is the
maximum allowed length) can contain a garbage value.
This can not be exploited because the buffer is still big enough to
hold the maximum possible amount of characters generated by the "%u%c"
format string.
Fix the logical bug, and initialize the 'durationlen' array to zeros
to be a little safer from other similar errors.
2022-10-17 08:45:09 +00:00
|
|
|
int durationlen[7] = { 0 };
|
2022-06-21 12:22:36 +02:00
|
|
|
isccfg_duration_t duration;
|
2019-09-02 15:46:28 +02:00
|
|
|
/*
|
|
|
|
* D ? The duration has a date part.
|
|
|
|
* T ? The duration has a time part.
|
|
|
|
*/
|
|
|
|
bool D = false, T = false;
|
|
|
|
|
|
|
|
REQUIRE(pctx != NULL);
|
|
|
|
REQUIRE(obj != NULL);
|
|
|
|
|
|
|
|
duration = obj->value.duration;
|
|
|
|
|
|
|
|
/* If this is not an ISO 8601 duration, just print it as a number. */
|
|
|
|
if (!duration.iso8601) {
|
2019-12-06 13:12:06 +01:00
|
|
|
cfg_print_rawuint(pctx, duration.parts[6]);
|
|
|
|
return;
|
2019-09-02 15:46:28 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Calculate length of string. */
|
|
|
|
buf[0] = 'P';
|
|
|
|
buf[1] = '\0';
|
|
|
|
str = &buf[1];
|
|
|
|
count = 2;
|
|
|
|
for (i = 0; i < 6; i++) {
|
|
|
|
if (duration.parts[i] > 0) {
|
|
|
|
durationlen[i] = 1 + numlen(duration.parts[i]);
|
|
|
|
if (i < 4) {
|
|
|
|
D = true;
|
|
|
|
} else {
|
|
|
|
T = true;
|
|
|
|
}
|
Fix a logical bug in cfg_print_duration()
The cfg_print_duration() function prints a ISO 8601 duration value
converted from an array of integers, where the parts of the date and
time are stored.
durationlen[6], which holds the "seconds" part of the duration, has
a special case in cfg_print_duration() to ensure that when there are
no values in the duration, the result still can be printed as "PT0S",
instead of just "P", so it can be a valid ISO 8601 duration value.
There is a logical error in one of the two special case code paths,
when it checks that no value from the "date" part is defined, and no
"hour" or "minute" from the "time" part are defined.
Because of the error, durationlen[6] can be used uninitialized, in
which case the second parameter passed to snprintf() (which is the
maximum allowed length) can contain a garbage value.
This can not be exploited because the buffer is still big enough to
hold the maximum possible amount of characters generated by the "%u%c"
format string.
Fix the logical bug, and initialize the 'durationlen' array to zeros
to be a little safer from other similar errors.
2022-10-17 08:45:09 +00:00
|
|
|
count += durationlen[i];
|
2019-09-02 15:46:28 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
* Special case for seconds which is not taken into account in the
|
|
|
|
* above for loop: Count the length of the seconds part if it is
|
|
|
|
* non-zero, or if all the other parts are also zero. In the latter
|
|
|
|
* case this function will print "PT0S".
|
|
|
|
*/
|
|
|
|
if (duration.parts[6] > 0 ||
|
2022-11-02 19:33:14 +01:00
|
|
|
(!D && !duration.parts[4] && !duration.parts[5]))
|
|
|
|
{
|
2019-09-02 15:46:28 +02:00
|
|
|
durationlen[6] = 1 + numlen(duration.parts[6]);
|
|
|
|
T = true;
|
|
|
|
count += durationlen[6];
|
|
|
|
}
|
|
|
|
/* Add one character for the time indicator. */
|
|
|
|
if (T) {
|
|
|
|
count++;
|
|
|
|
}
|
Handle large numbers when parsing/printing a duration
The isccfg_duration_fromtext() function is truncating large numbers
to 32 bits instead of capping or rejecting them, i.e. 64424509445,
which is 0xf00000005, gets parsed as 32-bit value 5 (0x00000005).
Fail parsing a duration if any of its components is bigger than
32 bits. Using those kind of big numbers has no practical use case
for a duration.
The isccfg_duration_toseconds() function can overflow the 32 bit
seconds variable when calculating the duration from its component
parts.
To avoid that, use 64-bit calculation and return UINT32_MAX if the
calculated value is bigger than UINT32_MAX. Again, a number this big
has no practical use case anyway.
The buffer for the generated duration string is limited to 64 bytes,
which, in theory, is smaller than the longest possible generated
duration string.
Use 80 bytes instead, calculated by the '7 x (10 + 1) + 3' formula,
where '7' is the count of the duration's parts (year, month, etc.), '10'
is their maximum length when printed as a decimal number, '1' is their
indicator character (Y, M, etc.), and 3 is two more indicators (P and T)
and the terminating NUL character.
2022-10-17 08:45:45 +00:00
|
|
|
INSIST(count < CFG_DURATION_MAXLEN);
|
2019-09-02 15:46:28 +02:00
|
|
|
|
|
|
|
/* Now print the duration. */
|
|
|
|
for (i = 0; i < 6; i++) {
|
|
|
|
/*
|
|
|
|
* We don't check here if weeks and other time indicator are
|
|
|
|
* used mutually exclusively.
|
|
|
|
*/
|
|
|
|
if (duration.parts[i] > 0) {
|
|
|
|
snprintf(str, durationlen[i] + 2, "%u%c",
|
|
|
|
(uint32_t)duration.parts[i], indicators[i]);
|
Fix an off-by-one error in cfg_print_duration()
The cfg_print_duration() checks added previously in the 'duration_test'
unit test uncovered a bug in cfg_print_duration().
When calculating the current 'str' pointer of the generated text in the
buffer 'buf', it erroneously adds 1 byte to compensate for that part's
indicator character. For example, to add 12 minutes, it needs to add
2 + 1 = 3 characters, where 2 is the length of "12", and 1 is the length
of "M" (for minute). The mistake was that the length of the indicator
is already included in 'durationlen[i]', so there is no need to
calculate it again.
In the result of this mistake the current pointer can advance further
than needed and end up after the zero-byte instead of right on it, which
essentially cuts off any further generated text. For example, for a
5 minutes and 30 seconds duration, instead of having this:
'P', 'T', '5', 'M', '3', '0', 'S', '\0'
The function generates this:
'P', 'T', '5', 'M', '\0', '3', '0', 'S', '\0'
Fix the bug by adding to 'str' just 'durationlen[i]' instead of
'durationlen[i] + 1'.
2022-10-17 08:45:26 +00:00
|
|
|
str += durationlen[i];
|
2019-09-02 15:46:28 +02:00
|
|
|
}
|
|
|
|
if (i == 3 && T) {
|
|
|
|
snprintf(str, 2, "T");
|
|
|
|
str += 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* Special case for seconds. */
|
|
|
|
if (duration.parts[6] > 0 ||
|
2022-11-02 19:33:14 +01:00
|
|
|
(!D && !duration.parts[4] && !duration.parts[5]))
|
|
|
|
{
|
2019-09-02 15:46:28 +02:00
|
|
|
snprintf(str, durationlen[6] + 2, "%u%c",
|
|
|
|
(uint32_t)duration.parts[6], indicators[6]);
|
|
|
|
}
|
|
|
|
cfg_print_chars(pctx, buf, strlen(buf));
|
|
|
|
}
|
|
|
|
|
2020-02-06 15:41:47 +01:00
|
|
|
void
|
|
|
|
cfg_print_duration_or_unlimited(cfg_printer_t *pctx, const cfg_obj_t *obj) {
|
2022-06-21 12:22:36 +02:00
|
|
|
isccfg_duration_t duration;
|
2020-02-06 15:41:47 +01:00
|
|
|
|
|
|
|
REQUIRE(pctx != NULL);
|
|
|
|
REQUIRE(obj != NULL);
|
|
|
|
|
|
|
|
duration = obj->value.duration;
|
|
|
|
|
|
|
|
if (duration.unlimited) {
|
|
|
|
cfg_print_cstr(pctx, "unlimited");
|
|
|
|
} else {
|
|
|
|
cfg_print_duration(pctx, obj);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-09-02 15:46:28 +02:00
|
|
|
bool
|
|
|
|
cfg_obj_isduration(const cfg_obj_t *obj) {
|
|
|
|
REQUIRE(obj != NULL);
|
|
|
|
return (obj->type->rep == &cfg_rep_duration);
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t
|
|
|
|
cfg_obj_asduration(const cfg_obj_t *obj) {
|
|
|
|
REQUIRE(obj != NULL && obj->type->rep == &cfg_rep_duration);
|
2022-06-27 16:31:43 +02:00
|
|
|
return isccfg_duration_toseconds(&(obj->value.duration));
|
2019-09-02 15:46:28 +02:00
|
|
|
}
|
|
|
|
|
2020-02-06 15:41:47 +01:00
|
|
|
static isc_result_t
|
2020-02-06 10:28:53 -08:00
|
|
|
parse_duration(cfg_parser_t *pctx, cfg_obj_t **ret) {
|
2019-09-02 15:46:28 +02:00
|
|
|
isc_result_t result;
|
|
|
|
cfg_obj_t *obj = NULL;
|
2022-06-21 12:22:36 +02:00
|
|
|
isccfg_duration_t duration;
|
2019-09-02 15:46:28 +02:00
|
|
|
|
2022-06-27 16:31:43 +02:00
|
|
|
result = isccfg_parse_duration(&pctx->token.value.as_textregion,
|
2022-06-21 12:22:36 +02:00
|
|
|
&duration);
|
2022-06-27 16:31:43 +02:00
|
|
|
|
2019-09-02 15:46:28 +02:00
|
|
|
if (result == ISC_R_RANGE) {
|
|
|
|
cfg_parser_error(pctx, CFG_LOG_NEAR,
|
|
|
|
"duration or TTL out of range");
|
|
|
|
return (result);
|
|
|
|
} else if (result != ISC_R_SUCCESS) {
|
|
|
|
goto cleanup;
|
|
|
|
}
|
2020-02-06 10:28:53 -08:00
|
|
|
|
2019-09-02 15:46:28 +02:00
|
|
|
CHECK(cfg_create_obj(pctx, &cfg_type_duration, &obj));
|
|
|
|
obj->value.duration = duration;
|
|
|
|
*ret = obj;
|
2020-02-06 10:28:53 -08:00
|
|
|
|
2019-09-02 15:46:28 +02:00
|
|
|
return (ISC_R_SUCCESS);
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
cfg_parser_error(pctx, CFG_LOG_NEAR,
|
|
|
|
"expected ISO 8601 duration or TTL value");
|
|
|
|
return (result);
|
|
|
|
}
|
|
|
|
|
2020-02-06 15:41:47 +01:00
|
|
|
isc_result_t
|
|
|
|
cfg_parse_duration(cfg_parser_t *pctx, const cfg_type_t *type,
|
|
|
|
cfg_obj_t **ret) {
|
|
|
|
isc_result_t result;
|
|
|
|
|
|
|
|
UNUSED(type);
|
|
|
|
|
|
|
|
CHECK(cfg_gettoken(pctx, 0));
|
|
|
|
if (pctx->token.type != isc_tokentype_string) {
|
|
|
|
result = ISC_R_UNEXPECTEDTOKEN;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2020-02-06 10:28:53 -08:00
|
|
|
return (parse_duration(pctx, ret));
|
2020-02-06 15:41:47 +01:00
|
|
|
|
|
|
|
cleanup:
|
|
|
|
cfg_parser_error(pctx, CFG_LOG_NEAR,
|
|
|
|
"expected ISO 8601 duration or TTL value");
|
|
|
|
return (result);
|
|
|
|
}
|
|
|
|
|
|
|
|
isc_result_t
|
|
|
|
cfg_parse_duration_or_unlimited(cfg_parser_t *pctx, const cfg_type_t *type,
|
|
|
|
cfg_obj_t **ret) {
|
|
|
|
isc_result_t result;
|
|
|
|
cfg_obj_t *obj = NULL;
|
2022-06-21 12:22:36 +02:00
|
|
|
isccfg_duration_t duration;
|
2020-02-06 15:41:47 +01:00
|
|
|
|
|
|
|
UNUSED(type);
|
|
|
|
|
|
|
|
CHECK(cfg_gettoken(pctx, 0));
|
|
|
|
if (pctx->token.type != isc_tokentype_string) {
|
|
|
|
result = ISC_R_UNEXPECTEDTOKEN;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (strcmp(TOKEN_STRING(pctx), "unlimited") == 0) {
|
|
|
|
for (int i = 0; i < 7; i++) {
|
|
|
|
duration.parts[i] = 0;
|
|
|
|
}
|
|
|
|
duration.iso8601 = false;
|
|
|
|
duration.unlimited = true;
|
|
|
|
|
|
|
|
CHECK(cfg_create_obj(pctx, &cfg_type_duration, &obj));
|
|
|
|
obj->value.duration = duration;
|
|
|
|
*ret = obj;
|
|
|
|
return (ISC_R_SUCCESS);
|
|
|
|
}
|
|
|
|
|
2020-02-06 10:28:53 -08:00
|
|
|
return (parse_duration(pctx, ret));
|
2020-02-06 15:41:47 +01:00
|
|
|
|
|
|
|
cleanup:
|
|
|
|
cfg_parser_error(pctx, CFG_LOG_NEAR,
|
|
|
|
"expected ISO 8601 duration, TTL value, or unlimited");
|
|
|
|
return (result);
|
|
|
|
}
|
|
|
|
|
2019-09-02 15:46:28 +02:00
|
|
|
/*%
|
|
|
|
* A duration as defined by ISO 8601 (P[n]Y[n]M[n]DT[n]H[n]M[n]S).
|
|
|
|
* - P is the duration indicator ("period") placed at the start.
|
|
|
|
* - Y is the year indicator that follows the value for the number of years.
|
|
|
|
* - M is the month indicator that follows the value for the number of months.
|
|
|
|
* - D is the day indicator that follows the value for the number of days.
|
|
|
|
* - T is the time indicator that precedes the time components.
|
|
|
|
* - H is the hour indicator that follows the value for the number of hours.
|
|
|
|
* - M is the minute indicator that follows the value for the number of
|
|
|
|
* minutes.
|
|
|
|
* - S is the second indicator that follows the value for the number of
|
|
|
|
* seconds.
|
|
|
|
*
|
|
|
|
* A duration can also be a TTL value (number + optional unit).
|
|
|
|
*/
|
2021-06-10 08:06:48 +02:00
|
|
|
cfg_type_t cfg_type_duration = { "duration", cfg_parse_duration,
|
|
|
|
cfg_print_duration, cfg_doc_terminal,
|
|
|
|
&cfg_rep_duration, NULL };
|
|
|
|
cfg_type_t cfg_type_duration_or_unlimited = { "duration_or_unlimited",
|
|
|
|
cfg_parse_duration_or_unlimited,
|
|
|
|
cfg_print_duration_or_unlimited,
|
|
|
|
cfg_doc_terminal,
|
|
|
|
&cfg_rep_duration,
|
|
|
|
NULL };
|
2019-09-02 15:46:28 +02:00
|
|
|
|
2001-09-01 01:41:40 +00:00
|
|
|
/*
|
2002-01-04 02:32:16 +00:00
|
|
|
* qstring (quoted string), ustring (unquoted string), astring
|
2019-09-02 15:46:28 +02:00
|
|
|
* (any string), sstring (secret string)
|
2001-02-15 04:14:15 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
/* Create a string object from a null-terminated C string. */
|
|
|
|
static isc_result_t
|
2001-07-23 00:23:30 +00:00
|
|
|
create_string(cfg_parser_t *pctx, const char *contents, const cfg_type_t *type,
|
2001-02-15 04:14:15 +00:00
|
|
|
cfg_obj_t **ret) {
|
|
|
|
isc_result_t result;
|
|
|
|
cfg_obj_t *obj = NULL;
|
|
|
|
int len;
|
|
|
|
|
2002-01-04 02:32:16 +00:00
|
|
|
CHECK(cfg_create_obj(pctx, type, &obj));
|
2001-02-15 04:14:15 +00:00
|
|
|
len = strlen(contents);
|
|
|
|
obj->value.string.length = len;
|
|
|
|
obj->value.string.base = isc_mem_get(pctx->mctx, len + 1);
|
|
|
|
if (obj->value.string.base == 0) {
|
2003-07-03 00:43:28 +00:00
|
|
|
isc_mem_put(pctx->mctx, obj, sizeof(*obj));
|
2001-02-15 04:14:15 +00:00
|
|
|
return (ISC_R_NOMEMORY);
|
|
|
|
}
|
2014-01-08 16:27:10 -08:00
|
|
|
memmove(obj->value.string.base, contents, len);
|
2001-02-15 04:14:15 +00:00
|
|
|
obj->value.string.base[len] = '\0';
|
|
|
|
|
|
|
|
*ret = obj;
|
|
|
|
cleanup:
|
|
|
|
return (result);
|
|
|
|
}
|
|
|
|
|
2002-01-04 02:32:16 +00:00
|
|
|
isc_result_t
|
|
|
|
cfg_parse_qstring(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
|
2008-09-25 04:02:39 +00:00
|
|
|
isc_result_t result;
|
2016-10-10 17:11:21 -07:00
|
|
|
|
|
|
|
REQUIRE(pctx != NULL);
|
|
|
|
REQUIRE(ret != NULL && *ret == NULL);
|
|
|
|
|
2001-02-15 04:14:15 +00:00
|
|
|
UNUSED(type);
|
|
|
|
|
2002-01-04 02:32:16 +00:00
|
|
|
CHECK(cfg_gettoken(pctx, CFG_LEXOPT_QSTRING));
|
2001-02-15 04:14:15 +00:00
|
|
|
if (pctx->token.type != isc_tokentype_qstring) {
|
2002-01-04 02:32:16 +00:00
|
|
|
cfg_parser_error(pctx, CFG_LOG_NEAR, "expected quoted string");
|
2001-02-15 04:14:15 +00:00
|
|
|
return (ISC_R_UNEXPECTEDTOKEN);
|
|
|
|
}
|
2016-10-10 17:11:21 -07:00
|
|
|
return (create_string(pctx, TOKEN_STRING(pctx), &cfg_type_qstring,
|
|
|
|
ret));
|
2001-02-15 04:14:15 +00:00
|
|
|
cleanup:
|
|
|
|
return (result);
|
|
|
|
}
|
|
|
|
|
|
|
|
static isc_result_t
|
2001-07-23 00:23:30 +00:00
|
|
|
parse_ustring(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
|
2008-09-25 04:02:39 +00:00
|
|
|
isc_result_t result;
|
2016-10-10 17:11:21 -07:00
|
|
|
|
2001-02-15 04:14:15 +00:00
|
|
|
UNUSED(type);
|
|
|
|
|
|
|
|
CHECK(cfg_gettoken(pctx, 0));
|
|
|
|
if (pctx->token.type != isc_tokentype_string) {
|
2002-01-04 02:32:16 +00:00
|
|
|
cfg_parser_error(pctx, CFG_LOG_NEAR,
|
|
|
|
"expected unquoted string");
|
2001-02-15 04:14:15 +00:00
|
|
|
return (ISC_R_UNEXPECTEDTOKEN);
|
|
|
|
}
|
|
|
|
return (create_string(pctx, TOKEN_STRING(pctx), &cfg_type_ustring,
|
|
|
|
ret));
|
|
|
|
cleanup:
|
|
|
|
return (result);
|
|
|
|
}
|
|
|
|
|
2002-01-04 02:32:16 +00:00
|
|
|
isc_result_t
|
2006-02-28 02:39:52 +00:00
|
|
|
cfg_parse_astring(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
|
2008-09-25 04:02:39 +00:00
|
|
|
isc_result_t result;
|
2016-10-10 17:11:21 -07:00
|
|
|
|
|
|
|
REQUIRE(pctx != NULL);
|
|
|
|
REQUIRE(ret != NULL && *ret == NULL);
|
|
|
|
|
2001-02-15 04:14:15 +00:00
|
|
|
UNUSED(type);
|
|
|
|
|
|
|
|
CHECK(cfg_getstringtoken(pctx));
|
|
|
|
return (create_string(pctx, TOKEN_STRING(pctx), &cfg_type_qstring,
|
|
|
|
ret));
|
|
|
|
cleanup:
|
|
|
|
return (result);
|
|
|
|
}
|
|
|
|
|
2014-01-10 16:56:36 +11:00
|
|
|
isc_result_t
|
|
|
|
cfg_parse_sstring(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
|
|
|
|
isc_result_t result;
|
2016-10-10 17:11:21 -07:00
|
|
|
|
|
|
|
REQUIRE(pctx != NULL);
|
|
|
|
REQUIRE(ret != NULL && *ret == NULL);
|
|
|
|
|
2014-01-10 16:56:36 +11:00
|
|
|
UNUSED(type);
|
|
|
|
|
|
|
|
CHECK(cfg_getstringtoken(pctx));
|
|
|
|
return (create_string(pctx, TOKEN_STRING(pctx), &cfg_type_sstring,
|
|
|
|
ret));
|
|
|
|
cleanup:
|
|
|
|
return (result);
|
|
|
|
}
|
|
|
|
|
2015-09-28 23:12:35 -07:00
|
|
|
static isc_result_t
|
|
|
|
parse_btext(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
|
|
|
|
isc_result_t result;
|
2016-10-10 17:11:21 -07:00
|
|
|
|
2015-09-28 23:12:35 -07:00
|
|
|
UNUSED(type);
|
|
|
|
|
|
|
|
CHECK(cfg_gettoken(pctx, ISC_LEXOPT_BTEXT));
|
|
|
|
if (pctx->token.type != isc_tokentype_btext) {
|
|
|
|
cfg_parser_error(pctx, CFG_LOG_NEAR, "expected bracketed text");
|
|
|
|
return (ISC_R_UNEXPECTEDTOKEN);
|
|
|
|
}
|
|
|
|
return (create_string(pctx, TOKEN_STRING(pctx),
|
|
|
|
&cfg_type_bracketed_text, ret));
|
|
|
|
cleanup:
|
|
|
|
return (result);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
print_btext(cfg_printer_t *pctx, const cfg_obj_t *obj) {
|
2016-11-29 15:28:28 +11:00
|
|
|
/*
|
|
|
|
* We need to print "{" instead of running print_open()
|
|
|
|
* in order to preserve the exact original formatting
|
|
|
|
* of the bracketed text. But we increment the indent value
|
|
|
|
* so that print_close() will leave us back in our original
|
|
|
|
* state.
|
|
|
|
*/
|
|
|
|
pctx->indent++;
|
2015-09-28 23:12:35 -07:00
|
|
|
cfg_print_cstr(pctx, "{");
|
|
|
|
cfg_print_chars(pctx, obj->value.string.base, obj->value.string.length);
|
|
|
|
print_close(pctx);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
doc_btext(cfg_printer_t *pctx, const cfg_type_t *type) {
|
|
|
|
UNUSED(type);
|
|
|
|
|
2016-11-02 10:04:57 +11:00
|
|
|
cfg_print_cstr(pctx, "{ <unspecified-text> }");
|
2015-09-28 23:12:35 -07:00
|
|
|
}
|
|
|
|
|
2018-04-17 08:29:14 -07:00
|
|
|
bool
|
2002-01-04 02:32:16 +00:00
|
|
|
cfg_is_enum(const char *s, const char *const *enums) {
|
2001-07-23 00:23:30 +00:00
|
|
|
const char *const *p;
|
2016-10-10 17:11:21 -07:00
|
|
|
|
|
|
|
REQUIRE(s != NULL);
|
|
|
|
REQUIRE(enums != NULL);
|
|
|
|
|
2001-03-02 01:10:51 +00:00
|
|
|
for (p = enums; *p != NULL; p++) {
|
|
|
|
if (strcasecmp(*p, s) == 0) {
|
2018-04-17 08:29:14 -07:00
|
|
|
return (true);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2001-03-02 01:10:51 +00:00
|
|
|
}
|
2018-04-17 08:29:14 -07:00
|
|
|
return (false);
|
2001-03-02 20:00:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static isc_result_t
|
2001-07-23 00:23:30 +00:00
|
|
|
check_enum(cfg_parser_t *pctx, cfg_obj_t *obj, const char *const *enums) {
|
2001-03-02 20:00:17 +00:00
|
|
|
const char *s = obj->value.string.base;
|
2016-10-10 17:11:21 -07:00
|
|
|
|
2002-01-04 02:32:16 +00:00
|
|
|
if (cfg_is_enum(s, enums)) {
|
2001-03-02 20:00:17 +00:00
|
|
|
return (ISC_R_SUCCESS);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2002-01-04 02:32:16 +00:00
|
|
|
cfg_parser_error(pctx, 0, "'%s' unexpected", s);
|
2001-03-02 01:10:51 +00:00
|
|
|
return (ISC_R_UNEXPECTEDTOKEN);
|
|
|
|
}
|
|
|
|
|
2002-01-04 02:32:16 +00:00
|
|
|
isc_result_t
|
|
|
|
cfg_parse_enum(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
|
2008-09-25 04:02:39 +00:00
|
|
|
isc_result_t result;
|
2001-03-02 01:10:51 +00:00
|
|
|
cfg_obj_t *obj = NULL;
|
2016-10-10 17:11:21 -07:00
|
|
|
|
|
|
|
REQUIRE(pctx != NULL);
|
|
|
|
REQUIRE(type != NULL);
|
|
|
|
REQUIRE(ret != NULL && *ret == NULL);
|
|
|
|
|
2001-03-02 01:10:51 +00:00
|
|
|
CHECK(parse_ustring(pctx, NULL, &obj));
|
|
|
|
CHECK(check_enum(pctx, obj, type->of));
|
|
|
|
*ret = obj;
|
|
|
|
return (ISC_R_SUCCESS);
|
|
|
|
cleanup:
|
2008-09-25 04:02:39 +00:00
|
|
|
CLEANUP_OBJ(obj);
|
2001-03-02 01:10:51 +00:00
|
|
|
return (result);
|
|
|
|
}
|
|
|
|
|
2002-01-04 02:32:16 +00:00
|
|
|
void
|
|
|
|
cfg_doc_enum(cfg_printer_t *pctx, const cfg_type_t *type) {
|
|
|
|
const char *const *p;
|
2016-10-10 17:11:21 -07:00
|
|
|
|
|
|
|
REQUIRE(pctx != NULL);
|
|
|
|
REQUIRE(type != NULL);
|
|
|
|
|
2015-01-06 22:57:57 -08:00
|
|
|
cfg_print_cstr(pctx, "( ");
|
2002-01-04 02:32:16 +00:00
|
|
|
for (p = type->of; *p != NULL; p++) {
|
|
|
|
cfg_print_cstr(pctx, *p);
|
|
|
|
if (p[1] != NULL) {
|
2015-01-06 22:57:57 -08:00
|
|
|
cfg_print_cstr(pctx, " | ");
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2001-03-02 20:00:17 +00:00
|
|
|
}
|
2015-01-06 22:57:57 -08:00
|
|
|
cfg_print_cstr(pctx, " )");
|
2001-03-02 20:00:17 +00:00
|
|
|
}
|
|
|
|
|
2018-08-12 23:06:00 -07:00
|
|
|
isc_result_t
|
|
|
|
cfg_parse_enum_or_other(cfg_parser_t *pctx, const cfg_type_t *enumtype,
|
|
|
|
const cfg_type_t *othertype, cfg_obj_t **ret) {
|
|
|
|
isc_result_t result;
|
|
|
|
CHECK(cfg_peektoken(pctx, 0));
|
|
|
|
if (pctx->token.type == isc_tokentype_string &&
|
|
|
|
cfg_is_enum(TOKEN_STRING(pctx), enumtype->of))
|
|
|
|
{
|
|
|
|
CHECK(cfg_parse_enum(pctx, enumtype, ret));
|
|
|
|
} else {
|
|
|
|
CHECK(cfg_parse_obj(pctx, othertype, ret));
|
|
|
|
}
|
|
|
|
cleanup:
|
|
|
|
return (result);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
cfg_doc_enum_or_other(cfg_printer_t *pctx, const cfg_type_t *enumtype,
|
|
|
|
const cfg_type_t *othertype) {
|
|
|
|
const char *const *p;
|
|
|
|
bool first = true;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If othertype is cfg_type_void, it means that enumtype is
|
|
|
|
* optional.
|
|
|
|
*/
|
|
|
|
|
|
|
|
if (othertype == &cfg_type_void) {
|
|
|
|
cfg_print_cstr(pctx, "[ ");
|
|
|
|
}
|
|
|
|
cfg_print_cstr(pctx, "( ");
|
|
|
|
for (p = enumtype->of; *p != NULL; p++) {
|
|
|
|
if (!first) {
|
|
|
|
cfg_print_cstr(pctx, " | ");
|
|
|
|
}
|
|
|
|
first = false;
|
|
|
|
cfg_print_cstr(pctx, *p);
|
|
|
|
}
|
|
|
|
if (othertype != &cfg_type_void) {
|
|
|
|
if (!first) {
|
|
|
|
cfg_print_cstr(pctx, " | ");
|
|
|
|
}
|
|
|
|
cfg_doc_terminal(pctx, othertype);
|
|
|
|
}
|
|
|
|
cfg_print_cstr(pctx, " )");
|
|
|
|
if (othertype == &cfg_type_void) {
|
|
|
|
cfg_print_cstr(pctx, " ]");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2002-01-04 02:32:16 +00:00
|
|
|
void
|
2006-02-28 02:39:52 +00:00
|
|
|
cfg_print_ustring(cfg_printer_t *pctx, const cfg_obj_t *obj) {
|
2016-10-10 17:11:21 -07:00
|
|
|
REQUIRE(pctx != NULL);
|
|
|
|
REQUIRE(obj != NULL);
|
|
|
|
|
2002-01-04 02:32:16 +00:00
|
|
|
cfg_print_chars(pctx, obj->value.string.base, obj->value.string.length);
|
2001-02-15 04:14:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2006-02-28 02:39:52 +00:00
|
|
|
print_qstring(cfg_printer_t *pctx, const cfg_obj_t *obj) {
|
2015-01-06 22:57:57 -08:00
|
|
|
cfg_print_cstr(pctx, "\"");
|
2020-03-23 10:28:33 +11:00
|
|
|
for (size_t i = 0; i < obj->value.string.length; i++) {
|
|
|
|
if (obj->value.string.base[i] == '"') {
|
|
|
|
cfg_print_cstr(pctx, "\\");
|
|
|
|
}
|
|
|
|
cfg_print_chars(pctx, &obj->value.string.base[i], 1);
|
|
|
|
}
|
2015-01-06 22:57:57 -08:00
|
|
|
cfg_print_cstr(pctx, "\"");
|
2001-02-15 04:14:15 +00:00
|
|
|
}
|
|
|
|
|
2014-01-10 16:56:36 +11:00
|
|
|
static void
|
|
|
|
print_sstring(cfg_printer_t *pctx, const cfg_obj_t *obj) {
|
2015-01-06 22:57:57 -08:00
|
|
|
cfg_print_cstr(pctx, "\"");
|
2014-01-10 16:56:36 +11:00
|
|
|
if ((pctx->flags & CFG_PRINTER_XKEY) != 0) {
|
|
|
|
unsigned int len = obj->value.string.length;
|
|
|
|
while (len-- > 0) {
|
2015-01-06 22:57:57 -08:00
|
|
|
cfg_print_cstr(pctx, "?");
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2014-01-10 16:56:36 +11:00
|
|
|
} else {
|
|
|
|
cfg_print_ustring(pctx, obj);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2015-01-06 22:57:57 -08:00
|
|
|
cfg_print_cstr(pctx, "\"");
|
2014-01-10 16:56:36 +11:00
|
|
|
}
|
|
|
|
|
2001-02-15 04:14:15 +00:00
|
|
|
static void
|
|
|
|
free_string(cfg_parser_t *pctx, cfg_obj_t *obj) {
|
2003-07-03 00:43:28 +00:00
|
|
|
isc_mem_put(pctx->mctx, obj->value.string.base,
|
|
|
|
obj->value.string.length + 1);
|
2001-02-15 04:14:15 +00:00
|
|
|
}
|
|
|
|
|
2018-04-17 08:29:14 -07:00
|
|
|
bool
|
2006-02-28 02:39:52 +00:00
|
|
|
cfg_obj_isstring(const cfg_obj_t *obj) {
|
2001-02-23 00:15:55 +00:00
|
|
|
REQUIRE(obj != NULL);
|
2018-04-17 08:29:14 -07:00
|
|
|
return (obj->type->rep == &cfg_rep_string);
|
2001-02-23 00:15:55 +00:00
|
|
|
}
|
|
|
|
|
2005-08-23 02:36:11 +00:00
|
|
|
const char *
|
2006-02-28 02:39:52 +00:00
|
|
|
cfg_obj_asstring(const cfg_obj_t *obj) {
|
2001-02-15 04:14:15 +00:00
|
|
|
REQUIRE(obj != NULL && obj->type->rep == &cfg_rep_string);
|
|
|
|
return (obj->value.string.base);
|
|
|
|
}
|
|
|
|
|
2002-01-04 02:32:16 +00:00
|
|
|
/* Quoted string only */
|
2021-06-10 08:06:48 +02:00
|
|
|
cfg_type_t cfg_type_qstring = { "quoted_string", cfg_parse_qstring,
|
|
|
|
print_qstring, cfg_doc_terminal,
|
|
|
|
&cfg_rep_string, NULL };
|
2002-01-04 02:32:16 +00:00
|
|
|
|
|
|
|
/* Unquoted string only */
|
2021-06-10 08:06:48 +02:00
|
|
|
cfg_type_t cfg_type_ustring = { "string", parse_ustring,
|
|
|
|
cfg_print_ustring, cfg_doc_terminal,
|
|
|
|
&cfg_rep_string, NULL };
|
2002-01-04 02:32:16 +00:00
|
|
|
|
|
|
|
/* Any string (quoted or unquoted); printed with quotes */
|
2021-06-10 08:06:48 +02:00
|
|
|
cfg_type_t cfg_type_astring = { "string", cfg_parse_astring,
|
|
|
|
print_qstring, cfg_doc_terminal,
|
|
|
|
&cfg_rep_string, NULL };
|
2002-01-04 02:32:16 +00:00
|
|
|
|
2014-01-10 16:56:36 +11:00
|
|
|
/*
|
|
|
|
* Any string (quoted or unquoted); printed with quotes.
|
|
|
|
* If CFG_PRINTER_XKEY is set when printing the string will be '?' out.
|
|
|
|
*/
|
2021-06-10 08:06:48 +02:00
|
|
|
cfg_type_t cfg_type_sstring = { "string", cfg_parse_sstring,
|
|
|
|
print_sstring, cfg_doc_terminal,
|
|
|
|
&cfg_rep_string, NULL };
|
2014-01-10 16:56:36 +11:00
|
|
|
|
2015-09-28 23:12:35 -07:00
|
|
|
/*
|
|
|
|
* Text enclosed in brackets. Used to pass a block of configuration
|
|
|
|
* text to dynamic library or external application. Checked for
|
|
|
|
* bracket balance, but not otherwise parsed.
|
|
|
|
*/
|
2021-06-10 08:06:48 +02:00
|
|
|
cfg_type_t cfg_type_bracketed_text = { "bracketed_text", parse_btext,
|
|
|
|
print_btext, doc_btext,
|
|
|
|
&cfg_rep_string, NULL };
|
2015-09-28 23:12:35 -07:00
|
|
|
|
2019-06-27 21:08:20 -07:00
|
|
|
#if defined(HAVE_GEOIP2)
|
2018-12-07 12:50:03 +11:00
|
|
|
/*
|
|
|
|
* "geoip" ACL element:
|
|
|
|
* geoip [ db <database> ] search-type <string>
|
|
|
|
*/
|
|
|
|
static const char *geoiptype_enums[] = {
|
|
|
|
"area", "areacode", "asnum", "city", "continent",
|
|
|
|
"country", "country3", "countryname", "domain", "isp",
|
|
|
|
"metro", "metrocode", "netspeed", "org", "postal",
|
|
|
|
"postalcode", "region", "regionname", "timezone", "tz",
|
|
|
|
NULL
|
|
|
|
};
|
|
|
|
static cfg_type_t cfg_type_geoiptype = { "geoiptype", cfg_parse_enum,
|
|
|
|
cfg_print_ustring, cfg_doc_enum,
|
|
|
|
&cfg_rep_string, &geoiptype_enums };
|
|
|
|
|
|
|
|
static cfg_tuplefielddef_t geoip_fields[] = {
|
|
|
|
{ "negated", &cfg_type_void, 0 },
|
2019-06-11 20:32:21 -07:00
|
|
|
{ "db", &cfg_type_astring, 0 },
|
2018-12-07 12:50:03 +11:00
|
|
|
{ "subtype", &cfg_type_geoiptype, 0 },
|
|
|
|
{ "search", &cfg_type_astring, 0 },
|
|
|
|
{ NULL, NULL, 0 }
|
|
|
|
};
|
|
|
|
|
|
|
|
static cfg_type_t cfg_type_geoip = { "geoip", parse_geoip, print_geoip,
|
|
|
|
doc_geoip, &cfg_rep_tuple, geoip_fields };
|
|
|
|
|
|
|
|
static isc_result_t
|
|
|
|
parse_geoip(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
|
|
|
|
isc_result_t result;
|
|
|
|
cfg_obj_t *obj = NULL;
|
|
|
|
const cfg_tuplefielddef_t *fields = type->of;
|
|
|
|
|
|
|
|
CHECK(cfg_create_tuple(pctx, type, &obj));
|
|
|
|
CHECK(cfg_parse_void(pctx, NULL, &obj->value.tuple[0]));
|
|
|
|
|
|
|
|
/* Parse the optional "db" field. */
|
|
|
|
CHECK(cfg_peektoken(pctx, 0));
|
|
|
|
if (pctx->token.type == isc_tokentype_string) {
|
|
|
|
CHECK(cfg_gettoken(pctx, 0));
|
|
|
|
if (strcasecmp(TOKEN_STRING(pctx), "db") == 0 &&
|
2022-11-02 19:33:14 +01:00
|
|
|
obj->value.tuple[1] == NULL)
|
|
|
|
{
|
2018-12-07 12:50:03 +11:00
|
|
|
CHECK(cfg_parse_obj(pctx, fields[1].type,
|
|
|
|
&obj->value.tuple[1]));
|
|
|
|
} else {
|
|
|
|
CHECK(cfg_parse_void(pctx, NULL, &obj->value.tuple[1]));
|
|
|
|
cfg_ungettoken(pctx);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
CHECK(cfg_parse_obj(pctx, fields[2].type, &obj->value.tuple[2]));
|
|
|
|
CHECK(cfg_parse_obj(pctx, fields[3].type, &obj->value.tuple[3]));
|
|
|
|
|
|
|
|
*ret = obj;
|
|
|
|
return (ISC_R_SUCCESS);
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
CLEANUP_OBJ(obj);
|
|
|
|
return (result);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
print_geoip(cfg_printer_t *pctx, const cfg_obj_t *obj) {
|
|
|
|
if (obj->value.tuple[1]->type->print != cfg_print_void) {
|
|
|
|
cfg_print_cstr(pctx, " db ");
|
|
|
|
cfg_print_obj(pctx, obj->value.tuple[1]);
|
|
|
|
}
|
|
|
|
cfg_print_obj(pctx, obj->value.tuple[2]);
|
|
|
|
cfg_print_obj(pctx, obj->value.tuple[3]);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
doc_geoip(cfg_printer_t *pctx, const cfg_type_t *type) {
|
|
|
|
UNUSED(type);
|
|
|
|
cfg_print_cstr(pctx, "[ db ");
|
2019-06-11 20:32:21 -07:00
|
|
|
cfg_doc_obj(pctx, &cfg_type_astring);
|
2018-12-07 12:50:03 +11:00
|
|
|
cfg_print_cstr(pctx, " ]");
|
|
|
|
cfg_print_cstr(pctx, " ");
|
|
|
|
cfg_doc_enum(pctx, &cfg_type_geoiptype);
|
|
|
|
cfg_print_cstr(pctx, " ");
|
2019-06-11 20:32:21 -07:00
|
|
|
cfg_doc_obj(pctx, &cfg_type_astring);
|
2018-12-07 12:50:03 +11:00
|
|
|
}
|
2019-06-27 21:08:20 -07:00
|
|
|
#endif /* HAVE_GEOIP2 */
|
2018-12-07 12:50:03 +11:00
|
|
|
|
2018-08-12 23:06:00 -07:00
|
|
|
static cfg_type_t cfg_type_addrmatchelt;
|
|
|
|
static cfg_type_t cfg_type_negated;
|
|
|
|
|
|
|
|
static isc_result_t
|
|
|
|
parse_addrmatchelt(cfg_parser_t *pctx, const cfg_type_t *type,
|
|
|
|
cfg_obj_t **ret) {
|
|
|
|
isc_result_t result;
|
|
|
|
UNUSED(type);
|
|
|
|
|
|
|
|
CHECK(cfg_peektoken(pctx, CFG_LEXOPT_QSTRING));
|
|
|
|
|
|
|
|
if (pctx->token.type == isc_tokentype_string ||
|
|
|
|
pctx->token.type == isc_tokentype_qstring)
|
|
|
|
{
|
|
|
|
if (pctx->token.type == isc_tokentype_string &&
|
|
|
|
(strcasecmp(TOKEN_STRING(pctx), "key") == 0))
|
|
|
|
{
|
|
|
|
CHECK(cfg_parse_obj(pctx, &cfg_type_keyref, ret));
|
|
|
|
} else if (pctx->token.type == isc_tokentype_string &&
|
|
|
|
(strcasecmp(TOKEN_STRING(pctx), "geoip") == 0))
|
|
|
|
{
|
2019-06-27 21:08:20 -07:00
|
|
|
#if defined(HAVE_GEOIP2)
|
2018-08-12 23:06:00 -07:00
|
|
|
CHECK(cfg_gettoken(pctx, 0));
|
|
|
|
CHECK(cfg_parse_obj(pctx, &cfg_type_geoip, ret));
|
|
|
|
#else /* if defined(HAVE_GEOIP2) */
|
|
|
|
cfg_parser_error(pctx, CFG_LOG_NEAR,
|
|
|
|
"'geoip' "
|
|
|
|
"not supported in this build");
|
|
|
|
return (ISC_R_UNEXPECTEDTOKEN);
|
|
|
|
#endif /* if defined(HAVE_GEOIP2) */
|
|
|
|
} else {
|
|
|
|
if (cfg_lookingat_netaddr(
|
|
|
|
pctx, CFG_ADDR_V4OK | CFG_ADDR_V4PREFIXOK |
|
|
|
|
CFG_ADDR_V6OK))
|
|
|
|
{
|
|
|
|
CHECK(cfg_parse_netprefix(pctx, NULL, ret));
|
|
|
|
} else {
|
|
|
|
CHECK(cfg_parse_astring(pctx, NULL, ret));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else if (pctx->token.type == isc_tokentype_special) {
|
|
|
|
if (pctx->token.value.as_char == '{') {
|
|
|
|
/* Nested match list. */
|
|
|
|
CHECK(cfg_parse_obj(pctx, &cfg_type_bracketed_aml,
|
|
|
|
ret));
|
|
|
|
} else if (pctx->token.value.as_char == '!') {
|
|
|
|
CHECK(cfg_gettoken(pctx, 0)); /* read "!" */
|
|
|
|
CHECK(cfg_parse_obj(pctx, &cfg_type_negated, ret));
|
|
|
|
} else {
|
|
|
|
goto bad;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
bad:
|
|
|
|
cfg_parser_error(pctx, CFG_LOG_NEAR,
|
|
|
|
"expected IP match list element");
|
|
|
|
return (ISC_R_UNEXPECTEDTOKEN);
|
|
|
|
}
|
|
|
|
cleanup:
|
|
|
|
return (result);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*%
|
|
|
|
* A negated address match list element (like "! 10.0.0.1").
|
|
|
|
* Somewhat sneakily, the caller is expected to parse the
|
|
|
|
* "!", but not to print it.
|
|
|
|
*/
|
|
|
|
static cfg_tuplefielddef_t negated_fields[] = {
|
|
|
|
{ "negated", &cfg_type_addrmatchelt, 0 }, { NULL, NULL, 0 }
|
|
|
|
};
|
|
|
|
|
|
|
|
static void
|
|
|
|
print_negated(cfg_printer_t *pctx, const cfg_obj_t *obj) {
|
|
|
|
cfg_print_cstr(pctx, "!");
|
|
|
|
cfg_print_tuple(pctx, obj);
|
|
|
|
}
|
|
|
|
|
|
|
|
static cfg_type_t cfg_type_negated = { "negated", cfg_parse_tuple,
|
|
|
|
print_negated, NULL,
|
|
|
|
&cfg_rep_tuple, &negated_fields };
|
|
|
|
|
|
|
|
/*% An address match list element */
|
|
|
|
|
|
|
|
static cfg_type_t cfg_type_addrmatchelt = { "address_match_element",
|
|
|
|
parse_addrmatchelt,
|
|
|
|
NULL,
|
|
|
|
cfg_doc_terminal,
|
|
|
|
NULL,
|
|
|
|
NULL };
|
|
|
|
|
2018-09-14 12:32:36 -07:00
|
|
|
/*%
|
|
|
|
* A bracketed address match list
|
|
|
|
*/
|
2021-06-10 08:06:48 +02:00
|
|
|
cfg_type_t cfg_type_bracketed_aml = { "bracketed_aml",
|
|
|
|
cfg_parse_bracketed_list,
|
|
|
|
cfg_print_bracketed_list,
|
|
|
|
cfg_doc_bracketed_list,
|
|
|
|
&cfg_rep_list,
|
|
|
|
&cfg_type_addrmatchelt };
|
2018-08-12 23:06:00 -07:00
|
|
|
|
2018-08-12 11:19:36 -07:00
|
|
|
/*
|
|
|
|
* Optional bracketed text
|
|
|
|
*/
|
|
|
|
static isc_result_t
|
|
|
|
parse_optional_btext(cfg_parser_t *pctx, const cfg_type_t *type,
|
|
|
|
cfg_obj_t **ret) {
|
|
|
|
isc_result_t result;
|
|
|
|
|
|
|
|
UNUSED(type);
|
|
|
|
|
|
|
|
CHECK(cfg_peektoken(pctx, ISC_LEXOPT_BTEXT));
|
|
|
|
if (pctx->token.type == isc_tokentype_btext) {
|
|
|
|
CHECK(cfg_parse_obj(pctx, &cfg_type_bracketed_text, ret));
|
|
|
|
} else {
|
|
|
|
CHECK(cfg_parse_obj(pctx, &cfg_type_void, ret));
|
|
|
|
}
|
|
|
|
cleanup:
|
|
|
|
return (result);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
print_optional_btext(cfg_printer_t *pctx, const cfg_obj_t *obj) {
|
|
|
|
if (obj->type == &cfg_type_void) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
pctx->indent++;
|
|
|
|
cfg_print_cstr(pctx, "{");
|
|
|
|
cfg_print_chars(pctx, obj->value.string.base, obj->value.string.length);
|
|
|
|
print_close(pctx);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
doc_optional_btext(cfg_printer_t *pctx, const cfg_type_t *type) {
|
|
|
|
UNUSED(type);
|
|
|
|
|
|
|
|
cfg_print_cstr(pctx, "[ { <unspecified-text> } ]");
|
|
|
|
}
|
|
|
|
|
2021-06-10 08:06:48 +02:00
|
|
|
cfg_type_t cfg_type_optional_bracketed_text = { "optional_btext",
|
|
|
|
parse_optional_btext,
|
|
|
|
print_optional_btext,
|
|
|
|
doc_optional_btext,
|
|
|
|
NULL,
|
|
|
|
NULL };
|
2018-08-12 11:19:36 -07:00
|
|
|
|
2002-01-04 02:32:16 +00:00
|
|
|
/*
|
|
|
|
* Booleans
|
|
|
|
*/
|
|
|
|
|
2018-04-17 08:29:14 -07:00
|
|
|
bool
|
2006-02-28 02:39:52 +00:00
|
|
|
cfg_obj_isboolean(const cfg_obj_t *obj) {
|
2001-02-23 00:15:55 +00:00
|
|
|
REQUIRE(obj != NULL);
|
2018-04-17 08:29:14 -07:00
|
|
|
return (obj->type->rep == &cfg_rep_boolean);
|
2001-02-23 00:15:55 +00:00
|
|
|
}
|
|
|
|
|
2018-04-17 08:29:14 -07:00
|
|
|
bool
|
2006-02-28 02:39:52 +00:00
|
|
|
cfg_obj_asboolean(const cfg_obj_t *obj) {
|
2001-02-22 01:40:53 +00:00
|
|
|
REQUIRE(obj != NULL && obj->type->rep == &cfg_rep_boolean);
|
|
|
|
return (obj->value.boolean);
|
|
|
|
}
|
|
|
|
|
2011-01-03 23:45:08 +00:00
|
|
|
isc_result_t
|
|
|
|
cfg_parse_boolean(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
|
2008-09-25 04:02:39 +00:00
|
|
|
isc_result_t result;
|
2018-04-17 08:29:14 -07:00
|
|
|
bool value;
|
2001-02-15 04:14:15 +00:00
|
|
|
cfg_obj_t *obj = NULL;
|
2016-10-10 17:11:21 -07:00
|
|
|
|
|
|
|
REQUIRE(pctx != NULL);
|
2018-06-27 11:10:59 +10:00
|
|
|
REQUIRE(ret != NULL && *ret == NULL);
|
2016-10-10 17:11:21 -07:00
|
|
|
|
2001-02-15 04:14:15 +00:00
|
|
|
UNUSED(type);
|
|
|
|
|
|
|
|
result = cfg_gettoken(pctx, 0);
|
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
return (result);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2001-02-15 04:14:15 +00:00
|
|
|
|
|
|
|
if (pctx->token.type != isc_tokentype_string) {
|
2001-03-02 20:00:17 +00:00
|
|
|
goto bad_boolean;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2001-02-15 04:14:15 +00:00
|
|
|
|
2002-01-22 19:31:57 +00:00
|
|
|
if ((strcasecmp(TOKEN_STRING(pctx), "true") == 0) ||
|
|
|
|
(strcasecmp(TOKEN_STRING(pctx), "yes") == 0) ||
|
|
|
|
(strcmp(TOKEN_STRING(pctx), "1") == 0))
|
|
|
|
{
|
2018-04-17 08:29:14 -07:00
|
|
|
value = true;
|
2002-01-22 19:31:57 +00:00
|
|
|
} else if ((strcasecmp(TOKEN_STRING(pctx), "false") == 0) ||
|
|
|
|
(strcasecmp(TOKEN_STRING(pctx), "no") == 0) ||
|
|
|
|
(strcmp(TOKEN_STRING(pctx), "0") == 0))
|
|
|
|
{
|
2018-04-17 08:29:14 -07:00
|
|
|
value = false;
|
2001-02-15 04:14:15 +00:00
|
|
|
} else {
|
|
|
|
goto bad_boolean;
|
|
|
|
}
|
|
|
|
|
2002-01-04 02:32:16 +00:00
|
|
|
CHECK(cfg_create_obj(pctx, &cfg_type_boolean, &obj));
|
2001-02-15 04:14:15 +00:00
|
|
|
obj->value.boolean = value;
|
|
|
|
*ret = obj;
|
|
|
|
return (result);
|
|
|
|
|
|
|
|
bad_boolean:
|
2002-01-04 02:32:16 +00:00
|
|
|
cfg_parser_error(pctx, CFG_LOG_NEAR, "boolean expected");
|
2001-02-15 04:14:15 +00:00
|
|
|
return (ISC_R_UNEXPECTEDTOKEN);
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
return (result);
|
|
|
|
}
|
|
|
|
|
2011-01-03 23:45:08 +00:00
|
|
|
void
|
|
|
|
cfg_print_boolean(cfg_printer_t *pctx, const cfg_obj_t *obj) {
|
2016-10-10 17:11:21 -07:00
|
|
|
REQUIRE(pctx != NULL);
|
|
|
|
REQUIRE(obj != NULL);
|
|
|
|
|
2001-02-15 04:14:15 +00:00
|
|
|
if (obj->value.boolean) {
|
2015-01-06 22:57:57 -08:00
|
|
|
cfg_print_cstr(pctx, "yes");
|
2001-02-15 04:14:15 +00:00
|
|
|
} else {
|
2015-01-06 22:57:57 -08:00
|
|
|
cfg_print_cstr(pctx, "no");
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2001-03-02 01:10:51 +00:00
|
|
|
}
|
2001-02-26 22:37:34 +00:00
|
|
|
|
2021-06-10 08:06:48 +02:00
|
|
|
cfg_type_t cfg_type_boolean = { "boolean", cfg_parse_boolean,
|
|
|
|
cfg_print_boolean, cfg_doc_terminal,
|
|
|
|
&cfg_rep_boolean, NULL };
|
2001-02-26 22:37:34 +00:00
|
|
|
|
2001-02-15 04:14:15 +00:00
|
|
|
/*
|
2001-02-15 18:53:03 +00:00
|
|
|
* Lists.
|
2001-02-15 04:14:15 +00:00
|
|
|
*/
|
|
|
|
|
2002-01-04 02:32:16 +00:00
|
|
|
isc_result_t
|
|
|
|
cfg_create_list(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **obj) {
|
2001-02-15 18:53:03 +00:00
|
|
|
isc_result_t result;
|
2016-10-10 17:11:21 -07:00
|
|
|
|
|
|
|
REQUIRE(pctx != NULL);
|
|
|
|
REQUIRE(type != NULL);
|
|
|
|
REQUIRE(obj != NULL && *obj == NULL);
|
|
|
|
|
2002-01-04 02:32:16 +00:00
|
|
|
CHECK(cfg_create_obj(pctx, type, obj));
|
2001-02-15 18:53:03 +00:00
|
|
|
ISC_LIST_INIT((*obj)->value.list);
|
|
|
|
cleanup:
|
|
|
|
return (result);
|
|
|
|
}
|
|
|
|
|
|
|
|
static isc_result_t
|
|
|
|
create_listelt(cfg_parser_t *pctx, cfg_listelt_t **eltp) {
|
|
|
|
cfg_listelt_t *elt;
|
2016-10-10 17:11:21 -07:00
|
|
|
|
2001-02-15 18:53:03 +00:00
|
|
|
elt = isc_mem_get(pctx->mctx, sizeof(*elt));
|
|
|
|
elt->obj = NULL;
|
|
|
|
ISC_LINK_INIT(elt, link);
|
|
|
|
*eltp = elt;
|
|
|
|
return (ISC_R_SUCCESS);
|
|
|
|
}
|
|
|
|
|
2001-05-28 06:05:24 +00:00
|
|
|
static void
|
2015-01-06 22:57:57 -08:00
|
|
|
free_listelt(cfg_parser_t *pctx, cfg_listelt_t *elt) {
|
|
|
|
if (elt->obj != NULL) {
|
|
|
|
cfg_obj_destroy(pctx, &elt->obj);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2001-05-28 06:05:24 +00:00
|
|
|
isc_mem_put(pctx->mctx, elt, sizeof(*elt));
|
|
|
|
}
|
|
|
|
|
2001-02-15 18:53:03 +00:00
|
|
|
static void
|
|
|
|
free_list(cfg_parser_t *pctx, cfg_obj_t *obj) {
|
|
|
|
cfg_listelt_t *elt, *next;
|
|
|
|
for (elt = ISC_LIST_HEAD(obj->value.list); elt != NULL; elt = next) {
|
|
|
|
next = ISC_LIST_NEXT(elt, link);
|
2015-01-06 22:57:57 -08:00
|
|
|
free_listelt(pctx, elt);
|
2001-02-15 18:53:03 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2002-01-04 02:32:16 +00:00
|
|
|
isc_result_t
|
|
|
|
cfg_parse_listelt(cfg_parser_t *pctx, const cfg_type_t *elttype,
|
|
|
|
cfg_listelt_t **ret) {
|
2001-02-15 04:14:15 +00:00
|
|
|
isc_result_t result;
|
|
|
|
cfg_listelt_t *elt = NULL;
|
|
|
|
cfg_obj_t *value = NULL;
|
|
|
|
|
2016-10-10 17:11:21 -07:00
|
|
|
REQUIRE(pctx != NULL);
|
|
|
|
REQUIRE(elttype != NULL);
|
|
|
|
REQUIRE(ret != NULL && *ret == NULL);
|
|
|
|
|
2001-02-15 04:14:15 +00:00
|
|
|
CHECK(create_listelt(pctx, &elt));
|
|
|
|
|
2002-01-04 02:32:16 +00:00
|
|
|
result = cfg_parse_obj(pctx, elttype, &value);
|
2001-02-15 04:14:15 +00:00
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
goto cleanup;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2001-02-15 04:14:15 +00:00
|
|
|
|
|
|
|
elt->obj = value;
|
|
|
|
|
|
|
|
*ret = elt;
|
|
|
|
return (ISC_R_SUCCESS);
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
isc_mem_put(pctx->mctx, elt, sizeof(*elt));
|
|
|
|
return (result);
|
|
|
|
}
|
|
|
|
|
2001-02-15 18:53:03 +00:00
|
|
|
/*
|
|
|
|
* Parse a homogeneous list whose elements are of type 'elttype'
|
|
|
|
* and where each element is terminated by a semicolon.
|
|
|
|
*/
|
2001-02-15 04:14:15 +00:00
|
|
|
static isc_result_t
|
2001-07-23 00:23:30 +00:00
|
|
|
parse_list(cfg_parser_t *pctx, const cfg_type_t *listtype, cfg_obj_t **ret) {
|
2001-02-15 04:14:15 +00:00
|
|
|
cfg_obj_t *listobj = NULL;
|
2001-07-23 00:23:30 +00:00
|
|
|
const cfg_type_t *listof = listtype->of;
|
2001-02-15 04:14:15 +00:00
|
|
|
isc_result_t result;
|
2003-07-03 01:50:25 +00:00
|
|
|
cfg_listelt_t *elt = NULL;
|
2001-02-15 04:14:15 +00:00
|
|
|
|
2002-01-04 02:32:16 +00:00
|
|
|
CHECK(cfg_create_list(pctx, listtype, &listobj));
|
2001-02-15 04:14:15 +00:00
|
|
|
|
|
|
|
for (;;) {
|
|
|
|
CHECK(cfg_peektoken(pctx, 0));
|
|
|
|
if (pctx->token.type == isc_tokentype_special &&
|
2003-07-03 01:50:25 +00:00
|
|
|
pctx->token.value.as_char == /*{*/ '}')
|
|
|
|
{
|
2001-02-15 04:14:15 +00:00
|
|
|
break;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2002-01-04 02:32:16 +00:00
|
|
|
CHECK(cfg_parse_listelt(pctx, listof, &elt));
|
2001-02-15 04:14:15 +00:00
|
|
|
CHECK(parse_semicolon(pctx));
|
|
|
|
ISC_LIST_APPEND(listobj->value.list, elt, link);
|
2003-07-03 01:50:25 +00:00
|
|
|
elt = NULL;
|
2001-02-15 04:14:15 +00:00
|
|
|
}
|
|
|
|
*ret = listobj;
|
|
|
|
return (ISC_R_SUCCESS);
|
|
|
|
|
|
|
|
cleanup:
|
2003-07-03 01:50:25 +00:00
|
|
|
if (elt != NULL) {
|
2015-01-06 22:57:57 -08:00
|
|
|
free_listelt(pctx, elt);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2001-02-15 04:14:15 +00:00
|
|
|
CLEANUP_OBJ(listobj);
|
|
|
|
return (result);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2006-02-28 02:39:52 +00:00
|
|
|
print_list(cfg_printer_t *pctx, const cfg_obj_t *obj) {
|
|
|
|
const cfg_list_t *list = &obj->value.list;
|
|
|
|
const cfg_listelt_t *elt;
|
2001-02-15 04:14:15 +00:00
|
|
|
|
|
|
|
for (elt = ISC_LIST_HEAD(*list); elt != NULL;
|
2022-11-02 19:33:14 +01:00
|
|
|
elt = ISC_LIST_NEXT(elt, link))
|
|
|
|
{
|
2015-01-06 22:57:57 -08:00
|
|
|
if ((pctx->flags & CFG_PRINTER_ONELINE) != 0) {
|
|
|
|
cfg_print_obj(pctx, elt->obj);
|
|
|
|
cfg_print_cstr(pctx, "; ");
|
|
|
|
} else {
|
2018-01-22 11:00:45 -08:00
|
|
|
cfg_print_indent(pctx);
|
2015-01-06 22:57:57 -08:00
|
|
|
cfg_print_obj(pctx, elt->obj);
|
|
|
|
cfg_print_cstr(pctx, ";\n");
|
|
|
|
}
|
2001-02-15 04:14:15 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2002-01-04 02:32:16 +00:00
|
|
|
isc_result_t
|
|
|
|
cfg_parse_bracketed_list(cfg_parser_t *pctx, const cfg_type_t *type,
|
2018-08-12 11:19:36 -07:00
|
|
|
cfg_obj_t **ret) {
|
2001-02-15 04:14:15 +00:00
|
|
|
isc_result_t result;
|
2016-10-10 17:11:21 -07:00
|
|
|
|
|
|
|
REQUIRE(pctx != NULL);
|
|
|
|
REQUIRE(type != NULL);
|
|
|
|
REQUIRE(ret != NULL && *ret == NULL);
|
|
|
|
|
2002-01-04 02:32:16 +00:00
|
|
|
CHECK(cfg_parse_special(pctx, '{'));
|
2001-02-15 04:14:15 +00:00
|
|
|
CHECK(parse_list(pctx, type, ret));
|
2002-01-04 02:32:16 +00:00
|
|
|
CHECK(cfg_parse_special(pctx, '}'));
|
2001-02-15 04:14:15 +00:00
|
|
|
cleanup:
|
|
|
|
return (result);
|
|
|
|
}
|
|
|
|
|
2002-01-04 02:32:16 +00:00
|
|
|
void
|
2006-02-28 02:39:52 +00:00
|
|
|
cfg_print_bracketed_list(cfg_printer_t *pctx, const cfg_obj_t *obj) {
|
2016-10-10 17:11:21 -07:00
|
|
|
REQUIRE(pctx != NULL);
|
|
|
|
REQUIRE(obj != NULL);
|
|
|
|
|
2001-02-15 04:14:15 +00:00
|
|
|
print_open(pctx);
|
|
|
|
print_list(pctx, obj);
|
|
|
|
print_close(pctx);
|
|
|
|
}
|
|
|
|
|
2002-01-04 02:32:16 +00:00
|
|
|
void
|
|
|
|
cfg_doc_bracketed_list(cfg_printer_t *pctx, const cfg_type_t *type) {
|
2016-10-10 17:11:21 -07:00
|
|
|
REQUIRE(pctx != NULL);
|
|
|
|
REQUIRE(type != NULL);
|
|
|
|
|
2015-01-06 22:57:57 -08:00
|
|
|
cfg_print_cstr(pctx, "{ ");
|
2002-01-04 02:32:16 +00:00
|
|
|
cfg_doc_obj(pctx, type->of);
|
2015-01-06 22:57:57 -08:00
|
|
|
cfg_print_cstr(pctx, "; ... }");
|
2002-01-04 02:32:16 +00:00
|
|
|
}
|
|
|
|
|
2001-02-15 04:14:15 +00:00
|
|
|
/*
|
|
|
|
* Parse a homogeneous list whose elements are of type 'elttype'
|
|
|
|
* and where elements are separated by space. The list ends
|
|
|
|
* before the first semicolon.
|
|
|
|
*/
|
2002-01-04 02:32:16 +00:00
|
|
|
isc_result_t
|
|
|
|
cfg_parse_spacelist(cfg_parser_t *pctx, const cfg_type_t *listtype,
|
|
|
|
cfg_obj_t **ret) {
|
2001-02-15 04:14:15 +00:00
|
|
|
cfg_obj_t *listobj = NULL;
|
2019-09-27 12:07:32 +02:00
|
|
|
const cfg_type_t *listof;
|
2001-02-15 04:14:15 +00:00
|
|
|
isc_result_t result;
|
|
|
|
|
2016-10-10 17:11:21 -07:00
|
|
|
REQUIRE(pctx != NULL);
|
|
|
|
REQUIRE(listtype != NULL);
|
|
|
|
REQUIRE(ret != NULL && *ret == NULL);
|
|
|
|
|
2019-09-27 12:07:32 +02:00
|
|
|
listof = listtype->of;
|
|
|
|
|
2002-01-04 02:32:16 +00:00
|
|
|
CHECK(cfg_create_list(pctx, listtype, &listobj));
|
2001-02-15 04:14:15 +00:00
|
|
|
|
|
|
|
for (;;) {
|
|
|
|
cfg_listelt_t *elt = NULL;
|
|
|
|
|
|
|
|
CHECK(cfg_peektoken(pctx, 0));
|
|
|
|
if (pctx->token.type == isc_tokentype_special &&
|
|
|
|
pctx->token.value.as_char == ';')
|
|
|
|
{
|
|
|
|
break;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2002-01-04 02:32:16 +00:00
|
|
|
CHECK(cfg_parse_listelt(pctx, listof, &elt));
|
2001-02-15 04:14:15 +00:00
|
|
|
ISC_LIST_APPEND(listobj->value.list, elt, link);
|
|
|
|
}
|
|
|
|
*ret = listobj;
|
|
|
|
return (ISC_R_SUCCESS);
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
CLEANUP_OBJ(listobj);
|
|
|
|
return (result);
|
|
|
|
}
|
|
|
|
|
2002-01-04 02:32:16 +00:00
|
|
|
void
|
2006-02-28 02:39:52 +00:00
|
|
|
cfg_print_spacelist(cfg_printer_t *pctx, const cfg_obj_t *obj) {
|
2021-09-28 10:14:02 +10:00
|
|
|
const cfg_list_t *list = NULL;
|
|
|
|
const cfg_listelt_t *elt = NULL;
|
2001-02-15 04:14:15 +00:00
|
|
|
|
2016-10-10 17:11:21 -07:00
|
|
|
REQUIRE(pctx != NULL);
|
|
|
|
REQUIRE(obj != NULL);
|
|
|
|
|
2021-09-28 10:14:02 +10:00
|
|
|
list = &obj->value.list;
|
|
|
|
|
2001-02-15 04:14:15 +00:00
|
|
|
for (elt = ISC_LIST_HEAD(*list); elt != NULL;
|
2022-11-02 19:33:14 +01:00
|
|
|
elt = ISC_LIST_NEXT(elt, link))
|
|
|
|
{
|
2002-01-04 02:32:16 +00:00
|
|
|
cfg_print_obj(pctx, elt->obj);
|
2001-02-15 04:14:15 +00:00
|
|
|
if (ISC_LIST_NEXT(elt, link) != NULL) {
|
2015-01-06 22:57:57 -08:00
|
|
|
cfg_print_cstr(pctx, " ");
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2001-02-15 04:14:15 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-04-17 08:29:14 -07:00
|
|
|
bool
|
2006-02-28 02:39:52 +00:00
|
|
|
cfg_obj_islist(const cfg_obj_t *obj) {
|
2001-02-23 00:15:55 +00:00
|
|
|
REQUIRE(obj != NULL);
|
2018-04-17 08:29:14 -07:00
|
|
|
return (obj->type->rep == &cfg_rep_list);
|
2001-02-23 00:15:55 +00:00
|
|
|
}
|
|
|
|
|
2006-02-28 02:39:52 +00:00
|
|
|
const cfg_listelt_t *
|
|
|
|
cfg_list_first(const cfg_obj_t *obj) {
|
2001-02-27 01:49:46 +00:00
|
|
|
REQUIRE(obj == NULL || obj->type->rep == &cfg_rep_list);
|
|
|
|
if (obj == NULL) {
|
|
|
|
return (NULL);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2001-02-15 18:53:03 +00:00
|
|
|
return (ISC_LIST_HEAD(obj->value.list));
|
|
|
|
}
|
|
|
|
|
2006-02-28 02:39:52 +00:00
|
|
|
const cfg_listelt_t *
|
|
|
|
cfg_list_next(const cfg_listelt_t *elt) {
|
2001-02-15 18:53:03 +00:00
|
|
|
REQUIRE(elt != NULL);
|
|
|
|
return (ISC_LIST_NEXT(elt, link));
|
|
|
|
}
|
|
|
|
|
2007-09-14 01:46:06 +00:00
|
|
|
/*
|
|
|
|
* Return the length of a list object. If obj is NULL or is not
|
|
|
|
* a list, return 0.
|
|
|
|
*/
|
|
|
|
unsigned int
|
2018-04-17 08:29:14 -07:00
|
|
|
cfg_list_length(const cfg_obj_t *obj, bool recurse) {
|
2007-09-14 01:46:06 +00:00
|
|
|
const cfg_listelt_t *elt;
|
|
|
|
unsigned int count = 0;
|
|
|
|
|
2007-10-12 04:17:18 +00:00
|
|
|
if (obj == NULL || !cfg_obj_islist(obj)) {
|
2007-09-14 01:46:06 +00:00
|
|
|
return (0U);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2007-09-14 01:46:06 +00:00
|
|
|
for (elt = cfg_list_first(obj); elt != NULL; elt = cfg_list_next(elt)) {
|
2007-10-12 04:17:18 +00:00
|
|
|
if (recurse && cfg_obj_islist(elt->obj)) {
|
|
|
|
count += cfg_list_length(elt->obj, recurse);
|
|
|
|
} else {
|
|
|
|
count++;
|
|
|
|
}
|
2007-09-14 01:46:06 +00:00
|
|
|
}
|
|
|
|
return (count);
|
|
|
|
}
|
|
|
|
|
2010-08-11 18:14:20 +00:00
|
|
|
cfg_obj_t *
|
2006-02-28 02:39:52 +00:00
|
|
|
cfg_listelt_value(const cfg_listelt_t *elt) {
|
2001-02-15 18:53:03 +00:00
|
|
|
REQUIRE(elt != NULL);
|
|
|
|
return (elt->obj);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Maps.
|
|
|
|
*/
|
|
|
|
|
2001-02-23 00:15:55 +00:00
|
|
|
/*
|
|
|
|
* Parse a map body. That's something like
|
|
|
|
*
|
|
|
|
* "foo 1; bar { glub; }; zap true; zap false;"
|
|
|
|
*
|
|
|
|
* i.e., a sequence of option names followed by values and
|
|
|
|
* terminated by semicolons. Used for the top level of
|
|
|
|
* the named.conf syntax, as well as for the body of the
|
|
|
|
* options, view, zone, and other statements.
|
|
|
|
*/
|
2002-01-04 02:32:16 +00:00
|
|
|
isc_result_t
|
|
|
|
cfg_parse_mapbody(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
|
2019-09-27 12:07:32 +02:00
|
|
|
const cfg_clausedef_t *const *clausesets;
|
2001-02-23 00:15:55 +00:00
|
|
|
isc_result_t result;
|
2001-07-23 00:23:30 +00:00
|
|
|
const cfg_clausedef_t *const *clauseset;
|
|
|
|
const cfg_clausedef_t *clause;
|
2001-02-23 00:15:55 +00:00
|
|
|
cfg_obj_t *value = NULL;
|
2001-02-15 04:14:15 +00:00
|
|
|
cfg_obj_t *obj = NULL;
|
2001-02-23 00:15:55 +00:00
|
|
|
cfg_obj_t *eltobj = NULL;
|
|
|
|
cfg_obj_t *includename = NULL;
|
|
|
|
isc_symvalue_t symval;
|
|
|
|
cfg_list_t *list = NULL;
|
2001-02-15 04:14:15 +00:00
|
|
|
|
2016-10-10 17:11:21 -07:00
|
|
|
REQUIRE(pctx != NULL);
|
|
|
|
REQUIRE(type != NULL);
|
|
|
|
REQUIRE(ret != NULL && *ret == NULL);
|
|
|
|
|
2019-09-27 12:07:32 +02:00
|
|
|
clausesets = type->of;
|
|
|
|
|
2001-02-23 00:15:55 +00:00
|
|
|
CHECK(create_map(pctx, type, &obj));
|
2001-02-15 04:14:15 +00:00
|
|
|
|
2001-02-23 00:15:55 +00:00
|
|
|
obj->value.map.clausesets = clausesets;
|
2001-02-15 04:14:15 +00:00
|
|
|
|
2001-02-23 00:15:55 +00:00
|
|
|
for (;;) {
|
|
|
|
cfg_listelt_t *elt;
|
2001-02-15 04:14:15 +00:00
|
|
|
|
2001-02-23 00:15:55 +00:00
|
|
|
redo:
|
|
|
|
/*
|
|
|
|
* Parse the option name and see if it is known.
|
|
|
|
*/
|
|
|
|
CHECK(cfg_gettoken(pctx, 0));
|
2001-02-15 04:14:15 +00:00
|
|
|
|
2001-02-23 00:15:55 +00:00
|
|
|
if (pctx->token.type != isc_tokentype_string) {
|
|
|
|
cfg_ungettoken(pctx);
|
|
|
|
break;
|
|
|
|
}
|
2001-02-15 04:14:15 +00:00
|
|
|
|
2001-02-23 00:15:55 +00:00
|
|
|
/*
|
|
|
|
* We accept "include" statements wherever a map body
|
|
|
|
* clause can occur.
|
|
|
|
*/
|
2002-01-22 19:31:57 +00:00
|
|
|
if (strcasecmp(TOKEN_STRING(pctx), "include") == 0) {
|
2001-02-23 00:15:55 +00:00
|
|
|
/*
|
|
|
|
* Turn the file name into a temporary configuration
|
|
|
|
* object just so that it is not overwritten by the
|
|
|
|
* semicolon token.
|
|
|
|
*/
|
2002-01-04 02:32:16 +00:00
|
|
|
CHECK(cfg_parse_obj(pctx, &cfg_type_qstring,
|
|
|
|
&includename));
|
2001-02-23 00:15:55 +00:00
|
|
|
CHECK(parse_semicolon(pctx));
|
2019-09-13 12:08:56 -03:00
|
|
|
|
|
|
|
/* Allow include to specify a pattern that follows
|
|
|
|
* the same rules as the shell e.g "/path/zone*.conf" */
|
|
|
|
glob_t glob_obj;
|
2019-10-23 16:25:06 -03:00
|
|
|
CHECK(isc_glob(includename->value.string.base,
|
|
|
|
&glob_obj));
|
2001-02-23 00:15:55 +00:00
|
|
|
cfg_obj_destroy(pctx, &includename);
|
2019-09-13 12:08:56 -03:00
|
|
|
|
|
|
|
for (size_t i = 0; i < glob_obj.gl_pathc; ++i) {
|
|
|
|
CHECK(parser_openfile(pctx,
|
|
|
|
glob_obj.gl_pathv[i]));
|
|
|
|
}
|
|
|
|
|
2019-10-23 16:25:06 -03:00
|
|
|
isc_globfree(&glob_obj);
|
|
|
|
|
2001-02-23 00:15:55 +00:00
|
|
|
goto redo;
|
|
|
|
}
|
2001-02-15 04:14:15 +00:00
|
|
|
|
2001-02-23 00:15:55 +00:00
|
|
|
clause = NULL;
|
|
|
|
for (clauseset = clausesets; *clauseset != NULL; clauseset++) {
|
|
|
|
for (clause = *clauseset; clause->name != NULL;
|
2022-11-02 19:33:14 +01:00
|
|
|
clause++)
|
|
|
|
{
|
2002-01-22 19:31:57 +00:00
|
|
|
if (strcasecmp(TOKEN_STRING(pctx),
|
2022-11-02 19:33:14 +01:00
|
|
|
clause->name) == 0)
|
|
|
|
{
|
2001-02-23 00:15:55 +00:00
|
|
|
goto done;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2001-02-23 00:15:55 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
done:
|
|
|
|
if (clause == NULL || clause->name == NULL) {
|
2018-06-08 11:04:21 +10:00
|
|
|
cfg_parser_error(pctx, CFG_LOG_NOPREP,
|
|
|
|
"unknown option");
|
2001-02-23 00:15:55 +00:00
|
|
|
/*
|
|
|
|
* Try to recover by parsing this option as an unknown
|
|
|
|
* option and discarding it.
|
|
|
|
*/
|
2018-06-08 11:04:21 +10:00
|
|
|
CHECK(cfg_parse_obj(pctx, &cfg_type_unsupported,
|
|
|
|
&eltobj));
|
2002-01-04 02:32:16 +00:00
|
|
|
cfg_obj_destroy(pctx, &eltobj);
|
|
|
|
CHECK(parse_semicolon(pctx));
|
|
|
|
continue;
|
2001-02-23 00:15:55 +00:00
|
|
|
}
|
2001-02-15 04:14:15 +00:00
|
|
|
|
2001-02-23 00:15:55 +00:00
|
|
|
/* Clause is known. */
|
2001-02-15 04:14:15 +00:00
|
|
|
|
2019-01-20 23:50:17 -08:00
|
|
|
/* Issue fatal errors if appropriate */
|
|
|
|
if ((clause->flags & CFG_CLAUSEFLAG_ANCIENT) != 0) {
|
|
|
|
cfg_parser_error(pctx, 0,
|
|
|
|
"option '%s' no longer exists",
|
|
|
|
clause->name);
|
|
|
|
CHECK(ISC_R_FAILURE);
|
|
|
|
}
|
2020-12-08 11:47:57 +01:00
|
|
|
if ((clause->flags & CFG_CLAUSEFLAG_NOTCONFIGURED) != 0) {
|
|
|
|
cfg_parser_error(pctx, 0,
|
|
|
|
"option '%s' was not "
|
|
|
|
"enabled at compile time",
|
|
|
|
clause->name);
|
|
|
|
CHECK(ISC_R_FAILURE);
|
|
|
|
}
|
2019-01-20 23:50:17 -08:00
|
|
|
|
2001-02-23 00:15:55 +00:00
|
|
|
/* Issue warnings if appropriate */
|
2018-06-08 11:04:21 +10:00
|
|
|
if ((pctx->flags & CFG_PCTX_NODEPRECATED) == 0 &&
|
|
|
|
(clause->flags & CFG_CLAUSEFLAG_DEPRECATED) != 0)
|
|
|
|
{
|
2019-01-20 23:50:17 -08:00
|
|
|
cfg_parser_warning(pctx, 0, "option '%s' is deprecated",
|
2018-06-08 11:04:21 +10:00
|
|
|
clause->name);
|
|
|
|
}
|
|
|
|
if ((clause->flags & CFG_CLAUSEFLAG_OBSOLETE) != 0) {
|
2019-01-20 23:50:17 -08:00
|
|
|
cfg_parser_warning(pctx, 0,
|
|
|
|
"option '%s' is obsolete and "
|
|
|
|
"should be removed ",
|
2018-06-08 11:04:21 +10:00
|
|
|
clause->name);
|
|
|
|
}
|
2020-12-08 11:47:57 +01:00
|
|
|
if ((clause->flags & CFG_CLAUSEFLAG_EXPERIMENTAL) != 0) {
|
|
|
|
cfg_parser_warning(pctx, 0,
|
|
|
|
"option '%s' is experimental and "
|
|
|
|
"subject to change in the future",
|
|
|
|
clause->name);
|
2010-06-22 04:03:38 +00:00
|
|
|
}
|
|
|
|
|
2001-02-23 00:15:55 +00:00
|
|
|
/* See if the clause already has a value; if not create one. */
|
|
|
|
result = isc_symtab_lookup(obj->value.map.symtab, clause->name,
|
|
|
|
0, &symval);
|
2001-02-15 04:14:15 +00:00
|
|
|
|
2001-02-23 00:15:55 +00:00
|
|
|
if ((clause->flags & CFG_CLAUSEFLAG_MULTI) != 0) {
|
|
|
|
/* Multivalued clause */
|
|
|
|
cfg_obj_t *listobj = NULL;
|
|
|
|
if (result == ISC_R_NOTFOUND) {
|
2002-01-04 02:32:16 +00:00
|
|
|
CHECK(cfg_create_list(pctx,
|
2001-02-23 00:15:55 +00:00
|
|
|
&cfg_type_implicitlist,
|
|
|
|
&listobj));
|
|
|
|
symval.as_pointer = listobj;
|
|
|
|
result = isc_symtab_define(
|
|
|
|
obj->value.map.symtab, clause->name, 1,
|
|
|
|
symval, isc_symexists_reject);
|
|
|
|
if (result != ISC_R_SUCCESS) {
|
2002-01-04 02:32:16 +00:00
|
|
|
cfg_parser_error(pctx, CFG_LOG_NEAR,
|
2001-07-03 07:43:02 +00:00
|
|
|
"isc_symtab_define(%s)"
|
|
|
|
" "
|
2001-07-03 17:12:19 +00:00
|
|
|
"failed",
|
|
|
|
clause->name);
|
2001-02-23 00:15:55 +00:00
|
|
|
isc_mem_put(pctx->mctx, list,
|
|
|
|
sizeof(cfg_list_t));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
} else {
|
2001-07-03 07:43:02 +00:00
|
|
|
INSIST(result == ISC_R_SUCCESS);
|
|
|
|
listobj = symval.as_pointer;
|
2001-02-23 00:15:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
elt = NULL;
|
2002-01-04 02:32:16 +00:00
|
|
|
CHECK(cfg_parse_listelt(pctx, clause->type, &elt));
|
2001-02-23 00:15:55 +00:00
|
|
|
CHECK(parse_semicolon(pctx));
|
|
|
|
|
|
|
|
ISC_LIST_APPEND(listobj->value.list, elt, link);
|
|
|
|
} else {
|
|
|
|
/* Single-valued clause */
|
|
|
|
if (result == ISC_R_NOTFOUND) {
|
2018-10-11 11:57:57 +02:00
|
|
|
bool callback = ((clause->flags &
|
|
|
|
CFG_CLAUSEFLAG_CALLBACK) !=
|
|
|
|
0);
|
2001-02-23 00:15:55 +00:00
|
|
|
CHECK(parse_symtab_elt(
|
|
|
|
pctx, clause->name, clause->type,
|
|
|
|
obj->value.map.symtab, callback));
|
|
|
|
CHECK(parse_semicolon(pctx));
|
|
|
|
} else if (result == ISC_R_SUCCESS) {
|
2019-01-20 23:50:17 -08:00
|
|
|
cfg_parser_error(pctx, CFG_LOG_NEAR,
|
|
|
|
"'%s' redefined",
|
|
|
|
clause->name);
|
2001-03-21 19:01:36 +00:00
|
|
|
result = ISC_R_EXISTS;
|
2001-02-23 00:15:55 +00:00
|
|
|
goto cleanup;
|
|
|
|
} else {
|
2002-01-04 02:32:16 +00:00
|
|
|
cfg_parser_error(pctx, CFG_LOG_NEAR,
|
2001-02-23 00:15:55 +00:00
|
|
|
"isc_symtab_define() failed");
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
*ret = obj;
|
|
|
|
return (ISC_R_SUCCESS);
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
CLEANUP_OBJ(value);
|
|
|
|
CLEANUP_OBJ(obj);
|
|
|
|
CLEANUP_OBJ(eltobj);
|
|
|
|
CLEANUP_OBJ(includename);
|
|
|
|
return (result);
|
|
|
|
}
|
|
|
|
|
|
|
|
static isc_result_t
|
|
|
|
parse_symtab_elt(cfg_parser_t *pctx, const char *name, cfg_type_t *elttype,
|
|
|
|
isc_symtab_t *symtab, bool callback) {
|
|
|
|
isc_result_t result;
|
|
|
|
cfg_obj_t *obj = NULL;
|
|
|
|
isc_symvalue_t symval;
|
|
|
|
|
2002-01-04 02:32:16 +00:00
|
|
|
CHECK(cfg_parse_obj(pctx, elttype, &obj));
|
2001-02-23 00:15:55 +00:00
|
|
|
|
|
|
|
if (callback && pctx->callback != NULL) {
|
|
|
|
CHECK(pctx->callback(name, obj, pctx->callbackarg));
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2008-09-25 04:02:39 +00:00
|
|
|
|
2001-02-23 00:15:55 +00:00
|
|
|
symval.as_pointer = obj;
|
|
|
|
CHECK(isc_symtab_define(symtab, name, 1, symval, isc_symexists_reject));
|
|
|
|
return (ISC_R_SUCCESS);
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
CLEANUP_OBJ(obj);
|
|
|
|
return (result);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Parse a map; e.g., "{ foo 1; bar { glub; }; zap true; zap false; }"
|
|
|
|
*/
|
2002-01-04 02:32:16 +00:00
|
|
|
isc_result_t
|
|
|
|
cfg_parse_map(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
|
2001-02-23 00:15:55 +00:00
|
|
|
isc_result_t result;
|
2016-10-10 17:11:21 -07:00
|
|
|
|
|
|
|
REQUIRE(pctx != NULL);
|
|
|
|
REQUIRE(type != NULL);
|
|
|
|
REQUIRE(ret != NULL && *ret == NULL);
|
|
|
|
|
2002-01-04 02:32:16 +00:00
|
|
|
CHECK(cfg_parse_special(pctx, '{'));
|
|
|
|
CHECK(cfg_parse_mapbody(pctx, type, ret));
|
|
|
|
CHECK(cfg_parse_special(pctx, '}'));
|
2001-02-23 00:15:55 +00:00
|
|
|
cleanup:
|
|
|
|
return (result);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2002-01-04 02:32:16 +00:00
|
|
|
* Subroutine for cfg_parse_named_map() and cfg_parse_addressed_map().
|
2001-02-23 00:15:55 +00:00
|
|
|
*/
|
|
|
|
static isc_result_t
|
2016-10-10 17:11:21 -07:00
|
|
|
parse_any_named_map(cfg_parser_t *pctx, cfg_type_t *nametype,
|
|
|
|
const cfg_type_t *type, cfg_obj_t **ret) {
|
2001-02-23 00:15:55 +00:00
|
|
|
isc_result_t result;
|
|
|
|
cfg_obj_t *idobj = NULL;
|
|
|
|
cfg_obj_t *mapobj = NULL;
|
|
|
|
|
2016-10-10 17:11:21 -07:00
|
|
|
REQUIRE(pctx != NULL);
|
|
|
|
REQUIRE(nametype != NULL);
|
|
|
|
REQUIRE(type != NULL);
|
|
|
|
REQUIRE(ret != NULL && *ret == NULL);
|
|
|
|
|
2002-01-04 02:32:16 +00:00
|
|
|
CHECK(cfg_parse_obj(pctx, nametype, &idobj));
|
|
|
|
CHECK(cfg_parse_map(pctx, type, &mapobj));
|
2001-02-23 00:15:55 +00:00
|
|
|
mapobj->value.map.id = idobj;
|
|
|
|
*ret = mapobj;
|
2015-04-29 03:16:50 +10:00
|
|
|
return (result);
|
2001-02-23 00:15:55 +00:00
|
|
|
cleanup:
|
|
|
|
CLEANUP_OBJ(idobj);
|
2015-04-29 03:16:50 +10:00
|
|
|
CLEANUP_OBJ(mapobj);
|
2001-02-23 00:15:55 +00:00
|
|
|
return (result);
|
|
|
|
}
|
|
|
|
|
2001-02-27 01:31:56 +00:00
|
|
|
/*
|
2008-09-25 04:02:39 +00:00
|
|
|
* Parse a map identified by a string name. E.g., "name { foo 1; }".
|
2001-02-27 01:31:56 +00:00
|
|
|
* Used for the "key" and "channel" statements.
|
|
|
|
*/
|
2002-01-04 02:32:16 +00:00
|
|
|
isc_result_t
|
|
|
|
cfg_parse_named_map(cfg_parser_t *pctx, const cfg_type_t *type,
|
|
|
|
cfg_obj_t **ret) {
|
2001-02-27 01:31:56 +00:00
|
|
|
return (parse_any_named_map(pctx, &cfg_type_astring, type, ret));
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Parse a map identified by a network address.
|
2005-01-17 00:46:05 +00:00
|
|
|
* Used to be used for the "server" statement.
|
2001-02-27 01:31:56 +00:00
|
|
|
*/
|
2002-01-04 02:32:16 +00:00
|
|
|
isc_result_t
|
|
|
|
cfg_parse_addressed_map(cfg_parser_t *pctx, const cfg_type_t *type,
|
|
|
|
cfg_obj_t **ret) {
|
2001-02-27 01:31:56 +00:00
|
|
|
return (parse_any_named_map(pctx, &cfg_type_netaddr, type, ret));
|
|
|
|
}
|
|
|
|
|
2005-01-17 00:46:05 +00:00
|
|
|
/*
|
|
|
|
* Parse a map identified by a network prefix.
|
|
|
|
* Used for the "server" statement.
|
|
|
|
*/
|
|
|
|
isc_result_t
|
|
|
|
cfg_parse_netprefix_map(cfg_parser_t *pctx, const cfg_type_t *type,
|
|
|
|
cfg_obj_t **ret) {
|
|
|
|
return (parse_any_named_map(pctx, &cfg_type_netprefix, type, ret));
|
|
|
|
}
|
|
|
|
|
2015-01-06 22:57:57 -08:00
|
|
|
static void
|
|
|
|
print_symval(cfg_printer_t *pctx, const char *name, cfg_obj_t *obj) {
|
|
|
|
if ((pctx->flags & CFG_PRINTER_ONELINE) == 0) {
|
2018-01-22 11:00:45 -08:00
|
|
|
cfg_print_indent(pctx);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2015-01-06 22:57:57 -08:00
|
|
|
|
|
|
|
cfg_print_cstr(pctx, name);
|
|
|
|
cfg_print_cstr(pctx, " ");
|
|
|
|
cfg_print_obj(pctx, obj);
|
|
|
|
|
|
|
|
if ((pctx->flags & CFG_PRINTER_ONELINE) == 0) {
|
|
|
|
cfg_print_cstr(pctx, ";\n");
|
|
|
|
} else {
|
|
|
|
cfg_print_cstr(pctx, "; ");
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2015-01-06 22:57:57 -08:00
|
|
|
}
|
|
|
|
|
2002-01-04 02:32:16 +00:00
|
|
|
void
|
2006-02-28 02:39:52 +00:00
|
|
|
cfg_print_mapbody(cfg_printer_t *pctx, const cfg_obj_t *obj) {
|
2001-07-23 00:23:30 +00:00
|
|
|
const cfg_clausedef_t *const *clauseset;
|
2001-02-23 00:15:55 +00:00
|
|
|
|
2016-10-10 17:11:21 -07:00
|
|
|
REQUIRE(pctx != NULL);
|
|
|
|
REQUIRE(obj != NULL);
|
|
|
|
|
2001-02-23 00:15:55 +00:00
|
|
|
for (clauseset = obj->value.map.clausesets; *clauseset != NULL;
|
2022-11-02 19:33:14 +01:00
|
|
|
clauseset++)
|
|
|
|
{
|
2001-02-23 00:15:55 +00:00
|
|
|
isc_symvalue_t symval;
|
2001-07-23 00:23:30 +00:00
|
|
|
const cfg_clausedef_t *clause;
|
2001-02-23 00:15:55 +00:00
|
|
|
|
|
|
|
for (clause = *clauseset; clause->name != NULL; clause++) {
|
2019-08-08 13:52:44 +10:00
|
|
|
isc_result_t result;
|
2001-02-23 00:15:55 +00:00
|
|
|
result = isc_symtab_lookup(obj->value.map.symtab,
|
|
|
|
clause->name, 0, &symval);
|
|
|
|
if (result == ISC_R_SUCCESS) {
|
2015-01-20 13:29:18 -08:00
|
|
|
cfg_obj_t *symobj = symval.as_pointer;
|
|
|
|
if (symobj->type == &cfg_type_implicitlist) {
|
2001-02-23 00:15:55 +00:00
|
|
|
/* Multivalued. */
|
2015-01-20 13:29:18 -08:00
|
|
|
cfg_list_t *list = &symobj->value.list;
|
2001-02-23 00:15:55 +00:00
|
|
|
cfg_listelt_t *elt;
|
|
|
|
for (elt = ISC_LIST_HEAD(*list);
|
|
|
|
elt != NULL;
|
2022-11-02 19:33:14 +01:00
|
|
|
elt = ISC_LIST_NEXT(elt, link))
|
|
|
|
{
|
2015-01-06 22:57:57 -08:00
|
|
|
print_symval(pctx, clause->name,
|
|
|
|
elt->obj);
|
2001-02-23 00:15:55 +00:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
/* Single-valued. */
|
2015-01-20 13:29:18 -08:00
|
|
|
print_symval(pctx, clause->name,
|
|
|
|
symobj);
|
2001-02-23 00:15:55 +00:00
|
|
|
}
|
|
|
|
} else if (result == ISC_R_NOTFOUND) {
|
|
|
|
/* do nothing */
|
|
|
|
} else {
|
2021-10-11 12:50:17 +02:00
|
|
|
UNREACHABLE();
|
2001-02-23 00:15:55 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-11-02 10:04:57 +11:00
|
|
|
static struct flagtext {
|
|
|
|
unsigned int flag;
|
|
|
|
const char *text;
|
2020-12-08 11:26:08 +01:00
|
|
|
} flagtexts[] = { { CFG_CLAUSEFLAG_OBSOLETE, "obsolete" },
|
2016-11-02 10:04:57 +11:00
|
|
|
{ CFG_CLAUSEFLAG_TESTONLY, "test only" },
|
|
|
|
{ CFG_CLAUSEFLAG_NOTCONFIGURED, "not configured" },
|
|
|
|
{ CFG_CLAUSEFLAG_MULTI, "may occur multiple times" },
|
|
|
|
{ CFG_CLAUSEFLAG_EXPERIMENTAL, "experimental" },
|
2018-08-12 23:06:00 -07:00
|
|
|
{ CFG_CLAUSEFLAG_DEPRECATED, "deprecated" },
|
2019-01-20 23:50:17 -08:00
|
|
|
{ CFG_CLAUSEFLAG_ANCIENT, "ancient" },
|
2016-11-02 10:04:57 +11:00
|
|
|
{ 0, NULL } };
|
|
|
|
|
2018-01-22 11:00:45 -08:00
|
|
|
void
|
|
|
|
cfg_print_clauseflags(cfg_printer_t *pctx, unsigned int flags) {
|
2016-11-02 10:04:57 +11:00
|
|
|
struct flagtext *p;
|
2018-04-17 08:29:14 -07:00
|
|
|
bool first = true;
|
2016-11-02 10:04:57 +11:00
|
|
|
for (p = flagtexts; p->flag != 0; p++) {
|
|
|
|
if ((flags & p->flag) != 0) {
|
|
|
|
if (first) {
|
|
|
|
cfg_print_cstr(pctx, " // ");
|
|
|
|
} else {
|
|
|
|
cfg_print_cstr(pctx, ", ");
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2016-11-02 10:04:57 +11:00
|
|
|
cfg_print_cstr(pctx, p->text);
|
2018-04-17 08:29:14 -07:00
|
|
|
first = false;
|
2016-11-02 10:04:57 +11:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2002-01-04 02:32:16 +00:00
|
|
|
void
|
|
|
|
cfg_doc_mapbody(cfg_printer_t *pctx, const cfg_type_t *type) {
|
|
|
|
const cfg_clausedef_t *const *clauseset;
|
|
|
|
const cfg_clausedef_t *clause;
|
2008-09-25 04:02:39 +00:00
|
|
|
|
2016-10-10 17:11:21 -07:00
|
|
|
REQUIRE(pctx != NULL);
|
|
|
|
REQUIRE(type != NULL);
|
|
|
|
|
2002-01-04 02:32:16 +00:00
|
|
|
for (clauseset = type->of; *clauseset != NULL; clauseset++) {
|
2018-01-22 11:00:45 -08:00
|
|
|
for (clause = *clauseset; clause->name != NULL; clause++) {
|
2019-08-07 10:31:19 -07:00
|
|
|
if (((pctx->flags & CFG_PRINTER_ACTIVEONLY) != 0) &&
|
|
|
|
(((clause->flags & CFG_CLAUSEFLAG_OBSOLETE) != 0) ||
|
|
|
|
((clause->flags & CFG_CLAUSEFLAG_TESTONLY) != 0)))
|
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
2022-02-25 16:33:30 -08:00
|
|
|
if ((clause->flags & CFG_CLAUSEFLAG_ANCIENT) != 0 ||
|
|
|
|
(clause->flags & CFG_CLAUSEFLAG_NODOC) != 0)
|
|
|
|
{
|
Remove a lot of obsoleted options
These options were ancient or made obsolete a long time ago, it is
safe to remove them.
Also stop printing ancient options, they should be treated the same as
unknown options.
Removed options: lwres, geoip-use-ecs, sit-secret, use-ixfr,
acache-cleaning-interval, acache-enable, additional-from-auth,
additional-from-cache, allow-v6-synthesis, dnssec-enable,
max-acache-size, nosit-udp-size, queryport-pool-ports,
queryport-pool-updateinterval, request-sit, use-queryport-pool, and
support-ixfr.
2020-12-08 15:08:32 +01:00
|
|
|
continue;
|
|
|
|
}
|
2002-01-04 02:32:16 +00:00
|
|
|
cfg_print_cstr(pctx, clause->name);
|
2015-01-06 22:57:57 -08:00
|
|
|
cfg_print_cstr(pctx, " ");
|
2002-01-04 02:32:16 +00:00
|
|
|
cfg_doc_obj(pctx, clause->type);
|
2016-11-02 10:04:57 +11:00
|
|
|
cfg_print_cstr(pctx, ";");
|
2018-01-22 11:00:45 -08:00
|
|
|
cfg_print_clauseflags(pctx, clause->flags);
|
2016-11-02 10:04:57 +11:00
|
|
|
cfg_print_cstr(pctx, "\n\n");
|
2002-01-04 02:32:16 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2006-02-28 02:39:52 +00:00
|
|
|
cfg_print_map(cfg_printer_t *pctx, const cfg_obj_t *obj) {
|
2016-10-10 17:11:21 -07:00
|
|
|
REQUIRE(pctx != NULL);
|
|
|
|
REQUIRE(obj != NULL);
|
|
|
|
|
2001-02-23 00:15:55 +00:00
|
|
|
if (obj->value.map.id != NULL) {
|
2002-01-04 02:32:16 +00:00
|
|
|
cfg_print_obj(pctx, obj->value.map.id);
|
2015-01-06 22:57:57 -08:00
|
|
|
cfg_print_cstr(pctx, " ");
|
2002-01-04 02:32:16 +00:00
|
|
|
}
|
|
|
|
print_open(pctx);
|
|
|
|
cfg_print_mapbody(pctx, obj);
|
|
|
|
print_close(pctx);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
cfg_doc_map(cfg_printer_t *pctx, const cfg_type_t *type) {
|
|
|
|
const cfg_clausedef_t *const *clauseset;
|
|
|
|
const cfg_clausedef_t *clause;
|
2008-09-25 04:02:39 +00:00
|
|
|
|
2016-10-10 17:11:21 -07:00
|
|
|
REQUIRE(pctx != NULL);
|
|
|
|
REQUIRE(type != NULL);
|
|
|
|
|
2002-01-04 02:32:16 +00:00
|
|
|
if (type->parse == cfg_parse_named_map) {
|
|
|
|
cfg_doc_obj(pctx, &cfg_type_astring);
|
2015-01-06 22:57:57 -08:00
|
|
|
cfg_print_cstr(pctx, " ");
|
2003-04-10 02:16:11 +00:00
|
|
|
} else if (type->parse == cfg_parse_addressed_map) {
|
|
|
|
cfg_doc_obj(pctx, &cfg_type_netaddr);
|
2015-01-06 22:57:57 -08:00
|
|
|
cfg_print_cstr(pctx, " ");
|
2005-01-17 00:46:05 +00:00
|
|
|
} else if (type->parse == cfg_parse_netprefix_map) {
|
|
|
|
cfg_doc_obj(pctx, &cfg_type_netprefix);
|
2015-01-06 22:57:57 -08:00
|
|
|
cfg_print_cstr(pctx, " ");
|
2001-02-23 00:15:55 +00:00
|
|
|
}
|
2008-09-25 04:02:39 +00:00
|
|
|
|
2001-02-23 00:15:55 +00:00
|
|
|
print_open(pctx);
|
2008-09-25 04:02:39 +00:00
|
|
|
|
2002-01-04 02:32:16 +00:00
|
|
|
for (clauseset = type->of; *clauseset != NULL; clauseset++) {
|
2018-01-22 11:00:45 -08:00
|
|
|
for (clause = *clauseset; clause->name != NULL; clause++) {
|
2019-08-07 10:31:19 -07:00
|
|
|
if (((pctx->flags & CFG_PRINTER_ACTIVEONLY) != 0) &&
|
|
|
|
(((clause->flags & CFG_CLAUSEFLAG_OBSOLETE) != 0) ||
|
|
|
|
((clause->flags & CFG_CLAUSEFLAG_TESTONLY) != 0)))
|
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
2022-02-25 16:33:30 -08:00
|
|
|
if ((clause->flags & CFG_CLAUSEFLAG_ANCIENT) != 0 ||
|
|
|
|
(clause->flags & CFG_CLAUSEFLAG_NODOC) != 0)
|
|
|
|
{
|
Remove a lot of obsoleted options
These options were ancient or made obsolete a long time ago, it is
safe to remove them.
Also stop printing ancient options, they should be treated the same as
unknown options.
Removed options: lwres, geoip-use-ecs, sit-secret, use-ixfr,
acache-cleaning-interval, acache-enable, additional-from-auth,
additional-from-cache, allow-v6-synthesis, dnssec-enable,
max-acache-size, nosit-udp-size, queryport-pool-ports,
queryport-pool-updateinterval, request-sit, use-queryport-pool, and
support-ixfr.
2020-12-08 15:08:32 +01:00
|
|
|
continue;
|
|
|
|
}
|
2018-01-22 11:00:45 -08:00
|
|
|
cfg_print_indent(pctx);
|
2002-01-04 02:32:16 +00:00
|
|
|
cfg_print_cstr(pctx, clause->name);
|
|
|
|
if (clause->type->print != cfg_print_void) {
|
2015-01-06 22:57:57 -08:00
|
|
|
cfg_print_cstr(pctx, " ");
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2002-01-04 02:32:16 +00:00
|
|
|
cfg_doc_obj(pctx, clause->type);
|
2015-01-06 22:57:57 -08:00
|
|
|
cfg_print_cstr(pctx, ";");
|
2018-01-22 11:00:45 -08:00
|
|
|
cfg_print_clauseflags(pctx, clause->flags);
|
2015-01-06 22:57:57 -08:00
|
|
|
cfg_print_cstr(pctx, "\n");
|
2002-01-04 02:32:16 +00:00
|
|
|
}
|
|
|
|
}
|
2001-02-23 00:15:55 +00:00
|
|
|
print_close(pctx);
|
|
|
|
}
|
|
|
|
|
2018-04-17 08:29:14 -07:00
|
|
|
bool
|
2006-02-28 02:39:52 +00:00
|
|
|
cfg_obj_ismap(const cfg_obj_t *obj) {
|
2001-02-23 00:15:55 +00:00
|
|
|
REQUIRE(obj != NULL);
|
2018-04-17 08:29:14 -07:00
|
|
|
return (obj->type->rep == &cfg_rep_map);
|
2001-02-23 00:15:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
isc_result_t
|
2006-02-28 02:39:52 +00:00
|
|
|
cfg_map_get(const cfg_obj_t *mapobj, const char *name, const cfg_obj_t **obj) {
|
2001-02-23 00:15:55 +00:00
|
|
|
isc_result_t result;
|
|
|
|
isc_symvalue_t val;
|
2006-02-28 02:39:52 +00:00
|
|
|
const cfg_map_t *map;
|
2008-09-25 04:02:39 +00:00
|
|
|
|
2001-02-23 00:15:55 +00:00
|
|
|
REQUIRE(mapobj != NULL && mapobj->type->rep == &cfg_rep_map);
|
|
|
|
REQUIRE(name != NULL);
|
|
|
|
REQUIRE(obj != NULL && *obj == NULL);
|
|
|
|
|
|
|
|
map = &mapobj->value.map;
|
2008-09-25 04:02:39 +00:00
|
|
|
|
2001-02-23 00:15:55 +00:00
|
|
|
result = isc_symtab_lookup(map->symtab, name, MAP_SYM, &val);
|
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
return (result);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2001-02-23 00:15:55 +00:00
|
|
|
*obj = val.as_pointer;
|
|
|
|
return (ISC_R_SUCCESS);
|
|
|
|
}
|
|
|
|
|
2006-02-28 02:39:52 +00:00
|
|
|
const cfg_obj_t *
|
|
|
|
cfg_map_getname(const cfg_obj_t *mapobj) {
|
2001-02-23 00:15:55 +00:00
|
|
|
REQUIRE(mapobj != NULL && mapobj->type->rep == &cfg_rep_map);
|
|
|
|
return (mapobj->value.map.id);
|
|
|
|
}
|
|
|
|
|
2013-11-13 20:35:40 -08:00
|
|
|
unsigned int
|
|
|
|
cfg_map_count(const cfg_obj_t *mapobj) {
|
|
|
|
const cfg_map_t *map;
|
2016-10-10 17:11:21 -07:00
|
|
|
|
2013-11-13 20:35:40 -08:00
|
|
|
REQUIRE(mapobj != NULL && mapobj->type->rep == &cfg_rep_map);
|
2016-10-10 17:11:21 -07:00
|
|
|
|
2013-11-13 20:35:40 -08:00
|
|
|
map = &mapobj->value.map;
|
|
|
|
return (isc_symtab_count(map->symtab));
|
|
|
|
}
|
2001-02-23 00:15:55 +00:00
|
|
|
|
2018-01-22 11:00:45 -08:00
|
|
|
const char *
|
|
|
|
cfg_map_firstclause(const cfg_type_t *map, const void **clauses,
|
|
|
|
unsigned int *idx) {
|
|
|
|
cfg_clausedef_t *const *clauseset;
|
|
|
|
|
|
|
|
REQUIRE(map != NULL && map->rep == &cfg_rep_map);
|
|
|
|
REQUIRE(idx != NULL);
|
|
|
|
REQUIRE(clauses != NULL && *clauses == NULL);
|
|
|
|
|
|
|
|
clauseset = map->of;
|
|
|
|
if (*clauseset == NULL) {
|
|
|
|
return (NULL);
|
|
|
|
}
|
|
|
|
*clauses = *clauseset;
|
|
|
|
*idx = 0;
|
|
|
|
while ((*clauseset)[*idx].name == NULL) {
|
|
|
|
*clauses = (*++clauseset);
|
|
|
|
if (*clauses == NULL) {
|
|
|
|
return (NULL);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2018-01-22 11:00:45 -08:00
|
|
|
}
|
|
|
|
return ((*clauseset)[*idx].name);
|
|
|
|
}
|
|
|
|
|
|
|
|
const char *
|
|
|
|
cfg_map_nextclause(const cfg_type_t *map, const void **clauses,
|
|
|
|
unsigned int *idx) {
|
|
|
|
cfg_clausedef_t *const *clauseset;
|
|
|
|
|
|
|
|
REQUIRE(map != NULL && map->rep == &cfg_rep_map);
|
|
|
|
REQUIRE(idx != NULL);
|
|
|
|
REQUIRE(clauses != NULL && *clauses != NULL);
|
|
|
|
|
|
|
|
clauseset = map->of;
|
|
|
|
while (*clauseset != NULL && *clauseset != *clauses) {
|
|
|
|
clauseset++;
|
|
|
|
}
|
|
|
|
INSIST(*clauseset == *clauses);
|
|
|
|
(*idx)++;
|
|
|
|
while ((*clauseset)[*idx].name == NULL) {
|
|
|
|
*idx = 0;
|
|
|
|
*clauses = (*++clauseset);
|
|
|
|
if (*clauses == NULL) {
|
|
|
|
return (NULL);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2018-01-22 11:00:45 -08:00
|
|
|
}
|
|
|
|
return ((*clauseset)[*idx].name);
|
|
|
|
}
|
|
|
|
|
2001-02-23 00:15:55 +00:00
|
|
|
/* Parse an arbitrary token, storing its raw text representation. */
|
|
|
|
static isc_result_t
|
2001-07-23 00:23:30 +00:00
|
|
|
parse_token(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
|
2001-02-23 00:15:55 +00:00
|
|
|
cfg_obj_t *obj = NULL;
|
2008-09-25 04:02:39 +00:00
|
|
|
isc_result_t result;
|
2001-02-23 00:15:55 +00:00
|
|
|
isc_region_t r;
|
|
|
|
|
|
|
|
UNUSED(type);
|
|
|
|
|
2002-01-04 02:32:16 +00:00
|
|
|
CHECK(cfg_create_obj(pctx, &cfg_type_token, &obj));
|
|
|
|
CHECK(cfg_gettoken(pctx, CFG_LEXOPT_QSTRING));
|
2001-02-23 00:15:55 +00:00
|
|
|
if (pctx->token.type == isc_tokentype_eof) {
|
|
|
|
cfg_ungettoken(pctx);
|
|
|
|
result = ISC_R_EOF;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
isc_lex_getlasttokentext(pctx->lexer, &pctx->token, &r);
|
|
|
|
|
|
|
|
obj->value.string.base = isc_mem_get(pctx->mctx, r.length + 1);
|
|
|
|
obj->value.string.length = r.length;
|
2014-01-08 16:27:10 -08:00
|
|
|
memmove(obj->value.string.base, r.base, r.length);
|
2001-02-23 00:15:55 +00:00
|
|
|
obj->value.string.base[r.length] = '\0';
|
|
|
|
*ret = obj;
|
2005-11-30 03:33:49 +00:00
|
|
|
return (result);
|
2001-02-23 00:15:55 +00:00
|
|
|
|
|
|
|
cleanup:
|
2005-11-30 03:33:49 +00:00
|
|
|
if (obj != NULL) {
|
|
|
|
isc_mem_put(pctx->mctx, obj, sizeof(*obj));
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2001-02-23 00:15:55 +00:00
|
|
|
return (result);
|
|
|
|
}
|
|
|
|
|
2021-06-10 08:06:48 +02:00
|
|
|
cfg_type_t cfg_type_token = { "token", parse_token,
|
|
|
|
cfg_print_ustring, cfg_doc_terminal,
|
|
|
|
&cfg_rep_string, NULL };
|
2001-02-23 00:15:55 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* An unsupported option. This is just a list of tokens with balanced braces
|
|
|
|
* ending in a semicolon.
|
|
|
|
*/
|
|
|
|
|
|
|
|
static isc_result_t
|
2001-07-23 00:23:30 +00:00
|
|
|
parse_unsupported(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
|
2001-02-23 00:15:55 +00:00
|
|
|
cfg_obj_t *listobj = NULL;
|
|
|
|
isc_result_t result;
|
|
|
|
int braces = 0;
|
|
|
|
|
2002-01-04 02:32:16 +00:00
|
|
|
CHECK(cfg_create_list(pctx, type, &listobj));
|
2001-02-23 00:15:55 +00:00
|
|
|
|
|
|
|
for (;;) {
|
|
|
|
cfg_listelt_t *elt = NULL;
|
|
|
|
|
|
|
|
CHECK(cfg_peektoken(pctx, 0));
|
2001-02-15 04:14:15 +00:00
|
|
|
if (pctx->token.type == isc_tokentype_special) {
|
|
|
|
if (pctx->token.value.as_char == '{') {
|
|
|
|
braces++;
|
|
|
|
} else if (pctx->token.value.as_char == '}') {
|
|
|
|
braces--;
|
2020-02-13 18:16:57 +01:00
|
|
|
} else if (pctx->token.value.as_char == ';') {
|
|
|
|
if (braces == 0) {
|
2001-02-15 04:14:15 +00:00
|
|
|
break;
|
2020-02-13 18:16:57 +01:00
|
|
|
}
|
|
|
|
}
|
2001-02-15 04:14:15 +00:00
|
|
|
}
|
|
|
|
if (pctx->token.type == isc_tokentype_eof || braces < 0) {
|
2002-01-04 02:32:16 +00:00
|
|
|
cfg_parser_error(pctx, CFG_LOG_NEAR,
|
|
|
|
"unexpected token");
|
2001-02-15 04:14:15 +00:00
|
|
|
result = ISC_R_UNEXPECTEDTOKEN;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2002-01-04 02:32:16 +00:00
|
|
|
CHECK(cfg_parse_listelt(pctx, &cfg_type_token, &elt));
|
2001-02-15 04:14:15 +00:00
|
|
|
ISC_LIST_APPEND(listobj->value.list, elt, link);
|
|
|
|
}
|
|
|
|
INSIST(braces == 0);
|
|
|
|
*ret = listobj;
|
|
|
|
return (ISC_R_SUCCESS);
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
CLEANUP_OBJ(listobj);
|
|
|
|
return (result);
|
|
|
|
}
|
|
|
|
|
2021-06-10 08:06:48 +02:00
|
|
|
cfg_type_t cfg_type_unsupported = { "unsupported", parse_unsupported,
|
|
|
|
cfg_print_spacelist, cfg_doc_terminal,
|
|
|
|
&cfg_rep_list, NULL };
|
2001-02-15 04:14:15 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Try interpreting the current token as a network address.
|
2001-02-28 19:54:10 +00:00
|
|
|
*
|
2002-01-04 02:32:16 +00:00
|
|
|
* 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
|
2008-09-25 04:02:39 +00:00
|
|
|
* "*" is interpreted as the IPv4 wildcard address if CFG_ADDR_V4OK is
|
2002-01-04 02:32:16 +00:00
|
|
|
* set (including the case where CFG_ADDR_V4OK and CFG_ADDR_V6OK are both set),
|
2001-02-28 19:54:10 +00:00
|
|
|
* and the IPv6 wildcard address otherwise.
|
2001-02-15 04:14:15 +00:00
|
|
|
*/
|
|
|
|
static isc_result_t
|
|
|
|
token_addr(cfg_parser_t *pctx, unsigned int flags, isc_netaddr_t *na) {
|
|
|
|
char *s;
|
|
|
|
struct in_addr in4a;
|
|
|
|
struct in6_addr in6a;
|
|
|
|
|
|
|
|
if (pctx->token.type != isc_tokentype_string) {
|
|
|
|
return (ISC_R_UNEXPECTEDTOKEN);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2001-02-15 04:14:15 +00:00
|
|
|
|
2002-01-22 19:31:57 +00:00
|
|
|
s = TOKEN_STRING(pctx);
|
2002-01-04 02:32:16 +00:00
|
|
|
if ((flags & CFG_ADDR_WILDOK) != 0 && strcmp(s, "*") == 0) {
|
|
|
|
if ((flags & CFG_ADDR_V4OK) != 0) {
|
2001-02-15 04:14:15 +00:00
|
|
|
isc_netaddr_any(na);
|
2001-02-16 02:43:30 +00:00
|
|
|
return (ISC_R_SUCCESS);
|
2002-01-04 02:32:16 +00:00
|
|
|
} else if ((flags & CFG_ADDR_V6OK) != 0) {
|
2001-02-15 04:14:15 +00:00
|
|
|
isc_netaddr_any6(na);
|
2001-02-16 02:43:30 +00:00
|
|
|
return (ISC_R_SUCCESS);
|
|
|
|
} else {
|
2021-10-11 12:50:17 +02:00
|
|
|
UNREACHABLE();
|
2001-02-16 02:43:30 +00:00
|
|
|
}
|
2001-02-15 04:14:15 +00:00
|
|
|
} else {
|
2002-01-04 02:32:16 +00:00
|
|
|
if ((flags & (CFG_ADDR_V4OK | CFG_ADDR_V4PREFIXOK)) != 0) {
|
2001-02-15 04:14:15 +00:00
|
|
|
if (inet_pton(AF_INET, s, &in4a) == 1) {
|
|
|
|
isc_netaddr_fromin(na, &in4a);
|
|
|
|
return (ISC_R_SUCCESS);
|
|
|
|
}
|
|
|
|
}
|
2017-09-13 00:14:37 -07:00
|
|
|
if ((flags & CFG_ADDR_V4PREFIXOK) != 0 && strlen(s) <= 15U) {
|
2001-02-15 04:14:15 +00:00
|
|
|
char buf[64];
|
|
|
|
int i;
|
|
|
|
|
2017-09-13 00:14:37 -07:00
|
|
|
strlcpy(buf, s, sizeof(buf));
|
2001-02-15 04:14:15 +00:00
|
|
|
for (i = 0; i < 3; i++) {
|
2017-09-13 00:14:37 -07:00
|
|
|
strlcat(buf, ".0", sizeof(buf));
|
2001-02-15 04:14:15 +00:00
|
|
|
if (inet_pton(AF_INET, buf, &in4a) == 1) {
|
|
|
|
isc_netaddr_fromin(na, &in4a);
|
2019-07-15 10:25:36 +10:00
|
|
|
return (ISC_R_IPV4PREFIX);
|
2001-02-15 04:14:15 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2017-09-13 00:14:37 -07:00
|
|
|
if ((flags & CFG_ADDR_V6OK) != 0 && strlen(s) <= 127U) {
|
2004-05-15 03:37:34 +00:00
|
|
|
char buf[128]; /* see lib/bind9/getaddresses.c */
|
2002-10-24 03:52:35 +00:00
|
|
|
char *d; /* zone delimiter */
|
2018-03-28 14:19:37 +02:00
|
|
|
uint32_t zone = 0; /* scope zone ID */
|
2002-10-24 03:52:35 +00:00
|
|
|
|
2017-09-13 00:14:37 -07:00
|
|
|
strlcpy(buf, s, sizeof(buf));
|
2002-10-24 03:52:35 +00:00
|
|
|
d = strchr(buf, '%');
|
|
|
|
if (d != NULL) {
|
|
|
|
*d = '\0';
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2002-10-24 03:52:35 +00:00
|
|
|
|
|
|
|
if (inet_pton(AF_INET6, buf, &in6a) == 1) {
|
|
|
|
if (d != NULL) {
|
|
|
|
isc_result_t result;
|
|
|
|
|
|
|
|
result = isc_netscope_pton(
|
|
|
|
AF_INET6, d + 1, &in6a, &zone);
|
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
return (result);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2002-10-24 03:52:35 +00:00
|
|
|
}
|
|
|
|
|
2001-02-15 04:14:15 +00:00
|
|
|
isc_netaddr_fromin6(na, &in6a);
|
2002-10-24 03:52:35 +00:00
|
|
|
isc_netaddr_setzone(na, zone);
|
2001-02-15 04:14:15 +00:00
|
|
|
return (ISC_R_SUCCESS);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2001-10-12 22:00:31 +00:00
|
|
|
return (ISC_R_UNEXPECTEDTOKEN);
|
2001-02-15 04:14:15 +00:00
|
|
|
}
|
|
|
|
|
2002-01-04 02:32:16 +00:00
|
|
|
isc_result_t
|
|
|
|
cfg_parse_rawaddr(cfg_parser_t *pctx, unsigned int flags, isc_netaddr_t *na) {
|
2001-02-15 04:14:15 +00:00
|
|
|
isc_result_t result;
|
2006-02-17 00:24:21 +00:00
|
|
|
const char *wild = "";
|
|
|
|
const char *prefix = "";
|
|
|
|
|
2016-10-10 17:11:21 -07:00
|
|
|
REQUIRE(pctx != NULL);
|
|
|
|
REQUIRE(na != NULL);
|
|
|
|
|
2001-02-15 04:14:15 +00:00
|
|
|
CHECK(cfg_gettoken(pctx, 0));
|
2001-10-12 22:00:31 +00:00
|
|
|
result = token_addr(pctx, flags, na);
|
2006-02-17 00:24:21 +00:00
|
|
|
if (result == ISC_R_UNEXPECTEDTOKEN) {
|
|
|
|
if ((flags & CFG_ADDR_WILDOK) != 0) {
|
|
|
|
wild = " or '*'";
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2006-02-17 00:24:21 +00:00
|
|
|
if ((flags & CFG_ADDR_V4PREFIXOK) != 0) {
|
|
|
|
wild = " or IPv4 prefix";
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2006-02-17 00:24:21 +00:00
|
|
|
if ((flags & CFG_ADDR_MASK) == CFG_ADDR_V4OK) {
|
|
|
|
cfg_parser_error(pctx, CFG_LOG_NEAR,
|
|
|
|
"expected IPv4 address%s%s", prefix,
|
|
|
|
wild);
|
|
|
|
} else if ((flags & CFG_ADDR_MASK) == CFG_ADDR_V6OK) {
|
|
|
|
cfg_parser_error(pctx, CFG_LOG_NEAR,
|
|
|
|
"expected IPv6 address%s%s", prefix,
|
|
|
|
wild);
|
|
|
|
} else {
|
|
|
|
cfg_parser_error(pctx, CFG_LOG_NEAR,
|
|
|
|
"expected IP address%s%s", prefix,
|
|
|
|
wild);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2006-02-17 00:24:21 +00:00
|
|
|
}
|
2001-02-15 04:14:15 +00:00
|
|
|
cleanup:
|
|
|
|
return (result);
|
|
|
|
}
|
|
|
|
|
2018-04-17 08:29:14 -07:00
|
|
|
bool
|
2002-01-04 02:32:16 +00:00
|
|
|
cfg_lookingat_netaddr(cfg_parser_t *pctx, unsigned int flags) {
|
2001-02-15 04:14:15 +00:00
|
|
|
isc_result_t result;
|
|
|
|
isc_netaddr_t na_dummy;
|
2016-10-10 17:11:21 -07:00
|
|
|
|
|
|
|
REQUIRE(pctx != NULL);
|
|
|
|
|
2001-02-15 04:14:15 +00:00
|
|
|
result = token_addr(pctx, flags, &na_dummy);
|
2019-07-15 10:25:36 +10:00
|
|
|
return (result == ISC_R_SUCCESS || result == ISC_R_IPV4PREFIX);
|
2001-02-15 04:14:15 +00:00
|
|
|
}
|
|
|
|
|
2002-01-04 02:32:16 +00:00
|
|
|
isc_result_t
|
|
|
|
cfg_parse_rawport(cfg_parser_t *pctx, unsigned int flags, in_port_t *port) {
|
2001-02-15 04:14:15 +00:00
|
|
|
isc_result_t result;
|
|
|
|
|
2016-10-10 17:11:21 -07:00
|
|
|
REQUIRE(pctx != NULL);
|
|
|
|
REQUIRE(port != NULL);
|
|
|
|
|
2001-02-15 04:14:15 +00:00
|
|
|
CHECK(cfg_gettoken(pctx, ISC_LEXOPT_NUMBER));
|
|
|
|
|
2002-01-04 02:32:16 +00:00
|
|
|
if ((flags & CFG_ADDR_WILDOK) != 0 &&
|
2001-02-15 04:14:15 +00:00
|
|
|
pctx->token.type == isc_tokentype_string &&
|
2002-01-22 19:31:57 +00:00
|
|
|
strcmp(TOKEN_STRING(pctx), "*") == 0)
|
|
|
|
{
|
2001-02-15 04:14:15 +00:00
|
|
|
*port = 0;
|
|
|
|
return (ISC_R_SUCCESS);
|
|
|
|
}
|
|
|
|
if (pctx->token.type != isc_tokentype_number) {
|
2002-01-04 02:32:16 +00:00
|
|
|
cfg_parser_error(pctx, CFG_LOG_NEAR,
|
2001-02-15 04:14:15 +00:00
|
|
|
"expected port number or '*'");
|
|
|
|
return (ISC_R_UNEXPECTEDTOKEN);
|
|
|
|
}
|
2004-03-18 02:58:08 +00:00
|
|
|
if (pctx->token.value.as_ulong >= 65536U) {
|
2002-01-04 02:32:16 +00:00
|
|
|
cfg_parser_error(pctx, CFG_LOG_NEAR,
|
2001-02-15 04:14:15 +00:00
|
|
|
"port number out of range");
|
|
|
|
return (ISC_R_UNEXPECTEDTOKEN);
|
|
|
|
}
|
2001-02-17 00:46:58 +00:00
|
|
|
*port = (in_port_t)(pctx->token.value.as_ulong);
|
2001-02-15 04:14:15 +00:00
|
|
|
return (ISC_R_SUCCESS);
|
|
|
|
cleanup:
|
|
|
|
return (result);
|
|
|
|
}
|
|
|
|
|
2002-01-04 02:32:16 +00:00
|
|
|
void
|
2006-02-28 02:39:52 +00:00
|
|
|
cfg_print_rawaddr(cfg_printer_t *pctx, const isc_netaddr_t *na) {
|
2001-02-15 04:14:15 +00:00
|
|
|
isc_result_t result;
|
|
|
|
char text[128];
|
|
|
|
isc_buffer_t buf;
|
|
|
|
|
2016-10-10 17:11:21 -07:00
|
|
|
REQUIRE(pctx != NULL);
|
|
|
|
REQUIRE(na != NULL);
|
|
|
|
|
2001-02-15 04:14:15 +00:00
|
|
|
isc_buffer_init(&buf, text, sizeof(text));
|
|
|
|
result = isc_netaddr_totext(na, &buf);
|
|
|
|
RUNTIME_CHECK(result == ISC_R_SUCCESS);
|
2015-01-06 22:57:57 -08:00
|
|
|
cfg_print_chars(pctx, isc_buffer_base(&buf),
|
|
|
|
isc_buffer_usedlength(&buf));
|
2001-02-15 04:14:15 +00:00
|
|
|
}
|
|
|
|
|
2001-02-27 01:31:56 +00:00
|
|
|
/* netaddr */
|
|
|
|
|
2004-07-23 04:15:27 +00:00
|
|
|
static unsigned int netaddr_flags = CFG_ADDR_V4OK | CFG_ADDR_V6OK;
|
|
|
|
static unsigned int netaddr4_flags = CFG_ADDR_V4OK;
|
|
|
|
static unsigned int netaddr4wild_flags = CFG_ADDR_V4OK | CFG_ADDR_WILDOK;
|
|
|
|
static unsigned int netaddr6_flags = CFG_ADDR_V6OK;
|
|
|
|
static unsigned int netaddr6wild_flags = CFG_ADDR_V6OK | CFG_ADDR_WILDOK;
|
|
|
|
|
2001-02-27 01:31:56 +00:00
|
|
|
static isc_result_t
|
2001-07-23 00:23:30 +00:00
|
|
|
parse_netaddr(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
|
2001-02-27 01:31:56 +00:00
|
|
|
isc_result_t result;
|
|
|
|
cfg_obj_t *obj = NULL;
|
|
|
|
isc_netaddr_t netaddr;
|
2004-07-23 04:15:27 +00:00
|
|
|
unsigned int flags = *(const unsigned int *)type->of;
|
|
|
|
|
2002-01-04 02:32:16 +00:00
|
|
|
CHECK(cfg_create_obj(pctx, type, &obj));
|
2004-07-23 04:15:27 +00:00
|
|
|
CHECK(cfg_parse_rawaddr(pctx, flags, &netaddr));
|
2001-02-27 01:31:56 +00:00
|
|
|
isc_sockaddr_fromnetaddr(&obj->value.sockaddr, &netaddr, 0);
|
|
|
|
*ret = obj;
|
|
|
|
return (ISC_R_SUCCESS);
|
|
|
|
cleanup:
|
|
|
|
CLEANUP_OBJ(obj);
|
|
|
|
return (result);
|
|
|
|
}
|
|
|
|
|
2004-07-23 04:15:27 +00:00
|
|
|
static void
|
|
|
|
cfg_doc_netaddr(cfg_printer_t *pctx, const cfg_type_t *type) {
|
|
|
|
const unsigned int *flagp = type->of;
|
|
|
|
int n = 0;
|
2018-10-11 11:57:57 +02:00
|
|
|
if (*flagp != CFG_ADDR_V4OK && *flagp != CFG_ADDR_V6OK) {
|
2015-01-06 22:57:57 -08:00
|
|
|
cfg_print_cstr(pctx, "( ");
|
2018-10-11 11:57:57 +02:00
|
|
|
}
|
|
|
|
if ((*flagp & CFG_ADDR_V4OK) != 0) {
|
2004-07-23 04:15:27 +00:00
|
|
|
cfg_print_cstr(pctx, "<ipv4_address>");
|
|
|
|
n++;
|
|
|
|
}
|
2018-10-11 11:57:57 +02:00
|
|
|
if ((*flagp & CFG_ADDR_V6OK) != 0) {
|
2004-07-23 04:15:27 +00:00
|
|
|
if (n != 0) {
|
2015-01-06 22:57:57 -08:00
|
|
|
cfg_print_cstr(pctx, " | ");
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2004-07-23 04:15:27 +00:00
|
|
|
cfg_print_cstr(pctx, "<ipv6_address>");
|
2008-09-25 04:02:39 +00:00
|
|
|
n++;
|
2004-07-23 04:15:27 +00:00
|
|
|
}
|
2018-10-11 11:57:57 +02:00
|
|
|
if ((*flagp & CFG_ADDR_WILDOK) != 0) {
|
2004-07-23 04:15:27 +00:00
|
|
|
if (n != 0) {
|
2015-01-06 22:57:57 -08:00
|
|
|
cfg_print_cstr(pctx, " | ");
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2015-01-06 22:57:57 -08:00
|
|
|
cfg_print_cstr(pctx, "*");
|
2004-07-23 04:15:27 +00:00
|
|
|
n++;
|
2011-03-11 06:11:27 +00:00
|
|
|
POST(n);
|
2004-07-23 04:15:27 +00:00
|
|
|
}
|
2018-10-11 11:57:57 +02:00
|
|
|
if (*flagp != CFG_ADDR_V4OK && *flagp != CFG_ADDR_V6OK) {
|
2015-01-06 22:57:57 -08:00
|
|
|
cfg_print_cstr(pctx, " )");
|
2018-10-11 11:57:57 +02:00
|
|
|
}
|
2004-07-23 04:15:27 +00:00
|
|
|
}
|
|
|
|
|
2021-06-10 08:06:48 +02:00
|
|
|
cfg_type_t cfg_type_netaddr = { "netaddr", parse_netaddr,
|
|
|
|
cfg_print_sockaddr, cfg_doc_netaddr,
|
|
|
|
&cfg_rep_sockaddr, &netaddr_flags };
|
2004-07-23 04:15:27 +00:00
|
|
|
|
2021-06-10 08:06:48 +02:00
|
|
|
cfg_type_t cfg_type_netaddr4 = { "netaddr4", parse_netaddr,
|
|
|
|
cfg_print_sockaddr, cfg_doc_netaddr,
|
|
|
|
&cfg_rep_sockaddr, &netaddr4_flags };
|
2004-07-23 04:15:27 +00:00
|
|
|
|
2021-06-10 08:06:48 +02:00
|
|
|
cfg_type_t cfg_type_netaddr4wild = { "netaddr4wild", parse_netaddr,
|
|
|
|
cfg_print_sockaddr, cfg_doc_netaddr,
|
|
|
|
&cfg_rep_sockaddr, &netaddr4wild_flags };
|
2004-07-23 04:15:27 +00:00
|
|
|
|
2021-06-10 08:06:48 +02:00
|
|
|
cfg_type_t cfg_type_netaddr6 = { "netaddr6", parse_netaddr,
|
|
|
|
cfg_print_sockaddr, cfg_doc_netaddr,
|
|
|
|
&cfg_rep_sockaddr, &netaddr6_flags };
|
2004-07-23 04:15:27 +00:00
|
|
|
|
2021-06-10 08:06:48 +02:00
|
|
|
cfg_type_t cfg_type_netaddr6wild = { "netaddr6wild", parse_netaddr,
|
|
|
|
cfg_print_sockaddr, cfg_doc_netaddr,
|
|
|
|
&cfg_rep_sockaddr, &netaddr6wild_flags };
|
2001-02-27 01:31:56 +00:00
|
|
|
|
|
|
|
/* netprefix */
|
|
|
|
|
2002-01-04 02:32:16 +00:00
|
|
|
isc_result_t
|
2002-01-22 19:31:57 +00:00
|
|
|
cfg_parse_netprefix(cfg_parser_t *pctx, const cfg_type_t *type,
|
|
|
|
cfg_obj_t **ret) {
|
2001-02-15 04:14:15 +00:00
|
|
|
cfg_obj_t *obj = NULL;
|
|
|
|
isc_result_t result;
|
|
|
|
isc_netaddr_t netaddr;
|
2011-03-11 06:11:27 +00:00
|
|
|
unsigned int addrlen = 0, prefixlen;
|
2019-07-15 10:25:36 +10:00
|
|
|
bool expectprefix;
|
2016-10-10 17:11:21 -07:00
|
|
|
|
|
|
|
REQUIRE(pctx != NULL);
|
|
|
|
REQUIRE(ret != NULL && *ret == NULL);
|
|
|
|
|
2001-02-15 04:14:15 +00:00
|
|
|
UNUSED(type);
|
|
|
|
|
2019-07-15 10:25:36 +10:00
|
|
|
result = cfg_parse_rawaddr(
|
|
|
|
pctx, CFG_ADDR_V4OK | CFG_ADDR_V4PREFIXOK | CFG_ADDR_V6OK,
|
|
|
|
&netaddr);
|
|
|
|
if (result != ISC_R_SUCCESS && result != ISC_R_IPV4PREFIX) {
|
|
|
|
CHECK(result);
|
|
|
|
}
|
2001-10-26 19:35:03 +00:00
|
|
|
switch (netaddr.family) {
|
|
|
|
case AF_INET:
|
|
|
|
addrlen = 32;
|
|
|
|
break;
|
|
|
|
case AF_INET6:
|
|
|
|
addrlen = 128;
|
|
|
|
break;
|
|
|
|
default:
|
2021-10-11 12:50:17 +02:00
|
|
|
UNREACHABLE();
|
2001-10-26 19:35:03 +00:00
|
|
|
}
|
2019-07-15 10:25:36 +10:00
|
|
|
expectprefix = (result == ISC_R_IPV4PREFIX);
|
2001-02-15 04:14:15 +00:00
|
|
|
CHECK(cfg_peektoken(pctx, 0));
|
|
|
|
if (pctx->token.type == isc_tokentype_special &&
|
|
|
|
pctx->token.value.as_char == '/')
|
|
|
|
{
|
|
|
|
CHECK(cfg_gettoken(pctx, 0)); /* read "/" */
|
|
|
|
CHECK(cfg_gettoken(pctx, ISC_LEXOPT_NUMBER));
|
|
|
|
if (pctx->token.type != isc_tokentype_number) {
|
2002-01-04 02:32:16 +00:00
|
|
|
cfg_parser_error(pctx, CFG_LOG_NEAR,
|
2019-07-15 10:25:36 +10:00
|
|
|
"expected prefix length");
|
2001-02-15 04:14:15 +00:00
|
|
|
return (ISC_R_UNEXPECTEDTOKEN);
|
|
|
|
}
|
|
|
|
prefixlen = pctx->token.value.as_ulong;
|
2001-10-26 19:35:03 +00:00
|
|
|
if (prefixlen > addrlen) {
|
2002-01-04 02:32:16 +00:00
|
|
|
cfg_parser_error(pctx, CFG_LOG_NOPREP,
|
2019-07-15 10:25:36 +10:00
|
|
|
"invalid prefix length");
|
2001-10-26 19:35:03 +00:00
|
|
|
return (ISC_R_RANGE);
|
2001-02-15 04:14:15 +00:00
|
|
|
}
|
2019-07-15 10:25:36 +10:00
|
|
|
result = isc_netaddr_prefixok(&netaddr, prefixlen);
|
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
char buf[ISC_NETADDR_FORMATSIZE + 1];
|
|
|
|
isc_netaddr_format(&netaddr, buf, sizeof(buf));
|
|
|
|
cfg_parser_error(pctx, CFG_LOG_NOPREP,
|
|
|
|
"'%s/%u': address/prefix length "
|
|
|
|
"mismatch",
|
|
|
|
buf, prefixlen);
|
|
|
|
return (ISC_R_FAILURE);
|
|
|
|
}
|
2001-10-26 19:35:03 +00:00
|
|
|
} else {
|
2019-07-15 10:25:36 +10:00
|
|
|
if (expectprefix) {
|
|
|
|
cfg_parser_error(pctx, CFG_LOG_NEAR,
|
|
|
|
"incomplete IPv4 address or prefix");
|
|
|
|
return (ISC_R_FAILURE);
|
|
|
|
}
|
2002-01-04 02:32:16 +00:00
|
|
|
prefixlen = addrlen;
|
2001-02-15 04:14:15 +00:00
|
|
|
}
|
2002-01-04 02:32:16 +00:00
|
|
|
CHECK(cfg_create_obj(pctx, &cfg_type_netprefix, &obj));
|
|
|
|
obj->value.netprefix.address = netaddr;
|
|
|
|
obj->value.netprefix.prefixlen = prefixlen;
|
|
|
|
*ret = obj;
|
|
|
|
return (ISC_R_SUCCESS);
|
2001-02-15 04:14:15 +00:00
|
|
|
cleanup:
|
2002-01-04 02:32:16 +00:00
|
|
|
cfg_parser_error(pctx, CFG_LOG_NEAR, "expected network prefix");
|
2001-02-15 04:14:15 +00:00
|
|
|
return (result);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2006-02-28 02:39:52 +00:00
|
|
|
print_netprefix(cfg_printer_t *pctx, const cfg_obj_t *obj) {
|
|
|
|
const cfg_netprefix_t *p = &obj->value.netprefix;
|
|
|
|
|
2002-01-04 02:32:16 +00:00
|
|
|
cfg_print_rawaddr(pctx, &p->address);
|
2015-01-06 22:57:57 -08:00
|
|
|
cfg_print_cstr(pctx, "/");
|
2002-01-04 02:32:16 +00:00
|
|
|
cfg_print_rawuint(pctx, p->prefixlen);
|
2001-02-15 04:14:15 +00:00
|
|
|
}
|
|
|
|
|
2018-04-17 08:29:14 -07:00
|
|
|
bool
|
2006-02-28 02:39:52 +00:00
|
|
|
cfg_obj_isnetprefix(const cfg_obj_t *obj) {
|
2002-01-04 02:32:16 +00:00
|
|
|
REQUIRE(obj != NULL);
|
2018-04-17 08:29:14 -07:00
|
|
|
return (obj->type->rep == &cfg_rep_netprefix);
|
2002-01-04 02:32:16 +00:00
|
|
|
}
|
2001-02-26 18:58:36 +00:00
|
|
|
|
2002-01-04 02:32:16 +00:00
|
|
|
void
|
2006-02-28 02:39:52 +00:00
|
|
|
cfg_obj_asnetprefix(const cfg_obj_t *obj, isc_netaddr_t *netaddr,
|
2011-02-21 06:07:49 +00:00
|
|
|
unsigned int *prefixlen) {
|
2002-01-04 02:32:16 +00:00
|
|
|
REQUIRE(obj != NULL && obj->type->rep == &cfg_rep_netprefix);
|
2011-02-21 06:07:49 +00:00
|
|
|
REQUIRE(netaddr != NULL);
|
|
|
|
REQUIRE(prefixlen != NULL);
|
|
|
|
|
2002-01-04 02:32:16 +00:00
|
|
|
*netaddr = obj->value.netprefix.address;
|
|
|
|
*prefixlen = obj->value.netprefix.prefixlen;
|
|
|
|
}
|
2001-02-15 04:14:15 +00:00
|
|
|
|
2021-06-10 08:06:48 +02:00
|
|
|
cfg_type_t cfg_type_netprefix = { "netprefix", cfg_parse_netprefix,
|
|
|
|
print_netprefix, cfg_doc_terminal,
|
|
|
|
&cfg_rep_netprefix, NULL };
|
2001-02-15 04:14:15 +00:00
|
|
|
|
|
|
|
static isc_result_t
|
2001-07-23 00:23:30 +00:00
|
|
|
parse_sockaddrsub(cfg_parser_t *pctx, const cfg_type_t *type, int flags,
|
2001-02-15 04:14:15 +00:00
|
|
|
cfg_obj_t **ret) {
|
|
|
|
isc_result_t result;
|
|
|
|
isc_netaddr_t netaddr;
|
|
|
|
in_port_t port = 0;
|
|
|
|
cfg_obj_t *obj = NULL;
|
2023-01-09 16:57:41 -08:00
|
|
|
int have_port = 0;
|
2001-02-15 04:14:15 +00:00
|
|
|
|
2002-01-04 02:32:16 +00:00
|
|
|
CHECK(cfg_create_obj(pctx, type, &obj));
|
|
|
|
CHECK(cfg_parse_rawaddr(pctx, flags, &netaddr));
|
2013-03-22 12:27:54 -07:00
|
|
|
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 {
|
|
|
|
break;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2013-03-22 12:27:54 -07:00
|
|
|
} else {
|
|
|
|
break;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2013-03-22 12:27:54 -07:00
|
|
|
}
|
|
|
|
if (have_port > 1) {
|
|
|
|
cfg_parser_error(pctx, 0, "expected at most one port");
|
|
|
|
result = ISC_R_UNEXPECTEDTOKEN;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2001-02-15 04:14:15 +00:00
|
|
|
isc_sockaddr_fromnetaddr(&obj->value.sockaddr, &netaddr, port);
|
|
|
|
*ret = obj;
|
|
|
|
return (ISC_R_SUCCESS);
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
CLEANUP_OBJ(obj);
|
|
|
|
return (result);
|
|
|
|
}
|
|
|
|
|
2002-01-04 02:32:16 +00:00
|
|
|
static unsigned int sockaddr_flags = CFG_ADDR_V4OK | CFG_ADDR_V6OK;
|
2021-06-10 08:06:48 +02:00
|
|
|
cfg_type_t cfg_type_sockaddr = { "sockaddr", cfg_parse_sockaddr,
|
|
|
|
cfg_print_sockaddr, cfg_doc_sockaddr,
|
|
|
|
&cfg_rep_sockaddr, &sockaddr_flags };
|
2002-01-04 02:32:16 +00:00
|
|
|
|
|
|
|
isc_result_t
|
|
|
|
cfg_parse_sockaddr(cfg_parser_t *pctx, const cfg_type_t *type,
|
|
|
|
cfg_obj_t **ret) {
|
2016-10-10 17:11:21 -07:00
|
|
|
const unsigned int *flagp;
|
|
|
|
|
|
|
|
REQUIRE(pctx != NULL);
|
|
|
|
REQUIRE(type != NULL);
|
|
|
|
REQUIRE(ret != NULL && *ret == NULL);
|
|
|
|
|
|
|
|
flagp = type->of;
|
|
|
|
|
2002-01-04 02:32:16 +00:00
|
|
|
return (parse_sockaddrsub(pctx, &cfg_type_sockaddr, *flagp, ret));
|
2001-02-28 19:54:10 +00:00
|
|
|
}
|
|
|
|
|
2002-01-04 02:32:16 +00:00
|
|
|
void
|
2006-02-28 02:39:52 +00:00
|
|
|
cfg_print_sockaddr(cfg_printer_t *pctx, const cfg_obj_t *obj) {
|
2001-02-15 04:14:15 +00:00
|
|
|
isc_netaddr_t netaddr;
|
|
|
|
in_port_t port;
|
|
|
|
char buf[ISC_NETADDR_FORMATSIZE];
|
|
|
|
|
2016-10-10 17:11:21 -07:00
|
|
|
REQUIRE(pctx != NULL);
|
|
|
|
REQUIRE(obj != NULL);
|
|
|
|
|
2001-02-15 04:14:15 +00:00
|
|
|
isc_netaddr_fromsockaddr(&netaddr, &obj->value.sockaddr);
|
|
|
|
isc_netaddr_format(&netaddr, buf, sizeof(buf));
|
2002-01-04 02:32:16 +00:00
|
|
|
cfg_print_cstr(pctx, buf);
|
2001-02-15 04:14:15 +00:00
|
|
|
port = isc_sockaddr_getport(&obj->value.sockaddr);
|
|
|
|
if (port != 0) {
|
2015-01-06 22:57:57 -08:00
|
|
|
cfg_print_cstr(pctx, " port ");
|
2002-01-04 02:32:16 +00:00
|
|
|
cfg_print_rawuint(pctx, port);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
cfg_doc_sockaddr(cfg_printer_t *pctx, const cfg_type_t *type) {
|
2019-09-27 12:07:32 +02:00
|
|
|
const unsigned int *flagp;
|
2002-01-04 02:32:16 +00:00
|
|
|
int n = 0;
|
2016-10-10 17:11:21 -07:00
|
|
|
|
|
|
|
REQUIRE(pctx != NULL);
|
|
|
|
REQUIRE(type != NULL);
|
|
|
|
|
2019-09-27 12:07:32 +02:00
|
|
|
flagp = type->of;
|
|
|
|
|
2015-01-06 22:57:57 -08:00
|
|
|
cfg_print_cstr(pctx, "( ");
|
2018-10-11 11:57:57 +02:00
|
|
|
if ((*flagp & CFG_ADDR_V4OK) != 0) {
|
2002-01-04 02:32:16 +00:00
|
|
|
cfg_print_cstr(pctx, "<ipv4_address>");
|
|
|
|
n++;
|
|
|
|
}
|
2018-10-11 11:57:57 +02:00
|
|
|
if ((*flagp & CFG_ADDR_V6OK) != 0) {
|
2002-01-04 02:32:16 +00:00
|
|
|
if (n != 0) {
|
2015-01-06 22:57:57 -08:00
|
|
|
cfg_print_cstr(pctx, " | ");
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2002-01-04 02:32:16 +00:00
|
|
|
cfg_print_cstr(pctx, "<ipv6_address>");
|
2008-09-25 04:02:39 +00:00
|
|
|
n++;
|
2002-01-04 02:32:16 +00:00
|
|
|
}
|
2018-10-11 11:57:57 +02:00
|
|
|
if ((*flagp & CFG_ADDR_WILDOK) != 0) {
|
2002-01-04 02:32:16 +00:00
|
|
|
if (n != 0) {
|
2015-01-06 22:57:57 -08:00
|
|
|
cfg_print_cstr(pctx, " | ");
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2015-01-06 22:57:57 -08:00
|
|
|
cfg_print_cstr(pctx, "*");
|
2002-01-04 02:32:16 +00:00
|
|
|
n++;
|
2011-03-11 06:11:27 +00:00
|
|
|
POST(n);
|
2002-01-04 02:32:16 +00:00
|
|
|
}
|
2015-01-06 22:57:57 -08:00
|
|
|
cfg_print_cstr(pctx, " ) ");
|
2018-10-11 11:57:57 +02:00
|
|
|
if ((*flagp & CFG_ADDR_WILDOK) != 0) {
|
2002-01-04 02:32:16 +00:00
|
|
|
cfg_print_cstr(pctx, "[ port ( <integer> | * ) ]");
|
|
|
|
} else {
|
|
|
|
cfg_print_cstr(pctx, "[ port <integer> ]");
|
2001-02-15 04:14:15 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-04-17 08:29:14 -07:00
|
|
|
bool
|
2006-02-28 02:39:52 +00:00
|
|
|
cfg_obj_issockaddr(const cfg_obj_t *obj) {
|
2001-02-23 00:15:55 +00:00
|
|
|
REQUIRE(obj != NULL);
|
2018-04-17 08:29:14 -07:00
|
|
|
return (obj->type->rep == &cfg_rep_sockaddr);
|
2001-02-23 00:15:55 +00:00
|
|
|
}
|
|
|
|
|
2006-02-28 02:39:52 +00:00
|
|
|
const isc_sockaddr_t *
|
|
|
|
cfg_obj_assockaddr(const cfg_obj_t *obj) {
|
2001-02-23 00:15:55 +00:00
|
|
|
REQUIRE(obj != NULL && obj->type->rep == &cfg_rep_sockaddr);
|
|
|
|
return (&obj->value.sockaddr);
|
|
|
|
}
|
|
|
|
|
2002-01-04 02:32:16 +00:00
|
|
|
isc_result_t
|
2001-02-15 04:14:15 +00:00
|
|
|
cfg_gettoken(cfg_parser_t *pctx, int options) {
|
|
|
|
isc_result_t result;
|
|
|
|
|
2016-10-10 17:11:21 -07:00
|
|
|
REQUIRE(pctx != NULL);
|
|
|
|
|
2001-02-15 04:14:15 +00:00
|
|
|
if (pctx->seen_eof) {
|
|
|
|
return (ISC_R_SUCCESS);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2001-02-15 04:14:15 +00:00
|
|
|
|
|
|
|
options |= (ISC_LEXOPT_EOF | ISC_LEXOPT_NOMORE);
|
|
|
|
|
|
|
|
redo:
|
2002-01-04 06:19:20 +00:00
|
|
|
pctx->token.type = isc_tokentype_unknown;
|
2001-02-15 04:14:15 +00:00
|
|
|
result = isc_lex_gettoken(pctx->lexer, options, &pctx->token);
|
2018-04-17 08:29:14 -07:00
|
|
|
pctx->ungotten = false;
|
2001-02-15 04:14:15 +00:00
|
|
|
pctx->line = isc_lex_getsourceline(pctx->lexer);
|
|
|
|
|
|
|
|
switch (result) {
|
|
|
|
case ISC_R_SUCCESS:
|
|
|
|
if (pctx->token.type == isc_tokentype_eof) {
|
|
|
|
result = isc_lex_close(pctx->lexer);
|
|
|
|
INSIST(result == ISC_R_NOMORE ||
|
|
|
|
result == ISC_R_SUCCESS);
|
|
|
|
|
|
|
|
if (isc_lex_getsourcename(pctx->lexer) != NULL) {
|
|
|
|
/*
|
|
|
|
* Closed an included file, not the main file.
|
|
|
|
*/
|
2001-05-28 06:05:24 +00:00
|
|
|
cfg_listelt_t *elt;
|
2001-06-07 01:58:49 +00:00
|
|
|
elt = ISC_LIST_TAIL(
|
|
|
|
pctx->open_files->value.list);
|
2001-05-28 06:05:24 +00:00
|
|
|
INSIST(elt != NULL);
|
2001-06-07 01:58:49 +00:00
|
|
|
ISC_LIST_UNLINK(pctx->open_files->value.list,
|
|
|
|
elt, link);
|
|
|
|
ISC_LIST_APPEND(pctx->closed_files->value.list,
|
|
|
|
elt, link);
|
2001-02-15 04:14:15 +00:00
|
|
|
goto redo;
|
|
|
|
}
|
2018-04-17 08:29:14 -07:00
|
|
|
pctx->seen_eof = true;
|
2001-02-15 04:14:15 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case ISC_R_NOSPACE:
|
|
|
|
/* More understandable than "ran out of space". */
|
2002-01-04 02:32:16 +00:00
|
|
|
cfg_parser_error(pctx, CFG_LOG_NEAR, "token too big");
|
2001-02-15 04:14:15 +00:00
|
|
|
break;
|
|
|
|
|
2002-01-04 05:42:12 +00:00
|
|
|
case ISC_R_IOERROR:
|
|
|
|
cfg_parser_error(pctx, 0, "%s", isc_result_totext(result));
|
|
|
|
break;
|
|
|
|
|
2001-02-15 04:14:15 +00:00
|
|
|
default:
|
2002-01-04 02:32:16 +00:00
|
|
|
cfg_parser_error(pctx, CFG_LOG_NEAR, "%s",
|
2002-01-04 05:42:12 +00:00
|
|
|
isc_result_totext(result));
|
2001-02-15 04:14:15 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
return (result);
|
|
|
|
}
|
|
|
|
|
2002-01-04 02:32:16 +00:00
|
|
|
void
|
2001-02-15 04:14:15 +00:00
|
|
|
cfg_ungettoken(cfg_parser_t *pctx) {
|
2016-10-10 17:11:21 -07:00
|
|
|
REQUIRE(pctx != NULL);
|
|
|
|
|
2001-02-15 04:14:15 +00:00
|
|
|
if (pctx->seen_eof) {
|
|
|
|
return;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2001-02-15 04:14:15 +00:00
|
|
|
isc_lex_ungettoken(pctx->lexer, &pctx->token);
|
2018-04-17 08:29:14 -07:00
|
|
|
pctx->ungotten = true;
|
2001-02-15 04:14:15 +00:00
|
|
|
}
|
|
|
|
|
2002-01-04 02:32:16 +00:00
|
|
|
isc_result_t
|
2001-02-15 04:14:15 +00:00
|
|
|
cfg_peektoken(cfg_parser_t *pctx, int options) {
|
|
|
|
isc_result_t result;
|
2016-10-10 17:11:21 -07:00
|
|
|
|
|
|
|
REQUIRE(pctx != NULL);
|
|
|
|
|
2001-02-15 04:14:15 +00:00
|
|
|
CHECK(cfg_gettoken(pctx, options));
|
|
|
|
cfg_ungettoken(pctx);
|
|
|
|
cleanup:
|
|
|
|
return (result);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Get a string token, accepting both the quoted and the unquoted form.
|
|
|
|
* Log an error if the next token is not a string.
|
|
|
|
*/
|
|
|
|
static isc_result_t
|
|
|
|
cfg_getstringtoken(cfg_parser_t *pctx) {
|
|
|
|
isc_result_t result;
|
|
|
|
|
2002-01-04 02:32:16 +00:00
|
|
|
result = cfg_gettoken(pctx, CFG_LEXOPT_QSTRING);
|
2001-02-15 04:14:15 +00:00
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
return (result);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2001-02-15 04:14:15 +00:00
|
|
|
|
|
|
|
if (pctx->token.type != isc_tokentype_string &&
|
|
|
|
pctx->token.type != isc_tokentype_qstring)
|
|
|
|
{
|
2002-01-04 02:32:16 +00:00
|
|
|
cfg_parser_error(pctx, CFG_LOG_NEAR, "expected string");
|
2001-02-15 04:14:15 +00:00
|
|
|
return (ISC_R_UNEXPECTEDTOKEN);
|
|
|
|
}
|
|
|
|
return (ISC_R_SUCCESS);
|
|
|
|
}
|
|
|
|
|
2002-01-04 02:32:16 +00:00
|
|
|
void
|
|
|
|
cfg_parser_error(cfg_parser_t *pctx, unsigned int flags, const char *fmt, ...) {
|
2001-02-15 04:14:15 +00:00
|
|
|
va_list args;
|
2016-10-10 17:11:21 -07:00
|
|
|
|
|
|
|
REQUIRE(pctx != NULL);
|
|
|
|
REQUIRE(fmt != NULL);
|
|
|
|
|
2001-02-15 04:14:15 +00:00
|
|
|
va_start(args, fmt);
|
2018-04-17 08:29:14 -07:00
|
|
|
parser_complain(pctx, false, flags, fmt, args);
|
2001-02-15 04:14:15 +00:00
|
|
|
va_end(args);
|
|
|
|
pctx->errors++;
|
|
|
|
}
|
|
|
|
|
2002-01-04 02:32:16 +00:00
|
|
|
void
|
|
|
|
cfg_parser_warning(cfg_parser_t *pctx, unsigned int flags, const char *fmt,
|
|
|
|
...) {
|
2001-02-15 04:14:15 +00:00
|
|
|
va_list args;
|
2016-10-10 17:11:21 -07:00
|
|
|
|
|
|
|
REQUIRE(pctx != NULL);
|
|
|
|
REQUIRE(fmt != NULL);
|
|
|
|
|
2001-02-15 04:14:15 +00:00
|
|
|
va_start(args, fmt);
|
2018-04-17 08:29:14 -07:00
|
|
|
parser_complain(pctx, true, flags, fmt, args);
|
2001-02-15 04:14:15 +00:00
|
|
|
va_end(args);
|
|
|
|
pctx->warnings++;
|
|
|
|
}
|
|
|
|
|
|
|
|
#define MAX_LOG_TOKEN 30 /* How much of a token to quote in log messages. */
|
|
|
|
|
2018-04-17 08:29:14 -07:00
|
|
|
static bool
|
2011-11-03 05:15:09 +00:00
|
|
|
have_current_file(cfg_parser_t *pctx) {
|
|
|
|
cfg_listelt_t *elt;
|
|
|
|
if (pctx->open_files == NULL) {
|
2018-04-17 08:29:14 -07:00
|
|
|
return (false);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2011-11-03 05:15:09 +00:00
|
|
|
|
|
|
|
elt = ISC_LIST_TAIL(pctx->open_files->value.list);
|
|
|
|
if (elt == NULL) {
|
2018-04-17 08:29:14 -07:00
|
|
|
return (false);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2011-11-03 05:15:09 +00:00
|
|
|
|
2018-04-17 08:29:14 -07:00
|
|
|
return (true);
|
2011-11-03 05:15:09 +00:00
|
|
|
}
|
|
|
|
|
2001-02-15 04:14:15 +00:00
|
|
|
static char *
|
|
|
|
current_file(cfg_parser_t *pctx) {
|
|
|
|
static char none[] = "none";
|
|
|
|
cfg_listelt_t *elt;
|
|
|
|
cfg_obj_t *fileobj;
|
|
|
|
|
2011-11-03 05:15:09 +00:00
|
|
|
if (!have_current_file(pctx)) {
|
2001-02-15 04:14:15 +00:00
|
|
|
return (none);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2011-11-03 05:15:09 +00:00
|
|
|
|
2001-06-07 01:58:49 +00:00
|
|
|
elt = ISC_LIST_TAIL(pctx->open_files->value.list);
|
2011-11-03 05:15:09 +00:00
|
|
|
if (elt == NULL) { /* shouldn't be possible, but... */
|
2001-02-15 04:14:15 +00:00
|
|
|
return (none);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2001-02-15 04:14:15 +00:00
|
|
|
|
|
|
|
fileobj = elt->obj;
|
|
|
|
INSIST(fileobj->type == &cfg_type_qstring);
|
|
|
|
return (fileobj->value.string.base);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2018-04-17 08:29:14 -07:00
|
|
|
parser_complain(cfg_parser_t *pctx, bool is_warning, unsigned int flags,
|
2001-02-15 04:14:15 +00:00
|
|
|
const char *format, va_list args) {
|
|
|
|
char tokenbuf[MAX_LOG_TOKEN + 10];
|
2018-08-21 10:45:29 +02:00
|
|
|
static char where[PATH_MAX + 100];
|
2001-02-15 04:14:15 +00:00
|
|
|
static char message[2048];
|
|
|
|
int level = ISC_LOG_ERROR;
|
|
|
|
const char *prep = "";
|
2003-04-11 07:25:31 +00:00
|
|
|
size_t len;
|
2001-02-15 04:14:15 +00:00
|
|
|
|
|
|
|
if (is_warning) {
|
|
|
|
level = ISC_LOG_WARNING;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2001-02-15 04:14:15 +00:00
|
|
|
|
2011-11-03 05:15:09 +00:00
|
|
|
where[0] = '\0';
|
|
|
|
if (have_current_file(pctx)) {
|
|
|
|
snprintf(where, sizeof(where), "%s:%u: ", current_file(pctx),
|
|
|
|
pctx->line);
|
2015-05-21 23:04:29 -07:00
|
|
|
} else if (pctx->buf_name != NULL) {
|
|
|
|
snprintf(where, sizeof(where), "%s: ", pctx->buf_name);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2001-02-15 04:14:15 +00:00
|
|
|
|
2003-04-11 07:25:31 +00:00
|
|
|
len = vsnprintf(message, sizeof(message), format, args);
|
2015-08-22 15:08:22 +10:00
|
|
|
#define ELLIPSIS " ... "
|
2017-09-13 00:14:37 -07:00
|
|
|
if (len >= sizeof(message)) {
|
2017-10-03 14:54:19 +11:00
|
|
|
message[sizeof(message) - sizeof(ELLIPSIS)] = 0;
|
|
|
|
strlcat(message, ELLIPSIS, sizeof(message));
|
2017-09-13 00:14:37 -07:00
|
|
|
}
|
2001-02-15 04:14:15 +00:00
|
|
|
|
2002-01-04 02:32:16 +00:00
|
|
|
if ((flags & (CFG_LOG_NEAR | CFG_LOG_BEFORE | CFG_LOG_NOPREP)) != 0) {
|
2001-02-15 04:14:15 +00:00
|
|
|
isc_region_t r;
|
|
|
|
|
|
|
|
if (pctx->ungotten) {
|
|
|
|
(void)cfg_gettoken(pctx, 0);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2001-02-15 04:14:15 +00:00
|
|
|
|
|
|
|
if (pctx->token.type == isc_tokentype_eof) {
|
|
|
|
snprintf(tokenbuf, sizeof(tokenbuf), "end of file");
|
2002-01-04 06:19:20 +00:00
|
|
|
} else if (pctx->token.type == isc_tokentype_unknown) {
|
|
|
|
flags = 0;
|
|
|
|
tokenbuf[0] = '\0';
|
2001-02-15 04:14:15 +00:00
|
|
|
} else {
|
|
|
|
isc_lex_getlasttokentext(pctx->lexer, &pctx->token, &r);
|
|
|
|
if (r.length > MAX_LOG_TOKEN) {
|
|
|
|
snprintf(tokenbuf, sizeof(tokenbuf),
|
|
|
|
"'%.*s...'", MAX_LOG_TOKEN, r.base);
|
|
|
|
} else {
|
|
|
|
snprintf(tokenbuf, sizeof(tokenbuf), "'%.*s'",
|
|
|
|
(int)r.length, r.base);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2001-02-15 04:14:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Choose a preposition. */
|
2018-10-11 11:57:57 +02:00
|
|
|
if ((flags & CFG_LOG_NEAR) != 0) {
|
2001-02-15 04:14:15 +00:00
|
|
|
prep = " near ";
|
2018-10-11 11:57:57 +02:00
|
|
|
} else if ((flags & CFG_LOG_BEFORE) != 0) {
|
2001-02-15 04:14:15 +00:00
|
|
|
prep = " before ";
|
2018-10-11 11:57:57 +02:00
|
|
|
} else {
|
2001-02-15 04:14:15 +00:00
|
|
|
prep = " ";
|
2018-10-11 11:57:57 +02:00
|
|
|
}
|
2001-02-15 04:14:15 +00:00
|
|
|
} else {
|
|
|
|
tokenbuf[0] = '\0';
|
|
|
|
}
|
|
|
|
isc_log_write(pctx->lctx, CAT, MOD, level, "%s%s%s%s", where, message,
|
|
|
|
prep, tokenbuf);
|
|
|
|
}
|
|
|
|
|
2001-02-22 00:36:26 +00:00
|
|
|
void
|
2006-02-28 02:39:52 +00:00
|
|
|
cfg_obj_log(const cfg_obj_t *obj, isc_log_t *lctx, int level, const char *fmt,
|
|
|
|
...) {
|
2001-02-22 00:36:26 +00:00
|
|
|
va_list ap;
|
|
|
|
char msgbuf[2048];
|
|
|
|
|
2016-10-10 17:11:21 -07:00
|
|
|
REQUIRE(obj != NULL);
|
|
|
|
REQUIRE(fmt != NULL);
|
|
|
|
|
2016-10-11 17:05:36 +11:00
|
|
|
if (!isc_log_wouldlog(lctx, level)) {
|
2001-02-22 00:36:26 +00:00
|
|
|
return;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2001-02-22 00:36:26 +00:00
|
|
|
|
2001-02-23 04:52:29 +00:00
|
|
|
va_start(ap, fmt);
|
2001-02-22 00:36:26 +00:00
|
|
|
vsnprintf(msgbuf, sizeof(msgbuf), fmt, ap);
|
|
|
|
va_end(ap);
|
2016-01-31 10:17:13 -08:00
|
|
|
|
2016-12-27 08:59:07 +11:00
|
|
|
if (obj->file != NULL) {
|
2016-01-31 10:17:13 -08:00
|
|
|
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);
|
|
|
|
}
|
2001-02-22 00:36:26 +00:00
|
|
|
}
|
|
|
|
|
2002-02-13 03:32:56 +00:00
|
|
|
const char *
|
2006-02-28 02:39:52 +00:00
|
|
|
cfg_obj_file(const cfg_obj_t *obj) {
|
2016-10-10 17:11:21 -07:00
|
|
|
REQUIRE(obj != NULL);
|
|
|
|
|
2002-02-13 03:32:56 +00:00
|
|
|
return (obj->file);
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned int
|
2006-02-28 02:39:52 +00:00
|
|
|
cfg_obj_line(const cfg_obj_t *obj) {
|
2016-10-10 17:11:21 -07:00
|
|
|
REQUIRE(obj != NULL);
|
|
|
|
|
2002-02-13 03:32:56 +00:00
|
|
|
return (obj->line);
|
|
|
|
}
|
|
|
|
|
2002-01-04 02:32:16 +00:00
|
|
|
isc_result_t
|
|
|
|
cfg_create_obj(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
|
2001-02-15 04:14:15 +00:00
|
|
|
cfg_obj_t *obj;
|
|
|
|
|
2016-10-10 17:11:21 -07:00
|
|
|
REQUIRE(pctx != NULL);
|
|
|
|
REQUIRE(type != NULL);
|
|
|
|
REQUIRE(ret != NULL && *ret == NULL);
|
|
|
|
|
2001-02-15 04:14:15 +00:00
|
|
|
obj = isc_mem_get(pctx->mctx, sizeof(cfg_obj_t));
|
2016-01-31 10:17:13 -08:00
|
|
|
|
2001-02-15 04:14:15 +00:00
|
|
|
obj->type = type;
|
|
|
|
obj->file = current_file(pctx);
|
|
|
|
obj->line = pctx->line;
|
2016-01-31 10:17:13 -08:00
|
|
|
obj->pctx = pctx;
|
|
|
|
|
2018-08-01 11:46:11 +02:00
|
|
|
isc_refcount_init(&obj->references, 1);
|
|
|
|
|
2001-03-02 20:00:17 +00:00
|
|
|
*ret = obj;
|
2016-01-31 10:17:13 -08:00
|
|
|
|
2001-02-15 04:14:15 +00:00
|
|
|
return (ISC_R_SUCCESS);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
map_symtabitem_destroy(char *key, unsigned int type, isc_symvalue_t symval,
|
|
|
|
void *userarg) {
|
|
|
|
cfg_obj_t *obj = symval.as_pointer;
|
|
|
|
cfg_parser_t *pctx = (cfg_parser_t *)userarg;
|
|
|
|
|
|
|
|
UNUSED(key);
|
|
|
|
UNUSED(type);
|
|
|
|
|
|
|
|
cfg_obj_destroy(pctx, &obj);
|
|
|
|
}
|
|
|
|
|
|
|
|
static isc_result_t
|
2001-07-23 00:23:30 +00:00
|
|
|
create_map(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
|
2001-02-15 04:14:15 +00:00
|
|
|
isc_result_t result;
|
|
|
|
isc_symtab_t *symtab = NULL;
|
|
|
|
cfg_obj_t *obj = NULL;
|
|
|
|
|
2002-01-04 02:32:16 +00:00
|
|
|
CHECK(cfg_create_obj(pctx, type, &obj));
|
2001-02-15 04:14:15 +00:00
|
|
|
CHECK(isc_symtab_create(pctx->mctx, 5, /* XXX */
|
2018-04-17 08:29:14 -07:00
|
|
|
map_symtabitem_destroy, pctx, false, &symtab));
|
2001-02-15 04:14:15 +00:00
|
|
|
obj->value.map.symtab = symtab;
|
|
|
|
obj->value.map.id = NULL;
|
|
|
|
|
2001-03-02 20:00:17 +00:00
|
|
|
*ret = obj;
|
2001-02-15 04:14:15 +00:00
|
|
|
return (ISC_R_SUCCESS);
|
|
|
|
|
|
|
|
cleanup:
|
2003-07-03 00:43:28 +00:00
|
|
|
if (obj != NULL) {
|
|
|
|
isc_mem_put(pctx->mctx, obj, sizeof(*obj));
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2001-02-15 04:14:15 +00:00
|
|
|
return (result);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
free_map(cfg_parser_t *pctx, cfg_obj_t *obj) {
|
2003-07-03 00:43:28 +00:00
|
|
|
CLEANUP_OBJ(obj->value.map.id);
|
2001-02-15 04:14:15 +00:00
|
|
|
isc_symtab_destroy(&obj->value.map.symtab);
|
|
|
|
}
|
|
|
|
|
2018-04-17 08:29:14 -07:00
|
|
|
bool
|
2006-02-28 02:39:52 +00:00
|
|
|
cfg_obj_istype(const cfg_obj_t *obj, const cfg_type_t *type) {
|
2016-10-10 17:11:21 -07:00
|
|
|
REQUIRE(obj != NULL);
|
|
|
|
REQUIRE(type != NULL);
|
|
|
|
|
2018-04-17 08:29:14 -07:00
|
|
|
return (obj->type == type);
|
2001-02-26 22:37:34 +00:00
|
|
|
}
|
|
|
|
|
2001-02-15 04:14:15 +00:00
|
|
|
/*
|
|
|
|
* Destroy 'obj', a configuration object created in 'pctx'.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
cfg_obj_destroy(cfg_parser_t *pctx, cfg_obj_t **objp) {
|
2013-01-17 14:38:28 +11:00
|
|
|
REQUIRE(objp != NULL && *objp != NULL);
|
|
|
|
REQUIRE(pctx != NULL);
|
|
|
|
|
2018-08-28 10:18:59 +02:00
|
|
|
cfg_obj_t *obj = *objp;
|
|
|
|
*objp = NULL;
|
2013-01-17 23:46:25 +00:00
|
|
|
|
2018-08-17 15:16:59 +02:00
|
|
|
if (isc_refcount_decrement(&obj->references) == 1) {
|
2010-08-11 18:14:20 +00:00
|
|
|
obj->type->rep->free(pctx, obj);
|
|
|
|
isc_refcount_destroy(&obj->references);
|
|
|
|
isc_mem_put(pctx->mctx, obj, sizeof(cfg_obj_t));
|
|
|
|
}
|
2001-02-15 04:14:15 +00:00
|
|
|
}
|
|
|
|
|
2010-08-11 18:14:20 +00:00
|
|
|
void
|
|
|
|
cfg_obj_attach(cfg_obj_t *src, cfg_obj_t **dest) {
|
|
|
|
REQUIRE(src != NULL);
|
|
|
|
REQUIRE(dest != NULL && *dest == NULL);
|
2016-10-10 17:11:21 -07:00
|
|
|
|
2018-08-17 15:16:59 +02:00
|
|
|
isc_refcount_increment(&src->references);
|
2010-08-11 18:14:20 +00:00
|
|
|
*dest = src;
|
|
|
|
}
|
|
|
|
|
2001-02-15 04:14:15 +00:00
|
|
|
static void
|
|
|
|
free_noop(cfg_parser_t *pctx, cfg_obj_t *obj) {
|
|
|
|
UNUSED(pctx);
|
|
|
|
UNUSED(obj);
|
|
|
|
}
|
2001-06-29 18:36:13 +00:00
|
|
|
|
2002-01-04 02:32:16 +00:00
|
|
|
void
|
|
|
|
cfg_doc_obj(cfg_printer_t *pctx, const cfg_type_t *type) {
|
2016-10-10 17:11:21 -07:00
|
|
|
REQUIRE(pctx != NULL);
|
|
|
|
REQUIRE(type != NULL);
|
|
|
|
|
2002-01-04 02:32:16 +00:00
|
|
|
type->doc(pctx, type);
|
2001-06-29 18:36:13 +00:00
|
|
|
}
|
|
|
|
|
2002-01-04 02:32:16 +00:00
|
|
|
void
|
|
|
|
cfg_doc_terminal(cfg_printer_t *pctx, const cfg_type_t *type) {
|
2016-10-10 17:11:21 -07:00
|
|
|
REQUIRE(pctx != NULL);
|
|
|
|
REQUIRE(type != NULL);
|
|
|
|
|
2015-01-06 22:57:57 -08:00
|
|
|
cfg_print_cstr(pctx, "<");
|
2002-01-04 02:32:16 +00:00
|
|
|
cfg_print_cstr(pctx, type->name);
|
2015-01-06 22:57:57 -08:00
|
|
|
cfg_print_cstr(pctx, ">");
|
2001-06-29 18:36:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2019-08-07 10:31:19 -07:00
|
|
|
cfg_print_grammar(const cfg_type_t *type, unsigned int flags,
|
2001-06-29 18:36:13 +00:00
|
|
|
void (*f)(void *closure, const char *text, int textlen),
|
|
|
|
void *closure) {
|
|
|
|
cfg_printer_t pctx;
|
2016-10-10 17:11:21 -07:00
|
|
|
|
2001-06-29 18:36:13 +00:00
|
|
|
pctx.f = f;
|
|
|
|
pctx.closure = closure;
|
|
|
|
pctx.indent = 0;
|
2019-08-07 10:31:19 -07:00
|
|
|
pctx.flags = flags;
|
2002-01-04 02:32:16 +00:00
|
|
|
cfg_doc_obj(&pctx, type);
|
2001-06-29 18:36:13 +00:00
|
|
|
}
|
2015-01-06 22:57:57 -08:00
|
|
|
|
|
|
|
isc_result_t
|
|
|
|
cfg_parser_mapadd(cfg_parser_t *pctx, cfg_obj_t *mapobj, cfg_obj_t *obj,
|
|
|
|
const char *clausename) {
|
|
|
|
isc_result_t result = ISC_R_SUCCESS;
|
|
|
|
const cfg_map_t *map;
|
|
|
|
isc_symvalue_t symval;
|
|
|
|
cfg_obj_t *destobj = NULL;
|
|
|
|
cfg_listelt_t *elt = NULL;
|
|
|
|
const cfg_clausedef_t *const *clauseset;
|
|
|
|
const cfg_clausedef_t *clause;
|
|
|
|
|
|
|
|
REQUIRE(pctx != NULL);
|
|
|
|
REQUIRE(mapobj != NULL && mapobj->type->rep == &cfg_rep_map);
|
|
|
|
REQUIRE(obj != NULL);
|
2016-10-10 17:11:21 -07:00
|
|
|
REQUIRE(clausename != NULL);
|
2015-01-06 22:57:57 -08:00
|
|
|
|
|
|
|
map = &mapobj->value.map;
|
|
|
|
|
|
|
|
clause = NULL;
|
|
|
|
for (clauseset = map->clausesets; *clauseset != NULL; clauseset++) {
|
|
|
|
for (clause = *clauseset; clause->name != NULL; clause++) {
|
|
|
|
if (strcasecmp(clause->name, clausename) == 0) {
|
|
|
|
goto breakout;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
breakout:
|
|
|
|
if (clause == NULL || clause->name == NULL) {
|
|
|
|
return (ISC_R_FAILURE);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2015-01-06 22:57:57 -08:00
|
|
|
|
|
|
|
result = isc_symtab_lookup(map->symtab, clausename, 0, &symval);
|
|
|
|
if (result == ISC_R_NOTFOUND) {
|
|
|
|
if ((clause->flags & CFG_CLAUSEFLAG_MULTI) != 0) {
|
|
|
|
CHECK(cfg_create_list(pctx, &cfg_type_implicitlist,
|
|
|
|
&destobj));
|
|
|
|
CHECK(create_listelt(pctx, &elt));
|
|
|
|
cfg_obj_attach(obj, &elt->obj);
|
|
|
|
ISC_LIST_APPEND(destobj->value.list, elt, link);
|
|
|
|
symval.as_pointer = destobj;
|
|
|
|
} else {
|
|
|
|
symval.as_pointer = obj;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2015-01-06 22:57:57 -08:00
|
|
|
|
|
|
|
CHECK(isc_symtab_define(map->symtab, clausename, 1, symval,
|
|
|
|
isc_symexists_reject));
|
|
|
|
} else {
|
|
|
|
cfg_obj_t *destobj2 = symval.as_pointer;
|
|
|
|
|
|
|
|
INSIST(result == ISC_R_SUCCESS);
|
|
|
|
|
|
|
|
if (destobj2->type == &cfg_type_implicitlist) {
|
|
|
|
CHECK(create_listelt(pctx, &elt));
|
|
|
|
cfg_obj_attach(obj, &elt->obj);
|
|
|
|
ISC_LIST_APPEND(destobj2->value.list, elt, link);
|
|
|
|
} else {
|
|
|
|
result = ISC_R_EXISTS;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2015-01-06 22:57:57 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
destobj = NULL;
|
|
|
|
elt = NULL;
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
if (elt != NULL) {
|
|
|
|
free_listelt(pctx, elt);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2015-01-06 22:57:57 -08:00
|
|
|
CLEANUP_OBJ(destobj);
|
|
|
|
|
|
|
|
return (result);
|
|
|
|
}
|
2018-12-03 15:30:02 +01:00
|
|
|
|
|
|
|
isc_result_t
|
|
|
|
cfg_pluginlist_foreach(const cfg_obj_t *config, const cfg_obj_t *list,
|
|
|
|
isc_log_t *lctx, pluginlist_cb_t *callback,
|
|
|
|
void *callback_data) {
|
|
|
|
isc_result_t result = ISC_R_SUCCESS;
|
|
|
|
const cfg_listelt_t *element;
|
|
|
|
|
|
|
|
REQUIRE(config != NULL);
|
|
|
|
REQUIRE(callback != NULL);
|
|
|
|
|
|
|
|
for (element = cfg_list_first(list); element != NULL;
|
|
|
|
element = cfg_list_next(element))
|
|
|
|
{
|
|
|
|
const cfg_obj_t *plugin = cfg_listelt_value(element);
|
|
|
|
const cfg_obj_t *obj;
|
|
|
|
const char *type, *library;
|
|
|
|
const char *parameters = NULL;
|
|
|
|
|
|
|
|
/* Get the path to the plugin module. */
|
|
|
|
obj = cfg_tuple_get(plugin, "type");
|
|
|
|
type = cfg_obj_asstring(obj);
|
|
|
|
|
|
|
|
/* Only query plugins are supported currently. */
|
|
|
|
if (strcasecmp(type, "query") != 0) {
|
|
|
|
cfg_obj_log(obj, lctx, ISC_LOG_ERROR,
|
|
|
|
"unsupported plugin type");
|
|
|
|
return (ISC_R_FAILURE);
|
|
|
|
}
|
|
|
|
|
|
|
|
library = cfg_obj_asstring(cfg_tuple_get(plugin, "library"));
|
|
|
|
|
|
|
|
obj = cfg_tuple_get(plugin, "parameters");
|
|
|
|
if (obj != NULL && cfg_obj_isstring(obj)) {
|
|
|
|
parameters = cfg_obj_asstring(obj);
|
|
|
|
}
|
|
|
|
|
|
|
|
result = callback(config, obj, library, parameters,
|
|
|
|
callback_data);
|
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return (result);
|
|
|
|
}
|