1/*
2 * Copyright (C) 2002 Stichting NLnet, Netherlands, stichting@nlnet.nl.
3 *
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the
6 * above copyright notice and this permission notice appear in all
7 * copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND STICHTING NLNET
10 * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
11 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
12 * STICHTING NLNET BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
13 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
14 * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
15 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE
16 * USE OR PERFORMANCE OF THIS SOFTWARE.
17 *
18 * The development of Dynamically Loadable Zones (DLZ) for Bind 9 was
19 * conceived and contributed by Rob Butler.
20 *
21 * Permission to use, copy, modify, and distribute this software for any
22 * purpose with or without fee is hereby granted, provided that the
23 * above copyright notice and this permission notice appear in all
24 * copies.
25 *
26 * THE SOFTWARE IS PROVIDED "AS IS" AND ROB BUTLER
27 * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
29 * ROB BUTLER BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
30 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
31 * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
32 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE
33 * USE OR PERFORMANCE OF THIS SOFTWARE.
34 */
35
36/*
37 * Copyright (C) 1999-2001  Internet Software Consortium.
38 *
39 * Permission to use, copy, modify, and distribute this software for any
40 * purpose with or without fee is hereby granted, provided that the above
41 * copyright notice and this permission notice appear in all copies.
42 *
43 * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
44 * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
45 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
46 * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
47 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
48 * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
49 * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
50 * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
51 */
52
53#ifdef DLZ_BDB
54
55#include <config.h>
56#include <stdio.h>
57#include <string.h>
58#include <stdlib.h>
59
60#include <dns/log.h>
61#include <dns/sdlz.h>
62#include <dns/result.h>
63
64#include <isc/mem.h>
65#include <isc/print.h>
66#include <isc/result.h>
67#include <isc/util.h>
68
69#include <named/globals.h>
70
71#include <dlz/dlz_bdbhpt_driver.h>
72
73#include <db.h>
74
75static dns_sdlzimplementation_t *dlz_bdbhpt = NULL;
76
77/* should the bdb driver use threads. */
78#ifdef ISC_PLATFORM_USETHREADS
79#define bdbhpt_threads DB_THREAD
80#else
81#define bdbhpt_threads 0
82#endif
83
84/* bdbhpt database names */
85#define dlz_data "dns_data"
86#define dlz_zone "dns_zone"
87#define dlz_xfr "dns_xfr"
88#define dlz_client "dns_client"
89
90	/* This structure contains all the Berkeley DB handles
91	 * for this instance of the bdbhpt driver.
92	 */
93
94typedef struct bdbhpt_instance {
95	DB_ENV	*dbenv;		/*%< bdbhpt environment */
96	DB	*data;		/*%< dns_data database handle */
97	DB	*zone;		/*%< zone database handle */
98	DB	*xfr;		/*%< zone xfr database handle */
99	DB	*client;	/*%< client database handle */
100	isc_mem_t *mctx;	/*%< memory context */
101
102} bdbhpt_instance_t;
103
104typedef struct bdbhpt_parsed_data {
105	char *host;
106	char *type;
107	int ttl;
108	char *data;
109} bdbhpt_parsed_data_t;
110
111
112/* forward reference */
113
114static isc_result_t
115bdbhpt_findzone(void *driverarg, void *dbdata, const char *name);
116
117/*%
118 * Reverses a string in place.
119 */
120
121static char *bdbhpt_strrev(char *str)
122{
123	char *p1, *p2;
124
125	if (! str || ! *str)
126		return str;
127	for (p1 = str, p2 = str + strlen(str) - 1; p2 > p1; ++p1, --p2)
128	{
129		*p1 ^= *p2;
130		*p2 ^= *p1;
131		*p1 ^= *p2;
132	}
133	return str;
134}
135
136/*%
137 * Parses the DBT from the Berkeley DB into a parsed_data record
138 * The parsed_data record should be allocated before and passed into the
139 * bdbhpt_parse_data function.  The char (type & data) fields should not
140 * be "free"d as that memory is part of the DBT data field.  It will be
141 * "free"d when the DBT is freed.
142 */
143
144static isc_result_t
145bdbhpt_parse_data(char *in, bdbhpt_parsed_data_t *pd) {
146
147	char *endp, *ttlStr;
148	char *tmp = in;
149	char *lastchar = (char *) &tmp[strlen(tmp)];
150
151	/*%
152	 * String should be formated as:
153	 *   replication_id
154	 *   (a space)
155	 *   host_name
156	 *   (a space)
157	 *   ttl
158	 *   (a space)
159	 *   type
160	 *   (a space)
161	 *   remaining data
162	 *
163	 * examples:
164	 *
165	 * 9191 host 10 A 127.0.0.1
166	 * server1_212 host 10 A 127.0.0.2
167	 * {xxxx-xxxx-xxxx-xxxx-xxxx} host 10 MX 20 mail.example.com
168	 */
169
170	/*
171	 * we don't need the replication id, so don't
172	 * bother saving a pointer to it.
173	 */
174
175	/* find space after replication id */
176	tmp = strchr(tmp, ' ');
177	/* verify we found a space */
178	if (tmp == NULL)
179		return ISC_R_FAILURE;
180	/* make sure it is safe to increment pointer */
181	if (++tmp > lastchar)
182		return ISC_R_FAILURE;
183
184	/* save pointer to host */
185	pd->host = tmp;
186
187	/* find space after host and change it to a '\0' */
188	tmp = strchr(tmp, ' ');
189	/* verify we found a space */
190	if (tmp == NULL)
191		return ISC_R_FAILURE;
192	/* change the space to a null (string terminator) */
193	tmp[0] = '\0';
194	/* make sure it is safe to increment pointer */
195	if (++tmp > lastchar)
196		return ISC_R_FAILURE;
197
198	/* save pointer to ttl string */
199	ttlStr = tmp;
200
201	/* find space after ttl and change it to a '\0' */
202	tmp = strchr(tmp, ' ');
203	/* verify we found a space */
204	if (tmp == NULL)
205		return ISC_R_FAILURE;
206	/* change the space to a null (string terminator) */
207	tmp[0] = '\0';
208	/* make sure it is safe to increment pointer */
209	if (++tmp > lastchar)
210		return ISC_R_FAILURE;
211
212	/* save pointer to dns type */
213	pd->type = tmp;
214
215	/* find space after type and change it to a '\0' */
216	tmp = strchr(tmp, ' ');
217	/* verify we found a space */
218	if (tmp == NULL)
219		return ISC_R_FAILURE;
220	/* change the space to a null (string terminator) */
221	tmp[0] = '\0';
222	/* make sure it is safe to increment pointer */
223	if (++tmp > lastchar)
224		return ISC_R_FAILURE;
225
226	/* save pointer to remainder of DNS data */
227	pd->data = tmp;
228
229	/* convert ttl string to integer */
230	pd->ttl = strtol(ttlStr, &endp, 10);
231	if (*endp != '\0' || pd->ttl < 0) {
232		isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
233			      DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
234			      "bdbhpt driver ttl must be a postive number");
235		return ISC_R_FAILURE;
236	}
237
238	/* if we get this far everything should have worked. */
239	return ISC_R_SUCCESS;
240}
241
242/*
243 * DLZ methods
244 */
245
246static isc_result_t
247bdbhpt_allowzonexfr(void *driverarg, void *dbdata, const char *name,
248		    const char *client)
249{
250	isc_result_t result;
251	bdbhpt_instance_t *db = (bdbhpt_instance_t *) dbdata;
252	DBT key, data;
253
254	/* check to see if we are authoritative for the zone first. */
255	result = bdbhpt_findzone(driverarg, dbdata, name);
256	if (result != ISC_R_SUCCESS)
257		return (ISC_R_NOTFOUND);
258
259	memset(&key, 0, sizeof(DBT));
260	key.flags = DB_DBT_MALLOC;
261	key.data = strdup(name);
262	if (key.data == NULL) {
263		result = ISC_R_NOMEMORY;
264		goto xfr_cleanup;
265	}
266	key.size = strlen(key.data);
267
268	memset(&data, 0, sizeof(DBT));
269	data.flags = DB_DBT_MALLOC;
270	data.data = strdup(client);
271	if (data.data == NULL) {
272		result = ISC_R_NOMEMORY;
273		goto xfr_cleanup;
274	}
275	data.size = strlen(data.data);
276
277	switch(db->client->get(db->client, NULL, &key, &data, DB_GET_BOTH)) {
278	case DB_NOTFOUND:
279		result = ISC_R_NOTFOUND;
280		break;
281	case 0:
282		result = ISC_R_SUCCESS;
283		break;
284	default:
285		result = ISC_R_FAILURE;
286	}
287
288 xfr_cleanup:
289
290	/* free any memory duplicate string in the key field */
291	if (key.data != NULL)
292		free(key.data);
293
294	/* free any memory allocated to the data field. */
295	if (data.data != NULL)
296		free(data.data);
297
298	return result;
299
300}
301
302/*%
303 * BDB does not allow a secondary index on a database that allows
304 * duplicates.  We have a few options:
305 *
306 * 1) kill speed by having lookup method use a secondary db which
307 * is associated to the primary DB with the DNS data.  Then have
308 * another secondary db for zone transfer which also points to
309 * the dns_data primary.  NO - The  point of this driver is
310 * lookup performance.
311 *
312 * 2) Blow up database size by storing DNS data twice.  Once for
313 * the lookup (dns_data) database, and a second time for the zone
314 * transfer (dns_xfr) database. NO - That would probably require
315 * a larger cache to provide good performance.  Also, that would
316 * make the DB larger on disk potentially slowing it as well.
317 *
318 * 3) Loop through the dns_xfr database with a cursor to get
319 * all the different hosts in a zone.  Then use the zone & host
320 * together to lookup the data in the dns_data database. YES -
321 * This may slow down zone xfr's a little, but that's ok they
322 * don't happen as often and don't need to be as fast. We can
323 * also use this table when deleting a zone (The BDB driver
324 * is read only - the delete would be used during replication
325 * updates by a separate process).
326 */
327
328static isc_result_t
329bdbhpt_allnodes(const char *zone, void *driverarg, void *dbdata,
330		dns_sdlzallnodes_t *allnodes)
331{
332
333	isc_result_t result = ISC_R_NOTFOUND;
334	bdbhpt_instance_t *db = (bdbhpt_instance_t *) dbdata;
335	DBC *xfr_cursor = NULL;
336	DBC *dns_cursor = NULL;
337	DBT xfr_key, xfr_data, dns_key, dns_data;
338	int xfr_flags;
339	int dns_flags;
340	int bdbhptres;
341	bdbhpt_parsed_data_t pd;
342	char *tmp = NULL, *tmp_zone, *tmp_zone_host = NULL;
343
344	UNUSED(driverarg);
345
346	memset(&xfr_key, 0, sizeof(DBT));
347	memset(&xfr_data, 0, sizeof(DBT));
348	memset(&dns_key, 0, sizeof(DBT));
349	memset(&dns_data, 0, sizeof(DBT));
350
351	xfr_key.data = tmp_zone = strdup(zone);
352	if (xfr_key.data == NULL)
353		return (ISC_R_NOMEMORY);
354
355	xfr_key.size = strlen(xfr_key.data);
356
357	/* get a cursor to loop through dns_xfr table */
358	if (db->xfr->cursor(db->xfr, NULL, &xfr_cursor, 0) != 0) {
359		result = ISC_R_FAILURE;
360		goto allnodes_cleanup;
361	}
362
363	/* get a cursor to loop through dns_data table */
364	if (db->data->cursor(db->data, NULL, &dns_cursor, 0) != 0) {
365		result = ISC_R_FAILURE;
366		goto allnodes_cleanup;
367	}
368
369	xfr_flags = DB_SET;
370
371	/* loop through xfr table for specified zone. */
372	while ((bdbhptres = xfr_cursor->c_get(xfr_cursor, &xfr_key, &xfr_data,
373					      xfr_flags)) == 0) {
374
375		xfr_flags = DB_NEXT_DUP;
376
377		/* +1 to allow for space between zone and host names */
378		dns_key.size = xfr_data.size + xfr_key.size + 1;
379
380		/* +1 to allow for null term at end of string. */
381		dns_key.data = tmp_zone_host = malloc(dns_key.size + 1);
382		if (dns_key.data == NULL)
383			goto allnodes_cleanup;
384
385		/*
386		 * construct search key for dns_data.
387		 * zone_name(a space)host_name
388		 */
389		strcpy(dns_key.data, zone);
390		strcat(dns_key.data, " ");
391		strncat(dns_key.data, xfr_data.data, xfr_data.size);
392
393		dns_flags = DB_SET;
394
395		while ((bdbhptres = dns_cursor->c_get(dns_cursor, &dns_key,
396						      &dns_data,
397						      dns_flags)) == 0) {
398
399			dns_flags = DB_NEXT_DUP;
400
401			/* +1 to allow for null term at end of string. */
402			tmp = realloc(tmp, dns_data.size + 1);
403			if (tmp == NULL)
404				goto allnodes_cleanup;
405
406			/* copy data to tmp string, and append null term. */
407			strncpy(tmp, dns_data.data, dns_data.size);
408			tmp[dns_data.size] = '\0';
409
410			/* split string into dns data parts. */
411			if (bdbhpt_parse_data(tmp, &pd) != ISC_R_SUCCESS)
412				goto allnodes_cleanup;
413
414			result = dns_sdlz_putnamedrr(allnodes, pd.host,
415						     pd.type, pd.ttl, pd.data);
416			if (result != ISC_R_SUCCESS)
417				goto allnodes_cleanup;
418
419		}  /* end inner while loop */
420
421		/* clean up memory */
422		if (tmp_zone_host != NULL) {
423			free(tmp_zone_host);
424			tmp_zone_host = NULL;
425		}
426	} /* end outer while loop */
427
428 allnodes_cleanup:
429
430	/* free any memory */
431	if (tmp != NULL)
432		free(tmp);
433
434	if (tmp_zone_host != NULL)
435		free(tmp_zone_host);
436
437	if (tmp_zone != NULL)
438		free(tmp_zone);
439
440	/* get rid of cursors */
441	if (xfr_cursor != NULL)
442		xfr_cursor->c_close(xfr_cursor);
443
444	if (dns_cursor != NULL)
445		dns_cursor->c_close(dns_cursor);
446
447	return result;
448}
449
450/*%
451 * Performs bdbhpt cleanup.
452 * Used by bdbhpt_create if there is an error starting up.
453 * Used by bdbhpt_destroy when the driver is shutting down.
454 */
455
456static void
457bdbhpt_cleanup(bdbhpt_instance_t *db) {
458
459	isc_mem_t *mctx;
460
461	/* close databases */
462	if (db->data != NULL)
463		db->data->close(db->data, 0);
464	if (db->xfr != NULL)
465		db->xfr->close(db->xfr, 0);
466	if (db->zone != NULL)
467		db->zone->close(db->zone, 0);
468	if (db->client != NULL)
469		db->client->close(db->client, 0);
470
471	/* close environment */
472	if (db->dbenv != NULL)
473		db->dbenv->close(db->dbenv, 0);
474
475	/* cleanup memory */
476	if (db->mctx != NULL) {
477		/* save mctx for later */
478		mctx = db->mctx;
479		/* return, and detach the memory */
480		isc_mem_put(mctx, db, sizeof(bdbhpt_instance_t));
481		isc_mem_detach(&mctx);
482	}
483}
484
485static isc_result_t
486bdbhpt_findzone(void *driverarg, void *dbdata, const char *name)
487{
488
489	isc_result_t result;
490	bdbhpt_instance_t *db = (bdbhpt_instance_t *) dbdata;
491	DBT key, data;
492
493	UNUSED(driverarg);
494
495	memset(&key, 0, sizeof(DBT));
496	memset(&data, 0, sizeof(DBT));
497	data.flags = DB_DBT_MALLOC;
498
499	key.data = strdup(name);
500
501	if (key.data == NULL)
502		return (ISC_R_NOMEMORY);
503
504	/*
505	 * reverse string to take advantage of BDB locality of reference
506	 * if we need futher lookups because the zone doesn't match the
507	 * first time.
508	 */
509	key.data = bdbhpt_strrev(key.data);
510	key.size = strlen(key.data);
511
512	switch(db->zone->get(db->zone, NULL, &key, &data, 0)) {
513	case DB_NOTFOUND:
514		result = ISC_R_NOTFOUND;
515		break;
516	case 0:
517		result = ISC_R_SUCCESS;
518		break;
519	default:
520		result = ISC_R_FAILURE;
521	}
522
523	/* free any memory duplicate string in the key field */
524	if (key.data != NULL)
525		free(key.data);
526
527	/* free any memory allocated to the data field. */
528	if (data.data != NULL)
529		free(data.data);
530
531	return result;
532}
533
534static isc_result_t
535bdbhpt_lookup(const char *zone, const char *name, void *driverarg,
536	      void *dbdata, dns_sdlzlookup_t *lookup)
537{
538
539	isc_result_t result = ISC_R_NOTFOUND;
540	bdbhpt_instance_t *db = (bdbhpt_instance_t *) dbdata;
541	DBC *data_cursor = NULL;
542	DBT key, data;
543	int bdbhptres;
544	int flags;
545
546	bdbhpt_parsed_data_t pd;
547	char *tmp = NULL;
548	char *keyStr = NULL;
549
550	UNUSED(driverarg);
551
552	memset(&key, 0, sizeof(DBT));
553	memset(&data, 0, sizeof(DBT));
554
555	key.size = strlen(zone) + strlen(name) + 1;
556
557	/* allocate mem for key */
558	key.data = keyStr = malloc((key.size + 1) * sizeof(char));
559
560	if (keyStr == NULL)
561		return ISC_R_NOMEMORY;
562
563	strcpy(keyStr, zone);
564	strcat(keyStr, " ");
565	strcat(keyStr, name);
566
567	/* get a cursor to loop through data */
568	if (db->data->cursor(db->data, NULL, &data_cursor, 0) != 0) {
569		result = ISC_R_FAILURE;
570		goto lookup_cleanup;
571	}
572
573	result = ISC_R_NOTFOUND;
574
575	flags = DB_SET;
576	while ((bdbhptres = data_cursor->c_get(data_cursor, &key, &data,
577					       flags)) == 0) {
578
579		flags = DB_NEXT_DUP;
580		tmp = realloc(tmp, data.size + 1);
581		if (tmp == NULL)
582			goto lookup_cleanup;
583
584		strncpy(tmp, data.data, data.size);
585		tmp[data.size] = '\0';
586
587		if (bdbhpt_parse_data(tmp, &pd) != ISC_R_SUCCESS)
588			goto lookup_cleanup;
589
590		result = dns_sdlz_putrr(lookup, pd.type, pd.ttl, pd.data);
591
592		if (result != ISC_R_SUCCESS)
593			goto lookup_cleanup;
594	} /* end while loop */
595
596 lookup_cleanup:
597
598	/* get rid of cursor */
599	if (data_cursor != NULL)
600		data_cursor->c_close(data_cursor);
601
602	if (keyStr != NULL)
603		free(keyStr);
604	if (tmp != NULL)
605		free(tmp);
606
607	return result;
608}
609
610/*% Initializes, sets flags and then opens Berkeley databases. */
611
612static isc_result_t
613bdbhpt_opendb(DB_ENV *db_env, DBTYPE db_type, DB **db, const char *db_name,
614	      char *db_file, int flags) {
615
616	int result;
617
618	/* Initialize the database. */
619	if ((result = db_create(db, db_env, 0)) != 0) {
620		isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
621			      DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
622			      "bdbhpt could not initialize %s database. "
623			      "bdbhpt error: %s",
624			      db_name, db_strerror(result));
625		return ISC_R_FAILURE;
626	}
627
628	/* set database flags. */
629	if ((result = (*db)->set_flags(*db, flags)) != 0) {
630		isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
631			      DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
632			      "bdbhpt could not set flags for %s database. "
633			      "bdbhpt error: %s",
634			      db_name, db_strerror(result));
635		return ISC_R_FAILURE;
636	}
637
638	/* open the database. */
639	if ((result = (*db)->open(*db, NULL, db_file, db_name, db_type,
640				  DB_RDONLY | bdbhpt_threads, 0)) != 0) {
641		isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
642			      DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
643			      "bdbhpt could not open %s database in %s. "
644			      "bdbhpt error: %s",
645			      db_name, db_file, db_strerror(result));
646		return ISC_R_FAILURE;
647	}
648
649	return ISC_R_SUCCESS;
650}
651
652static isc_result_t
653bdbhpt_create(const char *dlzname, unsigned int argc, char *argv[],
654	      void *driverarg, void **dbdata)
655{
656	isc_result_t result;
657	int bdbhptres;
658	int bdbFlags = 0;
659	bdbhpt_instance_t *db = NULL;
660
661	UNUSED(dlzname);
662	UNUSED(driverarg);
663
664	/* verify we have 4 arg's passed to the driver */
665	if (argc != 4) {
666		isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
667			      DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
668			      "bdbhpt driver requires at least "
669			      "3 command line args.");
670		return (ISC_R_FAILURE);
671	}
672
673	switch((char) *argv[1]) {
674		/*
675		 * Transactional mode.  Highest safety - lowest speed.
676		 */
677	case 'T':
678	case 't':
679		bdbFlags = DB_INIT_MPOOL | DB_INIT_LOCK |
680			   DB_INIT_LOG | DB_INIT_TXN;
681		isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
682			      DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(1),
683			      "bdbhpt driver using transactional mode.");
684		break;
685		/*
686		 * Concurrent mode.  Lower safety (no rollback) -
687		 * higher speed.
688		 */
689	case 'C':
690	case 'c':
691		bdbFlags = DB_INIT_CDB | DB_INIT_MPOOL;
692		isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
693			      DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(1),
694			      "bdbhpt driver using concurrent mode.");
695		break;
696		/*
697		 * Private mode. No inter-process communication & no locking.
698		 * Lowest saftey - highest speed.
699		 */
700	case 'P':
701	case 'p':
702		bdbFlags = DB_PRIVATE | DB_INIT_MPOOL;
703		isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
704			      DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(1),
705			      "bdbhpt driver using private mode.");
706		break;
707	default:
708		isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
709			      DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
710			      "bdbhpt driver requires the operating mode "
711			      "be set to P or C or T.  You specified '%s'",
712			      argv[1]);
713		return (ISC_R_FAILURE);
714	}
715
716	/* allocate and zero memory for driver structure */
717	db = isc_mem_get(ns_g_mctx, sizeof(bdbhpt_instance_t));
718	if (db == NULL) {
719		isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
720			      DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
721			      "Could not allocate memory for "
722			      "database instance object.");
723		return (ISC_R_NOMEMORY);
724	}
725	memset(db, 0, sizeof(bdbhpt_instance_t));
726
727	/* attach to the memory context */
728	isc_mem_attach(ns_g_mctx, &db->mctx);
729
730	/*
731	 * create bdbhpt environment
732	 * Basically bdbhpt allocates and assigns memory to db->dbenv
733	 */
734	bdbhptres = db_env_create(&db->dbenv, 0);
735	if (bdbhptres != 0) {
736		isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
737			      DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
738			      "bdbhpt environment could not be created. "
739			      "bdbhpt error: %s",
740			      db_strerror(bdbhptres));
741		result = ISC_R_FAILURE;
742		goto init_cleanup;
743	}
744
745	/* open bdbhpt environment */
746	bdbhptres = db->dbenv->open(db->dbenv, argv[2],
747				    bdbFlags | bdbhpt_threads | DB_CREATE, 0);
748	if (bdbhptres != 0) {
749		isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
750			      DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
751			      "bdbhpt environment at '%s' could not be opened."
752			      " bdbhpt error: %s",
753			      argv[2], db_strerror(bdbhptres));
754		result = ISC_R_FAILURE;
755		goto init_cleanup;
756	}
757
758	/* open dlz_data database. */
759	result = bdbhpt_opendb(db->dbenv, DB_UNKNOWN, &db->data,
760			       dlz_data, argv[3], DB_DUP | DB_DUPSORT);
761	if (result != ISC_R_SUCCESS)
762		goto init_cleanup;
763
764	/* open dlz_xfr database. */
765	result = bdbhpt_opendb(db->dbenv, DB_UNKNOWN, &db->xfr,
766			       dlz_xfr, argv[3], DB_DUP | DB_DUPSORT);
767	if (result != ISC_R_SUCCESS)
768		goto init_cleanup;
769
770	/* open dlz_zone database. */
771	result = bdbhpt_opendb(db->dbenv, DB_UNKNOWN, &db->zone,
772			       dlz_zone, argv[3], 0);
773	if (result != ISC_R_SUCCESS)
774		goto init_cleanup;
775
776	/* open dlz_client database. */
777	result = bdbhpt_opendb(db->dbenv, DB_UNKNOWN, &db->client,
778			       dlz_client, argv[3], DB_DUP | DB_DUPSORT);
779	if (result != ISC_R_SUCCESS)
780		goto init_cleanup;
781
782	*dbdata = db;
783
784	return(ISC_R_SUCCESS);
785
786 init_cleanup:
787
788	bdbhpt_cleanup(db);
789	return result;
790}
791
792static void
793bdbhpt_destroy(void *driverarg, void *dbdata)
794{
795	UNUSED(driverarg);
796
797	bdbhpt_cleanup((bdbhpt_instance_t *) dbdata);
798}
799
800/*
801 * bdbhpt_authority not needed as authority data is returned by lookup
802 */
803static dns_sdlzmethods_t dlz_bdbhpt_methods = {
804	bdbhpt_create,
805	bdbhpt_destroy,
806	bdbhpt_findzone,
807	bdbhpt_lookup,
808	NULL,
809	bdbhpt_allnodes,
810	bdbhpt_allowzonexfr,
811	NULL,
812	NULL,
813	NULL,
814	NULL,
815	NULL,
816	NULL,
817	NULL,
818};
819
820/*%
821 * Wrapper around dns_sdlzregister().
822 */
823isc_result_t
824dlz_bdbhpt_init(void) {
825	isc_result_t result;
826
827	/*
828	 * Write debugging message to log
829	 */
830	isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
831		      DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2),
832		      "Registering DLZ bdbhpt driver.");
833
834	result = dns_sdlzregister("bdbhpt", &dlz_bdbhpt_methods, NULL,
835				  DNS_SDLZFLAG_RELATIVEOWNER |
836				  DNS_SDLZFLAG_RELATIVERDATA |
837				  DNS_SDLZFLAG_THREADSAFE,
838				  ns_g_mctx, &dlz_bdbhpt);
839	if (result != ISC_R_SUCCESS) {
840		UNEXPECTED_ERROR(__FILE__, __LINE__,
841				 "dns_sdlzregister() failed: %s",
842				 isc_result_totext(result));
843		result = ISC_R_UNEXPECTED;
844	}
845
846
847	return result;
848}
849
850/*%
851 * Wrapper around dns_sdlzunregister().
852 */
853void
854dlz_bdbhpt_clear(void) {
855
856	/*
857	 * Write debugging message to log
858	 */
859	isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
860		      DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2),
861		      "Unregistering DLZ bdbhpt driver.");
862
863	if (dlz_bdbhpt != NULL)
864		dns_sdlzunregister(&dlz_bdbhpt);
865}
866
867#endif
868