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