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