fix: usr: Resolve "key defined in view is not found"

A recent change in `2956e4fc45b3c2142a3351682d4200647448f193` hardened the `key` name check when used in `primaries` to immediately reject the configuration if the key was not defined (rather than only checking whether the key name was correctly formed). However, the change introduced a regression that prevented the use of a `key` defined in a view. This is now fixed.

Merge branch '5761-key-view' into 'main'

See merge request isc-projects/bind9!11588
This commit is contained in:
Colin Vidal 2026-03-01 09:21:03 +01:00
commit 0d5f47e3ec
2 changed files with 88 additions and 47 deletions

View file

@ -0,0 +1,27 @@
/*
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
*
* SPDX-License-Identifier: MPL-2.0
*
* 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/.
*
* See the COPYRIGHT file distributed with this work for additional
* information regarding copyright ownership.
*/
view aview {
key akey {
algorithm hmac-sha256;
secret "9999abcd8765";
};
zone "azone" {
type secondary;
file "azone.db";
primaries {
1.2.3.4 key "akey";
};
};
};

View file

@ -85,8 +85,8 @@ static const cfg_obj_t *
find_maplist(const cfg_obj_t *config, const char *listname, const char *name);
static isc_result_t
validate_remotes(const cfg_obj_t *obj, const cfg_obj_t *config,
uint32_t *countp, isc_mem_t *mctx);
validate_remotes(const cfg_obj_t *obj, const cfg_obj_t *voptions,
const cfg_obj_t *config, uint32_t *countp, isc_mem_t *mctx);
static void
freekey(char *key, unsigned int type, isc_symvalue_t value, void *userarg) {
UNUSED(type);
@ -2093,7 +2093,7 @@ check_remoteserverlist(const cfg_obj_t *cctx, const char *list,
}
uint32_t dummy = 0;
result = validate_remotes(obj, cctx, &dummy, mctx);
result = validate_remotes(obj, NULL, cctx, &dummy, mctx);
if (result != ISC_R_SUCCESS) {
break;
}
@ -2423,16 +2423,56 @@ get_remoteservers_def(const char *name, const cfg_obj_t *cctx,
return get_remotes(cctx, "masters", name, ret);
}
static bool
lookup_key(const cfg_obj_t *config, const dns_name_t *keyname) {
const cfg_obj_t *keys = NULL;
if (config == NULL) {
return false;
}
(void)cfg_map_get(config, "key", &keys);
CFG_LIST_FOREACH(keys, elt) {
/*
* `key` are normalized TSIG which must be identified by
* a domain name, so this is needed. Otherwise, with a
* raw string comparison we could have:
*
* remote-servers { x.y.z.s key foo };
* key foo. {
* ...
* };
*
* This would otherwise fail, even though the key
* exists.
*/
const cfg_obj_t *foundkey = cfg_listelt_value(elt);
const char *foundkeystr =
cfg_obj_asstring(cfg_map_getname(foundkey));
dns_fixedname_t foundfname;
dns_name_t *foundkeyname = dns_fixedname_initname(&foundfname);
isc_result_t result = dns_name_fromstring(
foundkeyname, foundkeystr, dns_rootname, 0, NULL);
if (result == ISC_R_SUCCESS &&
dns_name_equal(keyname, foundkeyname))
{
return true;
}
}
return false;
}
static isc_result_t
validate_remotes_key(const cfg_obj_t *config, const cfg_obj_t *key) {
validate_remotes_key(const cfg_obj_t *voptions, const cfg_obj_t *config,
const cfg_obj_t *key) {
isc_result_t result = ISC_R_SUCCESS;
if (cfg_obj_isstring(key)) {
const cfg_obj_t *keys = NULL;
const char *str = cfg_obj_asstring(key);
dns_fixedname_t fname;
dns_name_t *nm = dns_fixedname_initname(&fname);
bool found = false;
result = dns_name_fromstring(nm, str, dns_rootname, 0, NULL);
if (result != ISC_R_SUCCESS) {
@ -2440,43 +2480,14 @@ validate_remotes_key(const cfg_obj_t *config, const cfg_obj_t *key) {
"'%s' is not a valid name", str);
}
result = cfg_map_get(config, "key", &keys);
CFG_LIST_FOREACH(keys, elt) {
/*
* `key` are normalized TSIG which must be identified by
* a domain name, so this is needed. Otherwise, with a
* raw string comparison we could have:
*
* remote-servers { x.y.z.s key foo };
* key foo. {
* ...
* };
*
* This would otherwise fail, even though the key
* exists.
*/
const cfg_obj_t *foundkey = cfg_listelt_value(elt);
const char *foundkeystr =
cfg_obj_asstring(cfg_map_getname(foundkey));
dns_fixedname_t foundfname;
dns_name_t *foundkeyname =
dns_fixedname_initname(&foundfname);
result = dns_name_fromstring(foundkeyname, foundkeystr,
dns_rootname, 0, NULL);
if (dns_name_equal(nm, foundkeyname)) {
found = true;
break;
if (!lookup_key(voptions, nm)) {
if (!lookup_key(config, nm)) {
cfg_obj_log(key, ISC_LOG_ERROR,
"key '%s' is not defined",
cfg_obj_asstring(key));
result = ISC_R_FAILURE;
}
}
if (!found) {
cfg_obj_log(key, ISC_LOG_ERROR,
"key '%s' is not defined",
cfg_obj_asstring(key));
result = ISC_R_FAILURE;
}
}
return result;
@ -2514,8 +2525,8 @@ validate_remotes_tls(const cfg_obj_t *config, const cfg_obj_t *tls) {
}
static isc_result_t
validate_remotes(const cfg_obj_t *obj, const cfg_obj_t *config,
uint32_t *countp, isc_mem_t *mctx) {
validate_remotes(const cfg_obj_t *obj, const cfg_obj_t *voptions,
const cfg_obj_t *config, uint32_t *countp, isc_mem_t *mctx) {
isc_result_t result = ISC_R_SUCCESS;
isc_result_t tresult;
uint32_t count = 0;
@ -2544,7 +2555,7 @@ resume:
key = cfg_tuple_get(cfg_listelt_value(element), "key");
tls = cfg_tuple_get(cfg_listelt_value(element), "tls");
result = validate_remotes_key(config, key);
result = validate_remotes_key(voptions, config, key);
if (result != ISC_R_SUCCESS) {
goto out;
}
@ -3680,7 +3691,8 @@ isccfg_check_zoneconf(const cfg_obj_t *zconfig, const cfg_obj_t *voptions,
}
if (obj != NULL && donotify) {
uint32_t count;
tresult = validate_remotes(obj, config, &count, mctx);
tresult = validate_remotes(obj, voptions, config,
&count, mctx);
if (tresult != ISC_R_SUCCESS && result == ISC_R_SUCCESS)
{
result = tresult;
@ -3766,7 +3778,8 @@ isccfg_check_zoneconf(const cfg_obj_t *zconfig, const cfg_obj_t *voptions,
result = ISC_R_FAILURE;
} else {
uint32_t count;
tresult = validate_remotes(obj, config, &count, mctx);
tresult = validate_remotes(obj, voptions, config,
&count, mctx);
if (tresult != ISC_R_SUCCESS && result == ISC_R_SUCCESS)
{
result = tresult;
@ -3791,7 +3804,8 @@ isccfg_check_zoneconf(const cfg_obj_t *zconfig, const cfg_obj_t *voptions,
"parental-agents", &obj);
if (obj != NULL) {
uint32_t count;
tresult = validate_remotes(obj, config, &count, mctx);
tresult = validate_remotes(obj, voptions, config,
&count, mctx);
if (tresult != ISC_R_SUCCESS && result == ISC_R_SUCCESS)
{
result = tresult;