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