1/*
2 * Portions Copyright (C) 2005, 2007, 2009-2012  Internet Systems Consortium, Inc. ("ISC")
3 * Portions Copyright (C) 1999-2001  Internet Software Consortium.
4 *
5 * Permission to use, copy, modify, and/or distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11 * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15 * PERFORMANCE OF THIS SOFTWARE.
16 */
17
18/*
19 * Copyright (C) 2002 Stichting NLnet, Netherlands, stichting@nlnet.nl.
20 *
21 * Permission to use, copy, modify, and distribute this software for any
22 * purpose with or without fee is hereby granted, provided that the
23 * above copyright notice and this permission notice appear in all
24 * copies.
25 *
26 * THE SOFTWARE IS PROVIDED "AS IS" AND STICHTING NLNET
27 * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
29 * STICHTING NLNET BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
30 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
31 * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
32 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE
33 * USE OR PERFORMANCE OF THIS SOFTWARE.
34 *
35 * The development of Dynamically Loadable Zones (DLZ) for Bind 9 was
36 * conceived and contributed by Rob Butler.
37 *
38 * Permission to use, copy, modify, and distribute this software for any
39 * purpose with or without fee is hereby granted, provided that the
40 * above copyright notice and this permission notice appear in all
41 * copies.
42 *
43 * THE SOFTWARE IS PROVIDED "AS IS" AND ROB BUTLER
44 * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
45 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
46 * ROB BUTLER BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
47 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
48 * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
49 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE
50 * USE OR PERFORMANCE OF THIS SOFTWARE.
51 */
52
53/* $Id$ */
54
55/*! \file */
56
57/***
58 *** Imports
59 ***/
60
61#include <config.h>
62
63#include <dns/fixedname.h>
64#include <dns/log.h>
65#include <dns/master.h>
66#include <dns/dlz.h>
67#include <dns/ssu.h>
68#include <dns/zone.h>
69
70
71#include <isc/buffer.h>
72#include <isc/magic.h>
73#include <isc/mem.h>
74#include <isc/once.h>
75#include <isc/rwlock.h>
76#include <isc/string.h>
77#include <isc/util.h>
78
79/***
80 *** Supported DLZ DB Implementations Registry
81 ***/
82
83static ISC_LIST(dns_dlzimplementation_t) dlz_implementations;
84static isc_rwlock_t dlz_implock;
85static isc_once_t once = ISC_ONCE_INIT;
86
87static void
88dlz_initialize(void) {
89	RUNTIME_CHECK(isc_rwlock_init(&dlz_implock, 0, 0) == ISC_R_SUCCESS);
90	ISC_LIST_INIT(dlz_implementations);
91}
92
93/*%
94 * Searches the dlz_implementations list for a driver matching name.
95 */
96static inline dns_dlzimplementation_t *
97dlz_impfind(const char *name) {
98	dns_dlzimplementation_t *imp;
99
100	for (imp = ISC_LIST_HEAD(dlz_implementations);
101	     imp != NULL;
102	     imp = ISC_LIST_NEXT(imp, link))
103		if (strcasecmp(name, imp->name) == 0)
104			return (imp);
105	return (NULL);
106}
107
108/***
109 *** Basic DLZ Methods
110 ***/
111
112isc_result_t
113dns_dlzallowzonexfr(dns_view_t *view, dns_name_t *name,
114		    isc_sockaddr_t *clientaddr, dns_db_t **dbp)
115{
116	isc_result_t result;
117	dns_dlzallowzonexfr_t allowzonexfr;
118	dns_dlzdb_t *dlzdatabase;
119
120	/*
121	 * Performs checks to make sure data is as we expect it to be.
122	 */
123	REQUIRE(DNS_DLZ_VALID(view->dlzdatabase));
124	REQUIRE(name != NULL);
125	REQUIRE(dbp != NULL && *dbp == NULL);
126
127	/* ask driver if the zone is supported */
128	dlzdatabase = view->dlzdatabase;
129	allowzonexfr = dlzdatabase->implementation->methods->allowzonexfr;
130	result = (*allowzonexfr)(dlzdatabase->implementation->driverarg,
131				 dlzdatabase->dbdata, dlzdatabase->mctx,
132				 view->rdclass, name, clientaddr, dbp);
133
134	if (result == ISC_R_NOTIMPLEMENTED)
135		return (ISC_R_NOTFOUND);
136	return (result);
137}
138
139isc_result_t
140dns_dlzcreate(isc_mem_t *mctx, const char *dlzname, const char *drivername,
141	      unsigned int argc, char *argv[], dns_dlzdb_t **dbp)
142{
143	dns_dlzimplementation_t *impinfo;
144	isc_result_t result;
145
146	/*
147	 * initialize the dlz_implementations list, this is guaranteed
148	 * to only really happen once.
149	 */
150	RUNTIME_CHECK(isc_once_do(&once, dlz_initialize) == ISC_R_SUCCESS);
151
152	/*
153	 * Performs checks to make sure data is as we expect it to be.
154	 */
155	REQUIRE(dbp != NULL && *dbp == NULL);
156	REQUIRE(dlzname != NULL);
157	REQUIRE(drivername != NULL);
158	REQUIRE(mctx != NULL);
159
160	/* write log message */
161	isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
162		      DNS_LOGMODULE_DLZ, ISC_LOG_INFO,
163		      "Loading '%s' using driver %s", dlzname, drivername);
164
165	/* lock the dlz_implementations list so we can search it. */
166	RWLOCK(&dlz_implock, isc_rwlocktype_read);
167
168	/* search for the driver implementation	 */
169	impinfo = dlz_impfind(drivername);
170	if (impinfo == NULL) {
171		RWUNLOCK(&dlz_implock, isc_rwlocktype_read);
172
173		isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
174			      DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
175			      "unsupported DLZ database driver '%s'."
176			      "  %s not loaded.",
177			      drivername, dlzname);
178
179		return (ISC_R_NOTFOUND);
180	}
181
182	/* Allocate memory to hold the DLZ database driver */
183	(*dbp) = isc_mem_get(mctx, sizeof(dns_dlzdb_t));
184	if ((*dbp) == NULL) {
185		RWUNLOCK(&dlz_implock, isc_rwlocktype_read);
186		return (ISC_R_NOMEMORY);
187	}
188
189	/* Make sure memory region is set to all 0's */
190	memset((*dbp), 0, sizeof(dns_dlzdb_t));
191
192	(*dbp)->implementation = impinfo;
193
194	/* Create a new database using implementation 'drivername'. */
195	result = ((impinfo->methods->create)(mctx, dlzname, argc, argv,
196					     impinfo->driverarg,
197					     &(*dbp)->dbdata));
198
199	/* mark the DLZ driver as valid */
200	if (result == ISC_R_SUCCESS) {
201		RWUNLOCK(&dlz_implock, isc_rwlocktype_read);
202		(*dbp)->magic = DNS_DLZ_MAGIC;
203		isc_mem_attach(mctx, &(*dbp)->mctx);
204		isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
205			      DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2),
206			      "DLZ driver loaded successfully.");
207		return (ISC_R_SUCCESS);
208	} else {
209		isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
210			      DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
211			      "DLZ driver failed to load.");
212	}
213
214	/* impinfo->methods->create failed. */
215	RWUNLOCK(&dlz_implock, isc_rwlocktype_read);
216	isc_mem_put(mctx, (*dbp), sizeof(dns_dlzdb_t));
217	return (result);
218}
219
220void
221dns_dlzdestroy(dns_dlzdb_t **dbp) {
222	isc_mem_t *mctx;
223	dns_dlzdestroy_t destroy;
224
225	/* Write debugging message to log */
226	isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
227		      DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2),
228		      "Unloading DLZ driver.");
229
230	/*
231	 * Perform checks to make sure data is as we expect it to be.
232	 */
233	REQUIRE(dbp != NULL && DNS_DLZ_VALID(*dbp));
234
235#ifdef BIND9
236	if ((*dbp)->ssutable != NULL) {
237		dns_ssutable_detach(&(*dbp)->ssutable);
238	}
239#endif
240
241	/* call the drivers destroy method */
242	if ((*dbp) != NULL) {
243		mctx = (*dbp)->mctx;
244		destroy = (*dbp)->implementation->methods->destroy;
245		(*destroy)((*dbp)->implementation->driverarg,(*dbp)->dbdata);
246		/* return memory */
247		isc_mem_put(mctx, (*dbp), sizeof(dns_dlzdb_t));
248		isc_mem_detach(&mctx);
249	}
250
251	*dbp = NULL;
252}
253
254
255isc_result_t
256dns_dlzfindzone(dns_view_t *view, dns_name_t *name, unsigned int minlabels,
257		dns_db_t **dbp)
258{
259	dns_fixedname_t fname;
260	dns_name_t *zonename;
261	unsigned int namelabels;
262	unsigned int i;
263	isc_result_t result;
264	dns_dlzfindzone_t findzone;
265	dns_dlzdb_t *dlzdatabase;
266
267	/*
268	 * Performs checks to make sure data is as we expect it to be.
269	 */
270	REQUIRE(DNS_DLZ_VALID(view->dlzdatabase));
271	REQUIRE(name != NULL);
272	REQUIRE(dbp != NULL && *dbp == NULL);
273
274	/* setup a "fixed" dns name */
275	dns_fixedname_init(&fname);
276	zonename = dns_fixedname_name(&fname);
277
278	/* count the number of labels in the name */
279	namelabels = dns_name_countlabels(name);
280
281	/*
282	 * loop through starting with the longest domain name and
283	 * trying shorter names portions of the name until we find a
284	 * match, have an error, or are below the 'minlabels'
285	 * threshold.  minlabels is 0, if the standard database didn't
286	 * have a zone name match.  Otherwise minlabels is the number
287	 * of labels in that name.  We need to beat that for a
288	 * "better" match for the DLZ database to be authoritative
289	 * instead of the standard database.
290	 */
291	for (i = namelabels; i > minlabels && i > 1; i--) {
292		if (i == namelabels) {
293			result = dns_name_copy(name, zonename, NULL);
294			if (result != ISC_R_SUCCESS)
295				return (result);
296		} else
297			dns_name_split(name, i, NULL, zonename);
298
299		/* ask SDLZ driver if the zone is supported */
300		dlzdatabase = view->dlzdatabase;
301		findzone = dlzdatabase->implementation->methods->findzone;
302		result = (*findzone)(dlzdatabase->implementation->driverarg,
303				     dlzdatabase->dbdata, dlzdatabase->mctx,
304				     view->rdclass, zonename, dbp);
305		if (result != ISC_R_NOTFOUND)
306			return (result);
307	}
308	return (ISC_R_NOTFOUND);
309}
310
311/*%
312 * Registers a DLZ driver.  This basically just adds the dlz
313 * driver to the list of available drivers in the dlz_implementations list.
314 */
315isc_result_t
316dns_dlzregister(const char *drivername, const dns_dlzmethods_t *methods,
317		void *driverarg, isc_mem_t *mctx,
318		dns_dlzimplementation_t **dlzimp)
319{
320
321	dns_dlzimplementation_t *dlz_imp;
322
323	/* Write debugging message to log */
324	isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
325		      DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2),
326		      "Registering DLZ driver '%s'", drivername);
327
328	/*
329	 * Performs checks to make sure data is as we expect it to be.
330	 */
331	REQUIRE(drivername != NULL);
332	REQUIRE(methods != NULL);
333	REQUIRE(methods->create != NULL);
334	REQUIRE(methods->destroy != NULL);
335	REQUIRE(methods->findzone != NULL);
336	REQUIRE(mctx != NULL);
337	REQUIRE(dlzimp != NULL && *dlzimp == NULL);
338
339	/*
340	 * initialize the dlz_implementations list, this is guaranteed
341	 * to only really happen once.
342	 */
343	RUNTIME_CHECK(isc_once_do(&once, dlz_initialize) == ISC_R_SUCCESS);
344
345	/* lock the dlz_implementations list so we can modify it. */
346	RWLOCK(&dlz_implock, isc_rwlocktype_write);
347
348	/*
349	 * check that another already registered driver isn't using
350	 * the same name
351	 */
352	dlz_imp = dlz_impfind(drivername);
353	if (dlz_imp != NULL) {
354		isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
355			      DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2),
356			      "DLZ Driver '%s' already registered",
357			      drivername);
358		RWUNLOCK(&dlz_implock, isc_rwlocktype_write);
359		return (ISC_R_EXISTS);
360	}
361
362	/*
363	 * Allocate memory for a dlz_implementation object.  Error if
364	 * we cannot.
365	 */
366	dlz_imp = isc_mem_get(mctx, sizeof(dns_dlzimplementation_t));
367	if (dlz_imp == NULL) {
368		RWUNLOCK(&dlz_implock, isc_rwlocktype_write);
369		return (ISC_R_NOMEMORY);
370	}
371
372	/* Make sure memory region is set to all 0's */
373	memset(dlz_imp, 0, sizeof(dns_dlzimplementation_t));
374
375	/* Store the data passed into this method */
376	dlz_imp->name = drivername;
377	dlz_imp->methods = methods;
378	dlz_imp->mctx = NULL;
379	dlz_imp->driverarg = driverarg;
380
381	/* attach the new dlz_implementation object to a memory context */
382	isc_mem_attach(mctx, &dlz_imp->mctx);
383
384	/*
385	 * prepare the dlz_implementation object to be put in a list,
386	 * and append it to the list
387	 */
388	ISC_LINK_INIT(dlz_imp, link);
389	ISC_LIST_APPEND(dlz_implementations, dlz_imp, link);
390
391	/* Unlock the dlz_implementations list.	 */
392	RWUNLOCK(&dlz_implock, isc_rwlocktype_write);
393
394	/* Pass back the dlz_implementation that we created. */
395	*dlzimp = dlz_imp;
396
397	return (ISC_R_SUCCESS);
398}
399
400/*%
401 * Helper function for dns_dlzstrtoargv().
402 * Pardon the gratuitous recursion.
403 */
404static isc_result_t
405dns_dlzstrtoargvsub(isc_mem_t *mctx, char *s, unsigned int *argcp,
406		    char ***argvp, unsigned int n)
407{
408	isc_result_t result;
409
410 restart:
411	/* Discard leading whitespace. */
412	while (*s == ' ' || *s == '\t')
413		s++;
414
415	if (*s == '\0') {
416		/* We have reached the end of the string. */
417		*argcp = n;
418		*argvp = isc_mem_get(mctx, n * sizeof(char *));
419		if (*argvp == NULL)
420			return (ISC_R_NOMEMORY);
421	} else {
422		char *p = s;
423		while (*p != ' ' && *p != '\t' && *p != '\0' && *p != '{') {
424			if (*p == '\n') {
425				*p = ' ';
426				goto restart;
427			}
428			p++;
429		}
430
431		/* do "grouping", items between { and } are one arg */
432		if (*p == '{') {
433			char *t = p;
434			/*
435			 * shift all characters to left by 1 to get rid of '{'
436			 */
437			while (*t != '\0') {
438				t++;
439				*(t-1) = *t;
440			}
441			while (*p != '\0' && *p != '}') {
442				p++;
443			}
444			/* get rid of '}' character */
445			if (*p == '}') {
446				*p = '\0';
447				p++;
448			}
449			/* normal case, no "grouping" */
450		} else if (*p != '\0')
451			*p++ = '\0';
452
453		result = dns_dlzstrtoargvsub(mctx, p, argcp, argvp, n + 1);
454		if (result != ISC_R_SUCCESS)
455			return (result);
456		(*argvp)[n] = s;
457	}
458	return (ISC_R_SUCCESS);
459}
460
461/*%
462 * Tokenize the string "s" into whitespace-separated words,
463 * return the number of words in '*argcp' and an array
464 * of pointers to the words in '*argvp'.  The caller
465 * must free the array using isc_mem_put().  The string
466 * is modified in-place.
467 */
468isc_result_t
469dns_dlzstrtoargv(isc_mem_t *mctx, char *s,
470		 unsigned int *argcp, char ***argvp)
471{
472	return(dns_dlzstrtoargvsub(mctx, s, argcp, argvp, 0));
473}
474
475/*%
476 * Unregisters a DLZ driver.  This basically just removes the dlz
477 * driver from the list of available drivers in the dlz_implementations list.
478 */
479void
480dns_dlzunregister(dns_dlzimplementation_t **dlzimp) {
481	dns_dlzimplementation_t *dlz_imp;
482	isc_mem_t *mctx;
483
484	/* Write debugging message to log */
485	isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
486		      DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2),
487		      "Unregistering DLZ driver.");
488
489	/*
490	 * Performs checks to make sure data is as we expect it to be.
491	 */
492	REQUIRE(dlzimp != NULL && *dlzimp != NULL);
493
494	/*
495	 * initialize the dlz_implementations list, this is guaranteed
496	 * to only really happen once.
497	 */
498	RUNTIME_CHECK(isc_once_do(&once, dlz_initialize) == ISC_R_SUCCESS);
499
500	dlz_imp = *dlzimp;
501
502	/* lock the dlz_implementations list so we can modify it. */
503	RWLOCK(&dlz_implock, isc_rwlocktype_write);
504
505	/* remove the dlz_implementation object from the list */
506	ISC_LIST_UNLINK(dlz_implementations, dlz_imp, link);
507	mctx = dlz_imp->mctx;
508
509	/*
510	 * Return the memory back to the available memory pool and
511	 * remove it from the memory context.
512	 */
513	isc_mem_put(mctx, dlz_imp, sizeof(dns_dlzimplementation_t));
514	isc_mem_detach(&mctx);
515
516	/* Unlock the dlz_implementations list. */
517	RWUNLOCK(&dlz_implock, isc_rwlocktype_write);
518}
519
520#ifdef BIND9
521/*
522 * Create a writeable DLZ zone. This can be called by DLZ drivers
523 * during configure() to create a zone that can be updated. The zone
524 * type is set to dns_zone_dlz, which is equivalent to a master zone
525 *
526 * This function uses a callback setup in dns_dlzconfigure() to call
527 * into the server zone code to setup the remaining pieces of server
528 * specific functionality on the zone
529 */
530isc_result_t
531dns_dlz_writeablezone(dns_view_t *view, const char *zone_name) {
532	dns_zone_t *zone = NULL;
533	dns_zone_t *dupzone = NULL;
534	isc_result_t result;
535	isc_buffer_t buffer;
536	dns_fixedname_t fixorigin;
537	dns_name_t *origin;
538	dns_dlzdb_t *dlzdatabase;
539
540	REQUIRE(DNS_DLZ_VALID(view->dlzdatabase));
541
542	dlzdatabase = view->dlzdatabase;
543
544	REQUIRE(dlzdatabase->configure_callback != NULL);
545
546	isc_buffer_init(&buffer, zone_name, strlen(zone_name));
547	isc_buffer_add(&buffer, strlen(zone_name));
548	dns_fixedname_init(&fixorigin);
549	result = dns_name_fromtext(dns_fixedname_name(&fixorigin),
550				   &buffer, dns_rootname, 0, NULL);
551	if (result != ISC_R_SUCCESS)
552		goto cleanup;
553	origin = dns_fixedname_name(&fixorigin);
554
555	/* See if the zone already exists */
556	result = dns_view_findzone(view, origin, &dupzone);
557	if (result == ISC_R_SUCCESS) {
558		dns_zone_detach(&dupzone);
559		result = ISC_R_EXISTS;
560		goto cleanup;
561	}
562	INSIST(dupzone == NULL);
563
564	/* Create it */
565	result = dns_zone_create(&zone, view->mctx);
566	if (result != ISC_R_SUCCESS)
567		goto cleanup;
568	result = dns_zone_setorigin(zone, origin);
569	if (result != ISC_R_SUCCESS)
570		goto cleanup;
571	dns_zone_setview(zone, view);
572
573	dns_zone_setadded(zone, ISC_TRUE);
574
575	if (dlzdatabase->ssutable == NULL) {
576		result = dns_ssutable_createdlz(dlzdatabase->mctx,
577						&dlzdatabase->ssutable,
578						view->dlzdatabase);
579		if (result != ISC_R_SUCCESS)
580			goto cleanup;
581	}
582	dns_zone_setssutable(zone, dlzdatabase->ssutable);
583
584	result = dlzdatabase->configure_callback(view, zone);
585	if (result != ISC_R_SUCCESS)
586		goto cleanup;
587
588	/*
589	 * Add the zone to its view in the new view list.
590	 */
591	result = dns_view_addzone(view, zone);
592
593 cleanup:
594	if (zone != NULL)
595		dns_zone_detach(&zone);
596
597	return (result);
598}
599#endif
600
601/*%
602 * Configure a DLZ driver. This is optional, and if supplied gives
603 * the backend an opportunity to configure parameters related to DLZ.
604 */
605isc_result_t
606dns_dlzconfigure(dns_view_t *view, isc_result_t (*callback)(dns_view_t *,
607		 dns_zone_t *))
608{
609	dns_dlzimplementation_t *impl;
610	dns_dlzdb_t *dlzdatabase;
611	isc_result_t result;
612
613	REQUIRE(view != NULL);
614	REQUIRE(DNS_DLZ_VALID(view->dlzdatabase));
615	REQUIRE(view->dlzdatabase->implementation != NULL);
616
617	dlzdatabase = view->dlzdatabase;
618	impl = dlzdatabase->implementation;
619
620	if (impl->methods->configure == NULL)
621		return (ISC_R_SUCCESS);
622
623	dlzdatabase->configure_callback = callback;
624
625	result = impl->methods->configure(impl->driverarg,
626					  dlzdatabase->dbdata, view);
627	return (result);
628}
629
630isc_boolean_t
631dns_dlz_ssumatch(dns_dlzdb_t *dlzdatabase,
632		  dns_name_t *signer, dns_name_t *name, isc_netaddr_t *tcpaddr,
633		  dns_rdatatype_t type, const dst_key_t *key)
634{
635	dns_dlzimplementation_t *impl;
636	isc_boolean_t r;
637
638	REQUIRE(dlzdatabase != NULL);
639	REQUIRE(dlzdatabase->implementation != NULL);
640	REQUIRE(dlzdatabase->implementation->methods != NULL);
641	impl = dlzdatabase->implementation;
642
643	if (impl->methods->ssumatch == NULL) {
644		isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
645			      DNS_LOGMODULE_DLZ, ISC_LOG_INFO,
646			      "No ssumatch method for DLZ database");
647		return (ISC_FALSE);
648	}
649
650	r = impl->methods->ssumatch(signer, name, tcpaddr, type, key,
651				    impl->driverarg, dlzdatabase->dbdata);
652	return (r);
653}
654