xref: /minix3/external/bsd/bind/dist/contrib/dlz/drivers/dlz_bdb_driver.c (revision 00b67f09dd46474d133c95011a48590a8e8f94c7)
1 /*	$NetBSD: dlz_bdb_driver.c,v 1.5 2014/12/10 04:37:55 christos Exp $	*/
2 
3 /*
4  * Copyright (C) 2002 Stichting NLnet, Netherlands, stichting@nlnet.nl.
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the
8  * above copyright notice and this permission notice appear in all
9  * copies.
10  *
11  * THE SOFTWARE IS PROVIDED "AS IS" AND STICHTING NLNET
12  * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
13  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
14  * STICHTING NLNET BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
15  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
16  * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
17  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE
18  * USE OR PERFORMANCE OF THIS SOFTWARE.
19  *
20  * The development of Dynamically Loadable Zones (DLZ) for Bind 9 was
21  * conceived and contributed by Rob Butler.
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 ROB BUTLER
29  * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
30  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
31  * ROB BUTLER 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 
38 /*
39  * Copyright (C) 1999-2001  Internet Software Consortium.
40  *
41  * Permission to use, copy, modify, and distribute this software for any
42  * purpose with or without fee is hereby granted, provided that the above
43  * copyright notice and this permission notice appear in all copies.
44  *
45  * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
46  * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
47  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
48  * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
49  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
50  * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
51  * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
52  * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
53  */
54 
55 #ifdef DLZ_BDB
56 
57 #include <config.h>
58 #include <stdio.h>
59 #include <string.h>
60 #include <stdlib.h>
61 
62 #include <dns/log.h>
63 #include <dns/sdlz.h>
64 #include <dns/result.h>
65 
66 #include <isc/mem.h>
67 #include <isc/print.h>
68 #include <isc/result.h>
69 #include <isc/util.h>
70 
71 #include <named/globals.h>
72 
73 #include <dlz/dlz_bdb_driver.h>
74 
75 #include <db.h>
76 
77 static dns_sdlzimplementation_t *dlz_bdb = NULL;
78 
79 /* should the bdb driver use threads. */
80 #ifdef ISC_PLATFORM_USETHREADS
81 #define bdb_threads DB_THREAD
82 #else
83 #define bdb_threads 0
84 #endif
85 
86 /* BDB database names */
87 #define dlz_data "dns_data"
88 #define dlz_zone "dns_zone"
89 #define dlz_host "dns_host"
90 #define dlz_client "dns_client"
91 
92 /*%
93  * This structure contains all the Berkeley DB handles
94  * for this instance of the BDB driver.
95  */
96 
97 typedef struct bdb_instance {
98 	DB_ENV	*dbenv;		/*%< BDB environment */
99 	DB	*data;		/*%< dns_data database handle */
100 	DB	*zone;		/*%< zone database handle */
101 	DB	*host;		/*%< host database handle */
102 	DB	*client;	/*%< client database handle */
103 	isc_mem_t *mctx;	/*%< memory context */
104 
105 } bdb_instance_t;
106 
107 typedef struct parsed_data {
108 	char *zone;
109 	char *host;
110 	char *type;
111 	int ttl;
112 	char *data;
113 } parsed_data_t;
114 
115 
116 /* forward reference */
117 
118 static isc_result_t
119 bdb_findzone(void *driverarg, void *dbdata, const char *name,
120 	     dns_clientinfomethods_t *methods, dns_clientinfo_t *clientinfo);
121 
122 /*%
123  * Parses the DBT from the Berkeley DB into a parsed_data record
124  * The parsed_data record should be allocated before and passed into the
125  * bdb_parse_data function.  The char (type & data) fields should not
126  * be "free"d as that memory is part of the DBT data field.  It will be
127  * "free"d when the DBT is freed.
128  */
129 
130 static isc_result_t
bdb_parse_data(char * in,parsed_data_t * pd)131 bdb_parse_data(char *in, parsed_data_t *pd) {
132 
133 	char *endp, *ttlStr;
134 	char *tmp = in;
135 	char *lastchar = (char *) &tmp[strlen(tmp) + 1];
136 
137 	/*%
138 	 * String should be formated as:
139 	 * zone(a space)host(a space)ttl(a space)type(a space)remaining data
140 	 * examples:
141 	 * example.com www 10 A 127.0.0.1
142 	 * example.com mail 10 A 127.0.0.2
143 	 * example.com @ 10 MX 20 mail.example.com
144 	 */
145 
146 	/* save pointer to zone */
147 	pd->zone = tmp;
148 
149 	/* find space after zone and change it to a '\0' */
150 	tmp = strchr(tmp, ' ');
151 	/* verify we found a space */
152 	if (tmp == NULL)
153 		return ISC_R_FAILURE;
154 	/* change the space to a null (string terminator) */
155 	tmp[0] = '\0';
156 	/* make sure it is safe to increment pointer */
157 	if (++tmp > lastchar)
158 		return ISC_R_FAILURE;
159 
160 	/* save pointer to host */
161 	pd->host = tmp;
162 
163 	/* find space after type and change it to a '\0' */
164 	tmp = strchr(tmp, ' ');
165 	/* verify we found a space */
166 	if (tmp == NULL)
167 		return ISC_R_FAILURE;
168 	/* change the space to a null (string terminator) */
169 	tmp[0] = '\0';
170 	/* make sure it is safe to increment pointer */
171 	if (++tmp > lastchar)
172 		return ISC_R_FAILURE;
173 
174 	/* save pointer to dns type */
175 	pd->type = tmp;
176 
177 	/* find space after type and change it to a '\0' */
178 	tmp = strchr(tmp, ' ');
179 	/* verify we found a space */
180 	if (tmp == NULL)
181 		return ISC_R_FAILURE;
182 	/* change the space to a null (string terminator) */
183 	tmp[0] = '\0';
184 	/* make sure it is safe to increment pointer */
185 	if (++tmp > lastchar)
186 		return ISC_R_FAILURE;
187 
188 	/* save pointer to dns ttl */
189 	ttlStr = tmp;
190 
191 	/* find space after ttl and change it to a '\0' */
192 	tmp = strchr(tmp, ' ');
193 	/* verify we found a space */
194 	if (tmp == NULL)
195 		return ISC_R_FAILURE;
196 	/* change the space to a null (string terminator) */
197 	tmp[0] = '\0';
198 	/* make sure it is safe to increment pointer */
199 	if (++tmp > lastchar)
200 		return ISC_R_FAILURE;
201 
202 	/* save pointer to remainder of DNS data */
203 	pd->data = tmp;
204 
205 	/* convert ttl string to integer */
206 	pd->ttl = strtol(ttlStr, &endp, 10);
207 	if (*endp != '\0' || pd->ttl < 0) {
208 		isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
209 			      DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
210 			      "BDB driver ttl must be a postive number");
211 		return ISC_R_FAILURE;
212 	}
213 
214 	/* if we get this far everything should have worked. */
215 	return ISC_R_SUCCESS;
216 }
217 
218 /*
219  * DLZ methods
220  */
221 
222 static isc_result_t
bdb_allowzonexfr(void * driverarg,void * dbdata,const char * name,const char * client)223 bdb_allowzonexfr(void *driverarg, void *dbdata, const char *name,
224 		 const char *client)
225 {
226 	isc_result_t result;
227 	bdb_instance_t *db = (bdb_instance_t *) dbdata;
228 	DBC *client_cursor = NULL;
229 	DBT key, data;
230 
231 	/* check to see if we are authoritative for the zone first. */
232 	result = bdb_findzone(driverarg, dbdata, name, NULL, NULL);
233 	if (result != ISC_R_SUCCESS)
234 		return (ISC_R_NOTFOUND);
235 
236 	memset(&key, 0, sizeof(DBT));
237 	key.flags = DB_DBT_MALLOC;
238 	key.data = strdup(name);
239 	if (key.data == NULL) {
240 		result = ISC_R_NOMEMORY;
241 		goto xfr_cleanup;
242 	}
243 	key.size = strlen(key.data);
244 
245 	memset(&data, 0, sizeof(DBT));
246 	data.flags = DB_DBT_MALLOC;
247 	data.data = strdup(client);
248 	if (data.data == NULL) {
249 		result = ISC_R_NOMEMORY;
250 		goto xfr_cleanup;
251 	}
252 	data.size = strlen(data.data);
253 
254 	/* get a cursor to loop through zone data */
255 	if (db->client->cursor(db->client, NULL, &client_cursor, 0) != 0) {
256 		result = ISC_R_FAILURE;
257 		goto xfr_cleanup;
258 	}
259 
260 	switch(client_cursor->c_get(client_cursor, &key, &data, DB_GET_BOTH)) {
261 	case DB_NOTFOUND:
262 	case DB_SECONDARY_BAD:
263 		result = ISC_R_NOTFOUND;
264 		break;
265 	case 0:
266 		result = ISC_R_SUCCESS;
267 		break;
268 	default:
269 		result = ISC_R_FAILURE;
270 	}
271 
272  xfr_cleanup:
273 
274 	/* free any memory duplicate string in the key field */
275 	if (key.data != NULL)
276 		free(key.data);
277 
278 	/* free any memory allocated to the data field. */
279 	if (data.data != NULL)
280 		free(data.data);
281 
282 	/* get rid of zone_cursor */
283 	if (client_cursor != NULL)
284 		client_cursor->c_close(client_cursor);
285 
286 	return result;
287 
288 }
289 
290 static isc_result_t
bdb_allnodes(const char * zone,void * driverarg,void * dbdata,dns_sdlzallnodes_t * allnodes)291 bdb_allnodes(const char *zone, void *driverarg, void *dbdata,
292 	     dns_sdlzallnodes_t *allnodes)
293 {
294 
295 	isc_result_t result = ISC_R_NOTFOUND;
296 	bdb_instance_t *db = (bdb_instance_t *) dbdata;
297 	DBC *zone_cursor = NULL;
298 	DBT key, data;
299 	int flags;
300 	int bdbres;
301 	parsed_data_t pd;
302 	char *tmp = NULL, *tmp_zone;
303 
304 	UNUSED(driverarg);
305 
306 	memset(&key, 0, sizeof(DBT));
307 	memset(&data, 0, sizeof(DBT));
308 
309 	key.data = tmp_zone = strdup(zone);
310 
311 	if (key.data == NULL)
312 		return (ISC_R_NOMEMORY);
313 
314 	key.size = strlen(key.data);
315 
316 	/* get a cursor to loop through zone data */
317 	if (db->zone->cursor(db->zone, NULL, &zone_cursor, 0) != 0) {
318 		result = ISC_R_FAILURE;
319 		goto allnodes_cleanup;
320 	}
321 
322 	flags = DB_SET;
323 
324 	while ((bdbres = zone_cursor->c_get(zone_cursor, &key, &data,
325 					    flags)) == 0) {
326 
327 		flags = DB_NEXT_DUP;
328 
329 		tmp = realloc(tmp, data.size + 1);
330 		if (tmp == NULL)
331 			goto allnodes_cleanup;
332 
333 		strncpy(tmp, data.data, data.size);
334 		tmp[data.size] = '\0';
335 
336 		if (bdb_parse_data(tmp, &pd) != ISC_R_SUCCESS)
337 			goto allnodes_cleanup;
338 
339 		result = dns_sdlz_putnamedrr(allnodes, pd.host, pd.type,
340 					     pd.ttl, pd.data);
341 		if (result != ISC_R_SUCCESS)
342 			goto allnodes_cleanup;
343 
344 	} /* end while loop */
345 
346  allnodes_cleanup:
347 
348 	if (tmp != NULL)
349 		free(tmp);
350 
351 	/* free any memory duplicate string in the key field */
352 	if (tmp_zone != NULL)
353 		free(tmp_zone);
354 
355 	/* get rid of zone_cursor */
356 	if (zone_cursor != NULL)
357 		zone_cursor->c_close(zone_cursor);
358 
359 	return result;
360 
361 }
362 
363 /*%
364  * Performs BDB cleanup.
365  * Used by bdb_create if there is an error starting up.
366  * Used by bdb_destroy when the driver is shutting down.
367  */
368 
369 static void
bdb_cleanup(bdb_instance_t * db)370 bdb_cleanup(bdb_instance_t *db) {
371 
372 	isc_mem_t *mctx;
373 
374 	/* close databases */
375 	if (db->data != NULL)
376 		db->data->close(db->data, 0);
377 	if (db->host != NULL)
378 		db->host->close(db->host, 0);
379 	if (db->zone != NULL)
380 		db->zone->close(db->zone, 0);
381 	if (db->client != NULL)
382 		db->client->close(db->client, 0);
383 
384 	/* close environment */
385 	if (db->dbenv != NULL)
386 		db->dbenv->close(db->dbenv, 0);
387 
388 	/* cleanup memory */
389 	if (db->mctx != NULL) {
390 		/* save mctx for later */
391 		mctx = db->mctx;
392 		/* return, and detach the memory */
393 		isc_mem_put(mctx, db, sizeof(bdb_instance_t));
394 		isc_mem_detach(&mctx);
395 	}
396 }
397 
398 static isc_result_t
bdb_findzone(void * driverarg,void * dbdata,const char * name,dns_clientinfomethods_t * methods,dns_clientinfo_t * clientinfo)399 bdb_findzone(void *driverarg, void *dbdata, const char *name,
400 	     dns_clientinfomethods_t *methods, dns_clientinfo_t *clientinfo)
401 {
402 
403 	isc_result_t result;
404 	bdb_instance_t *db = (bdb_instance_t *) dbdata;
405 	DBC *zone_cursor = NULL;
406 	DBT key, data;
407 
408 	UNUSED(driverarg);
409 	UNUSED(methods);
410 	UNUSED(clientinfo);
411 
412 	memset(&key, 0, sizeof(DBT));
413 	memset(&data, 0, sizeof(DBT));
414 	data.flags = DB_DBT_MALLOC;
415 
416 	key.data = strdup(name);
417 
418 	if (key.data == NULL)
419 		return (ISC_R_NOMEMORY);
420 
421 	key.size = strlen(key.data);
422 
423 	/* get a cursor to loop through zone data */
424 	if (db->zone->cursor(db->zone, NULL, &zone_cursor, 0) != 0) {
425 		result = ISC_R_NOTFOUND;
426 		goto findzone_cleanup;
427 	}
428 
429 	switch(zone_cursor->c_get(zone_cursor, &key, &data, DB_SET)) {
430 	case DB_NOTFOUND:
431 	case DB_SECONDARY_BAD:
432 		result = ISC_R_NOTFOUND;
433 		break;
434 	case 0:
435 		result = ISC_R_SUCCESS;
436 		break;
437 	default:
438 		result = ISC_R_FAILURE;
439 	}
440 
441  findzone_cleanup:
442 
443 	/* free any memory duplicate string in the key field */
444 	if (key.data != NULL)
445 		free(key.data);
446 
447 	/* free any memory allocated to the data field. */
448 	if (data.data != NULL)
449 		free(data.data);
450 
451 	/* get rid of zone_cursor */
452 	if (zone_cursor != NULL)
453 		zone_cursor->c_close(zone_cursor);
454 
455 	return result;
456 }
457 
458 static isc_result_t
bdb_lookup(const char * zone,const char * name,void * driverarg,void * dbdata,dns_sdlzlookup_t * lookup,dns_clientinfomethods_t * methods,dns_clientinfo_t * clientinfo)459 bdb_lookup(const char *zone, const char *name, void *driverarg,
460 	   void *dbdata, dns_sdlzlookup_t *lookup,
461 	   dns_clientinfomethods_t *methods, dns_clientinfo_t *clientinfo)
462 {
463 
464 	isc_result_t result = ISC_R_NOTFOUND;
465 	bdb_instance_t *db = (bdb_instance_t *) dbdata;
466 	DBC *zone_cursor = NULL;
467 	DBC *host_cursor = NULL;
468 	DBC *join_cursor = NULL;
469 	DBT key, data;
470 	DBC *cur_arr[3];
471 	int bdbres;
472 	parsed_data_t pd;
473 	char *tmp_zone, *tmp_host = NULL;
474 	char *tmp = NULL;
475 
476 	UNUSED(driverarg);
477 	UNUSED(methods);
478 	UNUSED(clientinfo);
479 
480 	memset(&key, 0, sizeof(DBT));
481 	memset(&data, 0, sizeof(DBT));
482 
483 	/* set zone key */
484 	key.data = tmp_zone = strdup(zone);
485 	if (key.data == NULL) {
486 		result = ISC_R_NOMEMORY;
487 		goto lookup_cleanup;
488 	}
489 	key.size = strlen(key.data);
490 
491 	/* get a cursor to loop through zone data */
492 	if (db->zone->cursor(db->zone, NULL, &zone_cursor, 0) != 0) {
493 		result = ISC_R_FAILURE;
494 		goto lookup_cleanup;
495 	}
496 
497 	/* initialize zone_cursor with zone_key */
498 	if (zone_cursor->c_get(zone_cursor, &key, &data, DB_SET) != 0) {
499 		result = ISC_R_NOTFOUND;
500 		goto lookup_cleanup;
501 	}
502 
503 	/* set host key */
504 	key.data = tmp_host = strdup(name);
505 	if (key.data == NULL) {
506 		result = ISC_R_NOMEMORY;
507 		goto lookup_cleanup;
508 	}
509 	key.size = strlen(key.data);
510 
511 	/* get a cursor to loop through host data */
512 	if (db->host->cursor(db->host, NULL, &host_cursor, 0) != 0) {
513 		result = ISC_R_FAILURE;
514 		goto lookup_cleanup;
515 	}
516 
517 	/* initialize host_cursor with host_key */
518 	if (host_cursor->c_get(host_cursor, &key, &data, DB_SET) != 0) {
519 		result = ISC_R_NOTFOUND;
520 		goto lookup_cleanup;
521 	}
522 
523 	cur_arr[0] = zone_cursor;
524 	cur_arr[1] = host_cursor;
525 	cur_arr[2] = NULL;
526 
527 	db->data->join(db->data, cur_arr, &join_cursor, 0);
528 
529 	while ((bdbres = join_cursor->c_get(join_cursor, &key,
530 					    &data, 0)) == 0) {
531 
532 		tmp = realloc(tmp, data.size + 1);
533 		if (tmp == NULL)
534 			goto lookup_cleanup;
535 
536 		strncpy(tmp, data.data, data.size);
537 		tmp[data.size] = '\0';
538 
539 		if (bdb_parse_data(tmp, &pd) != ISC_R_SUCCESS)
540 			goto lookup_cleanup;
541 
542 		result = dns_sdlz_putrr(lookup, pd.type, pd.ttl, pd.data);
543 
544 		if (result != ISC_R_SUCCESS)
545 			goto lookup_cleanup;
546 	} /* end while loop */
547 
548  lookup_cleanup:
549 
550 	if (tmp != NULL)
551 		free(tmp);
552 	if (tmp_zone != NULL)
553 		free(tmp_zone);
554 	if (tmp_host != NULL)
555 		free(tmp_host);
556 
557 	/* get rid of the joined cusor */
558 	if (join_cursor != NULL)
559 		join_cursor->c_close(join_cursor);
560 
561 	/* get rid of zone_cursor */
562 	if (zone_cursor != NULL)
563 		zone_cursor->c_close(zone_cursor);
564 
565 	/* get rid of host_cursor */
566 	if (host_cursor != NULL)
567 		host_cursor->c_close(host_cursor);
568 
569 	return result;
570 }
571 
572 
573 /*% Initializes, sets flags and then opens Berkeley databases. */
574 
575 static isc_result_t
bdb_opendb(DB_ENV * db_env,DBTYPE db_type,DB ** db,const char * db_name,char * db_file,int flags)576 bdb_opendb(DB_ENV *db_env, DBTYPE db_type, DB **db, const char *db_name,
577 	   char *db_file, int flags) {
578 
579 	int result;
580 
581 	/* Initialize the database. */
582 	if ((result = db_create(db, db_env, 0)) != 0) {
583 		isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
584 			      DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
585 			      "BDB could not initialize %s database. "
586 			      "BDB error: %s",
587 			      db_name, db_strerror(result));
588 		return ISC_R_FAILURE;
589 	}
590 
591 	/* set database flags. */
592 	if ((result = (*db)->set_flags(*db, flags)) != 0) {
593 		isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
594 			      DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
595 			      "BDB could not set flags for %s database. "
596 			      "BDB error: %s",
597 			      db_name, db_strerror(result));
598 		return ISC_R_FAILURE;
599 	}
600 
601 	/* open the database. */
602 	if ((result = (*db)->open(*db, NULL, db_file, db_name, db_type,
603 				  DB_RDONLY | bdb_threads, 0)) != 0) {
604 		isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
605 			      DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
606 			      "BDB could not open %s database in %s. "
607 			      "BDB error: %s",
608 			      db_name, db_file, db_strerror(result));
609 		return ISC_R_FAILURE;
610 	}
611 
612 	return ISC_R_SUCCESS;
613 }
614 
615 static isc_result_t
bdb_create(const char * dlzname,unsigned int argc,char * argv[],void * driverarg,void ** dbdata)616 bdb_create(const char *dlzname, unsigned int argc, char *argv[],
617 	   void *driverarg, void **dbdata)
618 {
619 	isc_result_t result;
620 	int bdbres;
621 	bdb_instance_t *db = NULL;
622 
623 	UNUSED(dlzname);
624 	UNUSED(driverarg);
625 
626 	/* verify we have 3 arg's passed to the driver */
627 	if (argc != 3) {
628 		isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
629 			      DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
630 			      "Berkeley DB driver requires at least "
631 			      "2 command line args.");
632 		return (ISC_R_FAILURE);
633 	}
634 
635 	/* allocate and zero memory for driver structure */
636 	db = isc_mem_get(ns_g_mctx, sizeof(bdb_instance_t));
637 	if (db == NULL) {
638 		isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
639 			      DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
640 			      "Could not allocate memory for "
641 			      "database instance object.");
642 		return (ISC_R_NOMEMORY);
643 	}
644 	memset(db, 0, sizeof(bdb_instance_t));
645 
646 	/* attach to the memory context */
647 	isc_mem_attach(ns_g_mctx, &db->mctx);
648 
649 	/* create BDB environment
650 	 * Basically BDB allocates and assigns memory to db->dbenv
651 	 */
652 	bdbres = db_env_create(&db->dbenv, 0);
653 	if (bdbres != 0) {
654 		isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
655 			      DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
656 			      "BDB environment could not be created. "
657 			      "BDB error: %s",
658 			      db_strerror(bdbres));
659 		result = ISC_R_FAILURE;
660 		goto init_cleanup;
661 	}
662 
663 	/* open BDB environment */
664 	bdbres = db->dbenv->open(db->dbenv, argv[1],
665 				 DB_INIT_CDB | DB_INIT_MPOOL |
666 				 bdb_threads | DB_CREATE,
667 				 0);
668 	if (bdbres != 0) {
669 		isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
670 			      DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
671 			      "BDB environment at '%s' could not be opened. "
672 			      "BDB error: %s",
673 			      argv[1], db_strerror(bdbres));
674 		result = ISC_R_FAILURE;
675 		goto init_cleanup;
676 	}
677 
678 	/* open dlz_data database. */
679 	result = bdb_opendb(db->dbenv, DB_UNKNOWN, &db->data,
680 			    dlz_data, argv[2], 0);
681 	if (result != ISC_R_SUCCESS)
682 		goto init_cleanup;
683 
684 	/* open dlz_host database. */
685 	result = bdb_opendb(db->dbenv, DB_UNKNOWN, &db->host,
686 			    dlz_host, argv[2],
687 			    DB_DUP | DB_DUPSORT);
688 	if (result != ISC_R_SUCCESS)
689 		goto init_cleanup;
690 
691 	/* open dlz_zone database. */
692 	result = bdb_opendb(db->dbenv, DB_UNKNOWN, &db->zone,
693 			    dlz_zone, argv[2],
694 			    DB_DUP | DB_DUPSORT);
695 	if (result != ISC_R_SUCCESS)
696 		goto init_cleanup;
697 
698 	/* open dlz_client database. */
699 	result = bdb_opendb(db->dbenv, DB_UNKNOWN, &db->client,
700 			    dlz_client, argv[2], DB_DUP | DB_DUPSORT);
701 	if (result != ISC_R_SUCCESS)
702 		goto init_cleanup;
703 
704 	/* associate the host secondary database with the primary database */
705 	bdbres = db->data->associate(db->data, NULL, db->host, NULL, 0);
706 	if (bdbres != 0) {
707 		isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
708 			      DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
709 			      "BDB could not associate %s database with %s. "
710 			      "BDB error: %s",
711 			      dlz_host, dlz_data, db_strerror(bdbres));
712 		result = ISC_R_FAILURE;
713 		goto init_cleanup;
714 	}
715 
716 	/* associate the zone secondary database with the primary database */
717 	bdbres = db->data->associate(db->data, NULL, db->zone, NULL, 0);
718 	if (bdbres != 0) {
719 		isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
720 			      DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
721 			      "BDB could not associate %s database with %s. "
722 			      "BDB error: %s",
723 			      dlz_zone, dlz_data, db_strerror(bdbres));
724 		result = ISC_R_FAILURE;
725 		goto init_cleanup;
726 	}
727 
728 	*dbdata = db;
729 
730 	return(ISC_R_SUCCESS);
731 
732  init_cleanup:
733 
734 	bdb_cleanup(db);
735 	return result;
736 }
737 
738 static void
bdb_destroy(void * driverarg,void * dbdata)739 bdb_destroy(void *driverarg, void *dbdata)
740 {
741 	UNUSED(driverarg);
742 
743 	bdb_cleanup((bdb_instance_t *) dbdata);
744 }
745 
746 /* bdb_authority not needed as authority data is returned by lookup */
747 static dns_sdlzmethods_t dlz_bdb_methods = {
748 	bdb_create,
749 	bdb_destroy,
750 	bdb_findzone,
751 	bdb_lookup,
752 	NULL,
753 	bdb_allnodes,
754 	bdb_allowzonexfr,
755 	NULL,
756 	NULL,
757 	NULL,
758 	NULL,
759 	NULL,
760 	NULL,
761 	NULL,
762 };
763 
764 /*%
765  * Wrapper around dns_sdlzregister().
766  */
767 isc_result_t
dlz_bdb_init(void)768 dlz_bdb_init(void) {
769 	isc_result_t result;
770 
771 	/*
772 	 * Write debugging message to log
773 	 */
774 	isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
775 		      DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2),
776 		      "Registering DLZ bdb driver.");
777 
778 	result = dns_sdlzregister("bdb", &dlz_bdb_methods, NULL,
779 				  DNS_SDLZFLAG_RELATIVEOWNER |
780 				  DNS_SDLZFLAG_RELATIVERDATA |
781 				  DNS_SDLZFLAG_THREADSAFE,
782 				  ns_g_mctx, &dlz_bdb);
783 	if (result != ISC_R_SUCCESS) {
784 		UNEXPECTED_ERROR(__FILE__, __LINE__,
785 				 "dns_sdlzregister() failed: %s",
786 				 isc_result_totext(result));
787 		result = ISC_R_UNEXPECTED;
788 	}
789 
790 
791 	return result;
792 }
793 
794 /*%
795  * Wrapper around dns_sdlzunregister().
796  */
797 void
dlz_bdb_clear(void)798 dlz_bdb_clear(void) {
799 
800 	/*
801 	 * Write debugging message to log
802 	 */
803 	isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
804 		      DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2),
805 		      "Unregistering DLZ bdb driver.");
806 
807 	if (dlz_bdb != NULL)
808 		dns_sdlzunregister(&dlz_bdb);
809 }
810 
811 #endif
812