summaryrefslogtreecommitdiffstats
path: root/contrib/dlz/modules/bdbhpt/dlz_bdbhpt_dynamic.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/dlz/modules/bdbhpt/dlz_bdbhpt_dynamic.c')
-rw-r--r--contrib/dlz/modules/bdbhpt/dlz_bdbhpt_dynamic.c826
1 files changed, 826 insertions, 0 deletions
diff --git a/contrib/dlz/modules/bdbhpt/dlz_bdbhpt_dynamic.c b/contrib/dlz/modules/bdbhpt/dlz_bdbhpt_dynamic.c
new file mode 100644
index 0000000..39112a4
--- /dev/null
+++ b/contrib/dlz/modules/bdbhpt/dlz_bdbhpt_dynamic.c
@@ -0,0 +1,826 @@
+/*
+ * Copyright (C) 2002 Stichting NLnet, Netherlands, stichting@nlnet.nl.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the
+ * above copyright notice and this permission notice appear in all
+ * copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND STICHTING NLNET
+ * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+ * STICHTING NLNET BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
+ * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE
+ * USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * The development of Dynamically Loadable Zones (DLZ) for Bind 9 was
+ * conceived and contributed by Rob Butler.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the
+ * above copyright notice and this permission notice appear in all
+ * copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ROB BUTLER
+ * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+ * ROB BUTLER BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
+ * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE
+ * USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC")
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * This is simply a merge of Andrew Tridgell's dlz_example.c and the
+ * original bdb_bdbhpt_driver.c
+ *
+ * This provides the externally loadable bdbhpt DLZ driver, without
+ * update support
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+
+#include <db.h>
+
+#include "dlz_minimal.h"
+
+/* should the bdb driver use threads. */
+#ifdef ISC_PLATFORM_USETHREADS
+#define bdbhpt_threads DB_THREAD
+#else
+#define bdbhpt_threads 0
+#endif
+
+/* bdbhpt database names */
+#define dlz_data "dns_data"
+#define dlz_zone "dns_zone"
+#define dlz_xfr "dns_xfr"
+#define dlz_client "dns_client"
+
+#define dlz_bdbhpt_dynamic_version "0.1"
+
+/*
+ * This structure contains all our DB handles and helper functions we
+ * inherit from the dlz_dlopen driver
+ *
+ */
+typedef struct bdbhpt_instance {
+ DB_ENV *dbenv; /* bdbhpt environment */
+ DB *data; /* dns_data database handle */
+ DB *zone; /* zone database handle */
+ DB *xfr; /* zone xfr database handle */
+ DB *client; /* client database handle */
+
+ /* Helper functions from the dlz_dlopen driver */
+ log_t *log;
+ dns_sdlz_putrr_t *putrr;
+ dns_sdlz_putnamedrr_t *putnamedrr;
+ dns_dlz_writeablezone_t *writeable_zone;
+} bdbhpt_instance_t;
+
+typedef struct bdbhpt_parsed_data {
+ char *host;
+ char *type;
+ int ttl;
+ char *data;
+} bdbhpt_parsed_data_t;
+
+static void
+b9_add_helper(struct bdbhpt_instance *db, const char *helper_name, void *ptr);
+
+/*%
+ * Reverses a string in place.
+ */
+static char
+*bdbhpt_strrev(char *str) {
+ char *p1, *p2;
+
+ if (! str || ! *str)
+ return str;
+ for (p1 = str, p2 = str + strlen(str) - 1; p2 > p1; ++p1, --p2) {
+ *p1 ^= *p2;
+ *p2 ^= *p1;
+ *p1 ^= *p2;
+ }
+ return str;
+}
+
+/*%
+ * Parses the DBT from the Berkeley DB into a parsed_data record
+ * The parsed_data record should be allocated before and passed into the
+ * bdbhpt_parse_data function. The char (type & data) fields should not
+ * be "free"d as that memory is part of the DBT data field. It will be
+ * "free"d when the DBT is freed.
+ */
+
+static isc_result_t
+bdbhpt_parse_data(log_t *log, char *in, bdbhpt_parsed_data_t *pd) {
+
+ char *endp, *ttlStr;
+ char *tmp = in;
+ char *lastchar = (char *) &tmp[strlen(tmp)];
+
+ /*%
+ * String should be formatted as:
+ * replication_id
+ * (a space)
+ * host_name
+ * (a space)
+ * ttl
+ * (a space)
+ * type
+ * (a space)
+ * remaining data
+ *
+ * examples:
+ *
+ * 9191 host 10 A 127.0.0.1
+ * server1_212 host 10 A 127.0.0.2
+ * {xxxx-xxxx-xxxx-xxxx-xxxx} host 10 MX 20 mail.example.com
+ */
+
+ /*
+ * we don't need the replication id, so don't
+ * bother saving a pointer to it.
+ */
+
+ /* find space after replication id */
+ tmp = strchr(tmp, ' ');
+ /* verify we found a space */
+ if (tmp == NULL)
+ return ISC_R_FAILURE;
+ /* make sure it is safe to increment pointer */
+ if (++tmp > lastchar)
+ return ISC_R_FAILURE;
+
+ /* save pointer to host */
+ pd->host = tmp;
+
+ /* find space after host and change it to a '\0' */
+ tmp = strchr(tmp, ' ');
+ /* verify we found a space */
+ if (tmp == NULL)
+ return ISC_R_FAILURE;
+ /* change the space to a null (string terminator) */
+ tmp[0] = '\0';
+ /* make sure it is safe to increment pointer */
+ if (++tmp > lastchar)
+ return ISC_R_FAILURE;
+
+ /* save pointer to ttl string */
+ ttlStr = tmp;
+
+ /* find space after ttl and change it to a '\0' */
+ tmp = strchr(tmp, ' ');
+ /* verify we found a space */
+ if (tmp == NULL)
+ return ISC_R_FAILURE;
+ /* change the space to a null (string terminator) */
+ tmp[0] = '\0';
+ /* make sure it is safe to increment pointer */
+ if (++tmp > lastchar)
+ return ISC_R_FAILURE;
+
+ /* save pointer to dns type */
+ pd->type = tmp;
+
+ /* find space after type and change it to a '\0' */
+ tmp = strchr(tmp, ' ');
+ /* verify we found a space */
+ if (tmp == NULL)
+ return ISC_R_FAILURE;
+ /* change the space to a null (string terminator) */
+ tmp[0] = '\0';
+ /* make sure it is safe to increment pointer */
+ if (++tmp > lastchar)
+ return ISC_R_FAILURE;
+
+ /* save pointer to remainder of DNS data */
+ pd->data = tmp;
+
+ /* convert ttl string to integer */
+ pd->ttl = strtol(ttlStr, &endp, 10);
+ if (*endp != '\0' || pd->ttl < 0) {
+ log(ISC_LOG_ERROR,
+ "bdbhpt_dynamic: "
+ "ttl must be a positive number");
+ return ISC_R_FAILURE;
+ }
+
+ /* if we get this far everything should have worked. */
+ return ISC_R_SUCCESS;
+}
+
+/*
+ * See if a zone transfer is allowed
+ */
+isc_result_t
+dlz_allowzonexfr(void *dbdata, const char *name, const char *client) {
+ isc_result_t result;
+ bdbhpt_instance_t *db = (bdbhpt_instance_t *) dbdata;
+ DBT key, data;
+
+ /* check to see if we are authoritative for the zone first. */
+#if DLZ_DLOPEN_VERSION >= 3
+ result = dlz_findzonedb(dbdata, name, NULL, NULL);
+#else
+ result = dlz_findzonedb(dbdata, name);
+#endif
+ if (result != ISC_R_SUCCESS)
+ return (ISC_R_NOTFOUND);
+
+ memset(&key, 0, sizeof(DBT));
+ key.flags = DB_DBT_MALLOC;
+ key.data = strdup(name);
+ if (key.data == NULL) {
+ result = ISC_R_NOMEMORY;
+ goto xfr_cleanup;
+ }
+ key.size = strlen(key.data);
+
+ memset(&data, 0, sizeof(DBT));
+ data.flags = DB_DBT_MALLOC;
+ data.data = strdup(client);
+ if (data.data == NULL) {
+ result = ISC_R_NOMEMORY;
+ goto xfr_cleanup;
+ }
+ data.size = strlen(data.data);
+
+ switch(db->client->get(db->client, NULL, &key, &data, DB_GET_BOTH)) {
+ case DB_NOTFOUND:
+ result = ISC_R_NOTFOUND;
+ break;
+ case 0:
+ result = ISC_R_SUCCESS;
+ break;
+ default:
+ result = ISC_R_FAILURE;
+ }
+
+ xfr_cleanup:
+ /* free any memory duplicate string in the key field */
+ if (key.data != NULL)
+ free(key.data);
+
+ /* free any memory allocated to the data field. */
+ if (data.data != NULL)
+ free(data.data);
+
+ return result;
+}
+
+/*%
+ * Perform a zone transfer
+ *
+ * BDB does not allow a secondary index on a database that allows
+ * duplicates. We have a few options:
+ *
+ * 1) kill speed by having lookup method use a secondary db which
+ * is associated to the primary DB with the DNS data. Then have
+ * another secondary db for zone transfer which also points to
+ * the dns_data primary. NO - The point of this driver is
+ * lookup performance.
+ *
+ * 2) Blow up database size by storing DNS data twice. Once for
+ * the lookup (dns_data) database, and a second time for the zone
+ * transfer (dns_xfr) database. NO - That would probably require
+ * a larger cache to provide good performance. Also, that would
+ * make the DB larger on disk potentially slowing it as well.
+ *
+ * 3) Loop through the dns_xfr database with a cursor to get
+ * all the different hosts in a zone. Then use the zone & host
+ * together to lookup the data in the dns_data database. YES -
+ * This may slow down zone xfr's a little, but that's ok they
+ * don't happen as often and don't need to be as fast. We can
+ * also use this table when deleting a zone (The BDB driver
+ * is read only - the delete would be used during replication
+ * updates by a separate process).
+ */
+isc_result_t
+dlz_allnodes(const char *zone, void *dbdata, dns_sdlzallnodes_t *allnodes) {
+ isc_result_t result = ISC_R_NOTFOUND;
+ bdbhpt_instance_t *db = (bdbhpt_instance_t *) dbdata;
+ DBC *xfr_cursor = NULL;
+ DBC *dns_cursor = NULL;
+ DBT xfr_key, xfr_data, dns_key, dns_data;
+ int xfr_flags;
+ int dns_flags;
+ int bdbhptres;
+ bdbhpt_parsed_data_t pd;
+ char *tmp = NULL, *tmp_zone, *tmp_zone_host = NULL;
+
+ memset(&xfr_key, 0, sizeof(DBT));
+ memset(&xfr_data, 0, sizeof(DBT));
+ memset(&dns_key, 0, sizeof(DBT));
+ memset(&dns_data, 0, sizeof(DBT));
+
+ xfr_key.data = tmp_zone = strdup(zone);
+ if (xfr_key.data == NULL)
+ return (ISC_R_NOMEMORY);
+
+ xfr_key.size = strlen(xfr_key.data);
+
+ /* get a cursor to loop through dns_xfr table */
+ if (db->xfr->cursor(db->xfr, NULL, &xfr_cursor, 0) != 0) {
+ result = ISC_R_FAILURE;
+ goto allnodes_cleanup;
+ }
+
+ /* get a cursor to loop through dns_data table */
+ if (db->data->cursor(db->data, NULL, &dns_cursor, 0) != 0) {
+ result = ISC_R_FAILURE;
+ goto allnodes_cleanup;
+ }
+
+ xfr_flags = DB_SET;
+
+ /* loop through xfr table for specified zone. */
+ while ((bdbhptres = xfr_cursor->c_get(xfr_cursor, &xfr_key,
+ &xfr_data, xfr_flags)) == 0)
+ {
+ xfr_flags = DB_NEXT_DUP;
+
+ /* +1 to allow for space between zone and host names */
+ dns_key.size = xfr_data.size + xfr_key.size + 1;
+
+ /* +1 to allow for null term at end of string. */
+ dns_key.data = tmp_zone_host = malloc(dns_key.size + 1);
+ if (dns_key.data == NULL)
+ goto allnodes_cleanup;
+
+ /*
+ * construct search key for dns_data.
+ * zone_name(a space)host_name
+ */
+ strcpy(dns_key.data, zone);
+ strcat(dns_key.data, " ");
+ strncat(dns_key.data, xfr_data.data, xfr_data.size);
+
+ dns_flags = DB_SET;
+
+ while ((bdbhptres = dns_cursor->c_get(dns_cursor,
+ &dns_key,
+ &dns_data,
+ dns_flags)) == 0)
+ {
+ dns_flags = DB_NEXT_DUP;
+
+ /* +1 to allow for null term at end of string. */
+ tmp = realloc(tmp, dns_data.size + 1);
+ if (tmp == NULL)
+ goto allnodes_cleanup;
+
+ /* copy data to tmp string, and append null term. */
+ strncpy(tmp, dns_data.data, dns_data.size);
+ tmp[dns_data.size] = '\0';
+
+ /* split string into dns data parts. */
+ if (bdbhpt_parse_data(db->log,
+ tmp, &pd) != ISC_R_SUCCESS)
+ goto allnodes_cleanup;
+ result = db->putnamedrr(allnodes, pd.host,
+ pd.type, pd.ttl, pd.data);
+ if (result != ISC_R_SUCCESS)
+ goto allnodes_cleanup;
+
+ } /* end inner while loop */
+
+ /* clean up memory */
+ if (tmp_zone_host != NULL) {
+ free(tmp_zone_host);
+ tmp_zone_host = NULL;
+ }
+ } /* end outer while loop */
+
+ allnodes_cleanup:
+ /* free any memory */
+ if (tmp != NULL)
+ free(tmp);
+
+ if (tmp_zone_host != NULL)
+ free(tmp_zone_host);
+
+ if (tmp_zone != NULL)
+ free(tmp_zone);
+
+ /* get rid of cursors */
+ if (xfr_cursor != NULL)
+ xfr_cursor->c_close(xfr_cursor);
+
+ if (dns_cursor != NULL)
+ dns_cursor->c_close(dns_cursor);
+
+ return result;
+}
+
+/*%
+ * Performs bdbhpt cleanup.
+ * Used by bdbhpt_create if there is an error starting up.
+ * Used by bdbhpt_destroy when the driver is shutting down.
+ */
+static void
+bdbhpt_cleanup(bdbhpt_instance_t *db) {
+ /* close databases */
+ if (db->data != NULL)
+ db->data->close(db->data, 0);
+ if (db->xfr != NULL)
+ db->xfr->close(db->xfr, 0);
+ if (db->zone != NULL)
+ db->zone->close(db->zone, 0);
+ if (db->client != NULL)
+ db->client->close(db->client, 0);
+
+ /* close environment */
+ if (db->dbenv != NULL)
+ db->dbenv->close(db->dbenv, 0);
+}
+
+/*
+ * See if we handle a given zone
+ */
+#if DLZ_DLOPEN_VERSION < 3
+isc_result_t
+dlz_findzonedb(void *dbdata, const char *name)
+#else
+isc_result_t
+dlz_findzonedb(void *dbdata, const char *name,
+ dns_clientinfomethods_t *methods,
+ dns_clientinfo_t *clientinfo)
+#endif
+{
+ isc_result_t result;
+ bdbhpt_instance_t *db = (bdbhpt_instance_t *) dbdata;
+ DBT key, data;
+
+ memset(&key, 0, sizeof(DBT));
+ memset(&data, 0, sizeof(DBT));
+ data.flags = DB_DBT_MALLOC;
+
+#if DLZ_DLOPEN_VERSION >= 3
+ UNUSED(methods);
+ UNUSED(clientinfo);
+#endif
+
+ key.data = strdup(name);
+
+ if (key.data == NULL)
+ return (ISC_R_NOMEMORY);
+
+ /*
+ * reverse string to take advantage of BDB locality of reference
+ * if we need futher lookups because the zone doesn't match the
+ * first time.
+ */
+ key.data = bdbhpt_strrev(key.data);
+ key.size = strlen(key.data);
+
+ switch(db->zone->get(db->zone, NULL, &key, &data, 0)) {
+ case DB_NOTFOUND:
+ result = ISC_R_NOTFOUND;
+ break;
+ case 0:
+ result = ISC_R_SUCCESS;
+ break;
+ default:
+ result = ISC_R_FAILURE;
+ }
+
+ /* free any memory duplicate string in the key field */
+ if (key.data != NULL)
+ free(key.data);
+
+ /* free any memory allocated to the data field. */
+ if (data.data != NULL)
+ free(data.data);
+
+ return result;
+}
+
+/*
+ * Look up one record in the database.
+ *
+ */
+#if DLZ_DLOPEN_VERSION == 1
+isc_result_t dlz_lookup(const char *zone, const char *name,
+ void *dbdata, dns_sdlzlookup_t *lookup)
+#else
+isc_result_t dlz_lookup(const char *zone, const char *name, void *dbdata,
+ dns_sdlzlookup_t *lookup,
+ dns_clientinfomethods_t *methods,
+ dns_clientinfo_t *clientinfo)
+#endif
+{
+ isc_result_t result = ISC_R_NOTFOUND;
+ bdbhpt_instance_t *db = (bdbhpt_instance_t *) dbdata;
+ DBC *data_cursor = NULL;
+ DBT key, data;
+ int bdbhptres;
+ int flags;
+
+ bdbhpt_parsed_data_t pd;
+ char *tmp = NULL;
+ char *keyStr = NULL;
+
+#if DLZ_DLOPEN_VERSION >= 2
+ UNUSED(methods);
+ UNUSED(clientinfo);
+#endif
+
+ memset(&key, 0, sizeof(DBT));
+ memset(&data, 0, sizeof(DBT));
+
+ key.size = strlen(zone) + strlen(name) + 1;
+
+ /* allocate mem for key */
+ key.data = keyStr = malloc((key.size + 1) * sizeof(char));
+
+ if (keyStr == NULL)
+ return ISC_R_NOMEMORY;
+
+ strcpy(keyStr, zone);
+ strcat(keyStr, " ");
+ strcat(keyStr, name);
+
+ /* get a cursor to loop through data */
+ if (db->data->cursor(db->data, NULL, &data_cursor, 0) != 0) {
+ result = ISC_R_FAILURE;
+ goto lookup_cleanup;
+ }
+
+ result = ISC_R_NOTFOUND;
+
+ flags = DB_SET;
+ while ((bdbhptres = data_cursor->c_get(data_cursor, &key, &data,
+ flags)) == 0)
+ {
+ flags = DB_NEXT_DUP;
+ tmp = realloc(tmp, data.size + 1);
+ if (tmp == NULL)
+ goto lookup_cleanup;
+
+ strncpy(tmp, data.data, data.size);
+ tmp[data.size] = '\0';
+
+ if (bdbhpt_parse_data(db->log, tmp, &pd) != ISC_R_SUCCESS)
+ goto lookup_cleanup;
+
+ result = db->putrr(lookup, pd.type, pd.ttl, pd.data);
+ if (result != ISC_R_SUCCESS)
+ goto lookup_cleanup;
+ } /* end while loop */
+
+ lookup_cleanup:
+ /* get rid of cursor */
+ if (data_cursor != NULL)
+ data_cursor->c_close(data_cursor);
+
+ if (keyStr != NULL)
+ free(keyStr);
+ if (tmp != NULL)
+ free(tmp);
+
+ return result;
+}
+
+/*%
+ * Initialises, sets flags and then opens Berkeley databases.
+ */
+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)
+{
+ int result;
+
+ /* Initialise the database. */
+ if ((result = db_create(db, db_env, 0)) != 0) {
+ log(ISC_LOG_ERROR,
+ "bdbhpt_dynamic: could not initialize %s database. "
+ "BerkeleyDB error: %s",
+ db_name, db_strerror(result));
+ return ISC_R_FAILURE;
+ }
+
+ /* set database flags. */
+ if ((result = (*db)->set_flags(*db, flags)) != 0) {
+ log(ISC_LOG_ERROR,
+ "bdbhpt_dynamic: could not set flags for %s database. "
+ "BerkeleyDB error: %s",
+ db_name, db_strerror(result));
+ return ISC_R_FAILURE;
+ }
+
+ /* open the database. */
+ if ((result = (*db)->open(*db, NULL, db_file, db_name, db_type,
+ DB_RDONLY | bdbhpt_threads, 0)) != 0) {
+ log(ISC_LOG_ERROR,
+ "bdbhpt_dynamic: could not open %s database in %s. "
+ "BerkeleyDB error: %s",
+ db_name, db_file, db_strerror(result));
+ return ISC_R_FAILURE;
+ }
+
+ return ISC_R_SUCCESS;
+}
+
+
+/*
+ * Called to initialize the driver
+ */
+isc_result_t
+dlz_create(const char *dlzname, unsigned int argc, char *argv[],
+ void **dbdata, ...)
+{
+ isc_result_t result;
+ int bdbhptres;
+ int bdbFlags = 0;
+ bdbhpt_instance_t *db = NULL;
+
+ const char *helper_name;
+ va_list ap;
+
+ UNUSED(dlzname);
+
+ /* Allocate memory for our db structures and helper functions */
+ db = calloc(1, sizeof(struct bdbhpt_instance));
+ if (db == NULL)
+ return (ISC_R_NOMEMORY);
+
+ /* Fill in the helper functions */
+ va_start(ap, dbdata);
+ while ((helper_name = va_arg(ap, const char *)) != NULL)
+ b9_add_helper(db, helper_name, va_arg(ap, void*));
+ va_end(ap);
+
+ /* verify we have 4 arg's passed to the driver */
+ if (argc != 4) {
+ db->log(ISC_LOG_ERROR,
+ "bdbhpt_dynamic: please supply 3 command line args. "
+ "You supplied: %s", argc);
+ return (ISC_R_FAILURE);
+ }
+
+ switch((char) *argv[1]) {
+ /*
+ * Transactional mode. Highest safety - lowest speed.
+ */
+ case 'T':
+ case 't':
+ bdbFlags = DB_INIT_MPOOL | DB_INIT_LOCK |
+ DB_INIT_LOG | DB_INIT_TXN;
+ db->log(ISC_LOG_INFO,
+ "bdbhpt_dynamic: using transactional mode.");
+ break;
+
+ /*
+ * Concurrent mode. Lower safety (no rollback) -
+ * higher speed.
+ */
+ case 'C':
+ case 'c':
+ bdbFlags = DB_INIT_CDB | DB_INIT_MPOOL;
+ db->log(ISC_LOG_INFO,
+ "bdbhpt_dynamic: using concurrent mode.");
+ break;
+
+ /*
+ * Private mode. No inter-process communication & no locking.
+ * Lowest saftey - highest speed.
+ */
+ case 'P':
+ case 'p':
+ bdbFlags = DB_PRIVATE | DB_INIT_MPOOL;
+ db->log(ISC_LOG_INFO,
+ "bdbhpt_dynamic: using private mode.");
+ break;
+ default:
+ db->log(ISC_LOG_ERROR,
+ "bdbhpt_dynamic: "
+ "operating mode must be set to P or C or T. "
+ "You specified '%s'", argv[1]);
+ return (ISC_R_FAILURE);
+ }
+
+ /*
+ * create bdbhpt environment
+ * Basically bdbhpt allocates and assigns memory to db->dbenv
+ */
+ bdbhptres = db_env_create(&db->dbenv, 0);
+ if (bdbhptres != 0) {
+ db->log(ISC_LOG_ERROR,
+ "bdbhpt_dynamic: db environment could not be created. "
+ "BerkeleyDB error: %s", db_strerror(bdbhptres));
+ result = ISC_R_FAILURE;
+ goto init_cleanup;
+ }
+
+ /* open bdbhpt environment */
+ bdbhptres = db->dbenv->open(db->dbenv, argv[2],
+ bdbFlags | bdbhpt_threads | DB_CREATE, 0);
+ if (bdbhptres != 0) {
+ db->log(ISC_LOG_ERROR,
+ "bdbhpt_dynamic: "
+ "db environment at '%s' could not be opened. "
+ "BerkeleyDB error: %s",
+ argv[2], db_strerror(bdbhptres));
+ result = ISC_R_FAILURE;
+ goto init_cleanup;
+ }
+
+ /* open dlz_data database. */
+ result = bdbhpt_opendb(db->log, db->dbenv, DB_UNKNOWN, &db->data,
+ dlz_data, argv[3], DB_DUP | DB_DUPSORT);
+ if (result != ISC_R_SUCCESS)
+ goto init_cleanup;
+
+ /* open dlz_xfr database. */
+ result = bdbhpt_opendb(db->log, db->dbenv, DB_UNKNOWN, &db->xfr,
+ dlz_xfr, argv[3], DB_DUP | DB_DUPSORT);
+ if (result != ISC_R_SUCCESS)
+ goto init_cleanup;
+
+ /* open dlz_zone database. */
+ result = bdbhpt_opendb(db->log, db->dbenv, DB_UNKNOWN, &db->zone,
+ dlz_zone, argv[3], 0);
+ if (result != ISC_R_SUCCESS)
+ goto init_cleanup;
+
+ /* open dlz_client database. */
+ result = bdbhpt_opendb(db->log, db->dbenv, DB_UNKNOWN, &db->client,
+ dlz_client, argv[3], DB_DUP | DB_DUPSORT);
+ if (result != ISC_R_SUCCESS)
+ goto init_cleanup;
+
+ *dbdata = db;
+
+ db->log(ISC_LOG_INFO,
+ "bdbhpt_dynamic: version %s, started",
+ dlz_bdbhpt_dynamic_version);
+ return(ISC_R_SUCCESS);
+
+ init_cleanup:
+ bdbhpt_cleanup(db);
+ return result;
+}
+
+/*
+ * Shut down the backend
+ */
+void
+dlz_destroy(void *dbdata) {
+ struct bdbhpt_instance *db = (struct bdbhpt_instance *)dbdata;
+
+ db->log(ISC_LOG_INFO,
+ "dlz_bdbhpt_dynamic (%s): shutting down",
+ dlz_bdbhpt_dynamic_version);
+ bdbhpt_cleanup((bdbhpt_instance_t *) dbdata);
+ free(db);
+}
+
+/*
+ * Return the version of the API
+ */
+int
+dlz_version(unsigned int *flags) {
+ UNUSED(flags);
+ return (DLZ_DLOPEN_VERSION);
+}
+
+/*
+ * Register a helper function from the bind9 dlz_dlopen driver
+ */
+static void
+b9_add_helper(struct bdbhpt_instance *db, const char *helper_name, void *ptr) {
+ if (strcmp(helper_name, "log") == 0)
+ db->log = (log_t *)ptr;
+ if (strcmp(helper_name, "putrr") == 0)
+ db->putrr = (dns_sdlz_putrr_t *)ptr;
+ if (strcmp(helper_name, "putnamedrr") == 0)
+ db->putnamedrr = (dns_sdlz_putnamedrr_t *)ptr;
+ if (strcmp(helper_name, "writeable_zone") == 0)
+ db->writeable_zone = (dns_dlz_writeablezone_t *)ptr;
+}
+