1225305Sdougb/*
2254402Serwin * Copyright (C) 2011-2013  Internet Systems Consortium, Inc. ("ISC")
3225305Sdougb *
4225305Sdougb * Permission to use, copy, modify, and/or distribute this software for any
5225305Sdougb * purpose with or without fee is hereby granted, provided that the above
6225305Sdougb * copyright notice and this permission notice appear in all copies.
7225305Sdougb *
8225305Sdougb * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
9225305Sdougb * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
10225305Sdougb * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
11225305Sdougb * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
12225305Sdougb * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
13225305Sdougb * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
14225305Sdougb * PERFORMANCE OF THIS SOFTWARE.
15225305Sdougb */
16225305Sdougb
17254897Serwin/* $Id$ */
18225305Sdougb
19225305Sdougb#include <config.h>
20225305Sdougb
21225305Sdougb#include <stdio.h>
22225305Sdougb#include <string.h>
23225305Sdougb#include <stdlib.h>
24225305Sdougb#include <dlfcn.h>
25225305Sdougb
26225305Sdougb#include <dns/log.h>
27225305Sdougb#include <dns/result.h>
28225305Sdougb#include <dns/dlz_dlopen.h>
29225305Sdougb
30225305Sdougb#include <isc/mem.h>
31225305Sdougb#include <isc/print.h>
32225305Sdougb#include <isc/result.h>
33225305Sdougb#include <isc/util.h>
34225305Sdougb
35225305Sdougb#include <named/globals.h>
36225305Sdougb
37225305Sdougb#include <dlz/dlz_dlopen_driver.h>
38225305Sdougb
39225305Sdougb#ifdef ISC_DLZ_DLOPEN
40225305Sdougbstatic dns_sdlzimplementation_t *dlz_dlopen = NULL;
41225305Sdougb
42225305Sdougb
43225305Sdougbtypedef struct dlopen_data {
44225305Sdougb	isc_mem_t *mctx;
45225305Sdougb	char *dl_path;
46225305Sdougb	char *dlzname;
47225305Sdougb	void *dl_handle;
48225305Sdougb	void *dbdata;
49225305Sdougb	unsigned int flags;
50225305Sdougb	isc_mutex_t lock;
51225305Sdougb	int version;
52225305Sdougb	isc_boolean_t in_configure;
53225305Sdougb
54225305Sdougb	dlz_dlopen_version_t *dlz_version;
55225305Sdougb	dlz_dlopen_create_t *dlz_create;
56225305Sdougb	dlz_dlopen_findzonedb_t *dlz_findzonedb;
57225305Sdougb	dlz_dlopen_lookup_t *dlz_lookup;
58225305Sdougb	dlz_dlopen_authority_t *dlz_authority;
59225305Sdougb	dlz_dlopen_allnodes_t *dlz_allnodes;
60225305Sdougb	dlz_dlopen_allowzonexfr_t *dlz_allowzonexfr;
61225305Sdougb	dlz_dlopen_newversion_t *dlz_newversion;
62225305Sdougb	dlz_dlopen_closeversion_t *dlz_closeversion;
63225305Sdougb	dlz_dlopen_configure_t *dlz_configure;
64225305Sdougb	dlz_dlopen_ssumatch_t *dlz_ssumatch;
65225305Sdougb	dlz_dlopen_addrdataset_t *dlz_addrdataset;
66225305Sdougb	dlz_dlopen_subrdataset_t *dlz_subrdataset;
67225305Sdougb	dlz_dlopen_delrdataset_t *dlz_delrdataset;
68225305Sdougb	dlz_dlopen_destroy_t *dlz_destroy;
69225305Sdougb} dlopen_data_t;
70225305Sdougb
71225305Sdougb/* Modules can choose whether they are lock-safe or not. */
72225305Sdougb#define MAYBE_LOCK(cd) \
73225305Sdougb	do { \
74225305Sdougb		if ((cd->flags & DNS_SDLZFLAG_THREADSAFE) == 0 && \
75225305Sdougb		    cd->in_configure == ISC_FALSE) \
76225305Sdougb			LOCK(&cd->lock); \
77225305Sdougb	} while (0)
78225305Sdougb
79225305Sdougb#define MAYBE_UNLOCK(cd) \
80225305Sdougb	do { \
81225305Sdougb		if ((cd->flags & DNS_SDLZFLAG_THREADSAFE) == 0 && \
82225305Sdougb		    cd->in_configure == ISC_FALSE) \
83225305Sdougb			UNLOCK(&cd->lock); \
84225305Sdougb	} while (0)
85225305Sdougb
86225305Sdougb/*
87225305Sdougb * Log a message at the given level.
88225305Sdougb */
89225305Sdougbstatic void dlopen_log(int level, const char *fmt, ...)
90225305Sdougb{
91225305Sdougb	va_list ap;
92225305Sdougb	va_start(ap, fmt);
93225305Sdougb	isc_log_vwrite(dns_lctx, DNS_LOGCATEGORY_DATABASE,
94225305Sdougb		       DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(level),
95225305Sdougb		       fmt, ap);
96225305Sdougb	va_end(ap);
97225305Sdougb}
98225305Sdougb
99225305Sdougb/*
100225305Sdougb * SDLZ methods
101225305Sdougb */
102225305Sdougb
103225305Sdougbstatic isc_result_t
104225305Sdougbdlopen_dlz_allnodes(const char *zone, void *driverarg, void *dbdata,
105225305Sdougb		    dns_sdlzallnodes_t *allnodes)
106225305Sdougb{
107225305Sdougb	dlopen_data_t *cd = (dlopen_data_t *) dbdata;
108225305Sdougb	isc_result_t result;
109225305Sdougb
110225305Sdougb
111225305Sdougb	UNUSED(driverarg);
112225305Sdougb
113225305Sdougb	if (cd->dlz_allnodes == NULL) {
114225305Sdougb		return (ISC_R_NOPERM);
115225305Sdougb	}
116225305Sdougb
117225305Sdougb	MAYBE_LOCK(cd);
118225305Sdougb	result = cd->dlz_allnodes(zone, cd->dbdata, allnodes);
119225305Sdougb	MAYBE_UNLOCK(cd);
120225305Sdougb	return (result);
121225305Sdougb}
122225305Sdougb
123225305Sdougb
124225305Sdougbstatic isc_result_t
125225305Sdougbdlopen_dlz_allowzonexfr(void *driverarg, void *dbdata, const char *name,
126225305Sdougb			const char *client)
127225305Sdougb{
128225305Sdougb	dlopen_data_t *cd = (dlopen_data_t *) dbdata;
129225305Sdougb	isc_result_t result;
130225305Sdougb
131225305Sdougb	UNUSED(driverarg);
132225305Sdougb
133225305Sdougb
134225305Sdougb	if (cd->dlz_allowzonexfr == NULL) {
135225305Sdougb		return (ISC_R_NOPERM);
136225305Sdougb	}
137225305Sdougb
138225305Sdougb	MAYBE_LOCK(cd);
139225305Sdougb	result = cd->dlz_allowzonexfr(cd->dbdata, name, client);
140225305Sdougb	MAYBE_UNLOCK(cd);
141225305Sdougb	return (result);
142225305Sdougb}
143225305Sdougb
144225305Sdougbstatic isc_result_t
145225305Sdougbdlopen_dlz_authority(const char *zone, void *driverarg, void *dbdata,
146254897Serwin		     dns_sdlzlookup_t *lookup)
147225305Sdougb{
148225305Sdougb	dlopen_data_t *cd = (dlopen_data_t *) dbdata;
149225305Sdougb	isc_result_t result;
150225305Sdougb
151225305Sdougb	UNUSED(driverarg);
152225305Sdougb
153225305Sdougb	if (cd->dlz_authority == NULL) {
154225305Sdougb		return (ISC_R_NOTIMPLEMENTED);
155225305Sdougb	}
156225305Sdougb
157225305Sdougb	MAYBE_LOCK(cd);
158225305Sdougb	result = cd->dlz_authority(zone, cd->dbdata, lookup);
159225305Sdougb	MAYBE_UNLOCK(cd);
160225305Sdougb	return (result);
161225305Sdougb}
162225305Sdougb
163225305Sdougbstatic isc_result_t
164225305Sdougbdlopen_dlz_findzonedb(void *driverarg, void *dbdata, const char *name)
165225305Sdougb{
166225305Sdougb	dlopen_data_t *cd = (dlopen_data_t *) dbdata;
167225305Sdougb	isc_result_t result;
168225305Sdougb
169225305Sdougb	UNUSED(driverarg);
170225305Sdougb
171225305Sdougb	MAYBE_LOCK(cd);
172225305Sdougb	result = cd->dlz_findzonedb(cd->dbdata, name);
173225305Sdougb	MAYBE_UNLOCK(cd);
174225305Sdougb	return (result);
175225305Sdougb}
176225305Sdougb
177225305Sdougb
178225305Sdougbstatic isc_result_t
179225305Sdougbdlopen_dlz_lookup(const char *zone, const char *name, void *driverarg,
180254897Serwin		  void *dbdata, dns_sdlzlookup_t *lookup,
181254897Serwin		  dns_clientinfomethods_t *methods,
182254897Serwin		  dns_clientinfo_t *clientinfo)
183225305Sdougb{
184225305Sdougb	dlopen_data_t *cd = (dlopen_data_t *) dbdata;
185225305Sdougb	isc_result_t result;
186225305Sdougb
187225305Sdougb	UNUSED(driverarg);
188225305Sdougb
189225305Sdougb	MAYBE_LOCK(cd);
190254897Serwin	result = cd->dlz_lookup(zone, name, cd->dbdata, lookup,
191254897Serwin				methods, clientinfo);
192225305Sdougb	MAYBE_UNLOCK(cd);
193225305Sdougb	return (result);
194225305Sdougb}
195225305Sdougb
196225305Sdougb/*
197225305Sdougb * Load a symbol from the library
198225305Sdougb */
199225305Sdougbstatic void *
200225305Sdougbdl_load_symbol(dlopen_data_t *cd, const char *symbol, isc_boolean_t mandatory) {
201225305Sdougb	void *ptr = dlsym(cd->dl_handle, symbol);
202225305Sdougb	if (ptr == NULL && mandatory) {
203225305Sdougb		dlopen_log(ISC_LOG_ERROR,
204225305Sdougb			   "dlz_dlopen: library '%s' is missing "
205225305Sdougb			   "required symbol '%s'", cd->dl_path, symbol);
206225305Sdougb	}
207225305Sdougb	return (ptr);
208225305Sdougb}
209225305Sdougb
210225305Sdougb/*
211225305Sdougb * Called at startup for each dlopen zone in named.conf
212225305Sdougb */
213225305Sdougbstatic isc_result_t
214225305Sdougbdlopen_dlz_create(const char *dlzname, unsigned int argc, char *argv[],
215225305Sdougb		  void *driverarg, void **dbdata)
216225305Sdougb{
217225305Sdougb	dlopen_data_t *cd;
218225305Sdougb	isc_mem_t *mctx = NULL;
219225305Sdougb	isc_result_t result = ISC_R_FAILURE;
220225305Sdougb	int dlopen_flags = 0;
221225305Sdougb
222225305Sdougb	UNUSED(driverarg);
223225305Sdougb
224225305Sdougb	if (argc < 2) {
225225305Sdougb		dlopen_log(ISC_LOG_ERROR,
226225305Sdougb			   "dlz_dlopen driver for '%s' needs a path to "
227225305Sdougb			   "the shared library", dlzname);
228225305Sdougb		return (ISC_R_FAILURE);
229225305Sdougb	}
230225305Sdougb
231254402Serwin	result = isc_mem_create(0, 0, &mctx);
232254402Serwin	if (result != ISC_R_SUCCESS)
233254402Serwin		return (result);
234225305Sdougb
235225305Sdougb	cd = isc_mem_get(mctx, sizeof(*cd));
236225305Sdougb	if (cd == NULL) {
237225305Sdougb		isc_mem_destroy(&mctx);
238225305Sdougb		return (ISC_R_NOMEMORY);
239225305Sdougb	}
240225305Sdougb	memset(cd, 0, sizeof(*cd));
241225305Sdougb
242225305Sdougb	cd->mctx = mctx;
243225305Sdougb
244225305Sdougb	cd->dl_path = isc_mem_strdup(cd->mctx, argv[1]);
245225305Sdougb	if (cd->dl_path == NULL) {
246225305Sdougb		goto failed;
247225305Sdougb	}
248225305Sdougb
249225305Sdougb	cd->dlzname = isc_mem_strdup(cd->mctx, dlzname);
250225305Sdougb	if (cd->dlzname == NULL) {
251225305Sdougb		goto failed;
252225305Sdougb	}
253225305Sdougb
254225305Sdougb	/* Initialize the lock */
255254402Serwin	result = isc_mutex_init(&cd->lock);
256254402Serwin	if (result != ISC_R_SUCCESS)
257254402Serwin		goto failed;
258225305Sdougb
259225305Sdougb	/* Open the library */
260236374Sdougb	dlopen_flags = RTLD_NOW|RTLD_GLOBAL;
261225305Sdougb
262225305Sdougb#ifdef RTLD_DEEPBIND
263225305Sdougb	/*
264225305Sdougb	 * If RTLD_DEEPBIND is available then use it. This can avoid
265225305Sdougb	 * issues with a module using a different version of a system
266225305Sdougb	 * library than one that bind9 uses. For example, bind9 may link
267225305Sdougb	 * to MIT kerberos, but the module may use Heimdal. If we don't
268225305Sdougb	 * use RTLD_DEEPBIND then we could end up with Heimdal functions
269225305Sdougb	 * calling MIT functions, which leads to bizarre results (usually
270225305Sdougb	 * a segfault).
271225305Sdougb	 */
272225305Sdougb	dlopen_flags |= RTLD_DEEPBIND;
273225305Sdougb#endif
274225305Sdougb
275225305Sdougb	cd->dl_handle = dlopen(cd->dl_path, dlopen_flags);
276225305Sdougb	if (cd->dl_handle == NULL) {
277225305Sdougb		dlopen_log(ISC_LOG_ERROR,
278225305Sdougb			   "dlz_dlopen failed to open library '%s' - %s",
279225305Sdougb			   cd->dl_path, dlerror());
280225305Sdougb		goto failed;
281225305Sdougb	}
282225305Sdougb
283225305Sdougb	/* Find the symbols */
284225305Sdougb	cd->dlz_version = (dlz_dlopen_version_t *)
285225305Sdougb		dl_load_symbol(cd, "dlz_version", ISC_TRUE);
286225305Sdougb	cd->dlz_create = (dlz_dlopen_create_t *)
287225305Sdougb		dl_load_symbol(cd, "dlz_create", ISC_TRUE);
288225305Sdougb	cd->dlz_lookup = (dlz_dlopen_lookup_t *)
289225305Sdougb		dl_load_symbol(cd, "dlz_lookup", ISC_TRUE);
290225305Sdougb	cd->dlz_findzonedb = (dlz_dlopen_findzonedb_t *)
291225305Sdougb		dl_load_symbol(cd, "dlz_findzonedb", ISC_TRUE);
292225305Sdougb
293225305Sdougb	if (cd->dlz_create == NULL ||
294225305Sdougb	    cd->dlz_lookup == NULL ||
295225305Sdougb	    cd->dlz_findzonedb == NULL)
296225305Sdougb	{
297225305Sdougb		/* We're missing a required symbol */
298225305Sdougb		goto failed;
299225305Sdougb	}
300225305Sdougb
301225305Sdougb	cd->dlz_allowzonexfr = (dlz_dlopen_allowzonexfr_t *)
302225305Sdougb		dl_load_symbol(cd, "dlz_allowzonexfr", ISC_FALSE);
303225305Sdougb	cd->dlz_allnodes = (dlz_dlopen_allnodes_t *)
304225305Sdougb		dl_load_symbol(cd, "dlz_allnodes",
305225305Sdougb			       ISC_TF(cd->dlz_allowzonexfr != NULL));
306225305Sdougb	cd->dlz_authority = (dlz_dlopen_authority_t *)
307225305Sdougb		dl_load_symbol(cd, "dlz_authority", ISC_FALSE);
308225305Sdougb	cd->dlz_newversion = (dlz_dlopen_newversion_t *)
309225305Sdougb		dl_load_symbol(cd, "dlz_newversion", ISC_FALSE);
310225305Sdougb	cd->dlz_closeversion = (dlz_dlopen_closeversion_t *)
311225305Sdougb		dl_load_symbol(cd, "dlz_closeversion",
312225305Sdougb			       ISC_TF(cd->dlz_newversion != NULL));
313225305Sdougb	cd->dlz_configure = (dlz_dlopen_configure_t *)
314225305Sdougb		dl_load_symbol(cd, "dlz_configure", ISC_FALSE);
315225305Sdougb	cd->dlz_ssumatch = (dlz_dlopen_ssumatch_t *)
316225305Sdougb		dl_load_symbol(cd, "dlz_ssumatch", ISC_FALSE);
317225305Sdougb	cd->dlz_addrdataset = (dlz_dlopen_addrdataset_t *)
318225305Sdougb		dl_load_symbol(cd, "dlz_addrdataset", ISC_FALSE);
319225305Sdougb	cd->dlz_subrdataset = (dlz_dlopen_subrdataset_t *)
320225305Sdougb		dl_load_symbol(cd, "dlz_subrdataset", ISC_FALSE);
321225305Sdougb	cd->dlz_delrdataset = (dlz_dlopen_delrdataset_t *)
322225305Sdougb		dl_load_symbol(cd, "dlz_delrdataset", ISC_FALSE);
323234010Sdougb	cd->dlz_destroy = (dlz_dlopen_destroy_t *)
324234010Sdougb		dl_load_symbol(cd, "dlz_destroy", ISC_FALSE);
325225305Sdougb
326225305Sdougb	/* Check the version of the API is the same */
327225305Sdougb	cd->version = cd->dlz_version(&cd->flags);
328225305Sdougb	if (cd->version != DLZ_DLOPEN_VERSION) {
329225305Sdougb		dlopen_log(ISC_LOG_ERROR,
330225305Sdougb			   "dlz_dlopen: incorrect version %d "
331225305Sdougb			   "should be %d in '%s'",
332225305Sdougb			   cd->version, DLZ_DLOPEN_VERSION, cd->dl_path);
333225305Sdougb		goto failed;
334225305Sdougb	}
335225305Sdougb
336225305Sdougb	/*
337225305Sdougb	 * Call the library's create function. Note that this is an
338225305Sdougb	 * extended version of dlz create, with the addition of
339225305Sdougb	 * named function pointers for helper functions that the
340225305Sdougb	 * driver will need. This avoids the need for the backend to
341225305Sdougb	 * link the BIND9 libraries
342225305Sdougb	 */
343225305Sdougb	MAYBE_LOCK(cd);
344225305Sdougb	result = cd->dlz_create(dlzname, argc-1, argv+1,
345225305Sdougb				&cd->dbdata,
346225305Sdougb				"log", dlopen_log,
347225305Sdougb				"putrr", dns_sdlz_putrr,
348225305Sdougb				"putnamedrr", dns_sdlz_putnamedrr,
349225305Sdougb				"writeable_zone", dns_dlz_writeablezone,
350225305Sdougb				NULL);
351225305Sdougb	MAYBE_UNLOCK(cd);
352225305Sdougb	if (result != ISC_R_SUCCESS)
353225305Sdougb		goto failed;
354225305Sdougb
355225305Sdougb	*dbdata = cd;
356225305Sdougb
357225305Sdougb	return (ISC_R_SUCCESS);
358225305Sdougb
359225305Sdougbfailed:
360225305Sdougb	dlopen_log(ISC_LOG_ERROR, "dlz_dlopen of '%s' failed", dlzname);
361254402Serwin	if (cd->dl_path != NULL)
362225305Sdougb		isc_mem_free(mctx, cd->dl_path);
363254402Serwin	if (cd->dlzname != NULL)
364225305Sdougb		isc_mem_free(mctx, cd->dlzname);
365254402Serwin	if (dlopen_flags != 0)
366225305Sdougb		(void) isc_mutex_destroy(&cd->lock);
367225305Sdougb#ifdef HAVE_DLCLOSE
368225305Sdougb	if (cd->dl_handle)
369225305Sdougb		dlclose(cd->dl_handle);
370225305Sdougb#endif
371225305Sdougb	isc_mem_put(mctx, cd, sizeof(*cd));
372225305Sdougb	isc_mem_destroy(&mctx);
373225305Sdougb	return (result);
374225305Sdougb}
375225305Sdougb
376225305Sdougb
377225305Sdougb/*
378225305Sdougb * Called when bind is shutting down
379225305Sdougb */
380225305Sdougbstatic void
381225305Sdougbdlopen_dlz_destroy(void *driverarg, void *dbdata) {
382225305Sdougb	dlopen_data_t *cd = (dlopen_data_t *) dbdata;
383225305Sdougb	isc_mem_t *mctx;
384225305Sdougb
385225305Sdougb	UNUSED(driverarg);
386225305Sdougb
387225305Sdougb	if (cd->dlz_destroy) {
388225305Sdougb		MAYBE_LOCK(cd);
389225305Sdougb		cd->dlz_destroy(cd->dbdata);
390225305Sdougb		MAYBE_UNLOCK(cd);
391225305Sdougb	}
392225305Sdougb
393225305Sdougb	if (cd->dl_path)
394225305Sdougb		isc_mem_free(cd->mctx, cd->dl_path);
395225305Sdougb	if (cd->dlzname)
396225305Sdougb		isc_mem_free(cd->mctx, cd->dlzname);
397225305Sdougb
398225305Sdougb#ifdef HAVE_DLCLOSE
399225305Sdougb	if (cd->dl_handle)
400225305Sdougb		dlclose(cd->dl_handle);
401225305Sdougb#endif
402225305Sdougb
403225305Sdougb	(void) isc_mutex_destroy(&cd->lock);
404225305Sdougb
405225305Sdougb	mctx = cd->mctx;
406225305Sdougb	isc_mem_put(mctx, cd, sizeof(*cd));
407225305Sdougb	isc_mem_destroy(&mctx);
408225305Sdougb}
409225305Sdougb
410225305Sdougb/*
411225305Sdougb * Called to start a transaction
412225305Sdougb */
413225305Sdougbstatic isc_result_t
414225305Sdougbdlopen_dlz_newversion(const char *zone, void *driverarg, void *dbdata,
415225305Sdougb		      void **versionp)
416225305Sdougb{
417225305Sdougb	dlopen_data_t *cd = (dlopen_data_t *) dbdata;
418225305Sdougb	isc_result_t result;
419225305Sdougb
420225305Sdougb	UNUSED(driverarg);
421225305Sdougb
422225305Sdougb	if (cd->dlz_newversion == NULL)
423225305Sdougb		return (ISC_R_NOTIMPLEMENTED);
424225305Sdougb
425225305Sdougb	MAYBE_LOCK(cd);
426225305Sdougb	result = cd->dlz_newversion(zone, cd->dbdata, versionp);
427225305Sdougb	MAYBE_UNLOCK(cd);
428225305Sdougb	return (result);
429225305Sdougb}
430225305Sdougb
431225305Sdougb/*
432225305Sdougb * Called to end a transaction
433225305Sdougb */
434225305Sdougbstatic void
435225305Sdougbdlopen_dlz_closeversion(const char *zone, isc_boolean_t commit,
436225305Sdougb			void *driverarg, void *dbdata, void **versionp)
437225305Sdougb{
438225305Sdougb	dlopen_data_t *cd = (dlopen_data_t *) dbdata;
439225305Sdougb
440225305Sdougb	UNUSED(driverarg);
441225305Sdougb
442225305Sdougb	if (cd->dlz_newversion == NULL) {
443225305Sdougb		*versionp = NULL;
444225305Sdougb		return;
445225305Sdougb	}
446225305Sdougb
447225305Sdougb	MAYBE_LOCK(cd);
448225305Sdougb	cd->dlz_closeversion(zone, commit, cd->dbdata, versionp);
449225305Sdougb	MAYBE_UNLOCK(cd);
450225305Sdougb}
451225305Sdougb
452225305Sdougb/*
453225305Sdougb * Called on startup to configure any writeable zones
454225305Sdougb */
455225305Sdougbstatic isc_result_t
456225305Sdougbdlopen_dlz_configure(dns_view_t *view, void *driverarg, void *dbdata) {
457225305Sdougb	dlopen_data_t *cd = (dlopen_data_t *) dbdata;
458225305Sdougb	isc_result_t result;
459225305Sdougb
460225305Sdougb	UNUSED(driverarg);
461225305Sdougb
462225305Sdougb	if (cd->dlz_configure == NULL)
463225305Sdougb		return (ISC_R_SUCCESS);
464225305Sdougb
465225305Sdougb	MAYBE_LOCK(cd);
466225305Sdougb	cd->in_configure = ISC_TRUE;
467225305Sdougb	result = cd->dlz_configure(view, cd->dbdata);
468225305Sdougb	cd->in_configure = ISC_FALSE;
469225305Sdougb	MAYBE_UNLOCK(cd);
470225305Sdougb
471225305Sdougb	return (result);
472225305Sdougb}
473225305Sdougb
474225305Sdougb
475225305Sdougb/*
476225305Sdougb * Check for authority to change a name
477225305Sdougb */
478225305Sdougbstatic isc_boolean_t
479225305Sdougbdlopen_dlz_ssumatch(const char *signer, const char *name, const char *tcpaddr,
480225305Sdougb		    const char *type, const char *key, isc_uint32_t keydatalen,
481225305Sdougb		    unsigned char *keydata, void *driverarg, void *dbdata)
482225305Sdougb{
483225305Sdougb	dlopen_data_t *cd = (dlopen_data_t *) dbdata;
484225305Sdougb	isc_boolean_t ret;
485225305Sdougb
486225305Sdougb	UNUSED(driverarg);
487225305Sdougb
488225305Sdougb	if (cd->dlz_ssumatch == NULL)
489225305Sdougb		return (ISC_FALSE);
490225305Sdougb
491225305Sdougb	MAYBE_LOCK(cd);
492225305Sdougb	ret = cd->dlz_ssumatch(signer, name, tcpaddr, type, key, keydatalen,
493225305Sdougb			       keydata, cd->dbdata);
494225305Sdougb	MAYBE_UNLOCK(cd);
495225305Sdougb
496225305Sdougb	return (ret);
497225305Sdougb}
498225305Sdougb
499225305Sdougb
500225305Sdougb/*
501225305Sdougb * Add an rdataset
502225305Sdougb */
503225305Sdougbstatic isc_result_t
504225305Sdougbdlopen_dlz_addrdataset(const char *name, const char *rdatastr,
505225305Sdougb		       void *driverarg, void *dbdata, void *version)
506225305Sdougb{
507225305Sdougb	dlopen_data_t *cd = (dlopen_data_t *) dbdata;
508225305Sdougb	isc_result_t result;
509225305Sdougb
510225305Sdougb	UNUSED(driverarg);
511225305Sdougb
512225305Sdougb	if (cd->dlz_addrdataset == NULL)
513225305Sdougb		return (ISC_R_NOTIMPLEMENTED);
514225305Sdougb
515225305Sdougb	MAYBE_LOCK(cd);
516225305Sdougb	result = cd->dlz_addrdataset(name, rdatastr, cd->dbdata, version);
517225305Sdougb	MAYBE_UNLOCK(cd);
518225305Sdougb
519225305Sdougb	return (result);
520225305Sdougb}
521225305Sdougb
522225305Sdougb/*
523225305Sdougb * Subtract an rdataset
524225305Sdougb */
525225305Sdougbstatic isc_result_t
526225305Sdougbdlopen_dlz_subrdataset(const char *name, const char *rdatastr,
527225305Sdougb		       void *driverarg, void *dbdata, void *version)
528225305Sdougb{
529225305Sdougb	dlopen_data_t *cd = (dlopen_data_t *) dbdata;
530225305Sdougb	isc_result_t result;
531225305Sdougb
532225305Sdougb	UNUSED(driverarg);
533225305Sdougb
534225305Sdougb	if (cd->dlz_subrdataset == NULL)
535225305Sdougb		return (ISC_R_NOTIMPLEMENTED);
536225305Sdougb
537225305Sdougb	MAYBE_LOCK(cd);
538225305Sdougb	result = cd->dlz_subrdataset(name, rdatastr, cd->dbdata, version);
539225305Sdougb	MAYBE_UNLOCK(cd);
540225305Sdougb
541225305Sdougb	return (result);
542225305Sdougb}
543225305Sdougb
544225305Sdougb/*
545225305Sdougb  delete a rdataset
546225305Sdougb */
547225305Sdougbstatic isc_result_t
548225305Sdougbdlopen_dlz_delrdataset(const char *name, const char *type,
549225305Sdougb		       void *driverarg, void *dbdata, void *version)
550225305Sdougb{
551225305Sdougb	dlopen_data_t *cd = (dlopen_data_t *) dbdata;
552225305Sdougb	isc_result_t result;
553225305Sdougb
554225305Sdougb	UNUSED(driverarg);
555225305Sdougb
556225305Sdougb	if (cd->dlz_delrdataset == NULL)
557225305Sdougb		return (ISC_R_NOTIMPLEMENTED);
558225305Sdougb
559225305Sdougb	MAYBE_LOCK(cd);
560225305Sdougb	result = cd->dlz_delrdataset(name, type, cd->dbdata, version);
561225305Sdougb	MAYBE_UNLOCK(cd);
562225305Sdougb
563225305Sdougb	return (result);
564225305Sdougb}
565225305Sdougb
566225305Sdougb
567225305Sdougbstatic dns_sdlzmethods_t dlz_dlopen_methods = {
568225305Sdougb	dlopen_dlz_create,
569225305Sdougb	dlopen_dlz_destroy,
570225305Sdougb	dlopen_dlz_findzonedb,
571225305Sdougb	dlopen_dlz_lookup,
572225305Sdougb	dlopen_dlz_authority,
573225305Sdougb	dlopen_dlz_allnodes,
574225305Sdougb	dlopen_dlz_allowzonexfr,
575225305Sdougb	dlopen_dlz_newversion,
576225305Sdougb	dlopen_dlz_closeversion,
577225305Sdougb	dlopen_dlz_configure,
578225305Sdougb	dlopen_dlz_ssumatch,
579225305Sdougb	dlopen_dlz_addrdataset,
580225305Sdougb	dlopen_dlz_subrdataset,
581225305Sdougb	dlopen_dlz_delrdataset
582225305Sdougb};
583225305Sdougb#endif
584225305Sdougb
585225305Sdougb/*
586225305Sdougb * Register driver with BIND
587225305Sdougb */
588225305Sdougbisc_result_t
589225305Sdougbdlz_dlopen_init(isc_mem_t *mctx) {
590225305Sdougb#ifndef ISC_DLZ_DLOPEN
591225305Sdougb	UNUSED(mctx);
592225305Sdougb	return (ISC_R_NOTIMPLEMENTED);
593225305Sdougb#else
594225305Sdougb	isc_result_t result;
595225305Sdougb
596225305Sdougb	dlopen_log(2, "Registering DLZ_dlopen driver");
597225305Sdougb
598225305Sdougb	result = dns_sdlzregister("dlopen", &dlz_dlopen_methods, NULL,
599225305Sdougb				  DNS_SDLZFLAG_RELATIVEOWNER |
600225305Sdougb				  DNS_SDLZFLAG_THREADSAFE,
601225305Sdougb				  mctx, &dlz_dlopen);
602225305Sdougb
603225305Sdougb	if (result != ISC_R_SUCCESS) {
604225305Sdougb		UNEXPECTED_ERROR(__FILE__, __LINE__,
605225305Sdougb				 "dns_sdlzregister() failed: %s",
606225305Sdougb				 isc_result_totext(result));
607225305Sdougb		result = ISC_R_UNEXPECTED;
608225305Sdougb	}
609225305Sdougb
610225305Sdougb	return (result);
611225305Sdougb#endif
612225305Sdougb}
613225305Sdougb
614225305Sdougb
615225305Sdougb/*
616225305Sdougb * Unregister the driver
617225305Sdougb */
618225305Sdougbvoid
619225305Sdougbdlz_dlopen_clear(void) {
620225305Sdougb#ifdef ISC_DLZ_DLOPEN
621225305Sdougb	dlopen_log(2, "Unregistering DLZ_dlopen driver");
622225305Sdougb	if (dlz_dlopen != NULL)
623225305Sdougb		dns_sdlzunregister(&dlz_dlopen);
624225305Sdougb#endif
625225305Sdougb}
626