Check key-directory duplicates for kasp zones

Don't allow the same zone with different dnssec-policies in separate
views have the same key-directory.

Track zones plus key-directory in a symtab and if there is a match,
check the offending zone's dnssec-policy name. If the name is "none"
(there is no kasp for the offending zone), or if the name is the same
(the zone shares keys), it is fine, otherwise it is an error (zones
in views using different policies cannot share the same key-directory).
This commit is contained in:
Matthijs Mekking
2021-05-04 15:35:39 +02:00
parent 8a90139c2c
commit 494e8b2cbd

View File

@@ -72,6 +72,9 @@ static isc_result_t
fileexist(const cfg_obj_t *obj, isc_symtab_t *symtab, bool writeable,
isc_log_t *logctxlogc);
static isc_result_t
keydirexist(const cfg_obj_t *zcgf, const char *dir, const char *kaspnamestr,
isc_symtab_t *symtab, isc_log_t *logctx, isc_mem_t *mctx);
static void
freekey(char *key, unsigned int type, isc_symvalue_t value, void *userarg) {
UNUSED(type);
@@ -2377,9 +2380,9 @@ cleanup:
static isc_result_t
check_zoneconf(const cfg_obj_t *zconfig, const cfg_obj_t *voptions,
const cfg_obj_t *config, isc_symtab_t *symtab,
isc_symtab_t *files, isc_symtab_t *inview, const char *viewname,
dns_rdataclass_t defclass, cfg_aclconfctx_t *actx,
isc_log_t *logctx, isc_mem_t *mctx) {
isc_symtab_t *files, isc_symtab_t *keydirs, isc_symtab_t *inview,
const char *viewname, dns_rdataclass_t defclass,
cfg_aclconfctx_t *actx, isc_log_t *logctx, isc_mem_t *mctx) {
const char *znamestr;
const char *typestr = NULL;
const char *target = NULL;
@@ -2404,6 +2407,8 @@ check_zoneconf(const cfg_obj_t *zconfig, const cfg_obj_t *voptions,
bool has_dnssecpolicy = false;
const void *clauses = NULL;
const char *option = NULL;
const char *kaspname = NULL;
const char *dir = NULL;
static const char *acls[] = {
"allow-notify",
"allow-transfer",
@@ -2633,8 +2638,8 @@ check_zoneconf(const cfg_obj_t *zconfig, const cfg_obj_t *voptions,
(void)cfg_map_get(zoptions, "dnssec-policy", &obj);
if (obj != NULL) {
const cfg_obj_t *kasps = NULL;
const char *kaspname = cfg_obj_asstring(obj);
kaspname = cfg_obj_asstring(obj);
if (strcmp(kaspname, "default") == 0) {
has_dnssecpolicy = true;
} else if (strcmp(kaspname, "insecure") == 0) {
@@ -3188,7 +3193,8 @@ check_zoneconf(const cfg_obj_t *zconfig, const cfg_obj_t *voptions,
obj = NULL;
tresult = cfg_map_get(zoptions, "key-directory", &obj);
if (tresult == ISC_R_SUCCESS) {
const char *dir = cfg_obj_asstring(obj);
dir = cfg_obj_asstring(obj);
tresult = isc_file_isdirectory(dir);
switch (tresult) {
case ISC_R_SUCCESS:
@@ -3210,6 +3216,25 @@ check_zoneconf(const cfg_obj_t *zconfig, const cfg_obj_t *voptions,
}
}
/*
* Make sure there is no other zone with the same
* key-directory and a different dnssec-policy.
*/
if (zname != NULL) {
char keydirbuf[DNS_NAME_FORMATSIZE + 128];
char *tmp = keydirbuf;
size_t len = sizeof(keydirbuf);
dns_name_format(zname, keydirbuf, sizeof(keydirbuf));
tmp += strlen(tmp);
len -= strlen(tmp);
(void)snprintf(tmp, len, "/%s", (dir == NULL) ? "(null)" : dir);
tresult = keydirexist(zconfig, (const char *)keydirbuf,
kaspname, keydirs, logctx, mctx);
if (tresult != ISC_R_SUCCESS) {
result = tresult;
}
}
/*
* Check various options.
*/
@@ -3420,6 +3445,56 @@ fileexist(const cfg_obj_t *obj, isc_symtab_t *symtab, bool writeable,
return (result);
}
static isc_result_t
keydirexist(const cfg_obj_t *zcfg, const char *keydir, const char *kaspnamestr,
isc_symtab_t *symtab, isc_log_t *logctx, isc_mem_t *mctx) {
isc_result_t result;
isc_symvalue_t symvalue;
char *symkey;
if (kaspnamestr == NULL || strcmp(kaspnamestr, "none") == 0) {
return (ISC_R_SUCCESS);
}
result = isc_symtab_lookup(symtab, keydir, 0, &symvalue);
if (result == ISC_R_SUCCESS) {
const cfg_obj_t *kasp = NULL;
const cfg_obj_t *exist = symvalue.as_cpointer;
const char *file = cfg_obj_file(exist);
unsigned int line = cfg_obj_line(exist);
/*
* Having the same key-directory for the same zone is fine
* iff the zone is using the same policy, or has no policy.
*/
(void)cfg_map_get(cfg_tuple_get(exist, "options"),
"dnssec-policy", &kasp);
if (kasp == NULL ||
strcmp(cfg_obj_asstring(kasp), "none") == 0 ||
strcmp(cfg_obj_asstring(kasp), kaspnamestr) == 0)
{
return (ISC_R_SUCCESS);
}
cfg_obj_log(zcfg, logctx, ISC_LOG_ERROR,
"key-directory '%s' already in use by zone %s with "
"policy %s: %s:%u",
keydir,
cfg_obj_asstring(cfg_tuple_get(exist, "name")),
cfg_obj_asstring(kasp), file, line);
return (ISC_R_EXISTS);
}
/*
* Add the new zone plus key-directory.
*/
symkey = isc_mem_strdup(mctx, keydir);
symvalue.as_cpointer = zcfg;
result = isc_symtab_define(symtab, symkey, 2, symvalue,
isc_symexists_reject);
return (result);
}
/*
* Check key list for duplicates key names and that the key names
* are valid domain names as these keys are used for TSIG.
@@ -4379,8 +4454,8 @@ check_dnstap(const cfg_obj_t *voptions, const cfg_obj_t *config,
static isc_result_t
check_viewconf(const cfg_obj_t *config, const cfg_obj_t *voptions,
const char *viewname, dns_rdataclass_t vclass,
isc_symtab_t *files, bool check_plugins, isc_symtab_t *inview,
isc_log_t *logctx, isc_mem_t *mctx) {
isc_symtab_t *files, isc_symtab_t *keydirs, bool check_plugins,
isc_symtab_t *inview, isc_log_t *logctx, isc_mem_t *mctx) {
const cfg_obj_t *zones = NULL;
const cfg_obj_t *view_tkeys = NULL, *global_tkeys = NULL;
const cfg_obj_t *view_mkeys = NULL, *global_mkeys = NULL;
@@ -4437,8 +4512,8 @@ check_viewconf(const cfg_obj_t *config, const cfg_obj_t *voptions,
const cfg_obj_t *zone = cfg_listelt_value(element);
tresult = check_zoneconf(zone, voptions, config, symtab, files,
inview, viewname, vclass, actx, logctx,
mctx);
keydirs, inview, viewname, vclass,
actx, logctx, mctx);
if (tresult != ISC_R_SUCCESS) {
result = ISC_R_FAILURE;
}
@@ -5035,6 +5110,7 @@ bind9_check_namedconf(const cfg_obj_t *config, bool check_plugins,
isc_result_t tresult;
isc_symtab_t *symtab = NULL;
isc_symtab_t *files = NULL;
isc_symtab_t *keydirs = NULL;
isc_symtab_t *inview = NULL;
static const char *builtin[] = { "localhost", "localnets", "any",
@@ -5086,6 +5162,12 @@ bind9_check_namedconf(const cfg_obj_t *config, bool check_plugins,
goto cleanup;
}
tresult = isc_symtab_create(mctx, 100, freekey, mctx, false, &keydirs);
if (tresult != ISC_R_SUCCESS) {
result = tresult;
goto cleanup;
}
tresult = isc_symtab_create(mctx, 100, freekey, mctx, true, &inview);
if (tresult != ISC_R_SUCCESS) {
result = tresult;
@@ -5094,8 +5176,8 @@ bind9_check_namedconf(const cfg_obj_t *config, bool check_plugins,
if (views == NULL) {
tresult = check_viewconf(config, NULL, NULL, dns_rdataclass_in,
files, check_plugins, inview, logctx,
mctx);
files, keydirs, check_plugins, inview,
logctx, mctx);
if (result == ISC_R_SUCCESS && tresult != ISC_R_SUCCESS) {
result = ISC_R_FAILURE;
}
@@ -5186,8 +5268,8 @@ bind9_check_namedconf(const cfg_obj_t *config, bool check_plugins,
}
if (tresult == ISC_R_SUCCESS) {
tresult = check_viewconf(config, voptions, key, vclass,
files, check_plugins, inview,
logctx, mctx);
files, keydirs, check_plugins,
inview, logctx, mctx);
}
if (tresult != ISC_R_SUCCESS) {
result = ISC_R_FAILURE;
@@ -5306,6 +5388,9 @@ cleanup:
if (files != NULL) {
isc_symtab_destroy(&files);
}
if (keydirs != NULL) {
isc_symtab_destroy(&keydirs);
}
return (result);
}