1 /*
2  * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
3  *
4  * SPDX-License-Identifier: MPL-2.0 AND ISC
5  *
6  * This Source Code Form is subject to the terms of the Mozilla Public
7  * License, v. 2.0. If a copy of the MPL was not distributed with this
8  * file, you can obtain one at https://mozilla.org/MPL/2.0/.
9  *
10  * See the COPYRIGHT file distributed with this work for additional
11  * information regarding copyright ownership.
12  */
13 
14 /*
15  * Copyright (C) 2002 Stichting NLnet, Netherlands, stichting@nlnet.nl.
16  *
17  * Permission to use, copy, modify, and distribute this software for any
18  * purpose with or without fee is hereby granted, provided that the
19  * above copyright notice and this permission notice appear in all
20  * copies.
21  *
22  * THE SOFTWARE IS PROVIDED "AS IS" AND STICHTING NLNET
23  * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
25  * STICHTING NLNET BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
26  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
27  * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
28  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE
29  * USE OR PERFORMANCE OF THIS SOFTWARE.
30  *
31  * The development of Dynamically Loadable Zones (DLZ) for Bind 9 was
32  * conceived and contributed by Rob Butler.
33  *
34  * Permission to use, copy, modify, and distribute this software for any
35  * purpose with or without fee is hereby granted, provided that the
36  * above copyright notice and this permission notice appear in all
37  * copies.
38  *
39  * THE SOFTWARE IS PROVIDED "AS IS" AND ROB BUTLER
40  * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
41  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
42  * ROB BUTLER BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
43  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
44  * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
45  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE
46  * USE OR PERFORMANCE OF THIS SOFTWARE.
47  */
48 
49 /*! \file */
50 
51 #include <inttypes.h>
52 #include <stdbool.h>
53 #include <string.h>
54 
55 #include <isc/buffer.h>
56 #include <isc/lex.h>
57 #include <isc/log.h>
58 #include <isc/magic.h>
59 #include <isc/mem.h>
60 #include <isc/once.h>
61 #include <isc/print.h>
62 #include <isc/region.h>
63 #include <isc/rwlock.h>
64 #include <isc/string.h>
65 #include <isc/util.h>
66 
67 #include <dns/callbacks.h>
68 #include <dns/db.h>
69 #include <dns/dbiterator.h>
70 #include <dns/dlz.h>
71 #include <dns/fixedname.h>
72 #include <dns/log.h>
73 #include <dns/master.h>
74 #include <dns/rdata.h>
75 #include <dns/rdatalist.h>
76 #include <dns/rdataset.h>
77 #include <dns/rdatasetiter.h>
78 #include <dns/rdatatype.h>
79 #include <dns/result.h>
80 #include <dns/sdlz.h>
81 #include <dns/types.h>
82 
83 #include "rdatalist_p.h"
84 
85 /*
86  * Private Types
87  */
88 
89 struct dns_sdlzimplementation {
90 	const dns_sdlzmethods_t *methods;
91 	isc_mem_t *mctx;
92 	void *driverarg;
93 	unsigned int flags;
94 	isc_mutex_t driverlock;
95 	dns_dlzimplementation_t *dlz_imp;
96 };
97 
98 struct dns_sdlz_db {
99 	/* Unlocked */
100 	dns_db_t common;
101 	void *dbdata;
102 	dns_sdlzimplementation_t *dlzimp;
103 
104 	/* Atomic */
105 	isc_refcount_t references;
106 
107 	/* Locked */
108 	dns_dbversion_t *future_version;
109 	int dummy_version;
110 };
111 
112 struct dns_sdlzlookup {
113 	/* Unlocked */
114 	unsigned int magic;
115 	dns_sdlz_db_t *sdlz;
116 	ISC_LIST(dns_rdatalist_t) lists;
117 	ISC_LIST(isc_buffer_t) buffers;
118 	dns_name_t *name;
119 	ISC_LINK(dns_sdlzlookup_t) link;
120 	dns_rdatacallbacks_t callbacks;
121 
122 	/* Atomic */
123 	isc_refcount_t references;
124 };
125 
126 typedef struct dns_sdlzlookup dns_sdlznode_t;
127 
128 struct dns_sdlzallnodes {
129 	dns_dbiterator_t common;
130 	ISC_LIST(dns_sdlznode_t) nodelist;
131 	dns_sdlznode_t *current;
132 	dns_sdlznode_t *origin;
133 };
134 
135 typedef dns_sdlzallnodes_t sdlz_dbiterator_t;
136 
137 typedef struct sdlz_rdatasetiter {
138 	dns_rdatasetiter_t common;
139 	dns_rdatalist_t *current;
140 } sdlz_rdatasetiter_t;
141 
142 #define SDLZDB_MAGIC ISC_MAGIC('D', 'L', 'Z', 'S')
143 
144 /*
145  * Note that "impmagic" is not the first four bytes of the struct, so
146  * ISC_MAGIC_VALID cannot be used.
147  */
148 
149 #define VALID_SDLZDB(sdlzdb) \
150 	((sdlzdb) != NULL && (sdlzdb)->common.impmagic == SDLZDB_MAGIC)
151 
152 #define SDLZLOOKUP_MAGIC	ISC_MAGIC('D', 'L', 'Z', 'L')
153 #define VALID_SDLZLOOKUP(sdlzl) ISC_MAGIC_VALID(sdlzl, SDLZLOOKUP_MAGIC)
154 #define VALID_SDLZNODE(sdlzn)	VALID_SDLZLOOKUP(sdlzn)
155 
156 /* These values are taken from RFC 1537 */
157 #define SDLZ_DEFAULT_REFRESH 28800U  /* 8 hours */
158 #define SDLZ_DEFAULT_RETRY   7200U   /* 2 hours */
159 #define SDLZ_DEFAULT_EXPIRE  604800U /* 7 days */
160 #define SDLZ_DEFAULT_MINIMUM 86400U  /* 1 day */
161 
162 /* This is a reasonable value */
163 #define SDLZ_DEFAULT_TTL (60 * 60 * 24)
164 
165 #ifdef __COVERITY__
166 #define MAYBE_LOCK(imp)	  LOCK(&imp->driverlock)
167 #define MAYBE_UNLOCK(imp) UNLOCK(&imp->driverlock)
168 #else /* ifdef __COVERITY__ */
169 #define MAYBE_LOCK(imp)                                     \
170 	do {                                                \
171 		unsigned int flags = imp->flags;            \
172 		if ((flags & DNS_SDLZFLAG_THREADSAFE) == 0) \
173 			LOCK(&imp->driverlock);             \
174 	} while (0)
175 
176 #define MAYBE_UNLOCK(imp)                                   \
177 	do {                                                \
178 		unsigned int flags = imp->flags;            \
179 		if ((flags & DNS_SDLZFLAG_THREADSAFE) == 0) \
180 			UNLOCK(&imp->driverlock);           \
181 	} while (0)
182 #endif /* ifdef __COVERITY__ */
183 
184 /*
185  * Forward references.
186  */
187 static isc_result_t
188 getnodedata(dns_db_t *db, const dns_name_t *name, bool create,
189 	    unsigned int options, dns_clientinfomethods_t *methods,
190 	    dns_clientinfo_t *clientinfo, dns_dbnode_t **nodep);
191 
192 static void
193 list_tordataset(dns_rdatalist_t *rdatalist, dns_db_t *db, dns_dbnode_t *node,
194 		dns_rdataset_t *rdataset);
195 
196 static void
197 detachnode(dns_db_t *db, dns_dbnode_t **targetp);
198 
199 static void
200 dbiterator_destroy(dns_dbiterator_t **iteratorp);
201 static isc_result_t
202 dbiterator_first(dns_dbiterator_t *iterator);
203 static isc_result_t
204 dbiterator_last(dns_dbiterator_t *iterator);
205 static isc_result_t
206 dbiterator_seek(dns_dbiterator_t *iterator, const dns_name_t *name);
207 static isc_result_t
208 dbiterator_prev(dns_dbiterator_t *iterator);
209 static isc_result_t
210 dbiterator_next(dns_dbiterator_t *iterator);
211 static isc_result_t
212 dbiterator_current(dns_dbiterator_t *iterator, dns_dbnode_t **nodep,
213 		   dns_name_t *name);
214 static isc_result_t
215 dbiterator_pause(dns_dbiterator_t *iterator);
216 static isc_result_t
217 dbiterator_origin(dns_dbiterator_t *iterator, dns_name_t *name);
218 
219 static dns_dbiteratormethods_t dbiterator_methods = {
220 	dbiterator_destroy, dbiterator_first, dbiterator_last,
221 	dbiterator_seek,    dbiterator_prev,  dbiterator_next,
222 	dbiterator_current, dbiterator_pause, dbiterator_origin
223 };
224 
225 /*
226  * Utility functions
227  */
228 
229 /*
230  * Log a message at the given level
231  */
232 static void
sdlz_log(int level,const char * fmt,...)233 sdlz_log(int level, const char *fmt, ...) {
234 	va_list ap;
235 	va_start(ap, fmt);
236 	isc_log_vwrite(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ,
237 		       ISC_LOG_DEBUG(level), fmt, ap);
238 	va_end(ap);
239 }
240 
241 /*% Converts the input string to lowercase, in place. */
242 static void
dns_sdlz_tolower(char * str)243 dns_sdlz_tolower(char *str) {
244 	unsigned int len = strlen(str);
245 	unsigned int i;
246 
247 	for (i = 0; i < len; i++) {
248 		if (str[i] >= 'A' && str[i] <= 'Z') {
249 			str[i] += 32;
250 		}
251 	}
252 }
253 
254 static inline unsigned int
initial_size(const char * data)255 initial_size(const char *data) {
256 	unsigned int len = (strlen(data) / 64) + 1;
257 	return (len * 64 + 64);
258 }
259 
260 /*
261  * Rdataset Iterator Methods. These methods were "borrowed" from the SDB
262  * driver interface.  See the SDB driver interface documentation for more info.
263  */
264 
265 static void
rdatasetiter_destroy(dns_rdatasetiter_t ** iteratorp)266 rdatasetiter_destroy(dns_rdatasetiter_t **iteratorp) {
267 	sdlz_rdatasetiter_t *sdlziterator = (sdlz_rdatasetiter_t *)(*iteratorp);
268 
269 	detachnode(sdlziterator->common.db, &sdlziterator->common.node);
270 	isc_mem_put(sdlziterator->common.db->mctx, sdlziterator,
271 		    sizeof(sdlz_rdatasetiter_t));
272 	*iteratorp = NULL;
273 }
274 
275 static isc_result_t
rdatasetiter_first(dns_rdatasetiter_t * iterator)276 rdatasetiter_first(dns_rdatasetiter_t *iterator) {
277 	sdlz_rdatasetiter_t *sdlziterator = (sdlz_rdatasetiter_t *)iterator;
278 	dns_sdlznode_t *sdlznode = (dns_sdlznode_t *)iterator->node;
279 
280 	if (ISC_LIST_EMPTY(sdlznode->lists)) {
281 		return (ISC_R_NOMORE);
282 	}
283 	sdlziterator->current = ISC_LIST_HEAD(sdlznode->lists);
284 	return (ISC_R_SUCCESS);
285 }
286 
287 static isc_result_t
rdatasetiter_next(dns_rdatasetiter_t * iterator)288 rdatasetiter_next(dns_rdatasetiter_t *iterator) {
289 	sdlz_rdatasetiter_t *sdlziterator = (sdlz_rdatasetiter_t *)iterator;
290 
291 	sdlziterator->current = ISC_LIST_NEXT(sdlziterator->current, link);
292 	if (sdlziterator->current == NULL) {
293 		return (ISC_R_NOMORE);
294 	} else {
295 		return (ISC_R_SUCCESS);
296 	}
297 }
298 
299 static void
rdatasetiter_current(dns_rdatasetiter_t * iterator,dns_rdataset_t * rdataset)300 rdatasetiter_current(dns_rdatasetiter_t *iterator, dns_rdataset_t *rdataset) {
301 	sdlz_rdatasetiter_t *sdlziterator = (sdlz_rdatasetiter_t *)iterator;
302 
303 	list_tordataset(sdlziterator->current, iterator->db, iterator->node,
304 			rdataset);
305 }
306 
307 static dns_rdatasetitermethods_t rdatasetiter_methods = {
308 	rdatasetiter_destroy, rdatasetiter_first, rdatasetiter_next,
309 	rdatasetiter_current
310 };
311 
312 /*
313  * DB routines. These methods were "borrowed" from the SDB driver interface.
314  * See the SDB driver interface documentation for more info.
315  */
316 
317 static void
attach(dns_db_t * source,dns_db_t ** targetp)318 attach(dns_db_t *source, dns_db_t **targetp) {
319 	dns_sdlz_db_t *sdlz = (dns_sdlz_db_t *)source;
320 
321 	REQUIRE(VALID_SDLZDB(sdlz));
322 
323 	isc_refcount_increment(&sdlz->references);
324 
325 	*targetp = source;
326 }
327 
328 static void
destroy(dns_sdlz_db_t * sdlz)329 destroy(dns_sdlz_db_t *sdlz) {
330 	sdlz->common.magic = 0;
331 	sdlz->common.impmagic = 0;
332 
333 	dns_name_free(&sdlz->common.origin, sdlz->common.mctx);
334 
335 	isc_refcount_destroy(&sdlz->references);
336 	isc_mem_putanddetach(&sdlz->common.mctx, sdlz, sizeof(dns_sdlz_db_t));
337 }
338 
339 static void
detach(dns_db_t ** dbp)340 detach(dns_db_t **dbp) {
341 	dns_sdlz_db_t *sdlz = (dns_sdlz_db_t *)(*dbp);
342 
343 	REQUIRE(VALID_SDLZDB(sdlz));
344 
345 	*dbp = NULL;
346 
347 	if (isc_refcount_decrement(&sdlz->references) == 1) {
348 		destroy(sdlz);
349 	}
350 }
351 
352 static isc_result_t
beginload(dns_db_t * db,dns_rdatacallbacks_t * callbacks)353 beginload(dns_db_t *db, dns_rdatacallbacks_t *callbacks) {
354 	UNUSED(db);
355 	UNUSED(callbacks);
356 	return (ISC_R_NOTIMPLEMENTED);
357 }
358 
359 static isc_result_t
endload(dns_db_t * db,dns_rdatacallbacks_t * callbacks)360 endload(dns_db_t *db, dns_rdatacallbacks_t *callbacks) {
361 	UNUSED(db);
362 	UNUSED(callbacks);
363 	return (ISC_R_NOTIMPLEMENTED);
364 }
365 
366 static isc_result_t
dump(dns_db_t * db,dns_dbversion_t * version,const char * filename,dns_masterformat_t masterformat)367 dump(dns_db_t *db, dns_dbversion_t *version, const char *filename,
368      dns_masterformat_t masterformat) {
369 	UNUSED(db);
370 	UNUSED(version);
371 	UNUSED(filename);
372 	UNUSED(masterformat);
373 	return (ISC_R_NOTIMPLEMENTED);
374 }
375 
376 static void
currentversion(dns_db_t * db,dns_dbversion_t ** versionp)377 currentversion(dns_db_t *db, dns_dbversion_t **versionp) {
378 	dns_sdlz_db_t *sdlz = (dns_sdlz_db_t *)db;
379 	REQUIRE(VALID_SDLZDB(sdlz));
380 	REQUIRE(versionp != NULL && *versionp == NULL);
381 
382 	*versionp = (void *)&sdlz->dummy_version;
383 	return;
384 }
385 
386 static isc_result_t
newversion(dns_db_t * db,dns_dbversion_t ** versionp)387 newversion(dns_db_t *db, dns_dbversion_t **versionp) {
388 	dns_sdlz_db_t *sdlz = (dns_sdlz_db_t *)db;
389 	char origin[DNS_NAME_MAXTEXT + 1];
390 	isc_result_t result;
391 
392 	REQUIRE(VALID_SDLZDB(sdlz));
393 
394 	if (sdlz->dlzimp->methods->newversion == NULL) {
395 		return (ISC_R_NOTIMPLEMENTED);
396 	}
397 
398 	dns_name_format(&sdlz->common.origin, origin, sizeof(origin));
399 
400 	result = sdlz->dlzimp->methods->newversion(
401 		origin, sdlz->dlzimp->driverarg, sdlz->dbdata, versionp);
402 	if (result != ISC_R_SUCCESS) {
403 		sdlz_log(ISC_LOG_ERROR,
404 			 "sdlz newversion on origin %s failed : %s", origin,
405 			 isc_result_totext(result));
406 		return (result);
407 	}
408 
409 	sdlz->future_version = *versionp;
410 	return (ISC_R_SUCCESS);
411 }
412 
413 static void
attachversion(dns_db_t * db,dns_dbversion_t * source,dns_dbversion_t ** targetp)414 attachversion(dns_db_t *db, dns_dbversion_t *source,
415 	      dns_dbversion_t **targetp) {
416 	dns_sdlz_db_t *sdlz = (dns_sdlz_db_t *)db;
417 
418 	REQUIRE(VALID_SDLZDB(sdlz));
419 	REQUIRE(source != NULL && source == (void *)&sdlz->dummy_version);
420 
421 	*targetp = source;
422 }
423 
424 static void
closeversion(dns_db_t * db,dns_dbversion_t ** versionp,bool commit)425 closeversion(dns_db_t *db, dns_dbversion_t **versionp, bool commit) {
426 	dns_sdlz_db_t *sdlz = (dns_sdlz_db_t *)db;
427 	char origin[DNS_NAME_MAXTEXT + 1];
428 
429 	REQUIRE(VALID_SDLZDB(sdlz));
430 	REQUIRE(versionp != NULL);
431 
432 	if (*versionp == (void *)&sdlz->dummy_version) {
433 		*versionp = NULL;
434 		return;
435 	}
436 
437 	REQUIRE(*versionp == sdlz->future_version);
438 	REQUIRE(sdlz->dlzimp->methods->closeversion != NULL);
439 
440 	dns_name_format(&sdlz->common.origin, origin, sizeof(origin));
441 
442 	sdlz->dlzimp->methods->closeversion(origin, commit,
443 					    sdlz->dlzimp->driverarg,
444 					    sdlz->dbdata, versionp);
445 	if (*versionp != NULL) {
446 		sdlz_log(ISC_LOG_ERROR, "sdlz closeversion on origin %s failed",
447 			 origin);
448 	}
449 
450 	sdlz->future_version = NULL;
451 }
452 
453 static isc_result_t
createnode(dns_sdlz_db_t * sdlz,dns_sdlznode_t ** nodep)454 createnode(dns_sdlz_db_t *sdlz, dns_sdlznode_t **nodep) {
455 	dns_sdlznode_t *node;
456 
457 	node = isc_mem_get(sdlz->common.mctx, sizeof(dns_sdlznode_t));
458 
459 	node->sdlz = NULL;
460 	attach((dns_db_t *)sdlz, (dns_db_t **)&node->sdlz);
461 	ISC_LIST_INIT(node->lists);
462 	ISC_LIST_INIT(node->buffers);
463 	ISC_LINK_INIT(node, link);
464 	node->name = NULL;
465 	dns_rdatacallbacks_init(&node->callbacks);
466 
467 	isc_refcount_init(&node->references, 1);
468 	node->magic = SDLZLOOKUP_MAGIC;
469 
470 	*nodep = node;
471 	return (ISC_R_SUCCESS);
472 }
473 
474 static void
destroynode(dns_sdlznode_t * node)475 destroynode(dns_sdlznode_t *node) {
476 	dns_rdatalist_t *list;
477 	dns_rdata_t *rdata;
478 	isc_buffer_t *b;
479 	dns_sdlz_db_t *sdlz;
480 	dns_db_t *db;
481 	isc_mem_t *mctx;
482 
483 	isc_refcount_destroy(&node->references);
484 
485 	sdlz = node->sdlz;
486 	mctx = sdlz->common.mctx;
487 
488 	while (!ISC_LIST_EMPTY(node->lists)) {
489 		list = ISC_LIST_HEAD(node->lists);
490 		while (!ISC_LIST_EMPTY(list->rdata)) {
491 			rdata = ISC_LIST_HEAD(list->rdata);
492 			ISC_LIST_UNLINK(list->rdata, rdata, link);
493 			isc_mem_put(mctx, rdata, sizeof(dns_rdata_t));
494 		}
495 		ISC_LIST_UNLINK(node->lists, list, link);
496 		isc_mem_put(mctx, list, sizeof(dns_rdatalist_t));
497 	}
498 
499 	while (!ISC_LIST_EMPTY(node->buffers)) {
500 		b = ISC_LIST_HEAD(node->buffers);
501 		ISC_LIST_UNLINK(node->buffers, b, link);
502 		isc_buffer_free(&b);
503 	}
504 
505 	if (node->name != NULL) {
506 		dns_name_free(node->name, mctx);
507 		isc_mem_put(mctx, node->name, sizeof(dns_name_t));
508 	}
509 
510 	node->magic = 0;
511 	isc_mem_put(mctx, node, sizeof(dns_sdlznode_t));
512 	db = &sdlz->common;
513 	detach(&db);
514 }
515 
516 static isc_result_t
getnodedata(dns_db_t * db,const dns_name_t * name,bool create,unsigned int options,dns_clientinfomethods_t * methods,dns_clientinfo_t * clientinfo,dns_dbnode_t ** nodep)517 getnodedata(dns_db_t *db, const dns_name_t *name, bool create,
518 	    unsigned int options, dns_clientinfomethods_t *methods,
519 	    dns_clientinfo_t *clientinfo, dns_dbnode_t **nodep) {
520 	dns_sdlz_db_t *sdlz = (dns_sdlz_db_t *)db;
521 	dns_sdlznode_t *node = NULL;
522 	isc_result_t result;
523 	isc_buffer_t b;
524 	char namestr[DNS_NAME_MAXTEXT + 1];
525 	isc_buffer_t b2;
526 	char zonestr[DNS_NAME_MAXTEXT + 1];
527 	bool isorigin;
528 	dns_sdlzauthorityfunc_t authority;
529 
530 	REQUIRE(VALID_SDLZDB(sdlz));
531 	REQUIRE(nodep != NULL && *nodep == NULL);
532 
533 	if (sdlz->dlzimp->methods->newversion == NULL) {
534 		REQUIRE(!create);
535 	}
536 
537 	isc_buffer_init(&b, namestr, sizeof(namestr));
538 	if ((sdlz->dlzimp->flags & DNS_SDLZFLAG_RELATIVEOWNER) != 0) {
539 		dns_name_t relname;
540 		unsigned int labels;
541 
542 		labels = dns_name_countlabels(name) -
543 			 dns_name_countlabels(&sdlz->common.origin);
544 		dns_name_init(&relname, NULL);
545 		dns_name_getlabelsequence(name, 0, labels, &relname);
546 		result = dns_name_totext(&relname, true, &b);
547 		if (result != ISC_R_SUCCESS) {
548 			return (result);
549 		}
550 	} else {
551 		result = dns_name_totext(name, true, &b);
552 		if (result != ISC_R_SUCCESS) {
553 			return (result);
554 		}
555 	}
556 	isc_buffer_putuint8(&b, 0);
557 
558 	isc_buffer_init(&b2, zonestr, sizeof(zonestr));
559 	result = dns_name_totext(&sdlz->common.origin, true, &b2);
560 	if (result != ISC_R_SUCCESS) {
561 		return (result);
562 	}
563 	isc_buffer_putuint8(&b2, 0);
564 
565 	result = createnode(sdlz, &node);
566 	if (result != ISC_R_SUCCESS) {
567 		return (result);
568 	}
569 
570 	isorigin = dns_name_equal(name, &sdlz->common.origin);
571 
572 	/* make sure strings are always lowercase */
573 	dns_sdlz_tolower(zonestr);
574 	dns_sdlz_tolower(namestr);
575 
576 	MAYBE_LOCK(sdlz->dlzimp);
577 
578 	/* try to lookup the host (namestr) */
579 	result = sdlz->dlzimp->methods->lookup(
580 		zonestr, namestr, sdlz->dlzimp->driverarg, sdlz->dbdata, node,
581 		methods, clientinfo);
582 
583 	/*
584 	 * If the name was not found and DNS_DBFIND_NOWILD is not
585 	 * set, then we try to find a wildcard entry.
586 	 *
587 	 * If DNS_DBFIND_NOZONECUT is set and there are multiple
588 	 * levels between the host and the zone origin, we also look
589 	 * for wildcards at each level.
590 	 */
591 	if (result == ISC_R_NOTFOUND && !create &&
592 	    (options & DNS_DBFIND_NOWILD) == 0) {
593 		unsigned int i, dlabels, nlabels;
594 
595 		nlabels = dns_name_countlabels(name);
596 		dlabels = nlabels - dns_name_countlabels(&sdlz->common.origin);
597 		for (i = 0; i < dlabels; i++) {
598 			char wildstr[DNS_NAME_MAXTEXT + 1];
599 			dns_fixedname_t fixed;
600 			const dns_name_t *wild;
601 
602 			dns_fixedname_init(&fixed);
603 			if (i == dlabels - 1) {
604 				wild = dns_wildcardname;
605 			} else {
606 				dns_name_t *fname;
607 				fname = dns_fixedname_name(&fixed);
608 				dns_name_getlabelsequence(
609 					name, i + 1, dlabels - i - 1, fname);
610 				result = dns_name_concatenate(
611 					dns_wildcardname, fname, fname, NULL);
612 				if (result != ISC_R_SUCCESS) {
613 					MAYBE_UNLOCK(sdlz->dlzimp);
614 					return (result);
615 				}
616 				wild = fname;
617 			}
618 
619 			isc_buffer_init(&b, wildstr, sizeof(wildstr));
620 			result = dns_name_totext(wild, true, &b);
621 			if (result != ISC_R_SUCCESS) {
622 				MAYBE_UNLOCK(sdlz->dlzimp);
623 				return (result);
624 			}
625 			isc_buffer_putuint8(&b, 0);
626 
627 			result = sdlz->dlzimp->methods->lookup(
628 				zonestr, wildstr, sdlz->dlzimp->driverarg,
629 				sdlz->dbdata, node, methods, clientinfo);
630 			if (result == ISC_R_SUCCESS) {
631 				break;
632 			}
633 		}
634 	}
635 
636 	MAYBE_UNLOCK(sdlz->dlzimp);
637 
638 	if (result == ISC_R_NOTFOUND && (isorigin || create)) {
639 		result = ISC_R_SUCCESS;
640 	}
641 
642 	if (result != ISC_R_SUCCESS) {
643 		isc_refcount_decrementz(&node->references);
644 		destroynode(node);
645 		return (result);
646 	}
647 
648 	if (isorigin && sdlz->dlzimp->methods->authority != NULL) {
649 		MAYBE_LOCK(sdlz->dlzimp);
650 		authority = sdlz->dlzimp->methods->authority;
651 		result = (*authority)(zonestr, sdlz->dlzimp->driverarg,
652 				      sdlz->dbdata, node);
653 		MAYBE_UNLOCK(sdlz->dlzimp);
654 		if (result != ISC_R_SUCCESS && result != ISC_R_NOTIMPLEMENTED) {
655 			isc_refcount_decrementz(&node->references);
656 			destroynode(node);
657 			return (result);
658 		}
659 	}
660 
661 	if (node->name == NULL) {
662 		node->name = isc_mem_get(sdlz->common.mctx, sizeof(dns_name_t));
663 		dns_name_init(node->name, NULL);
664 		dns_name_dup(name, sdlz->common.mctx, node->name);
665 	}
666 
667 	*nodep = node;
668 	return (ISC_R_SUCCESS);
669 }
670 
671 static isc_result_t
findnodeext(dns_db_t * db,const dns_name_t * name,bool create,dns_clientinfomethods_t * methods,dns_clientinfo_t * clientinfo,dns_dbnode_t ** nodep)672 findnodeext(dns_db_t *db, const dns_name_t *name, bool create,
673 	    dns_clientinfomethods_t *methods, dns_clientinfo_t *clientinfo,
674 	    dns_dbnode_t **nodep) {
675 	return (getnodedata(db, name, create, 0, methods, clientinfo, nodep));
676 }
677 
678 static isc_result_t
findnode(dns_db_t * db,const dns_name_t * name,bool create,dns_dbnode_t ** nodep)679 findnode(dns_db_t *db, const dns_name_t *name, bool create,
680 	 dns_dbnode_t **nodep) {
681 	return (getnodedata(db, name, create, 0, NULL, NULL, nodep));
682 }
683 
684 static isc_result_t
findzonecut(dns_db_t * db,const dns_name_t * name,unsigned int options,isc_stdtime_t now,dns_dbnode_t ** nodep,dns_name_t * foundname,dns_name_t * dcname,dns_rdataset_t * rdataset,dns_rdataset_t * sigrdataset)685 findzonecut(dns_db_t *db, const dns_name_t *name, unsigned int options,
686 	    isc_stdtime_t now, dns_dbnode_t **nodep, dns_name_t *foundname,
687 	    dns_name_t *dcname, dns_rdataset_t *rdataset,
688 	    dns_rdataset_t *sigrdataset) {
689 	UNUSED(db);
690 	UNUSED(name);
691 	UNUSED(options);
692 	UNUSED(now);
693 	UNUSED(nodep);
694 	UNUSED(foundname);
695 	UNUSED(dcname);
696 	UNUSED(rdataset);
697 	UNUSED(sigrdataset);
698 
699 	return (ISC_R_NOTIMPLEMENTED);
700 }
701 
702 static void
attachnode(dns_db_t * db,dns_dbnode_t * source,dns_dbnode_t ** targetp)703 attachnode(dns_db_t *db, dns_dbnode_t *source, dns_dbnode_t **targetp) {
704 	dns_sdlz_db_t *sdlz = (dns_sdlz_db_t *)db;
705 	dns_sdlznode_t *node = (dns_sdlznode_t *)source;
706 
707 	REQUIRE(VALID_SDLZDB(sdlz));
708 
709 	UNUSED(sdlz);
710 
711 	isc_refcount_increment(&node->references);
712 
713 	*targetp = source;
714 }
715 
716 static void
detachnode(dns_db_t * db,dns_dbnode_t ** targetp)717 detachnode(dns_db_t *db, dns_dbnode_t **targetp) {
718 	dns_sdlz_db_t *sdlz = (dns_sdlz_db_t *)db;
719 	dns_sdlznode_t *node;
720 
721 	REQUIRE(VALID_SDLZDB(sdlz));
722 	REQUIRE(targetp != NULL && *targetp != NULL);
723 
724 	UNUSED(sdlz);
725 
726 	node = (dns_sdlznode_t *)(*targetp);
727 	*targetp = NULL;
728 
729 	if (isc_refcount_decrement(&node->references) == 1) {
730 		destroynode(node);
731 	}
732 }
733 
734 static isc_result_t
expirenode(dns_db_t * db,dns_dbnode_t * node,isc_stdtime_t now)735 expirenode(dns_db_t *db, dns_dbnode_t *node, isc_stdtime_t now) {
736 	UNUSED(db);
737 	UNUSED(node);
738 	UNUSED(now);
739 	INSIST(0);
740 	ISC_UNREACHABLE();
741 }
742 
743 static void
printnode(dns_db_t * db,dns_dbnode_t * node,FILE * out)744 printnode(dns_db_t *db, dns_dbnode_t *node, FILE *out) {
745 	UNUSED(db);
746 	UNUSED(node);
747 	UNUSED(out);
748 	return;
749 }
750 
751 static isc_result_t
createiterator(dns_db_t * db,unsigned int options,dns_dbiterator_t ** iteratorp)752 createiterator(dns_db_t *db, unsigned int options,
753 	       dns_dbiterator_t **iteratorp) {
754 	dns_sdlz_db_t *sdlz = (dns_sdlz_db_t *)db;
755 	sdlz_dbiterator_t *sdlziter;
756 	isc_result_t result;
757 	isc_buffer_t b;
758 	char zonestr[DNS_NAME_MAXTEXT + 1];
759 
760 	REQUIRE(VALID_SDLZDB(sdlz));
761 
762 	if (sdlz->dlzimp->methods->allnodes == NULL) {
763 		return (ISC_R_NOTIMPLEMENTED);
764 	}
765 
766 	if ((options & DNS_DB_NSEC3ONLY) != 0 ||
767 	    (options & DNS_DB_NONSEC3) != 0) {
768 		return (ISC_R_NOTIMPLEMENTED);
769 	}
770 
771 	isc_buffer_init(&b, zonestr, sizeof(zonestr));
772 	result = dns_name_totext(&sdlz->common.origin, true, &b);
773 	if (result != ISC_R_SUCCESS) {
774 		return (result);
775 	}
776 	isc_buffer_putuint8(&b, 0);
777 
778 	sdlziter = isc_mem_get(sdlz->common.mctx, sizeof(sdlz_dbiterator_t));
779 
780 	sdlziter->common.methods = &dbiterator_methods;
781 	sdlziter->common.db = NULL;
782 	dns_db_attach(db, &sdlziter->common.db);
783 	sdlziter->common.relative_names = ((options & DNS_DB_RELATIVENAMES) !=
784 					   0);
785 	sdlziter->common.magic = DNS_DBITERATOR_MAGIC;
786 	ISC_LIST_INIT(sdlziter->nodelist);
787 	sdlziter->current = NULL;
788 	sdlziter->origin = NULL;
789 
790 	/* make sure strings are always lowercase */
791 	dns_sdlz_tolower(zonestr);
792 
793 	MAYBE_LOCK(sdlz->dlzimp);
794 	result = sdlz->dlzimp->methods->allnodes(
795 		zonestr, sdlz->dlzimp->driverarg, sdlz->dbdata, sdlziter);
796 	MAYBE_UNLOCK(sdlz->dlzimp);
797 	if (result != ISC_R_SUCCESS) {
798 		dns_dbiterator_t *iter = &sdlziter->common;
799 		dbiterator_destroy(&iter);
800 		return (result);
801 	}
802 
803 	if (sdlziter->origin != NULL) {
804 		ISC_LIST_UNLINK(sdlziter->nodelist, sdlziter->origin, link);
805 		ISC_LIST_PREPEND(sdlziter->nodelist, sdlziter->origin, link);
806 	}
807 
808 	*iteratorp = (dns_dbiterator_t *)sdlziter;
809 
810 	return (ISC_R_SUCCESS);
811 }
812 
813 static isc_result_t
findrdataset(dns_db_t * db,dns_dbnode_t * node,dns_dbversion_t * version,dns_rdatatype_t type,dns_rdatatype_t covers,isc_stdtime_t now,dns_rdataset_t * rdataset,dns_rdataset_t * sigrdataset)814 findrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
815 	     dns_rdatatype_t type, dns_rdatatype_t covers, isc_stdtime_t now,
816 	     dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset) {
817 	REQUIRE(VALID_SDLZNODE(node));
818 	dns_rdatalist_t *list;
819 	dns_sdlznode_t *sdlznode = (dns_sdlznode_t *)node;
820 
821 	UNUSED(db);
822 	UNUSED(version);
823 	UNUSED(covers);
824 	UNUSED(now);
825 	UNUSED(sigrdataset);
826 
827 	if (type == dns_rdatatype_sig || type == dns_rdatatype_rrsig) {
828 		return (ISC_R_NOTIMPLEMENTED);
829 	}
830 
831 	list = ISC_LIST_HEAD(sdlznode->lists);
832 	while (list != NULL) {
833 		if (list->type == type) {
834 			break;
835 		}
836 		list = ISC_LIST_NEXT(list, link);
837 	}
838 	if (list == NULL) {
839 		return (ISC_R_NOTFOUND);
840 	}
841 
842 	list_tordataset(list, db, node, rdataset);
843 
844 	return (ISC_R_SUCCESS);
845 }
846 
847 static isc_result_t
findext(dns_db_t * db,const dns_name_t * name,dns_dbversion_t * version,dns_rdatatype_t type,unsigned int options,isc_stdtime_t now,dns_dbnode_t ** nodep,dns_name_t * foundname,dns_clientinfomethods_t * methods,dns_clientinfo_t * clientinfo,dns_rdataset_t * rdataset,dns_rdataset_t * sigrdataset)848 findext(dns_db_t *db, const dns_name_t *name, dns_dbversion_t *version,
849 	dns_rdatatype_t type, unsigned int options, isc_stdtime_t now,
850 	dns_dbnode_t **nodep, dns_name_t *foundname,
851 	dns_clientinfomethods_t *methods, dns_clientinfo_t *clientinfo,
852 	dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset) {
853 	dns_sdlz_db_t *sdlz = (dns_sdlz_db_t *)db;
854 	dns_dbnode_t *node = NULL;
855 	dns_fixedname_t fname;
856 	dns_rdataset_t xrdataset;
857 	dns_name_t *xname;
858 	unsigned int nlabels, olabels;
859 	isc_result_t result;
860 	unsigned int i;
861 
862 	REQUIRE(VALID_SDLZDB(sdlz));
863 	REQUIRE(nodep == NULL || *nodep == NULL);
864 	REQUIRE(version == NULL || version == (void *)&sdlz->dummy_version ||
865 		version == sdlz->future_version);
866 
867 	UNUSED(sdlz);
868 
869 	if (!dns_name_issubdomain(name, &db->origin)) {
870 		return (DNS_R_NXDOMAIN);
871 	}
872 
873 	olabels = dns_name_countlabels(&db->origin);
874 	nlabels = dns_name_countlabels(name);
875 
876 	xname = dns_fixedname_initname(&fname);
877 
878 	if (rdataset == NULL) {
879 		dns_rdataset_init(&xrdataset);
880 		rdataset = &xrdataset;
881 	}
882 
883 	result = DNS_R_NXDOMAIN;
884 
885 	/*
886 	 * If we're not walking down searching for zone
887 	 * cuts, we can cut straight to the chase
888 	 */
889 	if ((options & DNS_DBFIND_NOZONECUT) != 0) {
890 		i = nlabels;
891 		goto search;
892 	}
893 
894 	for (i = olabels; i <= nlabels; i++) {
895 	search:
896 		/*
897 		 * Look up the next label.
898 		 */
899 		dns_name_getlabelsequence(name, nlabels - i, i, xname);
900 		result = getnodedata(db, xname, false, options, methods,
901 				     clientinfo, &node);
902 		if (result == ISC_R_NOTFOUND) {
903 			result = DNS_R_NXDOMAIN;
904 			continue;
905 		} else if (result != ISC_R_SUCCESS) {
906 			break;
907 		}
908 
909 		/*
910 		 * Look for a DNAME at the current label, unless this is
911 		 * the qname.
912 		 */
913 		if (i < nlabels) {
914 			result = findrdataset(db, node, version,
915 					      dns_rdatatype_dname, 0, now,
916 					      rdataset, sigrdataset);
917 			if (result == ISC_R_SUCCESS) {
918 				result = DNS_R_DNAME;
919 				break;
920 			}
921 		}
922 
923 		/*
924 		 * Look for an NS at the current label, unless this is the
925 		 * origin, glue is ok, or there are known to be no zone cuts.
926 		 */
927 		if (i != olabels && (options & DNS_DBFIND_GLUEOK) == 0 &&
928 		    (options & DNS_DBFIND_NOZONECUT) == 0)
929 		{
930 			result = findrdataset(db, node, version,
931 					      dns_rdatatype_ns, 0, now,
932 					      rdataset, sigrdataset);
933 
934 			if (result == ISC_R_SUCCESS && i == nlabels &&
935 			    type == dns_rdatatype_any) {
936 				result = DNS_R_ZONECUT;
937 				dns_rdataset_disassociate(rdataset);
938 				if (sigrdataset != NULL &&
939 				    dns_rdataset_isassociated(sigrdataset)) {
940 					dns_rdataset_disassociate(sigrdataset);
941 				}
942 				break;
943 			} else if (result == ISC_R_SUCCESS) {
944 				result = DNS_R_DELEGATION;
945 				break;
946 			}
947 		}
948 
949 		/*
950 		 * If the current name is not the qname, add another label
951 		 * and try again.
952 		 */
953 		if (i < nlabels) {
954 			detachnode(db, &node);
955 			node = NULL;
956 			continue;
957 		}
958 
959 		/*
960 		 * If we're looking for ANY, we're done.
961 		 */
962 		if (type == dns_rdatatype_any) {
963 			result = ISC_R_SUCCESS;
964 			break;
965 		}
966 
967 		/*
968 		 * Look for the qtype.
969 		 */
970 		result = findrdataset(db, node, version, type, 0, now, rdataset,
971 				      sigrdataset);
972 		if (result == ISC_R_SUCCESS) {
973 			break;
974 		}
975 
976 		/*
977 		 * Look for a CNAME
978 		 */
979 		if (type != dns_rdatatype_cname) {
980 			result = findrdataset(db, node, version,
981 					      dns_rdatatype_cname, 0, now,
982 					      rdataset, sigrdataset);
983 			if (result == ISC_R_SUCCESS) {
984 				result = DNS_R_CNAME;
985 				break;
986 			}
987 		}
988 
989 		result = DNS_R_NXRRSET;
990 		break;
991 	}
992 
993 	if (rdataset == &xrdataset && dns_rdataset_isassociated(rdataset)) {
994 		dns_rdataset_disassociate(rdataset);
995 	}
996 
997 	if (foundname != NULL) {
998 		dns_name_copynf(xname, foundname);
999 	}
1000 
1001 	if (nodep != NULL) {
1002 		*nodep = node;
1003 	} else if (node != NULL) {
1004 		detachnode(db, &node);
1005 	}
1006 
1007 	return (result);
1008 }
1009 
1010 static isc_result_t
find(dns_db_t * db,const dns_name_t * name,dns_dbversion_t * version,dns_rdatatype_t type,unsigned int options,isc_stdtime_t now,dns_dbnode_t ** nodep,dns_name_t * foundname,dns_rdataset_t * rdataset,dns_rdataset_t * sigrdataset)1011 find(dns_db_t *db, const dns_name_t *name, dns_dbversion_t *version,
1012      dns_rdatatype_t type, unsigned int options, isc_stdtime_t now,
1013      dns_dbnode_t **nodep, dns_name_t *foundname, dns_rdataset_t *rdataset,
1014      dns_rdataset_t *sigrdataset) {
1015 	return (findext(db, name, version, type, options, now, nodep, foundname,
1016 			NULL, NULL, rdataset, sigrdataset));
1017 }
1018 
1019 static isc_result_t
allrdatasets(dns_db_t * db,dns_dbnode_t * node,dns_dbversion_t * version,isc_stdtime_t now,dns_rdatasetiter_t ** iteratorp)1020 allrdatasets(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
1021 	     isc_stdtime_t now, dns_rdatasetiter_t **iteratorp) {
1022 	dns_sdlz_db_t *sdlz = (dns_sdlz_db_t *)db;
1023 	sdlz_rdatasetiter_t *iterator;
1024 
1025 	REQUIRE(VALID_SDLZDB(sdlz));
1026 
1027 	REQUIRE(version == NULL || version == (void *)&sdlz->dummy_version ||
1028 		version == sdlz->future_version);
1029 
1030 	UNUSED(version);
1031 	UNUSED(now);
1032 
1033 	iterator = isc_mem_get(db->mctx, sizeof(sdlz_rdatasetiter_t));
1034 
1035 	iterator->common.magic = DNS_RDATASETITER_MAGIC;
1036 	iterator->common.methods = &rdatasetiter_methods;
1037 	iterator->common.db = db;
1038 	iterator->common.node = NULL;
1039 	attachnode(db, node, &iterator->common.node);
1040 	iterator->common.version = version;
1041 	iterator->common.now = now;
1042 
1043 	*iteratorp = (dns_rdatasetiter_t *)iterator;
1044 
1045 	return (ISC_R_SUCCESS);
1046 }
1047 
1048 static isc_result_t
modrdataset(dns_db_t * db,dns_dbnode_t * node,dns_dbversion_t * version,dns_rdataset_t * rdataset,unsigned int options,dns_sdlzmodrdataset_t mod_function)1049 modrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
1050 	    dns_rdataset_t *rdataset, unsigned int options,
1051 	    dns_sdlzmodrdataset_t mod_function) {
1052 	dns_sdlz_db_t *sdlz = (dns_sdlz_db_t *)db;
1053 	dns_master_style_t *style = NULL;
1054 	isc_result_t result;
1055 	isc_buffer_t *buffer = NULL;
1056 	isc_mem_t *mctx;
1057 	dns_sdlznode_t *sdlznode;
1058 	char *rdatastr = NULL;
1059 	char name[DNS_NAME_MAXTEXT + 1];
1060 
1061 	REQUIRE(VALID_SDLZDB(sdlz));
1062 
1063 	if (mod_function == NULL) {
1064 		return (ISC_R_NOTIMPLEMENTED);
1065 	}
1066 
1067 	sdlznode = (dns_sdlznode_t *)node;
1068 
1069 	UNUSED(options);
1070 
1071 	dns_name_format(sdlznode->name, name, sizeof(name));
1072 
1073 	mctx = sdlz->common.mctx;
1074 
1075 	isc_buffer_allocate(mctx, &buffer, 1024);
1076 
1077 	result = dns_master_stylecreate(&style, 0, 0, 0, 0, 0, 0, 1, 0xffffffff,
1078 					mctx);
1079 	if (result != ISC_R_SUCCESS) {
1080 		goto cleanup;
1081 	}
1082 
1083 	result = dns_master_rdatasettotext(sdlznode->name, rdataset, style,
1084 					   NULL, buffer);
1085 	if (result != ISC_R_SUCCESS) {
1086 		goto cleanup;
1087 	}
1088 
1089 	if (isc_buffer_usedlength(buffer) < 1) {
1090 		result = ISC_R_BADADDRESSFORM;
1091 		goto cleanup;
1092 	}
1093 
1094 	rdatastr = isc_buffer_base(buffer);
1095 	if (rdatastr == NULL) {
1096 		result = ISC_R_NOMEMORY;
1097 		goto cleanup;
1098 	}
1099 	rdatastr[isc_buffer_usedlength(buffer) - 1] = 0;
1100 
1101 	MAYBE_LOCK(sdlz->dlzimp);
1102 	result = mod_function(name, rdatastr, sdlz->dlzimp->driverarg,
1103 			      sdlz->dbdata, version);
1104 	MAYBE_UNLOCK(sdlz->dlzimp);
1105 
1106 cleanup:
1107 	isc_buffer_free(&buffer);
1108 	if (style != NULL) {
1109 		dns_master_styledestroy(&style, mctx);
1110 	}
1111 
1112 	return (result);
1113 }
1114 
1115 static isc_result_t
addrdataset(dns_db_t * db,dns_dbnode_t * node,dns_dbversion_t * version,isc_stdtime_t now,dns_rdataset_t * rdataset,unsigned int options,dns_rdataset_t * addedrdataset)1116 addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
1117 	    isc_stdtime_t now, dns_rdataset_t *rdataset, unsigned int options,
1118 	    dns_rdataset_t *addedrdataset) {
1119 	dns_sdlz_db_t *sdlz = (dns_sdlz_db_t *)db;
1120 	isc_result_t result;
1121 
1122 	UNUSED(now);
1123 	UNUSED(addedrdataset);
1124 	REQUIRE(VALID_SDLZDB(sdlz));
1125 
1126 	if (sdlz->dlzimp->methods->addrdataset == NULL) {
1127 		return (ISC_R_NOTIMPLEMENTED);
1128 	}
1129 
1130 	result = modrdataset(db, node, version, rdataset, options,
1131 			     sdlz->dlzimp->methods->addrdataset);
1132 	return (result);
1133 }
1134 
1135 static isc_result_t
subtractrdataset(dns_db_t * db,dns_dbnode_t * node,dns_dbversion_t * version,dns_rdataset_t * rdataset,unsigned int options,dns_rdataset_t * newrdataset)1136 subtractrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
1137 		 dns_rdataset_t *rdataset, unsigned int options,
1138 		 dns_rdataset_t *newrdataset) {
1139 	dns_sdlz_db_t *sdlz = (dns_sdlz_db_t *)db;
1140 	isc_result_t result;
1141 
1142 	UNUSED(newrdataset);
1143 	REQUIRE(VALID_SDLZDB(sdlz));
1144 
1145 	if (sdlz->dlzimp->methods->subtractrdataset == NULL) {
1146 		return (ISC_R_NOTIMPLEMENTED);
1147 	}
1148 
1149 	result = modrdataset(db, node, version, rdataset, options,
1150 			     sdlz->dlzimp->methods->subtractrdataset);
1151 	return (result);
1152 }
1153 
1154 static isc_result_t
deleterdataset(dns_db_t * db,dns_dbnode_t * node,dns_dbversion_t * version,dns_rdatatype_t type,dns_rdatatype_t covers)1155 deleterdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
1156 	       dns_rdatatype_t type, dns_rdatatype_t covers) {
1157 	dns_sdlz_db_t *sdlz = (dns_sdlz_db_t *)db;
1158 	char name[DNS_NAME_MAXTEXT + 1];
1159 	char b_type[DNS_RDATATYPE_FORMATSIZE];
1160 	dns_sdlznode_t *sdlznode;
1161 	isc_result_t result;
1162 
1163 	UNUSED(covers);
1164 
1165 	REQUIRE(VALID_SDLZDB(sdlz));
1166 
1167 	if (sdlz->dlzimp->methods->delrdataset == NULL) {
1168 		return (ISC_R_NOTIMPLEMENTED);
1169 	}
1170 
1171 	sdlznode = (dns_sdlznode_t *)node;
1172 	dns_name_format(sdlznode->name, name, sizeof(name));
1173 	dns_rdatatype_format(type, b_type, sizeof(b_type));
1174 
1175 	MAYBE_LOCK(sdlz->dlzimp);
1176 	result = sdlz->dlzimp->methods->delrdataset(
1177 		name, b_type, sdlz->dlzimp->driverarg, sdlz->dbdata, version);
1178 	MAYBE_UNLOCK(sdlz->dlzimp);
1179 
1180 	return (result);
1181 }
1182 
1183 static bool
issecure(dns_db_t * db)1184 issecure(dns_db_t *db) {
1185 	UNUSED(db);
1186 
1187 	return (false);
1188 }
1189 
1190 static unsigned int
nodecount(dns_db_t * db)1191 nodecount(dns_db_t *db) {
1192 	UNUSED(db);
1193 
1194 	return (0);
1195 }
1196 
1197 static bool
ispersistent(dns_db_t * db)1198 ispersistent(dns_db_t *db) {
1199 	UNUSED(db);
1200 	return (true);
1201 }
1202 
1203 static void
overmem(dns_db_t * db,bool over)1204 overmem(dns_db_t *db, bool over) {
1205 	UNUSED(db);
1206 	UNUSED(over);
1207 }
1208 
1209 static void
settask(dns_db_t * db,isc_task_t * task)1210 settask(dns_db_t *db, isc_task_t *task) {
1211 	UNUSED(db);
1212 	UNUSED(task);
1213 }
1214 
1215 /*
1216  * getoriginnode() is used by the update code to find the
1217  * dns_rdatatype_dnskey record for a zone
1218  */
1219 static isc_result_t
getoriginnode(dns_db_t * db,dns_dbnode_t ** nodep)1220 getoriginnode(dns_db_t *db, dns_dbnode_t **nodep) {
1221 	dns_sdlz_db_t *sdlz = (dns_sdlz_db_t *)db;
1222 	isc_result_t result;
1223 
1224 	REQUIRE(VALID_SDLZDB(sdlz));
1225 	if (sdlz->dlzimp->methods->newversion == NULL) {
1226 		return (ISC_R_NOTIMPLEMENTED);
1227 	}
1228 
1229 	result = getnodedata(db, &sdlz->common.origin, false, 0, NULL, NULL,
1230 			     nodep);
1231 	if (result != ISC_R_SUCCESS) {
1232 		sdlz_log(ISC_LOG_ERROR, "sdlz getoriginnode failed: %s",
1233 			 isc_result_totext(result));
1234 	}
1235 	return (result);
1236 }
1237 
1238 static dns_dbmethods_t sdlzdb_methods = {
1239 	attach,
1240 	detach,
1241 	beginload,
1242 	endload,
1243 	NULL, /* serialize */
1244 	dump,
1245 	currentversion,
1246 	newversion,
1247 	attachversion,
1248 	closeversion,
1249 	findnode,
1250 	find,
1251 	findzonecut,
1252 	attachnode,
1253 	detachnode,
1254 	expirenode,
1255 	printnode,
1256 	createiterator,
1257 	findrdataset,
1258 	allrdatasets,
1259 	addrdataset,
1260 	subtractrdataset,
1261 	deleterdataset,
1262 	issecure,
1263 	nodecount,
1264 	ispersistent,
1265 	overmem,
1266 	settask,
1267 	getoriginnode,
1268 	NULL, /* transfernode */
1269 	NULL, /* getnsec3parameters */
1270 	NULL, /* findnsec3node */
1271 	NULL, /* setsigningtime */
1272 	NULL, /* getsigningtime */
1273 	NULL, /* resigned */
1274 	NULL, /* isdnssec */
1275 	NULL, /* getrrsetstats */
1276 	NULL, /* rpz_attach */
1277 	NULL, /* rpz_ready */
1278 	findnodeext,
1279 	findext,
1280 	NULL, /* setcachestats */
1281 	NULL, /* hashsize */
1282 	NULL, /* nodefullname */
1283 	NULL, /* getsize */
1284 	NULL, /* setservestalettl */
1285 	NULL, /* getservestalettl */
1286 	NULL, /* setservestalerefresh */
1287 	NULL, /* getservestalerefresh */
1288 	NULL, /* setgluecachestats */
1289 	NULL  /* adjusthashsize */
1290 };
1291 
1292 /*
1293  * Database Iterator Methods.  These methods were "borrowed" from the SDB
1294  * driver interface.  See the SDB driver interface documentation for more info.
1295  */
1296 
1297 static void
dbiterator_destroy(dns_dbiterator_t ** iteratorp)1298 dbiterator_destroy(dns_dbiterator_t **iteratorp) {
1299 	sdlz_dbiterator_t *sdlziter = (sdlz_dbiterator_t *)(*iteratorp);
1300 	dns_sdlz_db_t *sdlz = (dns_sdlz_db_t *)sdlziter->common.db;
1301 
1302 	while (!ISC_LIST_EMPTY(sdlziter->nodelist)) {
1303 		dns_sdlznode_t *node;
1304 		node = ISC_LIST_HEAD(sdlziter->nodelist);
1305 		ISC_LIST_UNLINK(sdlziter->nodelist, node, link);
1306 		isc_refcount_decrementz(&node->references);
1307 		destroynode(node);
1308 	}
1309 
1310 	dns_db_detach(&sdlziter->common.db);
1311 	isc_mem_put(sdlz->common.mctx, sdlziter, sizeof(sdlz_dbiterator_t));
1312 
1313 	*iteratorp = NULL;
1314 }
1315 
1316 static isc_result_t
dbiterator_first(dns_dbiterator_t * iterator)1317 dbiterator_first(dns_dbiterator_t *iterator) {
1318 	sdlz_dbiterator_t *sdlziter = (sdlz_dbiterator_t *)iterator;
1319 
1320 	sdlziter->current = ISC_LIST_HEAD(sdlziter->nodelist);
1321 	if (sdlziter->current == NULL) {
1322 		return (ISC_R_NOMORE);
1323 	} else {
1324 		return (ISC_R_SUCCESS);
1325 	}
1326 }
1327 
1328 static isc_result_t
dbiterator_last(dns_dbiterator_t * iterator)1329 dbiterator_last(dns_dbiterator_t *iterator) {
1330 	sdlz_dbiterator_t *sdlziter = (sdlz_dbiterator_t *)iterator;
1331 
1332 	sdlziter->current = ISC_LIST_TAIL(sdlziter->nodelist);
1333 	if (sdlziter->current == NULL) {
1334 		return (ISC_R_NOMORE);
1335 	} else {
1336 		return (ISC_R_SUCCESS);
1337 	}
1338 }
1339 
1340 static isc_result_t
dbiterator_seek(dns_dbiterator_t * iterator,const dns_name_t * name)1341 dbiterator_seek(dns_dbiterator_t *iterator, const dns_name_t *name) {
1342 	sdlz_dbiterator_t *sdlziter = (sdlz_dbiterator_t *)iterator;
1343 
1344 	sdlziter->current = ISC_LIST_HEAD(sdlziter->nodelist);
1345 	while (sdlziter->current != NULL) {
1346 		if (dns_name_equal(sdlziter->current->name, name)) {
1347 			return (ISC_R_SUCCESS);
1348 		}
1349 		sdlziter->current = ISC_LIST_NEXT(sdlziter->current, link);
1350 	}
1351 	return (ISC_R_NOTFOUND);
1352 }
1353 
1354 static isc_result_t
dbiterator_prev(dns_dbiterator_t * iterator)1355 dbiterator_prev(dns_dbiterator_t *iterator) {
1356 	sdlz_dbiterator_t *sdlziter = (sdlz_dbiterator_t *)iterator;
1357 
1358 	sdlziter->current = ISC_LIST_PREV(sdlziter->current, link);
1359 	if (sdlziter->current == NULL) {
1360 		return (ISC_R_NOMORE);
1361 	} else {
1362 		return (ISC_R_SUCCESS);
1363 	}
1364 }
1365 
1366 static isc_result_t
dbiterator_next(dns_dbiterator_t * iterator)1367 dbiterator_next(dns_dbiterator_t *iterator) {
1368 	sdlz_dbiterator_t *sdlziter = (sdlz_dbiterator_t *)iterator;
1369 
1370 	sdlziter->current = ISC_LIST_NEXT(sdlziter->current, link);
1371 	if (sdlziter->current == NULL) {
1372 		return (ISC_R_NOMORE);
1373 	} else {
1374 		return (ISC_R_SUCCESS);
1375 	}
1376 }
1377 
1378 static isc_result_t
dbiterator_current(dns_dbiterator_t * iterator,dns_dbnode_t ** nodep,dns_name_t * name)1379 dbiterator_current(dns_dbiterator_t *iterator, dns_dbnode_t **nodep,
1380 		   dns_name_t *name) {
1381 	sdlz_dbiterator_t *sdlziter = (sdlz_dbiterator_t *)iterator;
1382 
1383 	attachnode(iterator->db, sdlziter->current, nodep);
1384 	if (name != NULL) {
1385 		dns_name_copynf(sdlziter->current->name, name);
1386 		return (ISC_R_SUCCESS);
1387 	}
1388 	return (ISC_R_SUCCESS);
1389 }
1390 
1391 static isc_result_t
dbiterator_pause(dns_dbiterator_t * iterator)1392 dbiterator_pause(dns_dbiterator_t *iterator) {
1393 	UNUSED(iterator);
1394 	return (ISC_R_SUCCESS);
1395 }
1396 
1397 static isc_result_t
dbiterator_origin(dns_dbiterator_t * iterator,dns_name_t * name)1398 dbiterator_origin(dns_dbiterator_t *iterator, dns_name_t *name) {
1399 	UNUSED(iterator);
1400 	dns_name_copynf(dns_rootname, name);
1401 	return (ISC_R_SUCCESS);
1402 }
1403 
1404 /*
1405  * Rdataset Methods. These methods were "borrowed" from the SDB driver
1406  * interface.  See the SDB driver interface documentation for more info.
1407  */
1408 
1409 static void
disassociate(dns_rdataset_t * rdataset)1410 disassociate(dns_rdataset_t *rdataset) {
1411 	dns_dbnode_t *node = rdataset->private5;
1412 	dns_sdlznode_t *sdlznode = (dns_sdlznode_t *)node;
1413 	dns_db_t *db = (dns_db_t *)sdlznode->sdlz;
1414 
1415 	detachnode(db, &node);
1416 	isc__rdatalist_disassociate(rdataset);
1417 }
1418 
1419 static void
rdataset_clone(dns_rdataset_t * source,dns_rdataset_t * target)1420 rdataset_clone(dns_rdataset_t *source, dns_rdataset_t *target) {
1421 	dns_dbnode_t *node = source->private5;
1422 	dns_sdlznode_t *sdlznode = (dns_sdlznode_t *)node;
1423 	dns_db_t *db = (dns_db_t *)sdlznode->sdlz;
1424 	dns_dbnode_t *tempdb = NULL;
1425 
1426 	isc__rdatalist_clone(source, target);
1427 	attachnode(db, node, &tempdb);
1428 	source->private5 = tempdb;
1429 }
1430 
1431 static dns_rdatasetmethods_t rdataset_methods = {
1432 	disassociate,
1433 	isc__rdatalist_first,
1434 	isc__rdatalist_next,
1435 	isc__rdatalist_current,
1436 	rdataset_clone,
1437 	isc__rdatalist_count,
1438 	isc__rdatalist_addnoqname,
1439 	isc__rdatalist_getnoqname,
1440 	NULL, /* addclosest */
1441 	NULL, /* getclosest */
1442 	NULL, /* settrust */
1443 	NULL, /* expire */
1444 	NULL, /* clearprefetch */
1445 	NULL, /* setownercase */
1446 	NULL, /* getownercase */
1447 	NULL  /* addglue */
1448 };
1449 
1450 static void
list_tordataset(dns_rdatalist_t * rdatalist,dns_db_t * db,dns_dbnode_t * node,dns_rdataset_t * rdataset)1451 list_tordataset(dns_rdatalist_t *rdatalist, dns_db_t *db, dns_dbnode_t *node,
1452 		dns_rdataset_t *rdataset) {
1453 	/*
1454 	 * The sdlz rdataset is an rdatalist with some additions.
1455 	 *	- private1 & private2 are used by the rdatalist.
1456 	 *	- private3 & private 4 are unused.
1457 	 *	- private5 is the node.
1458 	 */
1459 
1460 	/* This should never fail. */
1461 	RUNTIME_CHECK(dns_rdatalist_tordataset(rdatalist, rdataset) ==
1462 		      ISC_R_SUCCESS);
1463 
1464 	rdataset->methods = &rdataset_methods;
1465 	dns_db_attachnode(db, node, &rdataset->private5);
1466 }
1467 
1468 /*
1469  * SDLZ core methods. This is the core of the new DLZ functionality.
1470  */
1471 
1472 /*%
1473  * Build a 'bind' database driver structure to be returned by
1474  * either the find zone or the allow zone transfer method.
1475  * This method is only available in this source file, it is
1476  * not made available anywhere else.
1477  */
1478 
1479 static isc_result_t
dns_sdlzcreateDBP(isc_mem_t * mctx,void * driverarg,void * dbdata,const dns_name_t * name,dns_rdataclass_t rdclass,dns_db_t ** dbp)1480 dns_sdlzcreateDBP(isc_mem_t *mctx, void *driverarg, void *dbdata,
1481 		  const dns_name_t *name, dns_rdataclass_t rdclass,
1482 		  dns_db_t **dbp) {
1483 	isc_result_t result;
1484 	dns_sdlz_db_t *sdlzdb;
1485 	dns_sdlzimplementation_t *imp;
1486 
1487 	/* check that things are as we expect */
1488 	REQUIRE(dbp != NULL && *dbp == NULL);
1489 	REQUIRE(name != NULL);
1490 
1491 	imp = (dns_sdlzimplementation_t *)driverarg;
1492 
1493 	/* allocate and zero memory for driver structure */
1494 	sdlzdb = isc_mem_get(mctx, sizeof(dns_sdlz_db_t));
1495 	memset(sdlzdb, 0, sizeof(dns_sdlz_db_t));
1496 
1497 	/* initialize and set origin */
1498 	dns_name_init(&sdlzdb->common.origin, NULL);
1499 	result = dns_name_dupwithoffsets(name, mctx, &sdlzdb->common.origin);
1500 	if (result != ISC_R_SUCCESS) {
1501 		goto mem_cleanup;
1502 	}
1503 
1504 	/* set the rest of the database structure attributes */
1505 	sdlzdb->dlzimp = imp;
1506 	sdlzdb->common.methods = &sdlzdb_methods;
1507 	sdlzdb->common.attributes = 0;
1508 	sdlzdb->common.rdclass = rdclass;
1509 	sdlzdb->common.mctx = NULL;
1510 	sdlzdb->dbdata = dbdata;
1511 	isc_refcount_init(&sdlzdb->references, 1);
1512 
1513 	/* attach to the memory context */
1514 	isc_mem_attach(mctx, &sdlzdb->common.mctx);
1515 
1516 	/* mark structure as valid */
1517 	sdlzdb->common.magic = DNS_DB_MAGIC;
1518 	sdlzdb->common.impmagic = SDLZDB_MAGIC;
1519 	*dbp = (dns_db_t *)sdlzdb;
1520 
1521 	return (result);
1522 mem_cleanup:
1523 	isc_mem_put(mctx, sdlzdb, sizeof(dns_sdlz_db_t));
1524 	return (result);
1525 }
1526 
1527 static isc_result_t
dns_sdlzallowzonexfr(void * driverarg,void * dbdata,isc_mem_t * mctx,dns_rdataclass_t rdclass,const dns_name_t * name,const isc_sockaddr_t * clientaddr,dns_db_t ** dbp)1528 dns_sdlzallowzonexfr(void *driverarg, void *dbdata, isc_mem_t *mctx,
1529 		     dns_rdataclass_t rdclass, const dns_name_t *name,
1530 		     const isc_sockaddr_t *clientaddr, dns_db_t **dbp) {
1531 	isc_buffer_t b;
1532 	isc_buffer_t b2;
1533 	char namestr[DNS_NAME_MAXTEXT + 1];
1534 	char clientstr[(sizeof "xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255.255.255."
1535 			       "255") +
1536 		       1];
1537 	isc_netaddr_t netaddr;
1538 	isc_result_t result;
1539 	dns_sdlzimplementation_t *imp;
1540 
1541 	/*
1542 	 * Perform checks to make sure data is as we expect it to be.
1543 	 */
1544 	REQUIRE(driverarg != NULL);
1545 	REQUIRE(name != NULL);
1546 	REQUIRE(clientaddr != NULL);
1547 	REQUIRE(dbp != NULL && *dbp == NULL);
1548 
1549 	imp = (dns_sdlzimplementation_t *)driverarg;
1550 
1551 	/* Convert DNS name to ascii text */
1552 	isc_buffer_init(&b, namestr, sizeof(namestr));
1553 	result = dns_name_totext(name, true, &b);
1554 	if (result != ISC_R_SUCCESS) {
1555 		return (result);
1556 	}
1557 	isc_buffer_putuint8(&b, 0);
1558 
1559 	/* convert client address to ascii text */
1560 	isc_buffer_init(&b2, clientstr, sizeof(clientstr));
1561 	isc_netaddr_fromsockaddr(&netaddr, clientaddr);
1562 	result = isc_netaddr_totext(&netaddr, &b2);
1563 	if (result != ISC_R_SUCCESS) {
1564 		return (result);
1565 	}
1566 	isc_buffer_putuint8(&b2, 0);
1567 
1568 	/* make sure strings are always lowercase */
1569 	dns_sdlz_tolower(namestr);
1570 	dns_sdlz_tolower(clientstr);
1571 
1572 	/* Call SDLZ driver's find zone method */
1573 	if (imp->methods->allowzonexfr != NULL) {
1574 		isc_result_t rresult = ISC_R_SUCCESS;
1575 
1576 		MAYBE_LOCK(imp);
1577 		result = imp->methods->allowzonexfr(imp->driverarg, dbdata,
1578 						    namestr, clientstr);
1579 		MAYBE_UNLOCK(imp);
1580 		/*
1581 		 * if zone is supported and transfers are (or might be)
1582 		 * allowed, build a 'bind' database driver
1583 		 */
1584 		if (result == ISC_R_SUCCESS || result == ISC_R_DEFAULT) {
1585 			rresult = dns_sdlzcreateDBP(mctx, driverarg, dbdata,
1586 						    name, rdclass, dbp);
1587 		}
1588 		if (rresult != ISC_R_SUCCESS) {
1589 			result = rresult;
1590 		}
1591 		return (result);
1592 	}
1593 
1594 	return (ISC_R_NOTIMPLEMENTED);
1595 }
1596 
1597 static isc_result_t
dns_sdlzcreate(isc_mem_t * mctx,const char * dlzname,unsigned int argc,char * argv[],void * driverarg,void ** dbdata)1598 dns_sdlzcreate(isc_mem_t *mctx, const char *dlzname, unsigned int argc,
1599 	       char *argv[], void *driverarg, void **dbdata) {
1600 	dns_sdlzimplementation_t *imp;
1601 	isc_result_t result = ISC_R_NOTFOUND;
1602 
1603 	/* Write debugging message to log */
1604 	sdlz_log(ISC_LOG_DEBUG(2), "Loading SDLZ driver.");
1605 
1606 	/*
1607 	 * Performs checks to make sure data is as we expect it to be.
1608 	 */
1609 	REQUIRE(driverarg != NULL);
1610 	REQUIRE(dlzname != NULL);
1611 	REQUIRE(dbdata != NULL);
1612 	UNUSED(mctx);
1613 
1614 	imp = driverarg;
1615 
1616 	/* If the create method exists, call it. */
1617 	if (imp->methods->create != NULL) {
1618 		MAYBE_LOCK(imp);
1619 		result = imp->methods->create(dlzname, argc, argv,
1620 					      imp->driverarg, dbdata);
1621 		MAYBE_UNLOCK(imp);
1622 	}
1623 
1624 	/* Write debugging message to log */
1625 	if (result == ISC_R_SUCCESS) {
1626 		sdlz_log(ISC_LOG_DEBUG(2), "SDLZ driver loaded successfully.");
1627 	} else {
1628 		sdlz_log(ISC_LOG_ERROR, "SDLZ driver failed to load.");
1629 	}
1630 
1631 	return (result);
1632 }
1633 
1634 static void
dns_sdlzdestroy(void * driverdata,void ** dbdata)1635 dns_sdlzdestroy(void *driverdata, void **dbdata) {
1636 	dns_sdlzimplementation_t *imp;
1637 
1638 	/* Write debugging message to log */
1639 	sdlz_log(ISC_LOG_DEBUG(2), "Unloading SDLZ driver.");
1640 
1641 	imp = driverdata;
1642 
1643 	/* If the destroy method exists, call it. */
1644 	if (imp->methods->destroy != NULL) {
1645 		MAYBE_LOCK(imp);
1646 		imp->methods->destroy(imp->driverarg, dbdata);
1647 		MAYBE_UNLOCK(imp);
1648 	}
1649 }
1650 
1651 static isc_result_t
dns_sdlzfindzone(void * driverarg,void * dbdata,isc_mem_t * mctx,dns_rdataclass_t rdclass,const dns_name_t * name,dns_clientinfomethods_t * methods,dns_clientinfo_t * clientinfo,dns_db_t ** dbp)1652 dns_sdlzfindzone(void *driverarg, void *dbdata, isc_mem_t *mctx,
1653 		 dns_rdataclass_t rdclass, const dns_name_t *name,
1654 		 dns_clientinfomethods_t *methods, dns_clientinfo_t *clientinfo,
1655 		 dns_db_t **dbp) {
1656 	isc_buffer_t b;
1657 	char namestr[DNS_NAME_MAXTEXT + 1];
1658 	isc_result_t result;
1659 	dns_sdlzimplementation_t *imp;
1660 
1661 	/*
1662 	 * Perform checks to make sure data is as we expect it to be.
1663 	 */
1664 	REQUIRE(driverarg != NULL);
1665 	REQUIRE(name != NULL);
1666 	REQUIRE(dbp != NULL && *dbp == NULL);
1667 
1668 	imp = (dns_sdlzimplementation_t *)driverarg;
1669 
1670 	/* Convert DNS name to ascii text */
1671 	isc_buffer_init(&b, namestr, sizeof(namestr));
1672 	result = dns_name_totext(name, true, &b);
1673 	if (result != ISC_R_SUCCESS) {
1674 		return (result);
1675 	}
1676 	isc_buffer_putuint8(&b, 0);
1677 
1678 	/* make sure strings are always lowercase */
1679 	dns_sdlz_tolower(namestr);
1680 
1681 	/* Call SDLZ driver's find zone method */
1682 	MAYBE_LOCK(imp);
1683 	result = imp->methods->findzone(imp->driverarg, dbdata, namestr,
1684 					methods, clientinfo);
1685 	MAYBE_UNLOCK(imp);
1686 
1687 	/*
1688 	 * if zone is supported build a 'bind' database driver
1689 	 * structure to return
1690 	 */
1691 	if (result == ISC_R_SUCCESS) {
1692 		result = dns_sdlzcreateDBP(mctx, driverarg, dbdata, name,
1693 					   rdclass, dbp);
1694 	}
1695 
1696 	return (result);
1697 }
1698 
1699 static isc_result_t
dns_sdlzconfigure(void * driverarg,void * dbdata,dns_view_t * view,dns_dlzdb_t * dlzdb)1700 dns_sdlzconfigure(void *driverarg, void *dbdata, dns_view_t *view,
1701 		  dns_dlzdb_t *dlzdb) {
1702 	isc_result_t result;
1703 	dns_sdlzimplementation_t *imp;
1704 
1705 	REQUIRE(driverarg != NULL);
1706 
1707 	imp = (dns_sdlzimplementation_t *)driverarg;
1708 
1709 	/* Call SDLZ driver's configure method */
1710 	if (imp->methods->configure != NULL) {
1711 		MAYBE_LOCK(imp);
1712 		result = imp->methods->configure(view, dlzdb, imp->driverarg,
1713 						 dbdata);
1714 		MAYBE_UNLOCK(imp);
1715 	} else {
1716 		result = ISC_R_SUCCESS;
1717 	}
1718 
1719 	return (result);
1720 }
1721 
1722 static bool
dns_sdlzssumatch(const dns_name_t * signer,const dns_name_t * name,const isc_netaddr_t * tcpaddr,dns_rdatatype_t type,const dst_key_t * key,void * driverarg,void * dbdata)1723 dns_sdlzssumatch(const dns_name_t *signer, const dns_name_t *name,
1724 		 const isc_netaddr_t *tcpaddr, dns_rdatatype_t type,
1725 		 const dst_key_t *key, void *driverarg, void *dbdata) {
1726 	dns_sdlzimplementation_t *imp;
1727 	char b_signer[DNS_NAME_FORMATSIZE];
1728 	char b_name[DNS_NAME_FORMATSIZE];
1729 	char b_addr[ISC_NETADDR_FORMATSIZE];
1730 	char b_type[DNS_RDATATYPE_FORMATSIZE];
1731 	char b_key[DST_KEY_FORMATSIZE];
1732 	isc_buffer_t *tkey_token = NULL;
1733 	isc_region_t token_region = { NULL, 0 };
1734 	uint32_t token_len = 0;
1735 	bool ret;
1736 
1737 	REQUIRE(driverarg != NULL);
1738 
1739 	imp = (dns_sdlzimplementation_t *)driverarg;
1740 	if (imp->methods->ssumatch == NULL) {
1741 		return (false);
1742 	}
1743 
1744 	/*
1745 	 * Format the request elements. sdlz operates on strings, not
1746 	 * structures
1747 	 */
1748 	if (signer != NULL) {
1749 		dns_name_format(signer, b_signer, sizeof(b_signer));
1750 	} else {
1751 		b_signer[0] = 0;
1752 	}
1753 
1754 	dns_name_format(name, b_name, sizeof(b_name));
1755 
1756 	if (tcpaddr != NULL) {
1757 		isc_netaddr_format(tcpaddr, b_addr, sizeof(b_addr));
1758 	} else {
1759 		b_addr[0] = 0;
1760 	}
1761 
1762 	dns_rdatatype_format(type, b_type, sizeof(b_type));
1763 
1764 	if (key != NULL) {
1765 		dst_key_format(key, b_key, sizeof(b_key));
1766 		tkey_token = dst_key_tkeytoken(key);
1767 	} else {
1768 		b_key[0] = 0;
1769 	}
1770 
1771 	if (tkey_token != NULL) {
1772 		isc_buffer_region(tkey_token, &token_region);
1773 		token_len = token_region.length;
1774 	}
1775 
1776 	MAYBE_LOCK(imp);
1777 	ret = imp->methods->ssumatch(b_signer, b_name, b_addr, b_type, b_key,
1778 				     token_len,
1779 				     token_len != 0 ? token_region.base : NULL,
1780 				     imp->driverarg, dbdata);
1781 	MAYBE_UNLOCK(imp);
1782 	return (ret);
1783 }
1784 
1785 static dns_dlzmethods_t sdlzmethods = { dns_sdlzcreate,	   dns_sdlzdestroy,
1786 					dns_sdlzfindzone,  dns_sdlzallowzonexfr,
1787 					dns_sdlzconfigure, dns_sdlzssumatch };
1788 
1789 /*
1790  * Public functions.
1791  */
1792 
1793 isc_result_t
dns_sdlz_putrr(dns_sdlzlookup_t * lookup,const char * type,dns_ttl_t ttl,const char * data)1794 dns_sdlz_putrr(dns_sdlzlookup_t *lookup, const char *type, dns_ttl_t ttl,
1795 	       const char *data) {
1796 	dns_rdatalist_t *rdatalist;
1797 	dns_rdata_t *rdata;
1798 	dns_rdatatype_t typeval;
1799 	isc_consttextregion_t r;
1800 	isc_buffer_t b;
1801 	isc_buffer_t *rdatabuf = NULL;
1802 	isc_lex_t *lex;
1803 	isc_result_t result;
1804 	unsigned int size;
1805 	isc_mem_t *mctx;
1806 	const dns_name_t *origin;
1807 
1808 	REQUIRE(VALID_SDLZLOOKUP(lookup));
1809 	REQUIRE(type != NULL);
1810 	REQUIRE(data != NULL);
1811 
1812 	mctx = lookup->sdlz->common.mctx;
1813 
1814 	r.base = type;
1815 	r.length = strlen(type);
1816 	result = dns_rdatatype_fromtext(&typeval, (void *)&r);
1817 	if (result != ISC_R_SUCCESS) {
1818 		return (result);
1819 	}
1820 
1821 	rdatalist = ISC_LIST_HEAD(lookup->lists);
1822 	while (rdatalist != NULL) {
1823 		if (rdatalist->type == typeval) {
1824 			break;
1825 		}
1826 		rdatalist = ISC_LIST_NEXT(rdatalist, link);
1827 	}
1828 
1829 	if (rdatalist == NULL) {
1830 		rdatalist = isc_mem_get(mctx, sizeof(dns_rdatalist_t));
1831 		dns_rdatalist_init(rdatalist);
1832 		rdatalist->rdclass = lookup->sdlz->common.rdclass;
1833 		rdatalist->type = typeval;
1834 		rdatalist->ttl = ttl;
1835 		ISC_LIST_APPEND(lookup->lists, rdatalist, link);
1836 	} else if (rdatalist->ttl > ttl) {
1837 		/*
1838 		 * BIND9 doesn't enforce all RRs in an RRset
1839 		 * having the same TTL, as per RFC 2136,
1840 		 * section 7.12. If a DLZ backend has
1841 		 * different TTLs, then the best
1842 		 * we can do is return the lowest.
1843 		 */
1844 		rdatalist->ttl = ttl;
1845 	}
1846 
1847 	rdata = isc_mem_get(mctx, sizeof(dns_rdata_t));
1848 	dns_rdata_init(rdata);
1849 
1850 	if ((lookup->sdlz->dlzimp->flags & DNS_SDLZFLAG_RELATIVERDATA) != 0) {
1851 		origin = &lookup->sdlz->common.origin;
1852 	} else {
1853 		origin = dns_rootname;
1854 	}
1855 
1856 	lex = NULL;
1857 	result = isc_lex_create(mctx, 64, &lex);
1858 	if (result != ISC_R_SUCCESS) {
1859 		goto failure;
1860 	}
1861 
1862 	size = initial_size(data);
1863 	do {
1864 		isc_buffer_constinit(&b, data, strlen(data));
1865 		isc_buffer_add(&b, strlen(data));
1866 
1867 		result = isc_lex_openbuffer(lex, &b);
1868 		if (result != ISC_R_SUCCESS) {
1869 			goto failure;
1870 		}
1871 
1872 		rdatabuf = NULL;
1873 		isc_buffer_allocate(mctx, &rdatabuf, size);
1874 
1875 		result = dns_rdata_fromtext(rdata, rdatalist->rdclass,
1876 					    rdatalist->type, lex, origin, false,
1877 					    mctx, rdatabuf, &lookup->callbacks);
1878 		if (result != ISC_R_SUCCESS) {
1879 			isc_buffer_free(&rdatabuf);
1880 		}
1881 		if (size >= 65535) {
1882 			break;
1883 		}
1884 		size *= 2;
1885 		if (size >= 65535) {
1886 			size = 65535;
1887 		}
1888 	} while (result == ISC_R_NOSPACE);
1889 
1890 	if (result != ISC_R_SUCCESS) {
1891 		result = DNS_R_SERVFAIL;
1892 		goto failure;
1893 	}
1894 
1895 	ISC_LIST_APPEND(rdatalist->rdata, rdata, link);
1896 	ISC_LIST_APPEND(lookup->buffers, rdatabuf, link);
1897 
1898 	if (lex != NULL) {
1899 		isc_lex_destroy(&lex);
1900 	}
1901 
1902 	return (ISC_R_SUCCESS);
1903 
1904 failure:
1905 	if (rdatabuf != NULL) {
1906 		isc_buffer_free(&rdatabuf);
1907 	}
1908 	if (lex != NULL) {
1909 		isc_lex_destroy(&lex);
1910 	}
1911 	isc_mem_put(mctx, rdata, sizeof(dns_rdata_t));
1912 
1913 	return (result);
1914 }
1915 
1916 isc_result_t
dns_sdlz_putnamedrr(dns_sdlzallnodes_t * allnodes,const char * name,const char * type,dns_ttl_t ttl,const char * data)1917 dns_sdlz_putnamedrr(dns_sdlzallnodes_t *allnodes, const char *name,
1918 		    const char *type, dns_ttl_t ttl, const char *data) {
1919 	dns_name_t *newname;
1920 	const dns_name_t *origin;
1921 	dns_fixedname_t fnewname;
1922 	dns_sdlz_db_t *sdlz = (dns_sdlz_db_t *)allnodes->common.db;
1923 	dns_sdlznode_t *sdlznode;
1924 	isc_mem_t *mctx = sdlz->common.mctx;
1925 	isc_buffer_t b;
1926 	isc_result_t result;
1927 
1928 	newname = dns_fixedname_initname(&fnewname);
1929 
1930 	if ((sdlz->dlzimp->flags & DNS_SDLZFLAG_RELATIVERDATA) != 0) {
1931 		origin = &sdlz->common.origin;
1932 	} else {
1933 		origin = dns_rootname;
1934 	}
1935 	isc_buffer_constinit(&b, name, strlen(name));
1936 	isc_buffer_add(&b, strlen(name));
1937 
1938 	result = dns_name_fromtext(newname, &b, origin, 0, NULL);
1939 	if (result != ISC_R_SUCCESS) {
1940 		return (result);
1941 	}
1942 
1943 	if (allnodes->common.relative_names) {
1944 		/* All names are relative to the root */
1945 		unsigned int nlabels = dns_name_countlabels(newname);
1946 		dns_name_getlabelsequence(newname, 0, nlabels - 1, newname);
1947 	}
1948 
1949 	sdlznode = ISC_LIST_HEAD(allnodes->nodelist);
1950 	if (sdlznode == NULL || !dns_name_equal(sdlznode->name, newname)) {
1951 		sdlznode = NULL;
1952 		result = createnode(sdlz, &sdlznode);
1953 		if (result != ISC_R_SUCCESS) {
1954 			return (result);
1955 		}
1956 		sdlznode->name = isc_mem_get(mctx, sizeof(dns_name_t));
1957 		dns_name_init(sdlznode->name, NULL);
1958 		dns_name_dup(newname, mctx, sdlznode->name);
1959 		ISC_LIST_PREPEND(allnodes->nodelist, sdlznode, link);
1960 		if (allnodes->origin == NULL &&
1961 		    dns_name_equal(newname, &sdlz->common.origin)) {
1962 			allnodes->origin = sdlznode;
1963 		}
1964 	}
1965 	return (dns_sdlz_putrr(sdlznode, type, ttl, data));
1966 }
1967 
1968 isc_result_t
dns_sdlz_putsoa(dns_sdlzlookup_t * lookup,const char * mname,const char * rname,uint32_t serial)1969 dns_sdlz_putsoa(dns_sdlzlookup_t *lookup, const char *mname, const char *rname,
1970 		uint32_t serial) {
1971 	char str[2 * DNS_NAME_MAXTEXT + 5 * (sizeof("2147483647")) + 7];
1972 	int n;
1973 
1974 	REQUIRE(mname != NULL);
1975 	REQUIRE(rname != NULL);
1976 
1977 	n = snprintf(str, sizeof str, "%s %s %u %u %u %u %u", mname, rname,
1978 		     serial, SDLZ_DEFAULT_REFRESH, SDLZ_DEFAULT_RETRY,
1979 		     SDLZ_DEFAULT_EXPIRE, SDLZ_DEFAULT_MINIMUM);
1980 	if (n >= (int)sizeof(str) || n < 0) {
1981 		return (ISC_R_NOSPACE);
1982 	}
1983 	return (dns_sdlz_putrr(lookup, "SOA", SDLZ_DEFAULT_TTL, str));
1984 }
1985 
1986 isc_result_t
dns_sdlzregister(const char * drivername,const dns_sdlzmethods_t * methods,void * driverarg,unsigned int flags,isc_mem_t * mctx,dns_sdlzimplementation_t ** sdlzimp)1987 dns_sdlzregister(const char *drivername, const dns_sdlzmethods_t *methods,
1988 		 void *driverarg, unsigned int flags, isc_mem_t *mctx,
1989 		 dns_sdlzimplementation_t **sdlzimp) {
1990 	dns_sdlzimplementation_t *imp;
1991 	isc_result_t result;
1992 
1993 	/*
1994 	 * Performs checks to make sure data is as we expect it to be.
1995 	 */
1996 	REQUIRE(drivername != NULL);
1997 	REQUIRE(methods != NULL);
1998 	REQUIRE(methods->findzone != NULL);
1999 	REQUIRE(methods->lookup != NULL);
2000 	REQUIRE(mctx != NULL);
2001 	REQUIRE(sdlzimp != NULL && *sdlzimp == NULL);
2002 	REQUIRE((flags &
2003 		 ~(DNS_SDLZFLAG_RELATIVEOWNER | DNS_SDLZFLAG_RELATIVERDATA |
2004 		   DNS_SDLZFLAG_THREADSAFE)) == 0);
2005 
2006 	/* Write debugging message to log */
2007 	sdlz_log(ISC_LOG_DEBUG(2), "Registering SDLZ driver '%s'", drivername);
2008 
2009 	/*
2010 	 * Allocate memory for a sdlz_implementation object.  Error if
2011 	 * we cannot.
2012 	 */
2013 	imp = isc_mem_get(mctx, sizeof(dns_sdlzimplementation_t));
2014 
2015 	/* Make sure memory region is set to all 0's */
2016 	memset(imp, 0, sizeof(dns_sdlzimplementation_t));
2017 
2018 	/* Store the data passed into this method */
2019 	imp->methods = methods;
2020 	imp->driverarg = driverarg;
2021 	imp->flags = flags;
2022 	imp->mctx = NULL;
2023 
2024 	/* attach the new sdlz_implementation object to a memory context */
2025 	isc_mem_attach(mctx, &imp->mctx);
2026 
2027 	/*
2028 	 * initialize the driver lock, error if we cannot
2029 	 * (used if a driver does not support multiple threads)
2030 	 */
2031 	isc_mutex_init(&imp->driverlock);
2032 
2033 	imp->dlz_imp = NULL;
2034 
2035 	/*
2036 	 * register the DLZ driver.  Pass in our "extra" sdlz information as
2037 	 * a driverarg.  (that's why we stored the passed in driver arg in our
2038 	 * sdlz_implementation structure)  Also, store the dlz_implementation
2039 	 * structure in our sdlz_implementation.
2040 	 */
2041 	result = dns_dlzregister(drivername, &sdlzmethods, imp, mctx,
2042 				 &imp->dlz_imp);
2043 
2044 	/* if registration fails, cleanup and get outta here. */
2045 	if (result != ISC_R_SUCCESS) {
2046 		goto cleanup_mutex;
2047 	}
2048 
2049 	*sdlzimp = imp;
2050 
2051 	return (ISC_R_SUCCESS);
2052 
2053 cleanup_mutex:
2054 	/* destroy the driver lock, we don't need it anymore */
2055 	isc_mutex_destroy(&imp->driverlock);
2056 
2057 	/*
2058 	 * return the memory back to the available memory pool and
2059 	 * remove it from the memory context.
2060 	 */
2061 	isc_mem_putanddetach(&imp->mctx, imp, sizeof(dns_sdlzimplementation_t));
2062 	return (result);
2063 }
2064 
2065 void
dns_sdlzunregister(dns_sdlzimplementation_t ** sdlzimp)2066 dns_sdlzunregister(dns_sdlzimplementation_t **sdlzimp) {
2067 	dns_sdlzimplementation_t *imp;
2068 
2069 	/* Write debugging message to log */
2070 	sdlz_log(ISC_LOG_DEBUG(2), "Unregistering SDLZ driver.");
2071 
2072 	/*
2073 	 * Performs checks to make sure data is as we expect it to be.
2074 	 */
2075 	REQUIRE(sdlzimp != NULL && *sdlzimp != NULL);
2076 
2077 	imp = *sdlzimp;
2078 	*sdlzimp = NULL;
2079 
2080 	/* Unregister the DLZ driver implementation */
2081 	dns_dlzunregister(&imp->dlz_imp);
2082 
2083 	/* destroy the driver lock, we don't need it anymore */
2084 	isc_mutex_destroy(&imp->driverlock);
2085 
2086 	/*
2087 	 * return the memory back to the available memory pool and
2088 	 * remove it from the memory context.
2089 	 */
2090 	isc_mem_putanddetach(&imp->mctx, imp, sizeof(dns_sdlzimplementation_t));
2091 }
2092 
2093 isc_result_t
dns_sdlz_setdb(dns_dlzdb_t * dlzdatabase,dns_rdataclass_t rdclass,const dns_name_t * name,dns_db_t ** dbp)2094 dns_sdlz_setdb(dns_dlzdb_t *dlzdatabase, dns_rdataclass_t rdclass,
2095 	       const dns_name_t *name, dns_db_t **dbp) {
2096 	isc_result_t result;
2097 
2098 	result = dns_sdlzcreateDBP(dlzdatabase->mctx,
2099 				   dlzdatabase->implementation->driverarg,
2100 				   dlzdatabase->dbdata, name, rdclass, dbp);
2101 	return (result);
2102 }
2103