From 4b362a82ebf511d0915585bbe55bdb9b989f439a Mon Sep 17 00:00:00 2001
From: Aram Sargsyan <aram@isc.org>
Date: Mon, 11 Oct 2021 18:13:39 +0000
Subject: [PATCH] Fix catalog zone reconfiguration crash

The following scenario triggers a "named" crash:

1. Configure a catalog zone.
2. Start "named".
3. Comment out the "catalog-zone" clause.
4. Run `rndc reconfig`.
5. Uncomment the "catalog-zone" clause.
6. Run `rndc reconfig` again.

Implement the required cleanup of the in-memory catalog zone during
the first `rndc reconfig`, so that the second `rndc reconfig` could
find it in an expected state.

(cherry picked from commit 43ac2cd229813c04438e027c42c0b93b9661adda)
Conflict: NA
Reference: https://gitlab.isc.org/isc-projects/bind9/-/commit/4b362a82ebf511d0915585bbe55bdb9b989f439a
---
 bin/named/server.c          |  2 ++
 lib/dns/include/dns/zone.h  | 20 ++++++++++++++++++++
 lib/dns/win32/libdns.def.in |  2 ++
 lib/dns/zone.c              | 18 ++++++++++++++++++
 4 files changed, 42 insertions(+)

diff --git a/bin/named/server.c b/bin/named/server.c
index 860ccae8a1..9c0f12f63f 100644
--- a/bin/named/server.c
+++ b/bin/named/server.c
@@ -6523,6 +6523,8 @@ configure_zone(const cfg_obj_t *config, const cfg_obj_t *zconfig,
 
 	if (zone_is_catz) {
 		dns_zone_catz_enable(zone, view->catzs);
+	} else if (dns_zone_catz_is_enabled(zone)) {
+		dns_zone_catz_disable(zone);
 	}
 
 	/*
diff --git a/lib/dns/include/dns/zone.h b/lib/dns/include/dns/zone.h
index 08e2263c5b..33ab5c60fd 100644
--- a/lib/dns/include/dns/zone.h
+++ b/lib/dns/include/dns/zone.h
@@ -2605,6 +2605,26 @@ dns_zone_catz_enable(dns_zone_t *zone, dns_catz_zones_t *catzs);
  * \li	prior to calling, zone->catzs is NULL or is equal to 'catzs'
  */
 
+void
+dns_zone_catz_disable(dns_zone_t *zone);
+/*%<
+ * Disable zone as catalog zone, if it is one.
+ *
+ * Requires:
+ *
+ * \li	'zone' is a valid zone object
+ */
+
+bool
+dns_zone_catz_is_enabled(dns_zone_t *zone);
+/*%<
+ * Return a boolean indicating whether the zone is enabled as catalog zone.
+ *
+ * Requires:
+ *
+ * \li	'zone' is a valid zone object
+ */
+
 void
 dns_zone_catz_enable_db(dns_zone_t *zone, dns_db_t *db);
 /*%<
diff --git a/lib/dns/win32/libdns.def.in b/lib/dns/win32/libdns.def.in
index 31f511103f..1e0f7cf64a 100644
--- a/lib/dns/win32/libdns.def.in
+++ b/lib/dns/win32/libdns.def.in
@@ -1173,8 +1173,10 @@ dns_xfrin_shutdown
 dns_zone_addnsec3chain
 dns_zone_asyncload
 dns_zone_attach
+dns_zone_catz_disable
 dns_zone_catz_enable
 dns_zone_catz_enable_db
+dns_zone_catz_is_enabled
 dns_zone_cdscheck
 dns_zone_checknames
 dns_zone_clearforwardacl
diff --git a/lib/dns/zone.c b/lib/dns/zone.c
index 65a3aacab7..bc33e6ede8 100644
--- a/lib/dns/zone.c
+++ b/lib/dns/zone.c
@@ -1942,6 +1942,24 @@ dns_zone_catz_enable(dns_zone_t *zone, dns_catz_zones_t *catzs) {
 	UNLOCK_ZONE(zone);
 }
 
+void
+dns_zone_catz_disable(dns_zone_t *zone) {
+	REQUIRE(DNS_ZONE_VALID(zone));
+
+	LOCK_ZONE(zone);
+	if (zone->catzs != NULL) {
+		dns_catz_catzs_detach(&zone->catzs);
+	}
+	UNLOCK_ZONE(zone);
+}
+
+bool
+dns_zone_catz_is_enabled(dns_zone_t *zone) {
+	REQUIRE(DNS_ZONE_VALID(zone));
+
+	return (zone->catzs != NULL);
+}
+
 /*
  * If a zone is a catalog zone, attach it to update notification in database.
  */
-- 
2.27.0

