xref: /netbsd-src/external/mpl/bind/dist/lib/dns/dlz.c (revision bcda20f65a8566e103791ec395f7f499ef322704)
1*bcda20f6Schristos /*	$NetBSD: dlz.c,v 1.9 2025/01/26 16:25:22 christos Exp $	*/
2d68c78b8Schristos 
3d68c78b8Schristos /*
48596601aSchristos  * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
58596601aSchristos  *
68596601aSchristos  * SPDX-License-Identifier: MPL-2.0 AND ISC
7d68c78b8Schristos  *
8d68c78b8Schristos  * This Source Code Form is subject to the terms of the Mozilla Public
9d68c78b8Schristos  * License, v. 2.0. If a copy of the MPL was not distributed with this
10fce770bdSchristos  * file, you can obtain one at https://mozilla.org/MPL/2.0/.
11d68c78b8Schristos  *
12d68c78b8Schristos  * See the COPYRIGHT file distributed with this work for additional
13d68c78b8Schristos  * information regarding copyright ownership.
14d68c78b8Schristos  */
15d68c78b8Schristos 
16d68c78b8Schristos /*
17d68c78b8Schristos  * Copyright (C) 2002 Stichting NLnet, Netherlands, stichting@nlnet.nl.
18d68c78b8Schristos  *
19d68c78b8Schristos  * Permission to use, copy, modify, and distribute this software for any
20d68c78b8Schristos  * purpose with or without fee is hereby granted, provided that the
21d68c78b8Schristos  * above copyright notice and this permission notice appear in all
22d68c78b8Schristos  * copies.
23d68c78b8Schristos  *
24d68c78b8Schristos  * THE SOFTWARE IS PROVIDED "AS IS" AND STICHTING NLNET
25d68c78b8Schristos  * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
26d68c78b8Schristos  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
27d68c78b8Schristos  * STICHTING NLNET BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
28d68c78b8Schristos  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
29d68c78b8Schristos  * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
30d68c78b8Schristos  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE
31d68c78b8Schristos  * USE OR PERFORMANCE OF THIS SOFTWARE.
32d68c78b8Schristos  *
33d68c78b8Schristos  * The development of Dynamically Loadable Zones (DLZ) for Bind 9 was
34d68c78b8Schristos  * conceived and contributed by Rob Butler.
35d68c78b8Schristos  *
36d68c78b8Schristos  * Permission to use, copy, modify, and distribute this software for any
37d68c78b8Schristos  * purpose with or without fee is hereby granted, provided that the
38d68c78b8Schristos  * above copyright notice and this permission notice appear in all
39d68c78b8Schristos  * copies.
40d68c78b8Schristos  *
41d68c78b8Schristos  * THE SOFTWARE IS PROVIDED "AS IS" AND ROB BUTLER
42d68c78b8Schristos  * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
43d68c78b8Schristos  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
44d68c78b8Schristos  * ROB BUTLER BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
45d68c78b8Schristos  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
46d68c78b8Schristos  * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
47d68c78b8Schristos  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE
48d68c78b8Schristos  * USE OR PERFORMANCE OF THIS SOFTWARE.
49d68c78b8Schristos  */
50d68c78b8Schristos 
51d68c78b8Schristos /*! \file */
52d68c78b8Schristos 
53d68c78b8Schristos /***
54d68c78b8Schristos  *** Imports
55d68c78b8Schristos  ***/
56d68c78b8Schristos 
57d4a20c3eSchristos #include <stdbool.h>
58d4a20c3eSchristos 
59d68c78b8Schristos #include <isc/buffer.h>
60d68c78b8Schristos #include <isc/commandline.h>
61d68c78b8Schristos #include <isc/magic.h>
62d68c78b8Schristos #include <isc/mem.h>
63*bcda20f6Schristos #include <isc/netmgr.h>
64d68c78b8Schristos #include <isc/once.h>
65*bcda20f6Schristos #include <isc/random.h>
66d68c78b8Schristos #include <isc/rwlock.h>
67d68c78b8Schristos #include <isc/string.h>
68d68c78b8Schristos #include <isc/util.h>
69d68c78b8Schristos 
705606745fSchristos #include <dns/db.h>
715606745fSchristos #include <dns/dlz.h>
725606745fSchristos #include <dns/fixedname.h>
735606745fSchristos #include <dns/log.h>
745606745fSchristos #include <dns/master.h>
755606745fSchristos #include <dns/ssu.h>
765606745fSchristos #include <dns/zone.h>
775606745fSchristos 
78d68c78b8Schristos /***
79d68c78b8Schristos  *** Supported DLZ DB Implementations Registry
80d68c78b8Schristos  ***/
81d68c78b8Schristos 
82d68c78b8Schristos static ISC_LIST(dns_dlzimplementation_t) dlz_implementations;
83d68c78b8Schristos static isc_rwlock_t dlz_implock;
84d68c78b8Schristos static isc_once_t once = ISC_ONCE_INIT;
85d68c78b8Schristos 
86d68c78b8Schristos static void
87d68c78b8Schristos dlz_initialize(void) {
88*bcda20f6Schristos 	isc_rwlock_init(&dlz_implock);
89d68c78b8Schristos 	ISC_LIST_INIT(dlz_implementations);
90d68c78b8Schristos }
91d68c78b8Schristos 
92d68c78b8Schristos /*%
93d68c78b8Schristos  * Searches the dlz_implementations list for a driver matching name.
94d68c78b8Schristos  */
958596601aSchristos static dns_dlzimplementation_t *
96d68c78b8Schristos dlz_impfind(const char *name) {
97d68c78b8Schristos 	dns_dlzimplementation_t *imp;
98d68c78b8Schristos 
995606745fSchristos 	for (imp = ISC_LIST_HEAD(dlz_implementations); imp != NULL;
100d68c78b8Schristos 	     imp = ISC_LIST_NEXT(imp, link))
1015606745fSchristos 	{
1025606745fSchristos 		if (strcasecmp(name, imp->name) == 0) {
103*bcda20f6Schristos 			return imp;
1045606745fSchristos 		}
1055606745fSchristos 	}
106*bcda20f6Schristos 	return NULL;
107d68c78b8Schristos }
108d68c78b8Schristos 
109d68c78b8Schristos /***
110d68c78b8Schristos  *** Basic DLZ Methods
111d68c78b8Schristos  ***/
112d68c78b8Schristos 
113d68c78b8Schristos isc_result_t
114d68c78b8Schristos dns_dlzallowzonexfr(dns_view_t *view, const dns_name_t *name,
1155606745fSchristos 		    const isc_sockaddr_t *clientaddr, dns_db_t **dbp) {
116d68c78b8Schristos 	isc_result_t result = ISC_R_NOTFOUND;
117d68c78b8Schristos 	dns_dlzallowzonexfr_t allowzonexfr;
118d68c78b8Schristos 	dns_dlzdb_t *dlzdb;
119d68c78b8Schristos 
120d68c78b8Schristos 	/*
121d68c78b8Schristos 	 * Performs checks to make sure data is as we expect it to be.
122d68c78b8Schristos 	 */
123d68c78b8Schristos 	REQUIRE(name != NULL);
124d68c78b8Schristos 	REQUIRE(dbp != NULL && *dbp == NULL);
125d68c78b8Schristos 
126d68c78b8Schristos 	/*
127d68c78b8Schristos 	 * Find a driver in which the zone exists and transfer is supported
128d68c78b8Schristos 	 */
1295606745fSchristos 	for (dlzdb = ISC_LIST_HEAD(view->dlz_searched); dlzdb != NULL;
130d68c78b8Schristos 	     dlzdb = ISC_LIST_NEXT(dlzdb, link))
131d68c78b8Schristos 	{
132d68c78b8Schristos 		REQUIRE(DNS_DLZ_VALID(dlzdb));
133d68c78b8Schristos 
134d68c78b8Schristos 		allowzonexfr = dlzdb->implementation->methods->allowzonexfr;
135d68c78b8Schristos 		result = (*allowzonexfr)(dlzdb->implementation->driverarg,
136d68c78b8Schristos 					 dlzdb->dbdata, dlzdb->mctx,
137d68c78b8Schristos 					 view->rdclass, name, clientaddr, dbp);
138d68c78b8Schristos 
139d68c78b8Schristos 		/*
1405606745fSchristos 		 * In these cases, we found the right database. Non-success
1415606745fSchristos 		 * result codes indicate the zone might not transfer.
142d68c78b8Schristos 		 */
1435606745fSchristos 		switch (result) {
1445606745fSchristos 		case ISC_R_SUCCESS:
1455606745fSchristos 		case ISC_R_NOPERM:
1465606745fSchristos 		case ISC_R_DEFAULT:
147*bcda20f6Schristos 			return result;
1485606745fSchristos 		default:
1495606745fSchristos 			break;
1505606745fSchristos 		}
151d68c78b8Schristos 	}
152d68c78b8Schristos 
1535606745fSchristos 	if (result == ISC_R_NOTIMPLEMENTED) {
154d68c78b8Schristos 		result = ISC_R_NOTFOUND;
1555606745fSchristos 	}
156d68c78b8Schristos 
157*bcda20f6Schristos 	return result;
158d68c78b8Schristos }
159d68c78b8Schristos 
160d68c78b8Schristos isc_result_t
161d68c78b8Schristos dns_dlzcreate(isc_mem_t *mctx, const char *dlzname, const char *drivername,
1625606745fSchristos 	      unsigned int argc, char *argv[], dns_dlzdb_t **dbp) {
163d68c78b8Schristos 	dns_dlzimplementation_t *impinfo;
164d68c78b8Schristos 	isc_result_t result;
165d68c78b8Schristos 	dns_dlzdb_t *db = NULL;
166d68c78b8Schristos 
167d68c78b8Schristos 	/*
168d68c78b8Schristos 	 * initialize the dlz_implementations list, this is guaranteed
169d68c78b8Schristos 	 * to only really happen once.
170d68c78b8Schristos 	 */
171*bcda20f6Schristos 	isc_once_do(&once, dlz_initialize);
172d68c78b8Schristos 
173d68c78b8Schristos 	/*
174d68c78b8Schristos 	 * Performs checks to make sure data is as we expect it to be.
175d68c78b8Schristos 	 */
176d68c78b8Schristos 	REQUIRE(dbp != NULL && *dbp == NULL);
177d68c78b8Schristos 	REQUIRE(dlzname != NULL);
178d68c78b8Schristos 	REQUIRE(drivername != NULL);
179d68c78b8Schristos 	REQUIRE(mctx != NULL);
180d68c78b8Schristos 
181d68c78b8Schristos 	/* write log message */
1825606745fSchristos 	isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ,
1835606745fSchristos 		      ISC_LOG_INFO, "Loading '%s' using driver %s", dlzname,
1845606745fSchristos 		      drivername);
185d68c78b8Schristos 
186d68c78b8Schristos 	/* lock the dlz_implementations list so we can search it. */
187d68c78b8Schristos 	RWLOCK(&dlz_implock, isc_rwlocktype_read);
188d68c78b8Schristos 
189d68c78b8Schristos 	/* search for the driver implementation	 */
190d68c78b8Schristos 	impinfo = dlz_impfind(drivername);
191d68c78b8Schristos 	if (impinfo == NULL) {
192d68c78b8Schristos 		RWUNLOCK(&dlz_implock, isc_rwlocktype_read);
193d68c78b8Schristos 
194d68c78b8Schristos 		isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
195d68c78b8Schristos 			      DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
196d68c78b8Schristos 			      "unsupported DLZ database driver '%s'."
197d68c78b8Schristos 			      "  %s not loaded.",
198d68c78b8Schristos 			      drivername, dlzname);
199d68c78b8Schristos 
200*bcda20f6Schristos 		return ISC_R_NOTFOUND;
201d68c78b8Schristos 	}
202d68c78b8Schristos 
203d68c78b8Schristos 	/* Allocate memory to hold the DLZ database driver */
204*bcda20f6Schristos 	db = isc_mem_get(mctx, sizeof(*db));
205*bcda20f6Schristos 	*db = (dns_dlzdb_t){
206*bcda20f6Schristos 		.implementation = impinfo,
207*bcda20f6Schristos 	};
208d68c78b8Schristos 
209d68c78b8Schristos 	ISC_LINK_INIT(db, link);
2105606745fSchristos 	if (dlzname != NULL) {
211d68c78b8Schristos 		db->dlzname = isc_mem_strdup(mctx, dlzname);
2125606745fSchristos 	}
213d68c78b8Schristos 
214d68c78b8Schristos 	/* Create a new database using implementation 'drivername'. */
215d68c78b8Schristos 	result = ((impinfo->methods->create)(mctx, dlzname, argc, argv,
2165606745fSchristos 					     impinfo->driverarg, &db->dbdata));
217d68c78b8Schristos 
218d68c78b8Schristos 	RWUNLOCK(&dlz_implock, isc_rwlocktype_read);
219*bcda20f6Schristos 	/* mark the DLZ driver as valid */
220*bcda20f6Schristos 	if (result != ISC_R_SUCCESS) {
221*bcda20f6Schristos 		goto failure;
222d68c78b8Schristos 	}
223d68c78b8Schristos 
224*bcda20f6Schristos 	db->magic = DNS_DLZ_MAGIC;
225*bcda20f6Schristos 	isc_mem_attach(mctx, &db->mctx);
226*bcda20f6Schristos 	isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ,
227*bcda20f6Schristos 		      ISC_LOG_DEBUG(2), "DLZ driver loaded successfully.");
228*bcda20f6Schristos 	*dbp = db;
229*bcda20f6Schristos 	return ISC_R_SUCCESS;
230*bcda20f6Schristos failure:
231*bcda20f6Schristos 	isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ,
232*bcda20f6Schristos 		      ISC_LOG_ERROR, "DLZ driver failed to load.");
233*bcda20f6Schristos 
234d68c78b8Schristos 	/* impinfo->methods->create failed. */
2358596601aSchristos 	isc_mem_free(mctx, db->dlzname);
236*bcda20f6Schristos 	isc_mem_put(mctx, db, sizeof(*db));
237*bcda20f6Schristos 	return result;
238d68c78b8Schristos }
239d68c78b8Schristos 
240d68c78b8Schristos void
241d68c78b8Schristos dns_dlzdestroy(dns_dlzdb_t **dbp) {
242d68c78b8Schristos 	dns_dlzdestroy_t destroy;
243d68c78b8Schristos 	dns_dlzdb_t *db;
244d68c78b8Schristos 
245d68c78b8Schristos 	/* Write debugging message to log */
2465606745fSchristos 	isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ,
2475606745fSchristos 		      ISC_LOG_DEBUG(2), "Unloading DLZ driver.");
248d68c78b8Schristos 
249d68c78b8Schristos 	/*
250d68c78b8Schristos 	 * Perform checks to make sure data is as we expect it to be.
251d68c78b8Schristos 	 */
252d68c78b8Schristos 	REQUIRE(dbp != NULL && DNS_DLZ_VALID(*dbp));
253d68c78b8Schristos 
254d68c78b8Schristos 	db = *dbp;
255d68c78b8Schristos 	*dbp = NULL;
256d68c78b8Schristos 
2575606745fSchristos 	if (db->ssutable != NULL) {
258d68c78b8Schristos 		dns_ssutable_detach(&db->ssutable);
2595606745fSchristos 	}
260d68c78b8Schristos 
261d68c78b8Schristos 	/* call the drivers destroy method */
2625606745fSchristos 	if (db->dlzname != NULL) {
263d68c78b8Schristos 		isc_mem_free(db->mctx, db->dlzname);
2645606745fSchristos 	}
265d68c78b8Schristos 	destroy = db->implementation->methods->destroy;
266d68c78b8Schristos 	(*destroy)(db->implementation->driverarg, db->dbdata);
267d68c78b8Schristos 	/* return memory and detach */
268*bcda20f6Schristos 	isc_mem_putanddetach(&db->mctx, db, sizeof(*db));
269d68c78b8Schristos }
270d68c78b8Schristos 
271d68c78b8Schristos /*%
272d68c78b8Schristos  * Registers a DLZ driver.  This basically just adds the dlz
273d68c78b8Schristos  * driver to the list of available drivers in the dlz_implementations list.
274d68c78b8Schristos  */
275d68c78b8Schristos isc_result_t
276d68c78b8Schristos dns_dlzregister(const char *drivername, const dns_dlzmethods_t *methods,
277d68c78b8Schristos 		void *driverarg, isc_mem_t *mctx,
2785606745fSchristos 		dns_dlzimplementation_t **dlzimp) {
279d68c78b8Schristos 	dns_dlzimplementation_t *dlz_imp;
280d68c78b8Schristos 
281d68c78b8Schristos 	/* Write debugging message to log */
2825606745fSchristos 	isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ,
2835606745fSchristos 		      ISC_LOG_DEBUG(2), "Registering DLZ driver '%s'",
2845606745fSchristos 		      drivername);
285d68c78b8Schristos 
286d68c78b8Schristos 	/*
287d68c78b8Schristos 	 * Performs checks to make sure data is as we expect it to be.
288d68c78b8Schristos 	 */
289d68c78b8Schristos 	REQUIRE(drivername != NULL);
290d68c78b8Schristos 	REQUIRE(methods != NULL);
291d68c78b8Schristos 	REQUIRE(methods->create != NULL);
292d68c78b8Schristos 	REQUIRE(methods->destroy != NULL);
293d68c78b8Schristos 	REQUIRE(methods->findzone != NULL);
294d68c78b8Schristos 	REQUIRE(mctx != NULL);
295d68c78b8Schristos 	REQUIRE(dlzimp != NULL && *dlzimp == NULL);
296d68c78b8Schristos 
297d68c78b8Schristos 	/*
298d68c78b8Schristos 	 * initialize the dlz_implementations list, this is guaranteed
299d68c78b8Schristos 	 * to only really happen once.
300d68c78b8Schristos 	 */
301*bcda20f6Schristos 	isc_once_do(&once, dlz_initialize);
302d68c78b8Schristos 
303d68c78b8Schristos 	/* lock the dlz_implementations list so we can modify it. */
304d68c78b8Schristos 	RWLOCK(&dlz_implock, isc_rwlocktype_write);
305d68c78b8Schristos 
306d68c78b8Schristos 	/*
307d68c78b8Schristos 	 * check that another already registered driver isn't using
308d68c78b8Schristos 	 * the same name
309d68c78b8Schristos 	 */
310d68c78b8Schristos 	dlz_imp = dlz_impfind(drivername);
311d68c78b8Schristos 	if (dlz_imp != NULL) {
312d68c78b8Schristos 		isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
313d68c78b8Schristos 			      DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2),
3145606745fSchristos 			      "DLZ Driver '%s' already registered", drivername);
315d68c78b8Schristos 		RWUNLOCK(&dlz_implock, isc_rwlocktype_write);
316*bcda20f6Schristos 		return ISC_R_EXISTS;
317d68c78b8Schristos 	}
318d68c78b8Schristos 
319d68c78b8Schristos 	/*
320d68c78b8Schristos 	 * Allocate memory for a dlz_implementation object.  Error if
321d68c78b8Schristos 	 * we cannot.
322d68c78b8Schristos 	 */
323*bcda20f6Schristos 	dlz_imp = isc_mem_get(mctx, sizeof(*dlz_imp));
324*bcda20f6Schristos 	*dlz_imp = (dns_dlzimplementation_t){
325*bcda20f6Schristos 		.name = drivername,
326*bcda20f6Schristos 		.methods = methods,
327*bcda20f6Schristos 		.driverarg = driverarg,
328*bcda20f6Schristos 	};
329d68c78b8Schristos 
330d68c78b8Schristos 	/* attach the new dlz_implementation object to a memory context */
331d68c78b8Schristos 	isc_mem_attach(mctx, &dlz_imp->mctx);
332d68c78b8Schristos 
333d68c78b8Schristos 	/*
334d68c78b8Schristos 	 * prepare the dlz_implementation object to be put in a list,
335d68c78b8Schristos 	 * and append it to the list
336d68c78b8Schristos 	 */
337d68c78b8Schristos 	ISC_LINK_INIT(dlz_imp, link);
338d68c78b8Schristos 	ISC_LIST_APPEND(dlz_implementations, dlz_imp, link);
339d68c78b8Schristos 
340d68c78b8Schristos 	/* Unlock the dlz_implementations list.	 */
341d68c78b8Schristos 	RWUNLOCK(&dlz_implock, isc_rwlocktype_write);
342d68c78b8Schristos 
343d68c78b8Schristos 	/* Pass back the dlz_implementation that we created. */
344d68c78b8Schristos 	*dlzimp = dlz_imp;
345d68c78b8Schristos 
346*bcda20f6Schristos 	return ISC_R_SUCCESS;
347d68c78b8Schristos }
348d68c78b8Schristos 
349d68c78b8Schristos /*%
350d68c78b8Schristos  * Tokenize the string "s" into whitespace-separated words,
351d68c78b8Schristos  * return the number of words in '*argcp' and an array
352d68c78b8Schristos  * of pointers to the words in '*argvp'.  The caller
353d68c78b8Schristos  * must free the array using isc_mem_put().  The string
354d68c78b8Schristos  * is modified in-place.
355d68c78b8Schristos  */
356d68c78b8Schristos isc_result_t
3575606745fSchristos dns_dlzstrtoargv(isc_mem_t *mctx, char *s, unsigned int *argcp, char ***argvp) {
358*bcda20f6Schristos 	return isc_commandline_strtoargv(mctx, s, argcp, argvp, 0);
359d68c78b8Schristos }
360d68c78b8Schristos 
361d68c78b8Schristos /*%
362d68c78b8Schristos  * Unregisters a DLZ driver.  This basically just removes the dlz
363d68c78b8Schristos  * driver from the list of available drivers in the dlz_implementations list.
364d68c78b8Schristos  */
365d68c78b8Schristos void
366d68c78b8Schristos dns_dlzunregister(dns_dlzimplementation_t **dlzimp) {
367d68c78b8Schristos 	dns_dlzimplementation_t *dlz_imp;
368d68c78b8Schristos 
369d68c78b8Schristos 	/* Write debugging message to log */
3705606745fSchristos 	isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ,
3715606745fSchristos 		      ISC_LOG_DEBUG(2), "Unregistering DLZ driver.");
372d68c78b8Schristos 
373d68c78b8Schristos 	/*
374d68c78b8Schristos 	 * Performs checks to make sure data is as we expect it to be.
375d68c78b8Schristos 	 */
376d68c78b8Schristos 	REQUIRE(dlzimp != NULL && *dlzimp != NULL);
377d68c78b8Schristos 
378d68c78b8Schristos 	/*
379d68c78b8Schristos 	 * initialize the dlz_implementations list, this is guaranteed
380d68c78b8Schristos 	 * to only really happen once.
381d68c78b8Schristos 	 */
382*bcda20f6Schristos 	isc_once_do(&once, dlz_initialize);
383d68c78b8Schristos 
384d68c78b8Schristos 	dlz_imp = *dlzimp;
385d68c78b8Schristos 
386d68c78b8Schristos 	/* lock the dlz_implementations list so we can modify it. */
387d68c78b8Schristos 	RWLOCK(&dlz_implock, isc_rwlocktype_write);
388d68c78b8Schristos 
389d68c78b8Schristos 	/* remove the dlz_implementation object from the list */
390d68c78b8Schristos 	ISC_LIST_UNLINK(dlz_implementations, dlz_imp, link);
391d68c78b8Schristos 
392d68c78b8Schristos 	/*
393d68c78b8Schristos 	 * Return the memory back to the available memory pool and
394d68c78b8Schristos 	 * remove it from the memory context.
395d68c78b8Schristos 	 */
3965606745fSchristos 	isc_mem_putanddetach(&dlz_imp->mctx, dlz_imp, sizeof(*dlz_imp));
397d68c78b8Schristos 
398d68c78b8Schristos 	/* Unlock the dlz_implementations list. */
399d68c78b8Schristos 	RWUNLOCK(&dlz_implock, isc_rwlocktype_write);
400d68c78b8Schristos }
401d68c78b8Schristos 
402d68c78b8Schristos /*
403d68c78b8Schristos  * Create a writeable DLZ zone. This can be called by DLZ drivers
404d68c78b8Schristos  * during configure() to create a zone that can be updated. The zone
405bb5aa156Schristos  * type is set to dns_zone_dlz, which is equivalent to a primary zone
406d68c78b8Schristos  *
407d68c78b8Schristos  * This function uses a callback setup in dns_dlzconfigure() to call
408d68c78b8Schristos  * into the server zone code to setup the remaining pieces of server
409d68c78b8Schristos  * specific functionality on the zone
410d68c78b8Schristos  */
411d68c78b8Schristos isc_result_t
412d68c78b8Schristos dns_dlz_writeablezone(dns_view_t *view, dns_dlzdb_t *dlzdb,
4135606745fSchristos 		      const char *zone_name) {
414d68c78b8Schristos 	dns_zone_t *zone = NULL;
415d68c78b8Schristos 	dns_zone_t *dupzone = NULL;
416d68c78b8Schristos 	isc_result_t result;
417d68c78b8Schristos 	isc_buffer_t buffer;
418d68c78b8Schristos 	dns_fixedname_t fixorigin;
419d68c78b8Schristos 	dns_name_t *origin;
420d68c78b8Schristos 
421d68c78b8Schristos 	REQUIRE(DNS_DLZ_VALID(dlzdb));
422d68c78b8Schristos 
423d68c78b8Schristos 	REQUIRE(dlzdb->configure_callback != NULL);
424d68c78b8Schristos 
425d68c78b8Schristos 	isc_buffer_constinit(&buffer, zone_name, strlen(zone_name));
426d68c78b8Schristos 	isc_buffer_add(&buffer, strlen(zone_name));
427d68c78b8Schristos 	dns_fixedname_init(&fixorigin);
4285606745fSchristos 	result = dns_name_fromtext(dns_fixedname_name(&fixorigin), &buffer,
4295606745fSchristos 				   dns_rootname, 0, NULL);
4305606745fSchristos 	if (result != ISC_R_SUCCESS) {
431d68c78b8Schristos 		goto cleanup;
4325606745fSchristos 	}
433d68c78b8Schristos 	origin = dns_fixedname_name(&fixorigin);
434d68c78b8Schristos 
435d68c78b8Schristos 	if (!dlzdb->search) {
436d68c78b8Schristos 		isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
437d68c78b8Schristos 			      DNS_LOGMODULE_DLZ, ISC_LOG_WARNING,
438d68c78b8Schristos 			      "DLZ %s has 'search no;', but attempted to "
439d68c78b8Schristos 			      "register writeable zone %s.",
440d68c78b8Schristos 			      dlzdb->dlzname, zone_name);
441d68c78b8Schristos 		result = ISC_R_SUCCESS;
442d68c78b8Schristos 		goto cleanup;
443d68c78b8Schristos 	}
444d68c78b8Schristos 
445d68c78b8Schristos 	/* See if the zone already exists */
446*bcda20f6Schristos 	result = dns_view_findzone(view, origin, DNS_ZTFIND_EXACT, &dupzone);
447d68c78b8Schristos 	if (result == ISC_R_SUCCESS) {
448d68c78b8Schristos 		dns_zone_detach(&dupzone);
449d68c78b8Schristos 		result = ISC_R_EXISTS;
450d68c78b8Schristos 		goto cleanup;
451d68c78b8Schristos 	}
452d68c78b8Schristos 	INSIST(dupzone == NULL);
453d68c78b8Schristos 
454d68c78b8Schristos 	/* Create it */
455*bcda20f6Schristos 	dns_zone_create(&zone, view->mctx, 0);
456d68c78b8Schristos 	result = dns_zone_setorigin(zone, origin);
4575606745fSchristos 	if (result != ISC_R_SUCCESS) {
458d68c78b8Schristos 		goto cleanup;
4595606745fSchristos 	}
460d68c78b8Schristos 	dns_zone_setview(zone, view);
461d68c78b8Schristos 
462d4a20c3eSchristos 	dns_zone_setadded(zone, true);
463d68c78b8Schristos 
464d68c78b8Schristos 	if (dlzdb->ssutable == NULL) {
465bb5aa156Schristos 		dns_ssutable_createdlz(dlzdb->mctx, &dlzdb->ssutable, dlzdb);
4665606745fSchristos 	}
467d68c78b8Schristos 	dns_zone_setssutable(zone, dlzdb->ssutable);
468d68c78b8Schristos 
469d68c78b8Schristos 	result = dlzdb->configure_callback(view, dlzdb, zone);
4705606745fSchristos 	if (result != ISC_R_SUCCESS) {
471d68c78b8Schristos 		goto cleanup;
4725606745fSchristos 	}
473d68c78b8Schristos 
474d68c78b8Schristos 	result = dns_view_addzone(view, zone);
475d68c78b8Schristos 
476d68c78b8Schristos cleanup:
4775606745fSchristos 	if (zone != NULL) {
478d68c78b8Schristos 		dns_zone_detach(&zone);
4795606745fSchristos 	}
480d68c78b8Schristos 
481*bcda20f6Schristos 	return result;
482d68c78b8Schristos }
483d68c78b8Schristos 
484d68c78b8Schristos /*%
485d68c78b8Schristos  * Configure a DLZ driver. This is optional, and if supplied gives
486d68c78b8Schristos  * the backend an opportunity to configure parameters related to DLZ.
487d68c78b8Schristos  */
488d68c78b8Schristos isc_result_t
489d68c78b8Schristos dns_dlzconfigure(dns_view_t *view, dns_dlzdb_t *dlzdb,
4905606745fSchristos 		 dlzconfigure_callback_t callback) {
491d68c78b8Schristos 	dns_dlzimplementation_t *impl;
492d68c78b8Schristos 	isc_result_t result;
493d68c78b8Schristos 
494d68c78b8Schristos 	REQUIRE(DNS_DLZ_VALID(dlzdb));
495d68c78b8Schristos 	REQUIRE(dlzdb->implementation != NULL);
496d68c78b8Schristos 
497d68c78b8Schristos 	impl = dlzdb->implementation;
498d68c78b8Schristos 
4995606745fSchristos 	if (impl->methods->configure == NULL) {
500*bcda20f6Schristos 		return ISC_R_SUCCESS;
5015606745fSchristos 	}
502d68c78b8Schristos 
503d68c78b8Schristos 	dlzdb->configure_callback = callback;
504d68c78b8Schristos 
5055606745fSchristos 	result = impl->methods->configure(impl->driverarg, dlzdb->dbdata, view,
5065606745fSchristos 					  dlzdb);
507*bcda20f6Schristos 	return result;
508d68c78b8Schristos }
509d68c78b8Schristos 
510d4a20c3eSchristos bool
511d68c78b8Schristos dns_dlz_ssumatch(dns_dlzdb_t *dlzdatabase, const dns_name_t *signer,
512d68c78b8Schristos 		 const dns_name_t *name, const isc_netaddr_t *tcpaddr,
5135606745fSchristos 		 dns_rdatatype_t type, const dst_key_t *key) {
514d68c78b8Schristos 	dns_dlzimplementation_t *impl;
515d4a20c3eSchristos 	bool r;
516d68c78b8Schristos 
517d68c78b8Schristos 	REQUIRE(dlzdatabase != NULL);
518d68c78b8Schristos 	REQUIRE(dlzdatabase->implementation != NULL);
519d68c78b8Schristos 	REQUIRE(dlzdatabase->implementation->methods != NULL);
520d68c78b8Schristos 	impl = dlzdatabase->implementation;
521d68c78b8Schristos 
522d68c78b8Schristos 	if (impl->methods->ssumatch == NULL) {
523d68c78b8Schristos 		isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
524d68c78b8Schristos 			      DNS_LOGMODULE_DLZ, ISC_LOG_INFO,
525d68c78b8Schristos 			      "No ssumatch method for DLZ database");
526*bcda20f6Schristos 		return false;
527d68c78b8Schristos 	}
528d68c78b8Schristos 
529d68c78b8Schristos 	r = impl->methods->ssumatch(signer, name, tcpaddr, type, key,
530d68c78b8Schristos 				    impl->driverarg, dlzdatabase->dbdata);
531*bcda20f6Schristos 	return r;
532d68c78b8Schristos }
533