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