+1913. [func] Integrate contibuted DLZ code into named. [RT #11382]
+
1912. [port] aix: atomic locking for powerpc. [RT #15020]
1911. [bug] Update windows socket code. [RT #14965]
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: check-tool.c,v 1.19 2005/08/24 23:53:54 marka Exp $ */
+/* $Id: check-tool.c,v 1.20 2005/09/05 00:10:51 marka Exp $ */
/*! \file */
dns_zone_setchecksrv(zone, checksrv);
CHECK(dns_zone_load(zone));
- if (zonep != NULL){
+ if (zonep != NULL) {
*zonep = zone;
zone = NULL;
}
# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
# PERFORMANCE OF THIS SOFTWARE.
-# $Id: Makefile.in,v 1.86 2005/01/12 01:56:06 marka Exp $
+# $Id: Makefile.in,v 1.87 2005/09/05 00:10:51 marka Exp $
srcdir = @srcdir@
VPATH = @srcdir@
DBDRIVER_INCLUDES =
DBDRIVER_LIBS =
+DLZ_DRIVER_DIR = ${top_srcdir}/contrib/dlz/drivers
+
+DLZDRIVER_OBJS = @DLZ_DRIVER_OBJS@
+DLZDRIVER_SRCS = @DLZ_DRIVER_SRCS@
+DLZDRIVER_INCLUDES = @DLZ_DRIVER_INCLUDES@
+DLZDRIVER_LIBS = @DLZ_DRIVER_LIBS@
+
CINCLUDES = -I${srcdir}/include -I${srcdir}/unix/include \
${LWRES_INCLUDES} ${DNS_INCLUDES} ${BIND9_INCLUDES} \
${ISCCFG_INCLUDES} ${ISCCC_INCLUDES} ${ISC_INCLUDES} \
- ${DBDRIVER_INCLUDES}
+ ${DLZDRIVER_INCLUDES} ${DBDRIVER_INCLUDES}
+
+CDEFINES = @USE_DLZ@
-CDEFINES =
CWARNINGS =
DNSLIBS = ../../lib/dns/libdns.@A@ @DNS_CRYPTO_LIBS@
${ISCCFGDEPLIBS} ${ISCCCDEPLIBS} ${ISCDEPLIBS}
LIBS = ${LWRESLIBS} ${DNSLIBS} ${BIND9LIBS} \
- ${ISCCFGLIBS} ${ISCCCLIBS} ${ISCLIBS} ${DBDRIVER_LIBS} @LIBS@
+ ${ISCCFGLIBS} ${ISCCCLIBS} ${ISCLIBS} \
+ ${DLZDRIVER_LIBS} ${DBDRIVER_LIBS} @LIBS@
SUBDIRS = unix
zoneconf.@O@ \
lwaddr.@O@ lwresd.@O@ lwdclient.@O@ lwderror.@O@ lwdgabn.@O@ \
lwdgnba.@O@ lwdgrbn.@O@ lwdnoop.@O@ lwsearch.@O@ \
- $(DBDRIVER_OBJS)
+ ${DLZDRIVER_OBJS} ${DBDRIVER_OBJS}
UOBJS = unix/os.@O@
zoneconf.c \
lwaddr.c lwresd.c lwdclient.c lwderror.c lwdgabn.c \
lwdgnba.c lwdgrbn.c lwdnoop.c lwsearch.c \
- $(DBDRIVER_SRCS)
+ ${DLZDRIVER_SRCS} ${DBDRIVER_SRCS}
MANPAGES = named.8 lwresd.8 named.conf.5
${INSTALL_DATA} ${srcdir}/lwresd.8 ${DESTDIR}${mandir}/man8
${INSTALL_DATA} ${srcdir}/named.conf.5 ${DESTDIR}${mandir}/man5
+@DLZ_DRIVER_RULES@
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: main.c,v 1.147 2005/06/10 07:00:19 marka Exp $ */
+/* $Id: main.c,v 1.148 2005/09/05 00:10:52 marka Exp $ */
/*! \file */
*/
/* #include "xxdb.h" */
+/*
+ * Include DLZ drivers if appropriate.
+ */
+#ifdef DLZ
+#include <dlz/dlz_drivers.h>
+#endif
+
static isc_boolean_t want_stats = ISC_FALSE;
static char program_name[ISC_DIR_NAMEMAX] = "named";
static char absolute_conffile[ISC_DIR_PATHMAX];
*/
/* xxdb_init(); */
+#ifdef DLZ
+ /*
+ * Registyer any DLZ drivers.
+ */
+ result = dlz_drivers_init();
+ if (result != ISC_R_SUCCESS)
+ ns_main_earlyfatal("dlz_drivers_init() failed: %s",
+ isc_result_totext(result));
+#endif
+
ns_server_create(ns_g_mctx, &ns_g_server);
}
*/
/* xxdb_clear(); */
+#ifdef DLZ
+ /*
+ * Unregister any DLZ drivers.
+ */
+ dlz_drivers_clear();
+#endif
+
isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_MAIN,
ISC_LOG_NOTICE, "exiting");
ns_log_shutdown();
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: query.c,v 1.272 2005/08/18 00:57:26 marka Exp $ */
+/* $Id: query.c,v 1.273 2005/09/05 00:10:52 marka Exp $ */
/*! \file */
#include <dns/adb.h>
#include <dns/byaddr.h>
#include <dns/db.h>
+#ifdef DLZ
+#include <dns/dlz.h>
+#endif
#include <dns/events.h>
#include <dns/message.h>
#include <dns/ncache.h>
client->query.authdb = NULL;
client->query.authzone = NULL;
client->query.authdbset = ISC_FALSE;
- client->query.isreferral = ISC_FALSE;
+ client->query.isreferral = ISC_FALSE;
query_reset(client, ISC_FALSE);
result = query_newdbversion(client, 3);
if (result != ISC_R_SUCCESS) {
/*
* This limits our searching to the zone where the first name
* (the query target) was looked for. This prevents following
- * CNAMES or DNAMES into other zones and prevents returning
+ * CNAMES or DNAMES into other zones and prevents returning
* additional data from other zones.
*/
if (!client->view->additionalfromauth &&
ISC_LOG_DEBUG(3),
"%s approved", msg);
}
- } else {
+ } else {
ns_client_aclmsg("query", name, qtype,
client->view->rdclass,
msg, sizeof(msg));
if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH)
result = dns_zone_getdb(zone, &db);
- if (result != ISC_R_SUCCESS)
+ if (result != ISC_R_SUCCESS)
goto fail;
result = query_validatezonedb(client, name, qtype, options, zone, db,
if (check_acl) {
isc_boolean_t log = ISC_TF((options & DNS_GETDB_NOLOG) == 0);
char msg[NS_CLIENT_ACLMSGSIZE("query (cache)")];
-
+
result = ns_client_checkaclsilent(client,
client->view->queryacl,
ISC_TRUE);
{
isc_result_t result;
+#ifdef DLZ
+ isc_result_t tresult;
+ unsigned int namelabels;
+ unsigned int zonelabels;
+ dns_zone_t *zone = NULL;
+ dns_db_t *tdbp;
+
+ REQUIRE(zonep != NULL && *zonep == NULL);
+
+ tdbp = NULL;
+
+ /* Calculate how many labels are in name. */
+ namelabels = dns_name_countlabels(name);
+ zonelabels = 0;
+
+ /* Try to find name in bind's standard database. */
+ result = query_getzonedb(client, name, qtype, options, &zone,
+ dbp, versionp);
+
+ /* See how many labels are in the zone's name. */
+ if (result == ISC_R_SUCCESS && zone != NULL)
+ zonelabels = dns_name_countlabels(dns_zone_getorigin(zone));
+ /*
+ * If # zone labels < # name labels, try to find an even better match
+ * Only try if a DLZ driver is loaded for this view
+ */
+ if (zonelabels < namelabels && client->view->dlzdatabase != NULL) {
+ tresult = dns_dlzfindzone(client->view, name,
+ zonelabels, &tdbp);
+ /* If we successful, we found a better match. */
+ if (tresult == ISC_R_SUCCESS) {
+ /*
+ * If the previous search returned a zone, detach it.
+ */
+ if (zone != NULL)
+ dns_zone_detach(&zone);
+
+ /*
+ * If the previous search returned a database,
+ * detach it.
+ */
+ if (*dbp != NULL)
+ dns_db_detach(dbp);
+
+ /*
+ * If the previous search returned a version, clear it.
+ */
+ *versionp = NULL;
+
+ /*
+ * Get our database version.
+ */
+ dns_db_currentversion(tdbp, versionp);
+
+ /*
+ * Be sure to return our database.
+ */
+ *dbp = tdbp;
+
+ /*
+ * We return a null zone, No stats for DLZ zones.
+ */
+ zone = NULL;
+ result = tresult;
+ }
+ }
+#else
result = query_getzonedb(client, name, qtype, options,
zonep, dbp, versionp);
+#endif
+
+ /* If successfull, Transfer ownership of zone. */
if (result == ISC_R_SUCCESS) {
+#ifdef DLZ
+ *zonep = zone;
+#endif
+ /*
+ * If neither attempt above succeeded, return the cache instead
+ */
*is_zonep = ISC_TRUE;
} else if (result == ISC_R_NOTFOUND) {
result = query_getcachedb(client, name, qtype, dbp, options);
*/
goto try_glue;
- result = dns_db_find(db, name, version, type, client->query.dboptions,
+ result = dns_db_find(db, name, version, type, client->query.dboptions,
client->now, &node, fname, rdataset,
sigrdataset);
if (result == ISC_R_SUCCESS)
* recursing to add address records, which in turn can cause
* recursion to add KEYs.
*/
- if (type == dns_rdatatype_srv && trdataset != NULL) {
+ if (type == dns_rdatatype_srv && trdataset != NULL) {
/*
* If we're adding SRV records to the additional data
* section, it's helpful if we add the SRV additional data
dns_db_closeversion(db_current, &version_current, ISC_FALSE);
if (db0 == NULL && db_current != NULL)
dns_db_detach(&db_current);
-
+
return (result);
}
* lookup and iterate over the node.
* XXXJT: this approach can cause a suboptimal result when the cache
* DB only has partial address types and the glue DB has remaining
- * ones.
+ * ones.
*/
type = dns_rdatatype_any;
setcache:
/*
* Set the new result in the cache if required. We do not support
- * caching additional data from a cache DB.
+ * caching additional data from a cache DB.
*/
if (needadditionalcache == ISC_TRUE &&
(additionaltype == dns_rdatasetadditional_fromauth ||
* Given:
* example SOA
* example NSEC b.example
- * b.example A
- * b.example NSEC a.d.example
- * a.d.example A
- * a.d.example NSEC g.f.example
- * g.f.example A
- * g.f.example NSEC z.i.example
- * z.i.example A
- * z.i.example NSEC example
+ * b.example A
+ * b.example NSEC a.d.example
+ * a.d.example A
+ * a.d.example NSEC g.f.example
+ * g.f.example A
+ * g.f.example NSEC z.i.example
+ * z.i.example A
+ * z.i.example NSEC example
*
* QNAME:
* a.example -> example NSEC b.example
- * owner common example
- * next common example
- * wild *.example
+ * owner common example
+ * next common example
+ * wild *.example
* d.b.example -> b.example NSEC a.d.example
* owner common b.example
* next common example
* wild *.f.example
* j.example -> z.i.example NSEC example
* owner common example
- * next common example
+ * next common example
* wild *.f.example
*/
options = client->query.dboptions | DNS_DBFIND_NOWILD;
name = wname;
goto again;
}
- }
+ }
cleanup:
if (rdataset != NULL)
query_putrdataset(client, &rdataset);
rdata_tonetaddr(dns_rdata_t *rdata, isc_netaddr_t *netaddr) {
struct in_addr ina;
struct in6_addr in6a;
-
+
switch (rdata->type) {
case dns_rdatatype_a:
INSIST(rdata->length == 4);
isc_netaddr_t netaddr;
dns_rdatasetorderfunc_t order = NULL;
void *order_arg = NULL;
-
+
isc_netaddr_fromsockaddr(&netaddr, &client->peeraddr);
switch (ns_sortlist_setup(client->view->sortlist,
&netaddr, &order_arg)) {
goto resume;
}
-
+
/*
* Not returning from recursion.
*/
if (event == NULL && client->query.restarts == 0) {
if (is_zone) {
- dns_zone_attach(zone, &client->query.authzone);
+#ifdef DLZ
+ if (zone != NULL) {
+ /*
+ * if is_zone = true, zone = NULL then this is
+ * a DLZ zone. Don't attempt to attach zone.
+ */
+#endif
+ dns_zone_attach(zone, &client->query.authzone);
+#ifdef DLZ
+ }
+#endif
dns_db_attach(db, &client->query.authdb);
}
client->query.authdbset = ISC_TRUE;
if ((message->flags & DNS_MESSAGEFLAG_RD) != 0)
client->query.attributes |= NS_QUERYATTR_WANTRECURSION;
-
+
if ((client->extflags & DNS_MESSAGEEXTFLAG_DO) != 0)
client->attributes |= NS_CLIENTATTR_WANTDNSSEC;
-
+
if (client->view->minimalresponses)
client->query.attributes |= (NS_QUERYATTR_NOAUTHORITY |
NS_QUERYATTR_NOADDITIONAL);
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: server.c,v 1.449 2005/08/23 02:36:07 marka Exp $ */
+/* $Id: server.c,v 1.450 2005/09/05 00:10:52 marka Exp $ */
/*! \file */
#include <dns/cache.h>
#include <dns/db.h>
#include <dns/dispatch.h>
+#ifdef DLZ
+#include <dns/dlz.h>
+#endif
#include <dns/forward.h>
#include <dns/journal.h>
#include <dns/keytable.h>
cfg_obj_t *forwarders;
cfg_obj_t *alternates;
cfg_obj_t *zonelist;
+#ifdef DLZ
+ cfg_obj_t *dlz;
+ unsigned int dlzargc;
+ char **dlzargv;
+#endif
cfg_obj_t *disabled;
cfg_obj_t *obj;
cfg_listelt_t *element;
actx));
}
+#ifdef DLZ
+ /*
+ * Create Dynamically Loadable Zone driver.
+ */
+ dlz = NULL;
+ if (voptions != NULL)
+ (void)cfg_map_get(voptions, "dlz", &dlz);
+ else
+ (void)cfg_map_get(config, "dlz", &dlz);
+
+ obj = NULL;
+ if (dlz != NULL) {
+ (void)cfg_map_get(cfg_tuple_get(dlz, "options"),
+ "database", &obj);
+ if (obj != NULL) {
+ char *s = isc_mem_strdup(mctx, cfg_obj_asstring(obj));
+ if (s == NULL) {
+ result = ISC_R_NOMEMORY;
+ goto cleanup;
+ }
+
+ result = dns_dlzstrtoargv(mctx, s, &dlzargc, &dlzargv);
+ if (result != ISC_R_SUCCESS) {
+ isc_mem_free(mctx, s);
+ goto cleanup;
+ }
+
+ obj = cfg_tuple_get(dlz, "name");
+ result = dns_dlzcreate(mctx, cfg_obj_asstring(obj),
+ dlzargv[0], dlzargc, dlzargv,
+ &view->dlzdatabase);
+ isc_mem_free(mctx, s);
+ isc_mem_put(mctx, dlzargv, dlzargc * sizeof(*dlzargv));
+ if (result == ISC_R_SUCCESS)
+ goto cleanup;
+ }
+ }
+#endif
+
/*
* Configure the view's cache. Try to reuse an existing
* cache if possible, otherwise create a new cache.
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: xfrout.c,v 1.119 2005/04/27 04:55:55 sra Exp $ */
+/* $Id: xfrout.c,v 1.120 2005/09/05 00:10:53 marka Exp $ */
#include <config.h>
#include <dns/db.h>
#include <dns/dbiterator.h>
+#ifdef DLZ
+#include <dns/dlz.h>
+#endif
#include <dns/fixedname.h>
#include <dns/journal.h>
#include <dns/message.h>
char msg[NS_CLIENT_ACLMSGSIZE("zone transfer")];
char keyname[DNS_NAME_FORMATSIZE];
isc_boolean_t is_poll = ISC_FALSE;
+#ifdef DLZ
+ isc_boolean_t is_dlz = ISC_FALSE;
+#endif
switch (reqtype) {
case dns_rdatatype_axfr:
result = dns_zt_find(client->view->zonetable, question_name, 0, NULL,
&zone);
+
if (result != ISC_R_SUCCESS)
- FAILQ(DNS_R_NOTAUTH, "non-authoritative zone",
- question_name, question_class);
- switch(dns_zone_gettype(zone)) {
- case dns_zone_master:
- case dns_zone_slave:
- break; /* Master and slave zones are OK for transfer. */
- default:
- FAILQ(DNS_R_NOTAUTH, "non-authoritative zone",
- question_name, question_class);
+#ifdef DLZ
+ {
+ /*
+ * Normal zone table does not have a match. Try the DLZ database
+ */
+ if (client->view->dlzdatabase != NULL) {
+ result = dns_dlzallowzonexfr(client->view,
+ question_name, &client->peeraddr,
+ &db);
+
+ if (result == ISC_R_NOPERM) {
+ char _buf1[DNS_NAME_FORMATSIZE];
+ char _buf2[DNS_RDATACLASS_FORMATSIZE];
+
+ result = DNS_R_REFUSED;
+ dns_name_format(question_name, _buf1,
+ sizeof(_buf1));
+ dns_rdataclass_format(question_class,
+ _buf2, sizeof(_buf2));
+ ns_client_log(client, DNS_LOGCATEGORY_SECURITY,
+ NS_LOGMODULE_XFER_OUT,
+ ISC_LOG_ERROR,
+ "zone transfer '%s/%s' denied",
+ _buf1, _buf2);
+ goto failure;
+ }
+ if (result != ISC_R_SUCCESS)
+#endif
+ FAILQ(DNS_R_NOTAUTH, "non-authoritative zone",
+ question_name, question_class);
+#ifdef DLZ
+ is_dlz = ISC_TRUE;
+ /*
+ * DLZ only support full zone transfer, not incremental
+ */
+ if (reqtype != dns_rdatatype_axfr) {
+ mnemonic = "AXFR-style IXFR";
+ reqtype = dns_rdatatype_axfr;
+ }
+
+ } else {
+ /*
+ * not DLZ and not in normal zone table, we are
+ * not authoritative
+ */
+ FAILQ(DNS_R_NOTAUTH, "non-authoritative zone",
+ question_name, question_class);
+ }
+ } else {
+ /* zone table has a match */
+#endif
+ switch(dns_zone_gettype(zone)) {
+ case dns_zone_master:
+ case dns_zone_slave:
+ break; /* Master and slave zones are OK for transfer. */
+ default:
+ FAILQ(DNS_R_NOTAUTH, "non-authoritative zone", question_name, question_class);
+ }
+ CHECK(dns_zone_getdb(zone, &db));
+ dns_db_currentversion(db, &ver);
+#ifdef DLZ
}
- CHECK(dns_zone_getdb(zone, &db));
- dns_db_currentversion(db, &ver);
+#endif
xfrout_log1(client, question_name, question_class, ISC_LOG_DEBUG(6),
"%s question section OK", mnemonic);
/*
* Decide whether to allow this transfer.
*/
- ns_client_aclmsg("zone transfer", question_name, reqtype,
- client->view->rdclass, msg, sizeof(msg));
- CHECK(ns_client_checkacl(client, msg,
- dns_zone_getxfracl(zone), ISC_TRUE,
- ISC_LOG_ERROR));
+#ifdef DLZ
+ /*
+ * if not a DLZ zone decide whether to allow this transfer.
+ */
+ if (!is_dlz) {
+#endif
+ ns_client_aclmsg("zone transfer", question_name, reqtype,
+ client->view->rdclass, msg, sizeof(msg));
+ CHECK(ns_client_checkacl(client, msg,
+ dns_zone_getxfracl(zone), ISC_TRUE,
+ ISC_LOG_ERROR));
+#ifdef DLZ
+ }
+#endif
/*
* AXFR over UDP is not possible.
/*
* Get a dynamically allocated copy of the current SOA.
*/
+#ifdef DLZ
+ if (is_dlz)
+ dns_db_currentversion(db, &ver);
+#endif
CHECK(dns_db_createsoatuple(db, ver, mctx, DNS_DIFFOP_EXISTS,
¤t_soa_tuple));
* Create the xfrout context object. This transfers the ownership
* of "stream", "db", "ver", and "quota" to the xfrout context object.
*/
- CHECK(xfrout_ctx_create(mctx, client, request->id, question_name,
- reqtype, question_class, db, ver, quota,
- stream, dns_message_gettsigkey(request),
- tsigbuf,
- dns_zone_getmaxxfrout(zone),
- dns_zone_getidleout(zone),
- (format == dns_many_answers) ?
- ISC_TRUE : ISC_FALSE,
- &xfr));
+
+
+
+#ifdef DLZ
+ if (is_dlz)
+ CHECK(xfrout_ctx_create(mctx, client, request->id, question_name,
+ reqtype, question_class, db, ver, quota,
+ stream, dns_message_gettsigkey(request),
+ tsigbuf,
+ 3600,
+ 3600,
+ (format == dns_many_answers) ?
+ ISC_TRUE : ISC_FALSE,
+ &xfr));
+ else
+#endif
+ CHECK(xfrout_ctx_create(mctx, client, request->id, question_name,
+ reqtype, question_class, db, ver, quota,
+ stream, dns_message_gettsigkey(request),
+ tsigbuf,
+ dns_zone_getmaxxfrout(zone),
+ dns_zone_getidleout(zone),
+ (format == dns_many_answers) ?
+ ISC_TRUE : ISC_FALSE,
+ &xfr));
+
xfr->mnemonic = mnemonic;
stream = NULL;
quota = NULL;
# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
# PERFORMANCE OF THIS SOFTWARE.
-# $Id: conf.sh.in,v 1.32 2005/07/27 04:12:00 marka Exp $
+# $Id: conf.sh.in,v 1.33 2005/09/05 00:10:53 marka Exp $
#
# Common configuration data for system tests, to be sourced into
# The "stress" test is not run by default since it creates enough
# load on the machine to make it unusable to other users.
# v6synth
-SUBDIRS="cacheclean checkconf checknames dnssec forward glue ixfr limits \
- lwresd masterfile masterformat notify nsupdate resolver sortlist stub \
+SUBDIRS="cacheclean checkconf checknames dnssec forward glue ixfr limits
+ lwresd masterfile masterformat notify nsupdate resolver sortlist stub
tkey unknown upforwd views xfer xferquota zonechecks"
# PERL will be an empty string if no perl interpreter was found.
# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
# PERFORMANCE OF THIS SOFTWARE.
#
-# $Id: configure,v 1.380 2005/09/01 03:36:18 marka Exp $
+# $Id: configure,v 1.381 2005/09/05 00:12:29 marka Exp $
#
# Portions Copyright (C) 1996-2001 Nominum, Inc.
#
# 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.
-# From configure.in Revision: 1.391 .
+# From configure.in Revision: 1.392 .
# Guess values for system-dependent variables and create Makefiles.
# Generated by GNU Autoconf 2.59.
#
# include <unistd.h>
#endif"
-ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS subdirs build build_cpu build_vendor build_os host host_cpu host_vendor host_os SET_MAKE RANLIB ac_ct_RANLIB INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA LN_S STD_CINCLUDES STD_CDEFINES STD_CWARNINGS CCOPT AR ARFLAGS LN ETAGS PERL CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT CPP EGREP ISC_SOCKADDR_LEN_T ISC_PLATFORM_HAVELONGLONG ISC_PLATFORM_HAVELIFCONF ISC_PLATFORM_NEEDSYSSELECTH LWRES_PLATFORM_NEEDSYSSELECTH USE_OPENSSL DST_OPENSSL_INC USE_GSSAPI DST_GSSAPI_INC DNS_CRYPTO_LIBS ALWAYS_DEFINES ISC_PLATFORM_USETHREADS ISC_THREAD_DIR MKDEPCC MKDEPCFLAGS MKDEPPROG IRIX_DNSSEC_WARNINGS_HACK purify_path PURIFY ECHO ac_ct_AR STRIP ac_ct_STRIP CXX CXXFLAGS ac_ct_CXX CXXCPP F77 FFLAGS ac_ct_F77 LIBTOOL O A SA LIBTOOL_MKDEP_SED LIBTOOL_MODE_COMPILE LIBTOOL_MODE_INSTALL LIBTOOL_MODE_LINK LIBTOOL_ALLOW_UNDEFINED LIBTOOL_IN_MAIN LIBBIND ISC_PLATFORM_HAVEIPV6 LWRES_PLATFORM_HAVEIPV6 ISC_PLATFORM_NEEDNETINETIN6H LWRES_PLATFORM_NEEDNETINETIN6H ISC_PLATFORM_NEEDNETINET6IN6H LWRES_PLATFORM_NEEDNETINET6IN6H ISC_PLATFORM_HAVEINADDR6 LWRES_PLATFORM_HAVEINADDR6 ISC_PLATFORM_NEEDIN6ADDRANY LWRES_PLATFORM_NEEDIN6ADDRANY ISC_PLATFORM_NEEDIN6ADDRLOOPBACK LWRES_PLATFORM_NEEDIN6ADDRLOOPBACK ISC_PLATFORM_HAVEIN6PKTINFO ISC_PLATFORM_FIXIN6ISADDR ISC_IPV6_H ISC_IPV6_O ISC_ISCIPV6_O ISC_IPV6_C LWRES_HAVE_SIN6_SCOPE_ID ISC_PLATFORM_HAVESCOPEID ISC_PLATFORM_HAVEIF_LADDRREQ ISC_PLATFORM_HAVEIF_LADDRCONF ISC_PLATFORM_NEEDNTOP ISC_PLATFORM_NEEDPTON ISC_PLATFORM_NEEDATON ISC_PLATFORM_HAVESALEN LWRES_PLATFORM_HAVESALEN ISC_PLATFORM_MSGHDRFLAVOR ISC_PLATFORM_NEEDPORTT ISC_LWRES_NEEDADDRINFO ISC_LWRES_NEEDRRSETINFO ISC_LWRES_SETHOSTENTINT ISC_LWRES_ENDHOSTENTINT ISC_LWRES_GETNETBYADDRINADDR ISC_LWRES_SETNETENTINT ISC_LWRES_ENDNETENTINT ISC_LWRES_GETHOSTBYADDRVOID ISC_LWRES_NEEDHERRNO ISC_LWRES_GETIPNODEPROTO ISC_LWRES_GETADDRINFOPROTO ISC_LWRES_GETNAMEINFOPROTO ISC_PLATFORM_NEEDSTRSEP ISC_PLATFORM_NEEDMEMMOVE ISC_PLATFORM_NEEDSTRTOUL LWRES_PLATFORM_NEEDSTRTOUL GENRANDOMLIB ISC_PLATFORM_NEEDSTRLCPY ISC_PLATFORM_NEEDSTRLCAT ISC_PLATFORM_NEEDSPRINTF LWRES_PLATFORM_NEEDSPRINTF ISC_PLATFORM_NEEDVSNPRINTF LWRES_PLATFORM_NEEDVSNPRINTF ISC_EXTRA_OBJS ISC_EXTRA_SRCS ISC_PLATFORM_QUADFORMAT LWRES_PLATFORM_QUADFORMAT ISC_PLATFORM_HAVESYSUNH ISC_PLATFORM_RLIMITTYPE ISC_PLATFORM_USEDECLSPEC LWRES_PLATFORM_USEDECLSPEC ISC_PLATFORM_BRACEPTHREADONCEINIT ISC_PLATFORM_HAVEIFNAMETOINDEX ISC_PLATFORM_HAVEXADD ISC_PLATFORM_HAVECMPXCHG ISC_PLATFORM_HAVEATOMICSTORE ISC_PLATFORM_USEGCCASM ISC_PLATFORM_USEOSFASM ISC_PLATFORM_USESTDASM ISC_ARCH_DIR LATEX PDFLATEX W3M XSLTPROC XMLLINT XSLT_DOCBOOK_STYLE_HTML XSLT_DOCBOOK_STYLE_XHTML XSLT_DOCBOOK_STYLE_MAN XSLT_DOCBOOK_CHUNK_HTML XSLT_DOCBOOK_CHUNK_XHTML XSLT_DOCBOOK_CHUNKTOC_HTML XSLT_DOCBOOK_CHUNKTOC_XHTML XSLT_DOCBOOK_MAKETOC_HTML XSLT_DOCBOOK_MAKETOC_XHTML XSLT_DB2LATEX_STYLE XSLT_DB2LATEX_ADMONITIONS BIND9_TOP_BUILDDIR BIND9_ISC_BUILDINCLUDE BIND9_ISCCC_BUILDINCLUDE BIND9_ISCCFG_BUILDINCLUDE BIND9_DNS_BUILDINCLUDE BIND9_LWRES_BUILDINCLUDE BIND9_BIND9_BUILDINCLUDE BIND9_VERSION LIBOBJS LTLIBOBJS'
-ac_subst_files='BIND9_MAKE_INCLUDES BIND9_MAKE_RULES LIBISC_API LIBISCCC_API LIBISCCFG_API LIBDNS_API LIBBIND9_API LIBLWRES_API'
+ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS subdirs build build_cpu build_vendor build_os host host_cpu host_vendor host_os SET_MAKE RANLIB ac_ct_RANLIB INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA LN_S STD_CINCLUDES STD_CDEFINES STD_CWARNINGS CCOPT AR ARFLAGS LN ETAGS PERL CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT CPP EGREP ISC_SOCKADDR_LEN_T ISC_PLATFORM_HAVELONGLONG ISC_PLATFORM_HAVELIFCONF ISC_PLATFORM_NEEDSYSSELECTH LWRES_PLATFORM_NEEDSYSSELECTH USE_OPENSSL DST_OPENSSL_INC USE_GSSAPI DST_GSSAPI_INC DNS_CRYPTO_LIBS ALWAYS_DEFINES ISC_PLATFORM_USETHREADS ISC_THREAD_DIR MKDEPCC MKDEPCFLAGS MKDEPPROG IRIX_DNSSEC_WARNINGS_HACK purify_path PURIFY ECHO ac_ct_AR STRIP ac_ct_STRIP CXX CXXFLAGS ac_ct_CXX CXXCPP F77 FFLAGS ac_ct_F77 LIBTOOL O A SA LIBTOOL_MKDEP_SED LIBTOOL_MODE_COMPILE LIBTOOL_MODE_INSTALL LIBTOOL_MODE_LINK LIBTOOL_ALLOW_UNDEFINED LIBTOOL_IN_MAIN LIBBIND ISC_PLATFORM_HAVEIPV6 LWRES_PLATFORM_HAVEIPV6 ISC_PLATFORM_NEEDNETINETIN6H LWRES_PLATFORM_NEEDNETINETIN6H ISC_PLATFORM_NEEDNETINET6IN6H LWRES_PLATFORM_NEEDNETINET6IN6H ISC_PLATFORM_HAVEINADDR6 LWRES_PLATFORM_HAVEINADDR6 ISC_PLATFORM_NEEDIN6ADDRANY LWRES_PLATFORM_NEEDIN6ADDRANY ISC_PLATFORM_NEEDIN6ADDRLOOPBACK LWRES_PLATFORM_NEEDIN6ADDRLOOPBACK ISC_PLATFORM_HAVEIN6PKTINFO ISC_PLATFORM_FIXIN6ISADDR ISC_IPV6_H ISC_IPV6_O ISC_ISCIPV6_O ISC_IPV6_C LWRES_HAVE_SIN6_SCOPE_ID ISC_PLATFORM_HAVESCOPEID ISC_PLATFORM_HAVEIF_LADDRREQ ISC_PLATFORM_HAVEIF_LADDRCONF ISC_PLATFORM_NEEDNTOP ISC_PLATFORM_NEEDPTON ISC_PLATFORM_NEEDATON ISC_PLATFORM_HAVESALEN LWRES_PLATFORM_HAVESALEN ISC_PLATFORM_MSGHDRFLAVOR ISC_PLATFORM_NEEDPORTT ISC_LWRES_NEEDADDRINFO ISC_LWRES_NEEDRRSETINFO ISC_LWRES_SETHOSTENTINT ISC_LWRES_ENDHOSTENTINT ISC_LWRES_GETNETBYADDRINADDR ISC_LWRES_SETNETENTINT ISC_LWRES_ENDNETENTINT ISC_LWRES_GETHOSTBYADDRVOID ISC_LWRES_NEEDHERRNO ISC_LWRES_GETIPNODEPROTO ISC_LWRES_GETADDRINFOPROTO ISC_LWRES_GETNAMEINFOPROTO ISC_PLATFORM_NEEDSTRSEP ISC_PLATFORM_NEEDMEMMOVE ISC_PLATFORM_NEEDSTRTOUL LWRES_PLATFORM_NEEDSTRTOUL GENRANDOMLIB ISC_PLATFORM_NEEDSTRLCPY ISC_PLATFORM_NEEDSTRLCAT ISC_PLATFORM_NEEDSPRINTF LWRES_PLATFORM_NEEDSPRINTF ISC_PLATFORM_NEEDVSNPRINTF LWRES_PLATFORM_NEEDVSNPRINTF ISC_EXTRA_OBJS ISC_EXTRA_SRCS ISC_PLATFORM_QUADFORMAT LWRES_PLATFORM_QUADFORMAT ISC_PLATFORM_HAVESYSUNH ISC_PLATFORM_RLIMITTYPE ISC_PLATFORM_USEDECLSPEC LWRES_PLATFORM_USEDECLSPEC ISC_PLATFORM_BRACEPTHREADONCEINIT ISC_PLATFORM_HAVEIFNAMETOINDEX ISC_PLATFORM_HAVEXADD ISC_PLATFORM_HAVECMPXCHG ISC_PLATFORM_HAVEATOMICSTORE ISC_PLATFORM_USEGCCASM ISC_PLATFORM_USEOSFASM ISC_PLATFORM_USESTDASM ISC_ARCH_DIR LATEX PDFLATEX W3M XSLTPROC XMLLINT XSLT_DOCBOOK_STYLE_HTML XSLT_DOCBOOK_STYLE_XHTML XSLT_DOCBOOK_STYLE_MAN XSLT_DOCBOOK_CHUNK_HTML XSLT_DOCBOOK_CHUNK_XHTML XSLT_DOCBOOK_CHUNKTOC_HTML XSLT_DOCBOOK_CHUNKTOC_XHTML XSLT_DOCBOOK_MAKETOC_HTML XSLT_DOCBOOK_MAKETOC_XHTML XSLT_DB2LATEX_STYLE XSLT_DB2LATEX_ADMONITIONS BIND9_TOP_BUILDDIR BIND9_ISC_BUILDINCLUDE BIND9_ISCCC_BUILDINCLUDE BIND9_ISCCFG_BUILDINCLUDE BIND9_DNS_BUILDINCLUDE BIND9_LWRES_BUILDINCLUDE BIND9_BIND9_BUILDINCLUDE BIND9_VERSION PG_CONFIG USE_DLZ DLZ_DRIVER_INCLUDES DLZ_DRIVER_LIBS DLZ_DRIVER_SRCS DLZ_DRIVER_OBJS LIBOBJS LTLIBOBJS'
+ac_subst_files='BIND9_MAKE_INCLUDES BIND9_MAKE_RULES LIBISC_API LIBISCCC_API LIBISCCFG_API LIBDNS_API LIBBIND9_API LIBLWRES_API DLZ_DRIVER_RULES'
# Initialize some variables set by options.
ac_init_help=
--with-tags[=TAGS]
include additional configurations [automatic]
--with-kame=PATH use Kame IPv6 default path /usr/local/v6
+ --with-dlz-postgres=PATH Build with Postgres DLZ driver yes|no|path.
+ (Required to use Postgres with DLZ)
+ --with-dlz-mysql=PATH Build with MySQL DLZ driver yes|no|path.
+ (Required to use MySQL with DLZ)
+ --with-dlz-bdb=PATH Build with Berkeley DB DLZ driver yes|no|path.
+ (Required to use Berkeley DB with DLZ)
+ --with-dlz-filesystem=PATH Build with filesystem DLZ driver yes|no.
+ (Required to use file system driver with DLZ)
+ --with-dlz-ldap=PATH Build with LDAP DLZ driver yes|no|path.
+ (Required to use LDAP with DLZ)
+ --with-dlz-odbc=PATH Build with ODBC DLZ driver yes|no|path.
+ (Required to use ODBC with DLZ)
+ --with-dlz-stub=PATH Build with stub DLZ driver yes|no.
+ (Required to use stub driver with DLZ)
Some influential environment variables:
CC C compiler command
+#
+# Make very sure that these are the first files processed by
+# config.status, since we use the processed output as the input for
+# AC_SUBST_FILE() subsitutions in other files.
+#
+ ac_config_files="$ac_config_files make/rules make/includes"
+
+
# Extract the first word of "ar", so it can be a program name with args.
set dummy ar; ac_word=$2
echo "$as_me:$LINENO: checking for $ac_word" >&5
esac
+
#
# was --with-openssl specified?
#
;;
*-*-irix6*)
# Find out which ABI we are using.
- echo '#line 8137 "configure"' > conftest.$ac_ext
+ echo '#line 8160 "configure"' > conftest.$ac_ext
if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
(eval $ac_compile) 2>&5
ac_status=$?
# Provide some information about the compiler.
-echo "$as_me:9134:" \
+echo "$as_me:9157:" \
"checking for Fortran 77 compiler version" >&5
ac_compiler=`set X $ac_compile; echo $2`
{ (eval echo "$as_me:$LINENO: \"$ac_compiler --version </dev/null >&5\"") >&5
-e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
- (eval echo "\"\$as_me:10195: $lt_compile\"" >&5)
+ (eval echo "\"\$as_me:10218: $lt_compile\"" >&5)
(eval "$lt_compile" 2>conftest.err)
ac_status=$?
cat conftest.err >&5
- echo "$as_me:10199: \$? = $ac_status" >&5
+ echo "$as_me:10222: \$? = $ac_status" >&5
if (exit $ac_status) && test -s "$ac_outfile"; then
# The compiler can only warn and ignore the option if not recognized
# So say no if there are warnings
-e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
- (eval echo "\"\$as_me:10438: $lt_compile\"" >&5)
+ (eval echo "\"\$as_me:10461: $lt_compile\"" >&5)
(eval "$lt_compile" 2>conftest.err)
ac_status=$?
cat conftest.err >&5
- echo "$as_me:10442: \$? = $ac_status" >&5
+ echo "$as_me:10465: \$? = $ac_status" >&5
if (exit $ac_status) && test -s "$ac_outfile"; then
# The compiler can only warn and ignore the option if not recognized
# So say no if there are warnings
-e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
- (eval echo "\"\$as_me:10498: $lt_compile\"" >&5)
+ (eval echo "\"\$as_me:10521: $lt_compile\"" >&5)
(eval "$lt_compile" 2>out/conftest.err)
ac_status=$?
cat out/conftest.err >&5
- echo "$as_me:10502: \$? = $ac_status" >&5
+ echo "$as_me:10525: \$? = $ac_status" >&5
if (exit $ac_status) && test -s out/conftest2.$ac_objext
then
# The compiler can only warn and ignore the option if not recognized
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
lt_status=$lt_dlunknown
cat > conftest.$ac_ext <<EOF
-#line 12683 "configure"
+#line 12706 "configure"
#include "confdefs.h"
#if HAVE_DLFCN_H
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
lt_status=$lt_dlunknown
cat > conftest.$ac_ext <<EOF
-#line 12781 "configure"
+#line 12804 "configure"
#include "confdefs.h"
#if HAVE_DLFCN_H
-e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
- (eval echo "\"\$as_me:14978: $lt_compile\"" >&5)
+ (eval echo "\"\$as_me:15001: $lt_compile\"" >&5)
(eval "$lt_compile" 2>conftest.err)
ac_status=$?
cat conftest.err >&5
- echo "$as_me:14982: \$? = $ac_status" >&5
+ echo "$as_me:15005: \$? = $ac_status" >&5
if (exit $ac_status) && test -s "$ac_outfile"; then
# The compiler can only warn and ignore the option if not recognized
# So say no if there are warnings
-e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
- (eval echo "\"\$as_me:15038: $lt_compile\"" >&5)
+ (eval echo "\"\$as_me:15061: $lt_compile\"" >&5)
(eval "$lt_compile" 2>out/conftest.err)
ac_status=$?
cat out/conftest.err >&5
- echo "$as_me:15042: \$? = $ac_status" >&5
+ echo "$as_me:15065: \$? = $ac_status" >&5
if (exit $ac_status) && test -s out/conftest2.$ac_objext
then
# The compiler can only warn and ignore the option if not recognized
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
lt_status=$lt_dlunknown
cat > conftest.$ac_ext <<EOF
-#line 16399 "configure"
+#line 16422 "configure"
#include "confdefs.h"
#if HAVE_DLFCN_H
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
lt_status=$lt_dlunknown
cat > conftest.$ac_ext <<EOF
-#line 16497 "configure"
+#line 16520 "configure"
#include "confdefs.h"
#if HAVE_DLFCN_H
-e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
- (eval echo "\"\$as_me:17334: $lt_compile\"" >&5)
+ (eval echo "\"\$as_me:17357: $lt_compile\"" >&5)
(eval "$lt_compile" 2>conftest.err)
ac_status=$?
cat conftest.err >&5
- echo "$as_me:17338: \$? = $ac_status" >&5
+ echo "$as_me:17361: \$? = $ac_status" >&5
if (exit $ac_status) && test -s "$ac_outfile"; then
# The compiler can only warn and ignore the option if not recognized
# So say no if there are warnings
-e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
- (eval echo "\"\$as_me:17394: $lt_compile\"" >&5)
+ (eval echo "\"\$as_me:17417: $lt_compile\"" >&5)
(eval "$lt_compile" 2>out/conftest.err)
ac_status=$?
cat out/conftest.err >&5
- echo "$as_me:17398: \$? = $ac_status" >&5
+ echo "$as_me:17421: \$? = $ac_status" >&5
if (exit $ac_status) && test -s out/conftest2.$ac_objext
then
# The compiler can only warn and ignore the option if not recognized
-e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
- (eval echo "\"\$as_me:19433: $lt_compile\"" >&5)
+ (eval echo "\"\$as_me:19456: $lt_compile\"" >&5)
(eval "$lt_compile" 2>conftest.err)
ac_status=$?
cat conftest.err >&5
- echo "$as_me:19437: \$? = $ac_status" >&5
+ echo "$as_me:19460: \$? = $ac_status" >&5
if (exit $ac_status) && test -s "$ac_outfile"; then
# The compiler can only warn and ignore the option if not recognized
# So say no if there are warnings
-e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
- (eval echo "\"\$as_me:19676: $lt_compile\"" >&5)
+ (eval echo "\"\$as_me:19699: $lt_compile\"" >&5)
(eval "$lt_compile" 2>conftest.err)
ac_status=$?
cat conftest.err >&5
- echo "$as_me:19680: \$? = $ac_status" >&5
+ echo "$as_me:19703: \$? = $ac_status" >&5
if (exit $ac_status) && test -s "$ac_outfile"; then
# The compiler can only warn and ignore the option if not recognized
# So say no if there are warnings
-e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
- (eval echo "\"\$as_me:19736: $lt_compile\"" >&5)
+ (eval echo "\"\$as_me:19759: $lt_compile\"" >&5)
(eval "$lt_compile" 2>out/conftest.err)
ac_status=$?
cat out/conftest.err >&5
- echo "$as_me:19740: \$? = $ac_status" >&5
+ echo "$as_me:19763: \$? = $ac_status" >&5
if (exit $ac_status) && test -s out/conftest2.$ac_objext
then
# The compiler can only warn and ignore the option if not recognized
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
lt_status=$lt_dlunknown
cat > conftest.$ac_ext <<EOF
-#line 21921 "configure"
+#line 21944 "configure"
#include "confdefs.h"
#if HAVE_DLFCN_H
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
lt_status=$lt_dlunknown
cat > conftest.$ac_ext <<EOF
-#line 22019 "configure"
+#line 22042 "configure"
#include "confdefs.h"
#if HAVE_DLFCN_H
;;
esac
+
#
# Here begins a very long section to determine the system's networking
# capabilities. The order of the tests is signficant.
LIBLWRES_API=$srcdir/lib/lwres/api
+#
+# Configure any DLZ drivers.
+#
+# If config.dlz.in selects one or more DLZ drivers, it will set
+# USE_DLZ to a non-empty value, which will be our clue to
+# enable the DLZ core functions.
+#
+# This section has to come after the libtool stuff because it needs to
+# know how to name the driver object files.
+#
+
+USE_DLZ=""
+DLZ_DRIVER_INCLUDES=""
+DLZ_DRIVER_LIBS=""
+DLZ_DRIVER_SRCS=""
+DLZ_DRIVER_OBJS=""
+
+# Copyright (C) 2005 Internet Systems Consortium, Inc. ("ISC")
+#
+# 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 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.
+
+#
+# Shorthand. Note quoting: DLZ_DRIVER_DIR expanded in Makefile, not here.
+#
+dlzdir='${DLZ_DRIVER_DIR}'
+
+#
+# Private autoconf macro to simplify configuring drivers:
+#
+# DLZ_ADD_DRIVER(DEFINE, DRIVER, INCLUDES, LIBS)
+#
+# where:
+# DEFINE is FOO (to define -DDLZ_FOO)
+# DRIVER is dlz_foo_driver (sources without the .c)
+# INCLUDES is any necessary include definitions
+# LIBS is any necessary library definitions
+#
+
+
+#
+# Check for the various DLZ drivers
+#
+
+#
+# Was --with-dlz-postgres specified?
+#
+
+echo "$as_me:$LINENO: checking for Postgres DLZ driver" >&5
+echo $ECHO_N "checking for Postgres DLZ driver... $ECHO_C" >&6
+
+# Check whether --with-dlz_postgres or --without-dlz_postgres was given.
+if test "${with_dlz_postgres+set}" = set; then
+ withval="$with_dlz_postgres"
+ use_dlz_postgres="$withval"
+else
+ use_dlz_postgres="no"
+fi;
+
+if test "$use_dlz_postgres" = "yes"
+then
+ # User did not specify a path - guess it
+ # Ask Postgres to tell us where it is
+
+ for ac_prog in pg_config
+do
+ # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_path_PG_CONFIG+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ case $PG_CONFIG in
+ [\\/]* | ?:[\\/]*)
+ ac_cv_path_PG_CONFIG="$PG_CONFIG" # Let the user override the test with a path.
+ ;;
+ *)
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_path_PG_CONFIG="$as_dir/$ac_word$ac_exec_ext"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+ ;;
+esac
+fi
+PG_CONFIG=$ac_cv_path_PG_CONFIG
+
+if test -n "$PG_CONFIG"; then
+ echo "$as_me:$LINENO: result: $PG_CONFIG" >&5
+echo "${ECHO_T}$PG_CONFIG" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+ test -n "$PG_CONFIG" && break
+done
+test -n "$PG_CONFIG" || PG_CONFIG="not found"
+
+
+ if test "$PG_CONFIG" != "not found"
+ then
+ use_dlz_postgres=`$PG_CONFIG --includedir`
+ use_dlz_postgres_lib=`$PG_CONFIG --libdir`
+ fi
+fi
+
+if test "$use_dlz_postgres" = "yes"
+then
+ # User did not specify path and Postgres didn't say - guess it
+
+ pgdirs="/usr /usr/local /usr/local/pgsql /usr/pkg"
+ for d in $pgdirs
+ do
+ if test -f $d/include/libpq-fe.h
+ then
+ use_dlz_postgres=$d/include
+ use_dlz_postgres_lib=$d/lib
+ break
+ fi
+ done
+fi
+
+if test "$use_dlz_postgres" = "yes"
+then
+ # Still no joy, give up
+
+ echo "$as_me:$LINENO: result: not found" >&5
+echo "${ECHO_T}not found" >&6
+ { { echo "$as_me:$LINENO: error: No pg_config and PostgreSQL was not found in any of $pgdirs; use --with-dlz-postgres=/path or put pg_config in your path" >&5
+echo "$as_me: error: No pg_config and PostgreSQL was not found in any of $pgdirs; use --with-dlz-postgres=/path or put pg_config in your path" >&2;}
+ { (exit 1); exit 1; }; }
+fi
+
+case "$use_dlz_postgres" in
+ no)
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+ ;;
+ *)
+
+ USE_DLZ="$USE_DLZ -DDLZ_POSTGRES"
+ for i in dlz_postgres_driver
+ do
+ DLZ_DRIVER_SRCS="$DLZ_DRIVER_SRCS $dlzdir/$i.c"
+ DLZ_DRIVER_OBJS="$DLZ_DRIVER_OBJS $i.$O"
+ done
+ if test -n "-I$use_dlz_postgres"
+ then
+ DLZ_DRIVER_INCLUDES="$DLZ_DRIVER_INCLUDES -I$use_dlz_postgres"
+ fi
+ if test -n "-L$use_dlz_postgres_lib -lpq"
+ then
+ DLZ_DRIVER_LIBS="$DLZ_DRIVER_LIBS -L$use_dlz_postgres_lib -lpq"
+ fi
+
+
+ echo "$as_me:$LINENO: result: using PostgreSQL from $use_dlz_postgres_lib and $use_dlz_postgres" >&5
+echo "${ECHO_T}using PostgreSQL from $use_dlz_postgres_lib and $use_dlz_postgres" >&6
+ ;;
+esac
+
+
+#
+# Was --with-dlz-mysql specified?
+#
+
+echo "$as_me:$LINENO: checking for MySQL DLZ driver" >&5
+echo $ECHO_N "checking for MySQL DLZ driver... $ECHO_C" >&6
+
+# Check whether --with-dlz_mysql or --without-dlz_mysql was given.
+if test "${with_dlz_mysql+set}" = set; then
+ withval="$with_dlz_mysql"
+ use_dlz_mysql="$withval"
+else
+ use_dlz_mysql="no"
+fi;
+
+if test "$use_dlz_mysql" = "yes"
+then
+ # User did not specify a path - guess it
+ mysqldirs="/usr /usr/local /usr/local/mysql /usr/pkg"
+ for d in $mysqldirs
+ do
+ if test -f $d/include/mysql/mysql.h
+ then
+ use_dlz_mysql=$d
+ break
+ fi
+ done
+fi
+
+if test "$use_dlz_mysql" = "yes"
+then
+ echo "$as_me:$LINENO: result: not found" >&5
+echo "${ECHO_T}not found" >&6
+ { { echo "$as_me:$LINENO: error: MySQL was not found in any of $mysqldirs; use --with-dlz-mysql=/path" >&5
+echo "$as_me: error: MySQL was not found in any of $mysqldirs; use --with-dlz-mysql=/path" >&2;}
+ { (exit 1); exit 1; }; }
+fi
+
+case "$use_dlz_mysql" in
+ no)
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+ ;;
+ *)
+
+ USE_DLZ="$USE_DLZ -DDLZ_MYSQL"
+ for i in dlz_mysql_driver
+ do
+ DLZ_DRIVER_SRCS="$DLZ_DRIVER_SRCS $dlzdir/$i.c"
+ DLZ_DRIVER_OBJS="$DLZ_DRIVER_OBJS $i.$O"
+ done
+ if test -n "-I$use_dlz_mysql/include/mysql"
+ then
+ DLZ_DRIVER_INCLUDES="$DLZ_DRIVER_INCLUDES -I$use_dlz_mysql/include/mysql"
+ fi
+ if test -n "-L$use_dlz_mysql/lib/mysql -lmysqlclient -lz -lcrypt -lm"
+ then
+ DLZ_DRIVER_LIBS="$DLZ_DRIVER_LIBS -L$use_dlz_mysql/lib/mysql -lmysqlclient -lz -lcrypt -lm"
+ fi
+
+
+ echo "$as_me:$LINENO: result: using mysql from $use_dlz_mysql/lib/mysql and $use_dlz_mysql/include/mysql" >&5
+echo "${ECHO_T}using mysql from $use_dlz_mysql/lib/mysql and $use_dlz_mysql/include/mysql" >&6
+ ;;
+esac
+
+
+#
+# Was --with-dlz-bdb specified?
+#
+
+echo "$as_me:$LINENO: checking for Berkeley DB DLZ driver" >&5
+echo $ECHO_N "checking for Berkeley DB DLZ driver... $ECHO_C" >&6
+
+# Check whether --with-dlz_bdb or --without-dlz_bdb was given.
+if test "${with_dlz_bdb+set}" = set; then
+ withval="$with_dlz_bdb"
+ use_dlz_bdb="$withval"
+else
+ use_dlz_bdb="no"
+fi;
+
+case "$use_dlz_bdb" in
+ no)
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+ ;;
+ *)
+ if test "$use_dlz_bdb" = "yes"
+ then
+ # User did not specify a path - guess directories
+ bdbdirs="/usr/local /usr/pkg /usr"
+ elif test -d "$use_dlz_bdb"
+ then
+ # User specified directory and it exists
+ bdbdirs="$use_dlz_bdb"
+ else
+ echo "$as_me:$LINENO: result: not found" >&5
+echo "${ECHO_T}not found" >&6
+ { { echo "$as_me:$LINENO: error: path $use_dlz_bdb does not exist" >&5
+echo "$as_me: error: path $use_dlz_bdb does not exist" >&2;}
+ { (exit 1); exit 1; }; }
+ bdbdirs=""
+ fi
+
+ # Use path we were given or guessed. This is insanely
+ # complicated because we have to search for a bunch of
+ # platform-specific variations and have to check
+ # separately for include and library directories.
+
+ # Set both to yes, so we can check them later
+ dlz_bdb_inc="yes"
+ dlz_bdb_libs="yes"
+
+ for dd in $bdbdirs
+ do
+ # Skip nonexistant directories
+ if test ! -d "$dd"
+ then
+ continue
+ fi
+
+ # Check other locations for includes.
+ # Order is important (sigh).
+
+ bdb_incdirs="/ /db42/ /db41/ /db4/ /db/"
+ for d in $bdb_incdirs
+ do
+ if test -f "$dd/include${d}db.h"
+ then
+ dlz_bdb_inc="-I$dd/include${d}"
+ break
+ fi
+ done
+
+ # Give up on this directory if we couldn't
+ # find the include subdir
+
+ if test "$dlz_bdb_inc" = "yes"
+ then
+ continue
+ fi
+
+ # Look for libname other than libdb.so.
+ # Order is important (sigh).
+
+ bdb_libnames="db42 db-4.2 db41 db-4.1 db"
+ for d in $bdb_libnames
+ do
+ if test -f "$dd/lib/lib${d}.so"
+ then
+ if test "$dd" != "/usr"
+ then
+ dlz_bdb_libs="-L${dd}/lib "
+ fi
+ dlz_bdb_libs="${dlz_bdb_libs}-l${d}"
+ break
+ fi
+ done
+
+ # If we found both incdir and lib, we're done
+ if test "$dlz_bdb_libs" != "yes"
+ then
+ break
+ fi
+
+ # Otherwise, we're starting over
+
+ dlz_bdb_inc="yes"
+ dlz_bdb_libs="yes"
+ done
+
+ # Done searching, now make sure we got everything.
+
+ if test "$dlz_bdb_inc" = "yes"
+ then
+ echo "$as_me:$LINENO: result: not found" >&5
+echo "${ECHO_T}not found" >&6
+ { { echo "$as_me:$LINENO: error: could not find Berkeley DB include directory" >&5
+echo "$as_me: error: could not find Berkeley DB include directory" >&2;}
+ { (exit 1); exit 1; }; }
+ fi
+
+ if test "$dlz_bdb_libs" = "yes"
+ then
+ echo "$as_me:$LINENO: result: not found" >&5
+echo "${ECHO_T}not found" >&6
+ { { echo "$as_me:$LINENO: error: could not find Berkeley DB library" >&5
+echo "$as_me: error: could not find Berkeley DB library" >&2;}
+ { (exit 1); exit 1; }; }
+ fi
+
+
+ USE_DLZ="$USE_DLZ -DDLZ_BDB"
+ for i in dlz_bdb_driver dlz_bdbhpt_driver
+ do
+ DLZ_DRIVER_SRCS="$DLZ_DRIVER_SRCS $dlzdir/$i.c"
+ DLZ_DRIVER_OBJS="$DLZ_DRIVER_OBJS $i.$O"
+ done
+ if test -n "$dlz_bdb_inc"
+ then
+ DLZ_DRIVER_INCLUDES="$DLZ_DRIVER_INCLUDES $dlz_bdb_inc"
+ fi
+ if test -n "$dlz_bdb_libs"
+ then
+ DLZ_DRIVER_LIBS="$DLZ_DRIVER_LIBS $dlz_bdb_libs"
+ fi
+
+
+ echo "$as_me:$LINENO: result: using Berkeley DB: $dlz_bdb_inc $dlz_bdb_libs" >&5
+echo "${ECHO_T}using Berkeley DB: $dlz_bdb_inc $dlz_bdb_libs" >&6
+
+ ac_config_files="$ac_config_files contrib/dlz/bin/dlzbdb/Makefile"
+
+ ;;
+esac
+
+
+#
+# Was --with-dlz-filesystem specified?
+#
+
+echo "$as_me:$LINENO: checking for file system DLZ driver" >&5
+echo $ECHO_N "checking for file system DLZ driver... $ECHO_C" >&6
+
+# Check whether --with-dlz_filesystem or --without-dlz_filesystem was given.
+if test "${with_dlz_filesystem+set}" = set; then
+ withval="$with_dlz_filesystem"
+ use_dlz_filesystem="$withval"
+else
+ use_dlz_filesystem="no"
+fi;
+
+case "$use_dlz_filesystem" in
+ no)
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+ ;;
+ *)
+
+ USE_DLZ="$USE_DLZ -DDLZ_FILESYSTEM"
+ for i in dlz_filesystem_driver
+ do
+ DLZ_DRIVER_SRCS="$DLZ_DRIVER_SRCS $dlzdir/$i.c"
+ DLZ_DRIVER_OBJS="$DLZ_DRIVER_OBJS $i.$O"
+ done
+ if test -n ""
+ then
+ DLZ_DRIVER_INCLUDES="$DLZ_DRIVER_INCLUDES "
+ fi
+ if test -n ""
+ then
+ DLZ_DRIVER_LIBS="$DLZ_DRIVER_LIBS "
+ fi
+
+
+ echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+ ;;
+esac
+
+
+#
+# Was --with-dlz-ldap specified?
+#
+
+echo "$as_me:$LINENO: checking for LDAP DLZ driver" >&5
+echo $ECHO_N "checking for LDAP DLZ driver... $ECHO_C" >&6
+
+# Check whether --with-dlz_ldap or --without-dlz_ldap was given.
+if test "${with_dlz_ldap+set}" = set; then
+ withval="$with_dlz_ldap"
+ use_dlz_ldap="$withval"
+else
+ use_dlz_ldap="no"
+fi;
+
+if test "$use_dlz_ldap" = "yes"
+then
+ # User did not specify a path - guess it
+ ldapdirs="/usr /usr/local /usr/pkg"
+ for d in $ldapdirs
+ do
+ if test -f $d/include/ldap.h
+ then
+ use_dlz_ldap=$d
+ break
+ fi
+ done
+fi
+
+if test "$use_dlz_ldap" = "yes"
+then
+ echo "$as_me:$LINENO: result: not found" >&5
+echo "${ECHO_T}not found" >&6
+ { { echo "$as_me:$LINENO: error: LDAP headers were not found in any of $ldapdirs; use --with-dlz-ldap=/path" >&5
+echo "$as_me: error: LDAP headers were not found in any of $ldapdirs; use --with-dlz-ldap=/path" >&2;}
+ { (exit 1); exit 1; }; }
+fi
+
+case "$use_dlz_ldap" in
+ no)
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+ ;;
+ *)
+
+ USE_DLZ="$USE_DLZ -DDLZ_LDAP"
+ for i in dlz_ldap_driver
+ do
+ DLZ_DRIVER_SRCS="$DLZ_DRIVER_SRCS $dlzdir/$i.c"
+ DLZ_DRIVER_OBJS="$DLZ_DRIVER_OBJS $i.$O"
+ done
+ if test -n "-I$use_dlz_ldap/include"
+ then
+ DLZ_DRIVER_INCLUDES="$DLZ_DRIVER_INCLUDES -I$use_dlz_ldap/include"
+ fi
+ if test -n "-L$use_dlz_ldap/lib -lldap -llber"
+ then
+ DLZ_DRIVER_LIBS="$DLZ_DRIVER_LIBS -L$use_dlz_ldap/lib -lldap -llber"
+ fi
+
+
+ echo "$as_me:$LINENO: result: using LDAP from $use_dlz_ldap/lib and $use_dlz_ldap/include" >&5
+echo "${ECHO_T}using LDAP from $use_dlz_ldap/lib and $use_dlz_ldap/include" >&6
+ ;;
+esac
+
+
+#
+# Was --with-dlz-odbc specified?
+#
+
+echo "$as_me:$LINENO: checking for ODBC DLZ driver" >&5
+echo $ECHO_N "checking for ODBC DLZ driver... $ECHO_C" >&6
+
+# Check whether --with-dlz_odbc or --without-dlz_odbc was given.
+if test "${with_dlz_odbc+set}" = set; then
+ withval="$with_dlz_odbc"
+ use_dlz_odbc="$withval"
+else
+ use_dlz_odbc="no"
+fi;
+
+if test "$use_dlz_odbc" = "yes"
+then
+ # User did not specify a path - guess it
+ odbcdirs="/usr /usr/local /usr/pkg"
+ for d in $odbcdirs
+ do
+ if test -f $d/include/sql.h -a -f $d/lib/libodbc.a
+ then
+ use_dlz_odbc=$d
+ break
+ fi
+ done
+fi
+
+case "$use_dlz_odbc" in
+ no)
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+ ;;
+ yes)
+ echo "$as_me:$LINENO: result: not found" >&5
+echo "${ECHO_T}not found" >&6
+ { { echo "$as_me:$LINENO: error: ODBC headers were not found in any of $odbcdirs; use --with-dlz-odbc=/path" >&5
+echo "$as_me: error: ODBC headers were not found in any of $odbcdirs; use --with-dlz-odbc=/path" >&2;}
+ { (exit 1); exit 1; }; }
+ ;;
+ *)
+
+ USE_DLZ="$USE_DLZ -DDLZ_ODBC"
+ for i in dlz_odbc_driver
+ do
+ DLZ_DRIVER_SRCS="$DLZ_DRIVER_SRCS $dlzdir/$i.c"
+ DLZ_DRIVER_OBJS="$DLZ_DRIVER_OBJS $i.$O"
+ done
+ if test -n "-I$use_dlz_odbc/include"
+ then
+ DLZ_DRIVER_INCLUDES="$DLZ_DRIVER_INCLUDES -I$use_dlz_odbc/include"
+ fi
+ if test -n "-L$use_dlz_odbc/lib -lodbc"
+ then
+ DLZ_DRIVER_LIBS="$DLZ_DRIVER_LIBS -L$use_dlz_odbc/lib -lodbc"
+ fi
+
+
+ echo "$as_me:$LINENO: result: using ODBC from $use_dlz_odbc" >&5
+echo "${ECHO_T}using ODBC from $use_dlz_odbc" >&6
+ ;;
+esac
+
+
+#
+# Was --with-dlz-stub specified?
+#
+
+echo "$as_me:$LINENO: checking for stub DLZ driver" >&5
+echo $ECHO_N "checking for stub DLZ driver... $ECHO_C" >&6
+
+# Check whether --with-dlz_stub or --without-dlz_stub was given.
+if test "${with_dlz_stub+set}" = set; then
+ withval="$with_dlz_stub"
+ use_dlz_stub="$withval"
+else
+ use_dlz_stub="no"
+fi;
+
+case "$use_dlz_stub" in
+ no)
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+ ;;
+ *)
+
+
+ USE_DLZ="$USE_DLZ -DDLZ_STUB"
+ for i in dlz_stub_driver
+ do
+ DLZ_DRIVER_SRCS="$DLZ_DRIVER_SRCS $dlzdir/$i.c"
+ DLZ_DRIVER_OBJS="$DLZ_DRIVER_OBJS $i.$O"
+ done
+ if test -n ""
+ then
+ DLZ_DRIVER_INCLUDES="$DLZ_DRIVER_INCLUDES "
+ fi
+ if test -n ""
+ then
+ DLZ_DRIVER_LIBS="$DLZ_DRIVER_LIBS "
+ fi
+
+
+ echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+ ;;
+esac
+
+
+# Add any additional DLZ drivers here.
+
+#
+# Finally, some generic stuff that applies to all drivers, assuming
+# we're compiling DLZ at all.
+#
+if test -n "$USE_DLZ"
+then
+ #
+ # Where to find DLZ driver header files.
+ #
+ DLZ_DRIVER_INCLUDES="-I$dlzdir/include $DLZ_DRIVER_INCLUDES"
+
+ #
+ # Initialization and shutdown wrappers, helper functions.
+ #
+ DLZ_DRIVER_SRCS="$dlzdir/dlz_drivers.c $dlzdir/sdlz_helper.c $DLZ_DRIVER_SRCS"
+ DLZ_DRIVER_OBJS="dlz_drivers.$O sdlz_helper.$O $DLZ_DRIVER_OBJS"
+fi
+
+
+echo "$as_me:$LINENO: checking for DLZ" >&5
+echo $ECHO_N "checking for DLZ... $ECHO_C" >&6
+
+if test -n "$USE_DLZ"
+then
+ echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+ USE_DLZ="-DDLZ $USE_DLZ"
+ DLZ_DRIVER_RULES=contrib/dlz/drivers/rules
+ ac_config_files="$ac_config_files $DLZ_DRIVER_RULES"
+
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+ DLZ_DRIVER_RULES=/dev/null
+fi
+
+
+
+
+
+
+
+
+
#
# Commands to run at the end of config.status.
# Don't just put these into configure, it won't work right if somebody
ac_config_commands="$ac_config_commands chmod"
+#
+# Files to configure. These are listed here because we used to
+# specify them as arguments to AC_OUTPUT. It's (now) ok to move these
+# elsewhere if there's a good reason for doing so.
+#
+
+ ac_config_files="$ac_config_files Makefile make/Makefile make/mkdep lib/Makefile lib/isc/Makefile lib/isc/include/Makefile lib/isc/include/isc/Makefile lib/isc/include/isc/platform.h lib/isc/unix/Makefile lib/isc/unix/include/Makefile lib/isc/unix/include/isc/Makefile lib/isc/nls/Makefile lib/isc/$thread_dir/Makefile lib/isc/$thread_dir/include/Makefile lib/isc/$thread_dir/include/isc/Makefile lib/isccc/Makefile lib/isccc/include/Makefile lib/isccc/include/isccc/Makefile lib/isccfg/Makefile lib/isccfg/include/Makefile lib/isccfg/include/isccfg/Makefile lib/dns/Makefile lib/dns/include/Makefile lib/dns/include/dns/Makefile lib/dns/include/dst/Makefile lib/bind9/Makefile lib/bind9/include/Makefile lib/bind9/include/bind9/Makefile lib/lwres/Makefile lib/lwres/include/Makefile lib/lwres/include/lwres/Makefile lib/lwres/include/lwres/netdb.h lib/lwres/include/lwres/platform.h lib/lwres/man/Makefile lib/lwres/unix/Makefile lib/lwres/unix/include/Makefile lib/lwres/unix/include/lwres/Makefile lib/tests/Makefile lib/tests/include/Makefile lib/tests/include/tests/Makefile bin/Makefile bin/check/Makefile bin/named/Makefile bin/named/unix/Makefile bin/rndc/Makefile bin/rndc/unix/Makefile bin/dig/Makefile bin/nsupdate/Makefile bin/tests/Makefile bin/tests/names/Makefile bin/tests/master/Makefile bin/tests/rbt/Makefile bin/tests/db/Makefile bin/tests/tasks/Makefile bin/tests/timers/Makefile bin/tests/dst/Makefile bin/tests/mem/Makefile bin/tests/net/Makefile bin/tests/sockaddr/Makefile bin/tests/system/Makefile bin/tests/system/conf.sh bin/tests/system/lwresd/Makefile bin/tests/system/tkey/Makefile bin/tests/headerdep_test.sh bin/dnssec/Makefile doc/Makefile doc/arm/Makefile doc/misc/Makefile isc-config.sh doc/xsl/Makefile doc/xsl/isc-docbook-chunk.xsl doc/xsl/isc-docbook-html.xsl doc/xsl/isc-docbook-latex.xsl doc/xsl/isc-manpage.xsl"
+
+
#
# Do it
#
- ac_config_files="$ac_config_files make/rules make/includes Makefile make/Makefile make/mkdep lib/Makefile lib/isc/Makefile lib/isc/include/Makefile lib/isc/include/isc/Makefile lib/isc/include/isc/platform.h lib/isc/unix/Makefile lib/isc/unix/include/Makefile lib/isc/unix/include/isc/Makefile lib/isc/nls/Makefile lib/isc/$thread_dir/Makefile lib/isc/$thread_dir/include/Makefile lib/isc/$thread_dir/include/isc/Makefile lib/isccc/Makefile lib/isccc/include/Makefile lib/isccc/include/isccc/Makefile lib/isccfg/Makefile lib/isccfg/include/Makefile lib/isccfg/include/isccfg/Makefile lib/dns/Makefile lib/dns/include/Makefile lib/dns/include/dns/Makefile lib/dns/include/dst/Makefile lib/bind9/Makefile lib/bind9/include/Makefile lib/bind9/include/bind9/Makefile lib/lwres/Makefile lib/lwres/include/Makefile lib/lwres/include/lwres/Makefile lib/lwres/include/lwres/netdb.h lib/lwres/include/lwres/platform.h lib/lwres/man/Makefile lib/lwres/unix/Makefile lib/lwres/unix/include/Makefile lib/lwres/unix/include/lwres/Makefile lib/tests/Makefile lib/tests/include/Makefile lib/tests/include/tests/Makefile bin/Makefile bin/check/Makefile bin/named/Makefile bin/named/unix/Makefile bin/rndc/Makefile bin/rndc/unix/Makefile bin/dig/Makefile bin/nsupdate/Makefile bin/tests/Makefile bin/tests/names/Makefile bin/tests/master/Makefile bin/tests/rbt/Makefile bin/tests/db/Makefile bin/tests/tasks/Makefile bin/tests/timers/Makefile bin/tests/dst/Makefile bin/tests/mem/Makefile bin/tests/net/Makefile bin/tests/sockaddr/Makefile bin/tests/system/Makefile bin/tests/system/conf.sh bin/tests/system/lwresd/Makefile bin/tests/system/tkey/Makefile bin/tests/headerdep_test.sh bin/dnssec/Makefile doc/Makefile doc/arm/Makefile doc/misc/Makefile isc-config.sh doc/xsl/Makefile doc/xsl/isc-docbook-chunk.xsl doc/xsl/isc-docbook-html.xsl doc/xsl/isc-docbook-latex.xsl doc/xsl/isc-manpage.xsl"
cat >confcache <<\_ACEOF
# This file is a shell script that caches the results of configure
# tests run on this system so they can be shared between configure
# Handling of arguments.
"make/rules" ) CONFIG_FILES="$CONFIG_FILES make/rules" ;;
"make/includes" ) CONFIG_FILES="$CONFIG_FILES make/includes" ;;
+ "contrib/dlz/bin/dlzbdb/Makefile" ) CONFIG_FILES="$CONFIG_FILES contrib/dlz/bin/dlzbdb/Makefile" ;;
+ "$DLZ_DRIVER_RULES" ) CONFIG_FILES="$CONFIG_FILES $DLZ_DRIVER_RULES" ;;
"Makefile" ) CONFIG_FILES="$CONFIG_FILES Makefile" ;;
"make/Makefile" ) CONFIG_FILES="$CONFIG_FILES make/Makefile" ;;
"make/mkdep" ) CONFIG_FILES="$CONFIG_FILES make/mkdep" ;;
s,@BIND9_LWRES_BUILDINCLUDE@,$BIND9_LWRES_BUILDINCLUDE,;t t
s,@BIND9_BIND9_BUILDINCLUDE@,$BIND9_BIND9_BUILDINCLUDE,;t t
s,@BIND9_VERSION@,$BIND9_VERSION,;t t
+s,@PG_CONFIG@,$PG_CONFIG,;t t
+s,@USE_DLZ@,$USE_DLZ,;t t
+s,@DLZ_DRIVER_INCLUDES@,$DLZ_DRIVER_INCLUDES,;t t
+s,@DLZ_DRIVER_LIBS@,$DLZ_DRIVER_LIBS,;t t
+s,@DLZ_DRIVER_SRCS@,$DLZ_DRIVER_SRCS,;t t
+s,@DLZ_DRIVER_OBJS@,$DLZ_DRIVER_OBJS,;t t
s,@LIBOBJS@,$LIBOBJS,;t t
s,@LTLIBOBJS@,$LTLIBOBJS,;t t
/@BIND9_MAKE_INCLUDES@/r $BIND9_MAKE_INCLUDES
s,@LIBBIND9_API@,,;t t
/@LIBLWRES_API@/r $LIBLWRES_API
s,@LIBLWRES_API@,,;t t
+/@DLZ_DRIVER_RULES@/r $DLZ_DRIVER_RULES
+s,@DLZ_DRIVER_RULES@,,;t t
CEOF
_ACEOF
esyscmd([sed "s/^/# /" COPYRIGHT])dnl
AC_DIVERT_POP()dnl
-AC_REVISION($Revision: 1.391 $)
+AC_REVISION($Revision: 1.392 $)
AC_INIT(lib/dns/name.c)
-AC_PREREQ(2.13)
+AC_PREREQ(2.59)
AC_CONFIG_HEADER(config.h)
AC_CONFIG_SUBDIRS(lib/bind)
AC_SUBST(STD_CWARNINGS)
AC_SUBST(CCOPT)
+#
+# Make very sure that these are the first files processed by
+# config.status, since we use the processed output as the input for
+# AC_SUBST_FILE() subsitutions in other files.
+#
+AC_CONFIG_FILES([make/rules make/includes])
+
AC_PATH_PROG(AR, ar)
ARFLAGS="cruv"
AC_SUBST(AR)
#
AC_C_BIGENDIAN
+
#
# was --with-openssl specified?
#
;;
esac
+
#
# Here begins a very long section to determine the system's networking
# capabilities. The order of the tests is signficant.
AC_SUBST_FILE(LIBLWRES_API)
LIBLWRES_API=$srcdir/lib/lwres/api
+#
+# Configure any DLZ drivers.
+#
+# If config.dlz.in selects one or more DLZ drivers, it will set
+# USE_DLZ to a non-empty value, which will be our clue to
+# enable the DLZ core functions.
+#
+# This section has to come after the libtool stuff because it needs to
+# know how to name the driver object files.
+#
+
+USE_DLZ=""
+DLZ_DRIVER_INCLUDES=""
+DLZ_DRIVER_LIBS=""
+DLZ_DRIVER_SRCS=""
+DLZ_DRIVER_OBJS=""
+
+sinclude(contrib/dlz/config.dlz.in)
+
+AC_MSG_CHECKING(for DLZ)
+
+if test -n "$USE_DLZ"
+then
+ AC_MSG_RESULT(yes)
+ USE_DLZ="-DDLZ $USE_DLZ"
+ DLZ_DRIVER_RULES=contrib/dlz/drivers/rules
+ AC_CONFIG_FILES([$DLZ_DRIVER_RULES])
+else
+ AC_MSG_RESULT(no)
+ DLZ_DRIVER_RULES=/dev/null
+fi
+
+AC_SUBST(USE_DLZ)
+AC_SUBST(DLZ_DRIVER_INCLUDES)
+AC_SUBST(DLZ_DRIVER_LIBS)
+AC_SUBST(DLZ_DRIVER_SRCS)
+AC_SUBST(DLZ_DRIVER_OBJS)
+AC_SUBST_FILE(DLZ_DRIVER_RULES)
+
+
#
# Commands to run at the end of config.status.
# Don't just put these into configure, it won't work right if somebody
[chmod a+x isc-config.sh])
#
-# Do it
+# Files to configure. These are listed here because we used to
+# specify them as arguments to AC_OUTPUT. It's (now) ok to move these
+# elsewhere if there's a good reason for doing so.
#
-AC_OUTPUT(
- make/rules
- make/includes
+AC_CONFIG_FILES([
Makefile
make/Makefile
make/mkdep
doc/xsl/isc-docbook-html.xsl
doc/xsl/isc-docbook-latex.xsl
doc/xsl/isc-manpage.xsl
-)
+])
+
+#
+# Do it
+#
+
+AC_OUTPUT
# Tell Emacs to edit this file in shell mode.
# Local Variables:
--- /dev/null
+Makefile
+dlzbdb
+*.o
--- /dev/null
+# Copyright (C) 1998-2001 Internet Software Consortium.
+#
+# 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 INTERNET SOFTWARE CONSORTIUM
+# DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+# INTERNET SOFTWARE CONSORTIUM 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.
+
+# $Id: Makefile.in,v 1.2 2005/09/05 00:10:54 marka Exp $
+
+srcdir = @srcdir@
+VPATH = @srcdir@
+top_srcdir = @top_srcdir@
+
+@BIND9_VERSION@
+
+@BIND9_MAKE_INCLUDES@
+
+DLZINCLUDES = @DLZ_BDB_INC@
+
+CINCLUDES = -I${srcdir}/include -I${srcdir}/unix/include \
+ ${ISC_INCLUDES} ${DLZINCLUDES}
+
+CDEFINES = @USE_DLZ_BDB@
+CWARNINGS =
+
+DLZLIBS = @DLZ_BDB_LIBS@
+ISCLIBS = ../../lib/isc/libisc.@A@
+
+DEPLIBS = ${ISCDEPLIBS}
+
+LIBS = ${ISCLIBS} ${DLZLIBS} @LIBS@
+
+TARGETS = dlzbdb
+
+SRCS = dlzbdb.c
+
+#MANPAGES =
+
+#HTMLPAGES =
+
+#MANOBJS = ${MANPAGES} ${HTMLPAGES}
+
+@BIND9_MAKE_RULES@
+
+dlzbdb.@O@: dlzbdb.c
+ ${LIBTOOL} ${CC} ${ALL_CFLAGS} -DVERSION=\"${VERSION}\" \
+ -c ${srcdir}/dlzbdb.c
+
+dlzbdb: dlzbdb.@O@ ${DEPLIBS}
+ ${LIBTOOL} ${PURIFY} ${CC} ${CFLAGS} -o $@ dlzbdb.@O@ ${LIBS}
+
+doc man:: ${MANOBJS}
+
+#docclean manclean maintainer-clean::
+# rm -f ${MANOBJS}
+
+clean distclean maintainer-clean::
+ rm -f ${TARGETS}
+
+installdirs:
+ $(SHELL) ${top_srcdir}/mkinstalldirs ${DESTDIR}${sbindir}
+# $(SHELL) ${top_srcdir}/mkinstalldirs ${DESTDIR}${mandir}/man8
+
+install:: dlzbdb installdirs
+ ${LIBTOOL} ${INSTALL_PROGRAM} dlzbdb ${DESTDIR}${sbindir}
--- /dev/null
+/*
+ * 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) 1999-2001 Internet Software Consortium.
+ *
+ * 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 INTERNET SOFTWARE CONSORTIUM
+ * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+ * INTERNET SOFTWARE CONSORTIUM 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.
+ */
+
+#ifdef DLZ_BDB
+
+/*
+ * exit codes
+ * 0 everything ok
+ * 1 error parsing command line
+ * 2 Missing, too many or invalid combination of command line parameters
+ * 3 Unable to open BDB database.
+ * 4 Unable to allocate memory for, or create lexer.
+ * 5 unable to perform BDB cursor operation
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include <isc/buffer.h>
+#include <isc/commandline.h>
+#include <isc/formatcheck.h>
+#include <isc/lex.h>
+#include <isc/mem.h>
+#include <isc/result.h>
+#include <isc/string.h>
+#include <isc/util.h>
+
+#include <db.h>
+
+/* shut up compiler warnings about no previous prototype */
+
+static void
+show_usage(void);
+
+int
+getzone(DB *dbp, const DBT *pkey, const DBT *pdata, DBT *skey);
+
+int
+gethost(DB *dbp, const DBT *pkey, const DBT *pdata, DBT *skey);
+
+void
+bdb_cleanup(void);
+
+isc_result_t
+bdb_opendb(DBTYPE db_type, DB **db_out, const char *db_name, int flags);
+
+void
+put_data(isc_boolean_t dns_data, char *input_key, char *input_data);
+
+void
+insert_data(void);
+
+isc_result_t
+openBDB(void);
+
+isc_result_t
+open_lexer(void);
+
+void
+close_lexer(void);
+
+isc_result_t
+bulk_write(char type, DB *database, DBC *dbcursor, DBT *bdbkey, DBT *bdbdata);
+
+void
+operation_add(void);
+
+void
+operation_bulk(void);
+
+void
+operation_listOrDelete(isc_boolean_t dlt);
+
+
+/*%
+ * Maximum length of a single data line that
+ * may be inserted into database by this program.
+ * If you need to insert a line of data that is more
+ * than 10,000 characters change this definition.
+ */
+
+#define max_data_len 10000
+
+/*%
+ * BDB database names. If you want to use different
+ * database names change them here.
+ */
+
+#define dlz_data "dns_data"
+#define dlz_zone "dns_zone"
+#define dlz_host "dns_host"
+#define dlz_client "dns_client"
+
+
+/*%
+ * Error code returned by BDB secondary index callback functions.
+ * This error is returned if the callback function could not create
+ * the secondary index for any reason.
+ */
+
+#define BDBparseErr 1
+
+/* A struct to hold all the relevant info about the database */
+
+typedef struct bdb_instance {
+ DB_ENV *dbenv; /* BDB environment */
+ DB *data; /* dns_data database handle */
+ DBC *cursor; /* database cursor */
+ DBC *cursor2; /* second cursor used during list operation. */
+ DBC *cursor3; /* third cursor used during list operation */
+ DBC *cursor4; /* fourth cursor used during list operation */
+ DB *zone; /* zone database handle */
+ DB *host; /* host database handle */
+ DB *client; /* client database handle */
+} bdb_instance_t;
+
+/* Possible operations */
+
+#define list 1 /* list data */
+#define dele 2 /* delete data */
+#define add 3 /* add a single piece of data */
+#define bulk 4 /* bulk load data */
+
+
+/*%
+ * quit macro is used instead of exit. quit always trys to close the lexer
+ * and the BDB database before exiting.
+ */
+
+#define quit(i) close_lexer(); bdb_cleanup(); exit(i);
+
+/*%
+ * checkOp is used to verify that only one operation (list, del, add,
+ * bulk from file, bulk from stdin) is specified on the command line.
+ * This prevents a user from specifying two operations on the command
+ * line, which would make no sense anyway.
+ */
+
+#define checkOp(x) if (x != 0) {fprintf(stderr, "\nonly one operation "\
+ "(l e d a f s) may be specified\n"); quit(2);}
+
+/*%
+ * checkParam is used to only allow a parameter to be specified once.
+ * I.E. the parameter key can only be used on the command line once.
+ * any attempt to use it twice causes an error.
+ */
+
+#define checkParam(x, y) if (x != NULL) {fprintf(stderr, "\n%s may only "\
+ "be specified once\n", y); quit(2);}
+
+/*%
+ * checkInvalidParam is used to only allow paramters which make sense for
+ * the operation selected. I.E. passing the key parameter makes no sense
+ * for the add operation, and thus it isn't allowed.
+ */
+
+#define checkInvalidParam(x, y, z) if (x != NULL) {fprintf(stderr, "\n%s "\
+ "may not be specified %s\n", y, z); quit(2);}
+
+/*%
+ * checkInvalidOption is used to only allow paramters which make sense for
+ * the operation selected - but checks boolean options.
+ * I.E. passing the "b" bare_list parameter makes no sense for the add
+ * operation, and thus it isn't allowed.
+ * if w == x then output error message "flag", "message"
+ */
+
+#define checkInvalidOption(w, x, y, z) if (w == x) {fprintf(stderr, "\n%s "\
+ "may not be specified %s\n", y, z); quit(2);}
+
+/* Global Variables */
+
+int operation = 0; /*%< operation to perform. */
+/*% allow new lock files or DB to be created. */
+isc_boolean_t create_allowed = isc_boolean_false;
+char *key = NULL; /*%< key to use in list & del operations */
+
+/*% dump DB in DLZBDB bulk format */
+isc_boolean_t list_everything = isc_boolean_false;
+unsigned int key_val; /*%< key as unsigned int used in list & del operations */
+char *zone = NULL; /*%< zone to use in list operations */
+char *host = NULL; /*%< host to use in list operations */
+char *c_zone = NULL; /*%< client zone to use in list operations */
+char *c_ip = NULL; /*%< client IP to use in list operations */
+char *a_data = NULL; /*%< data in add operation */
+char *bulk_file = NULL; /*%< bulk data file to load */
+char *db_envdir = NULL; /*%< BDB environment location */
+char *db_file = NULL; /*%< BDB database file location. */
+bdb_instance_t db; /* BDB instance we are operating on */
+isc_lex_t *lexer = NULL; /*%< lexer for use to use in parsing input */
+isc_mem_t *lex_mctx = NULL; /*%< memory context for lexer */
+char lex_data_buf[max_data_len]; /*%< data array to use for lex_buffer below */
+isc_buffer_t lex_buffer; /*%< buffer for lexer during add operation */
+
+
+/*%
+ * Displays usage message
+ */
+
+static void
+show_usage(void) {
+ fprintf(stderr, "\n\n\
+---Usage:---------------------------------------------------------------------\
+\n\n\
+ List data:\n\
+ dlzbdb -l [-k key] [-z zone] [-h host] [-c client_zone] [-i client_ip]\n\
+ BDB_environment BDB_database\n\n\
+ Delete data:\n\
+ dlzbdb -d [-k key] [-c client_zone] [-i client_ip]\n\
+ BDB_environment BDB_database\n\n\
+ Bulk load data from file:\n\
+ dlzbdb -f file_to_load BDB_environment BDB_database\n\n\
+ Bulk load data from stdin\n\
+ dlzbdb -s BDB_environment BDB_database\n\n\
+ Add data:\n\
+ dlzbdb -a \"dns data to be added\" BDB_environment BDB_database\n\n\
+ Export data:\n\
+ dlzbdb -e BDB_environment BDB_database\n\n\
+ Normally operations can only be performed on an existing database files.\n\
+ Use the -n flag with any operation to allow files to be created.\n\
+ Existing files will NOT be truncated by using the -n flag.\n\
+ The -n flag will allow a new database to be created, or allow new\n\
+ environment files to be created for an existing database.\n\n\
+---Format for -f & -a options:------------------------------------------------\
+\n\n\
+db_type zone host dns_type ttl ip\n\
+db_type zone host dns_type ttl mx_priority mail_host\n\
+db_type zone host dns_type ttl nm_svr resp_psn serial refresh retry expire min\
+\n\
+db_type zone client_ip\n\n\
+---Examples:------------------------------------------------------------------\
+\n\n\
+d mynm.com www A 10 127.0.0.1\n\
+d mynm.com @ MX 10 5 mail\n\
+d mynm.com @ SOA 10 ns1.mynm.com. root.mynm.com. 2 28800 7200 604800 86400\n\
+c mynm.com 127.0.0.1\n\
+c mynm.com 192.168.0.10\n\
+");
+quit(1);
+}
+
+
+/*% BDB callback to create zone secondary index */
+
+int
+getzone(DB *dbp, const DBT *pkey, const DBT *pdata, DBT *skey) {
+ char *tmp;
+ char *left;
+ char *right;
+ int result=0;
+
+ UNUSED(dbp);
+ UNUSED(pkey);
+
+ /* Allocate memory to use in parsing the string */
+ tmp = right = malloc(pdata->size + 1);
+
+ /* verify memory was allocated */
+ if (right == NULL) {
+ result = BDBparseErr;
+ goto getzone_cleanup;
+ }
+
+ /* copy data string into newly allocated memory */
+ strncpy(right, pdata->data, pdata->size);
+ right[pdata->size] = '\0';
+
+ /* split string at the first space */
+ left = isc_string_separate(&right, " ");
+
+ /* copy string for "zone" secondary index */
+ skey->data = strdup(left);
+ if (skey->data == NULL) {
+ result = BDBparseErr;
+ goto getzone_cleanup;
+ }
+ /* set required values for BDB */
+ skey->size = strlen(skey->data);
+ skey->flags = DB_DBT_APPMALLOC;
+
+ getzone_cleanup:
+
+ /* cleanup memory */
+ if (tmp != NULL)
+ free(tmp);
+
+ return result;
+}
+
+/*%
+ * BDB callback to create host secondary index
+ */
+
+int
+gethost(DB *dbp, const DBT *pkey, const DBT *pdata, DBT *skey) {
+ char *tmp;
+ char *left;
+ char *right;
+ int result=0;
+
+ UNUSED(dbp);
+ UNUSED(pkey);
+
+ /* allocate memory to use in parsing the string */
+ tmp = right = malloc(pdata->size + 1);
+
+ /* verify memory was allocated */
+ if (tmp == NULL) {
+ result = BDBparseErr;
+ goto gethost_cleanup;
+ }
+
+ /* copy data string into newly allocated memory */
+ strncpy(right, pdata->data, pdata->size);
+ right[pdata->size] = '\0';
+
+ /* we don't care about left string. */
+ /* memory of left string will be freed when tmp is freed. */
+ isc_string_separate(&right, " ");
+
+ /* verify right still has some characters left */
+ if (right == NULL) {
+ result = BDBparseErr;
+ goto gethost_cleanup;
+ }
+
+ /* get "host" from data string */
+ left = isc_string_separate(&right, " ");
+ /* copy string for "host" secondary index */
+ skey->data = strdup(left);
+ if (skey->data == NULL) {
+ result = BDBparseErr;
+ goto gethost_cleanup;
+ }
+ /* set required values for BDB */
+ skey->size = strlen(skey->data);
+ skey->flags = DB_DBT_APPMALLOC;
+
+ gethost_cleanup:
+
+ /* cleanup memory */
+ if (tmp != NULL)
+ free(tmp);
+
+ return result;
+}
+
+/*%
+ * Performs BDB cleanup. Close each database that we opened.
+ * Close environment. Set each var to NULL so we know they
+ * were closed and don't accidentally try to close them twice.
+ */
+
+void
+bdb_cleanup(void) {
+
+ /* close cursors */
+ if (db.cursor4 != NULL) {
+ db.cursor4->c_close(db.cursor4);
+ db.cursor4 = NULL;
+ }
+
+ if (db.cursor3 != NULL) {
+ db.cursor3->c_close(db.cursor3);
+ db.cursor3 = NULL;
+ }
+
+ if (db.cursor2 != NULL) {
+ db.cursor2->c_close(db.cursor2);
+ db.cursor2 = NULL;
+ }
+
+ if (db.cursor != NULL) {
+ db.cursor->c_close(db.cursor);
+ db.cursor = NULL;
+ }
+
+ /* close databases */
+ if (db.data != NULL) {
+ db.data->close(db.data, 0);
+ db.data = NULL;
+ }
+ if (db.host != NULL) {
+ db.host->close(db.host, 0);
+ db.host = NULL;
+ }
+ if (db.zone != NULL) {
+ db.zone->close(db.zone, 0);
+ db.zone = NULL;
+ }
+ if (db.client != NULL) {
+ db.client->close(db.client, 0);
+ db.client = NULL;
+ }
+
+ /* close environment */
+ if (db.dbenv != NULL) {
+ db.dbenv->close(db.dbenv, 0);
+ db.dbenv = NULL;
+ }
+}
+
+/*% Initializes, sets flags and then opens Berkeley databases. */
+
+isc_result_t
+bdb_opendb(DBTYPE db_type, DB **db_out, const char *db_name, int flags) {
+
+ int result;
+ int createFlag = 0;
+
+ /* Initialize the database. */
+ if ((result = db_create(db_out, db.dbenv, 0)) != 0) {
+ fprintf(stderr, "BDB could not initialize %s database. BDB error: %s",
+ db_name, db_strerror(result));
+ return ISC_R_FAILURE;
+ }
+
+ /* set database flags. */
+ if ((result = (*db_out)->set_flags(*db_out, flags)) != 0) {
+ fprintf(stderr, "BDB could not set flags for %s database. BDB error: %s",
+ db_name, db_strerror(result));
+ return ISC_R_FAILURE;
+ }
+
+ if (create_allowed == isc_boolean_true) {
+ createFlag = DB_CREATE;
+ }
+ /* open the database. */
+ if ((result = (*db_out)->open(*db_out, NULL, db_file, db_name, db_type,
+ createFlag, 0)) != 0) {
+ fprintf(stderr, "BDB could not open %s database in %s. BDB error: %s",
+ db_name, db_file, db_strerror(result));
+ return ISC_R_FAILURE;
+ }
+
+ return ISC_R_SUCCESS;
+}
+
+/*%
+ * parses input and adds it to the BDB database
+ * Lexer should be instantiated, and either a file or buffer opened for it.
+ * The insert_data function is used by both the add, and bulk insert
+ * operations
+ */
+
+void
+put_data(isc_boolean_t dns_data, char *input_key, char *input_data) {
+
+ int bdbres;
+ DBT key, data;
+
+ /* make sure key & data are completely empty */
+ memset(&key, 0, sizeof(key));
+ memset(&data, 0, sizeof(data));
+
+ /* if client data, setup key for insertion */
+ if (!dns_data && input_key != NULL) {
+ key.data = input_key;
+ key.size = strlen(input_key);
+ key.flags = 0;
+ }
+ /* always setup data for insertion */
+ data.data = input_data;
+ data.size = strlen(input_data);
+ data.flags = 0;
+
+ /* execute insert against appropriate database. */
+ if (dns_data) {
+ bdbres = db.data->put(db.data, NULL, &key, &data, DB_APPEND);
+ } else {
+ bdbres = db.client->put(db.client, NULL, &key, &data, 0);
+ }
+
+ /* if something went wrong, log error and quit */
+ if (bdbres != 0) {
+ fprintf(stderr, "BDB could not insert data. Error: %s",
+ db_strerror(bdbres));
+ quit(5);
+ }
+}
+
+void
+insert_data(void) {
+ unsigned int opt =
+ ISC_LEXOPT_EOL | /* Want end-of-line token. */
+ ISC_LEXOPT_EOF | /* Want end-of-file token. */
+ ISC_LEXOPT_QSTRING | /* Recognize qstrings. */
+ ISC_LEXOPT_QSTRINGMULTILINE; /* Allow multiline "" strings */
+
+ isc_result_t result;
+ isc_token_t token; /* token from lexer */
+ isc_boolean_t loop = isc_boolean_true;
+ isc_boolean_t have_czone = isc_boolean_false;
+ char data_arr[max_data_len];
+ isc_buffer_t buf;
+ char data_arr2[max_data_len];
+ isc_buffer_t buf2;
+ char data_type = 'u'; /* u =unknown, b =bad token, d/D =DNS, c/C =client IP */
+
+ /* Initialize buffers */
+ isc_buffer_init(&buf, &data_arr, max_data_len);
+ isc_buffer_init(&buf2, &data_arr2, max_data_len);
+
+ while (loop) {
+ result = isc_lex_gettoken(lexer, opt, &token);
+ if (result != ISC_R_SUCCESS)
+ goto data_cleanup;
+
+ switch(token.type) {
+ case isc_tokentype_string:
+ if (data_type == 'u') {
+ /* store data_type */
+ strncpy(&data_type, token.value.as_pointer, 1);
+ /* verify data_type was specified correctly on input */
+ if (strlen(token.value.as_pointer) > 1 || (
+ data_type != 'd' && data_type != 'D' &&
+ data_type != 'c' && data_type != 'C') ) {
+ /* if not, set to 'b' so this line is ignored. */
+ data_type = 'b';
+ }
+ } else if (data_type == 'c' || data_type == 'C') {
+ if (have_czone == isc_boolean_true) {
+ isc_buffer_putstr(&buf2, token.value.as_pointer);
+ /* add string terminator to buffer */
+ isc_buffer_putmem(&buf2, "\0", 1);
+ } else {
+ isc_buffer_putstr(&buf, token.value.as_pointer);
+ /* add string terminator to buffer */
+ isc_buffer_putmem(&buf, "\0", 1);
+ have_czone = isc_boolean_true;
+ }
+ } else {
+ isc_buffer_putstr(&buf, token.value.as_pointer);
+ isc_buffer_putstr(&buf, " ");
+ }
+ break;
+ case isc_tokentype_qstring:
+ isc_buffer_putstr(&buf, "\"");
+ isc_buffer_putstr(&buf, token.value.as_pointer);
+ isc_buffer_putstr(&buf, "\" ");
+ break;
+ case isc_tokentype_eol:
+ case isc_tokentype_eof:
+
+ if ((data_type != 'u' && isc_buffer_usedlength(&buf) > 0) || data_type == 'b') {
+ /* perform insert operation */
+ if (data_type == 'd' || data_type == 'D') {
+ /* add string terminator to buffer */
+ isc_buffer_putmem(&buf, "\0", 1);
+ put_data(isc_boolean_true, NULL, (char *) &data_arr);
+ } else if (data_type == 'c' || data_type == 'C') {
+ put_data(isc_boolean_false, (char *) &data_arr,
+ (char *) &data_arr2);
+ } else if (data_type == 'b') {
+ fprintf(stderr, "Bad / unknown token encountered on line %lu."\
+ " Skipping line.", isc_lex_getsourceline(lexer) - 1);
+ } else {
+ fprintf(stderr, "Bad / unknown db data type encountered on " \
+ "line %lu. Skipping line\n", isc_lex_getsourceline(lexer) - 1);
+ }
+ }
+
+ if (token.type == isc_tokentype_eof) {
+ loop = isc_boolean_false;
+ }
+
+ /* reset buffer for next insert */
+ isc_buffer_clear(&buf);
+ isc_buffer_clear(&buf2);
+ have_czone = isc_boolean_false;
+ data_type ='u';
+ break;
+ default:
+ data_type = 'b';
+ break;
+ }
+ }
+
+ return;
+
+ data_cleanup:
+ /* let user know we had problems */
+ fprintf(stderr, "Unknown error processing tokens during \"add\" or " \
+ "\"bulk\" operation.\nStoped processing on line %lu.",
+ isc_lex_getsourceline(lexer));
+}
+
+
+isc_result_t
+openBDB(void) {
+
+ int bdbres;
+ isc_result_t result;
+
+ /* create BDB environment */
+ /* Basically BDB allocates and assigns memory to db->dbenv */
+ bdbres = db_env_create(&db.dbenv, 0);
+ if (bdbres != 0) {
+ fprintf(stderr, "BDB environment could not be created. BDB error: %s",
+ db_strerror(bdbres));
+ result = ISC_R_FAILURE;
+ goto openBDB_cleanup;
+ }
+
+ /* open BDB environment */
+ if (create_allowed == isc_boolean_true) {
+ /* allowed to create new files */
+ bdbres = db.dbenv->open(db.dbenv, db_envdir,
+ DB_INIT_CDB | DB_INIT_MPOOL | DB_CREATE, 0);
+ } else { /* not allowed to create new files. */
+ bdbres = db.dbenv->open(db.dbenv, db_envdir,
+ DB_INIT_CDB | DB_INIT_MPOOL, 0);
+ }
+ if (bdbres != 0) {
+ fprintf(stderr, "BDB environment at '%s' could not be opened. BDB " \
+ "error: %s", db_envdir, db_strerror(bdbres));
+ result = ISC_R_FAILURE;
+ goto openBDB_cleanup;
+ }
+
+ /* open dlz_data database. */
+
+ result = bdb_opendb(DB_RECNO, &db.data, dlz_data, 0);
+ if (result != ISC_R_SUCCESS)
+ goto openBDB_cleanup;
+
+ /* open dlz_host database */
+ result = bdb_opendb(DB_BTREE, &db.host, dlz_host, DB_DUP | DB_DUPSORT);
+ if (result != ISC_R_SUCCESS)
+ goto openBDB_cleanup;
+
+ /* open dlz_zone database. */
+ result = bdb_opendb(DB_BTREE, &db.zone, dlz_zone, DB_DUP | DB_DUPSORT);
+ if (result != ISC_R_SUCCESS)
+ goto openBDB_cleanup;
+
+ /* open dlz_client database. */
+ result = bdb_opendb(DB_BTREE, &db.client, dlz_client, DB_DUP | DB_DUPSORT);
+ if (result != ISC_R_SUCCESS)
+ goto openBDB_cleanup;
+
+ /* associate the host secondary database with the primary database */
+ bdbres = db.data->associate(db.data, NULL, db.host, gethost, 0);
+ if (bdbres != 0) {
+ fprintf(stderr, "BDB could not associate %s database with %s. BDB "\
+ "error: %s", dlz_host, dlz_data, db_strerror(bdbres));
+ result = ISC_R_FAILURE;
+ goto openBDB_cleanup;
+ }
+
+ /* associate the zone secondary database with the primary database */
+ bdbres = db.data->associate(db.data, NULL, db.zone, getzone, 0);
+ if (bdbres != 0) {
+ fprintf(stderr, "BDB could not associate %s database with %s. BDB "\
+ "error: %s", dlz_zone, dlz_data, db_strerror(bdbres));
+ result = ISC_R_FAILURE;
+ goto openBDB_cleanup;
+ }
+
+ return result;
+
+ openBDB_cleanup:
+
+ bdb_cleanup();
+ return result;
+}
+
+/*% Create & open lexer to parse input data */
+
+isc_result_t
+open_lexer(void) {
+ isc_result_t result;
+
+ /* check if we already opened the lexer, if we did, return success */
+ if (lexer != NULL)
+ return ISC_R_SUCCESS;
+
+ /* allocate memory for lexer, and verify it was allocated */
+ result = isc_mem_create(0, 0, &lex_mctx);
+ if (result != ISC_R_SUCCESS) {
+ fprintf(stderr, "unexpected error creating lexer\n");
+ return result;
+ }
+
+ /* create lexer */
+ result = isc_lex_create(lex_mctx, 1500, &lexer);
+ if (result != ISC_R_SUCCESS)
+ fprintf(stderr, "unexpected error creating lexer\n");
+
+ /* set allowed commenting style */
+ isc_lex_setcomments(lexer, ISC_LEXCOMMENT_C | /* Allow C comments */
+ ISC_LEXCOMMENT_CPLUSPLUS | /* Allow C++ comments */
+ ISC_LEXCOMMENT_SHELL); /* Allow shellcomments */
+
+ isc_buffer_init(&lex_buffer, &lex_data_buf, max_data_len);
+
+ return result;
+}
+
+/*% Close the lexer, and cleanup memory */
+
+void
+close_lexer(void) {
+
+ /* If lexer is still open, close it & destroy it. */
+ if (lexer != NULL) {
+ isc_lex_close(lexer);
+ isc_lex_destroy(&lexer);
+ }
+
+ /* if lexer memory is still allocated, destroy it. */
+ if (lex_mctx != NULL)
+ isc_mem_destroy(&lex_mctx);
+}
+
+/*% Perform add operation */
+
+void
+operation_add(void) {
+ /* check for any parameters that are not allowed during add */
+ checkInvalidParam(key, "k", "for add operation");
+ checkInvalidParam(zone, "z", "for add operation");
+ checkInvalidParam(host, "h", "for add operation");
+ checkInvalidParam(c_zone, "c", "for add operation");
+ checkInvalidParam(c_ip, "i", "for add operation");
+ checkInvalidOption(list_everything, isc_boolean_true, "e",
+ "for add operation");
+
+ /* if open lexer fails it alread prints error messages. */
+ if (open_lexer() != ISC_R_SUCCESS) {
+ quit(4);
+ }
+
+ /* copy input data to buffer */
+ isc_buffer_putstr(&lex_buffer, a_data);
+
+ /* tell lexer to use buffer as input */
+ if (isc_lex_openbuffer(lexer, &lex_buffer) != ISC_R_SUCCESS) {
+ fprintf(stderr, "unexpected error opening lexer buffer");
+ quit(4);
+ }
+
+ /*common logic for "add" & "bulk" operations are handled by insert_data */
+ insert_data();
+}
+
+/*% Perform bulk insert operation */
+
+void
+operation_bulk(void) {
+ /* check for any parameters that are not allowed during bulk */
+ checkInvalidParam(key, "k", "for bulk load operation");
+ checkInvalidParam(zone, "z", "for bulk load operation");
+ checkInvalidParam(host, "h", "for bulk load operation");
+ checkInvalidParam(c_zone, "c", "for bulk load operation");
+ checkInvalidParam(c_ip, "i", "for bulk load operation");
+ checkInvalidOption(list_everything, isc_boolean_true, "e",
+ "for bulk load operation");
+
+ /* if open lexer fails it already prints error messages. */
+ if (open_lexer() != ISC_R_SUCCESS) {
+ quit(4);
+ }
+
+ if (bulk_file == NULL) {
+ if (isc_lex_openstream(lexer, stdin) != ISC_R_SUCCESS) {
+ fprintf(stderr, "unexpected error opening stdin by lexer.");
+ quit(4);
+ }
+ } else if (isc_lex_openfile(lexer, bulk_file) != ISC_R_SUCCESS) {
+ fprintf(stderr, "unexpected error opening %s by lexer.", bulk_file);
+ quit(4);
+ }
+
+ /* common logic for "add" & "bulk" operations are handled by insert_data */
+ insert_data();
+}
+
+isc_result_t
+bulk_write(char type, DB *database, DBC *dbcursor, DBT *bdbkey, DBT *bdbdata) {
+
+ int bdbres;
+ db_recno_t recNum;
+ char *retkey = NULL, *retdata;
+ size_t retklen = 0, retdlen;
+ void *p;
+
+ /* use a 5MB buffer for the bulk dump */
+ int buffer_size = 5 * 1024 * 1024;
+
+ /* try to allocate a 5 MB buffer, if we fail write err msg, die. */
+ bdbdata->data = malloc(buffer_size);
+ if (bdbdata->data == NULL) {
+ fprintf(stderr,
+ "Unable to allocate 5 MB buffer for bulk database dump\n");
+ return ISC_R_FAILURE;
+ }
+ bdbdata->ulen = buffer_size;
+ bdbdata->flags = DB_DBT_USERMEM;
+
+ /* get a cursor, make sure it worked. */
+ bdbres = database->cursor(database, NULL, &dbcursor, 0);
+ if (bdbres != 0) {
+ fprintf(stderr, "Unexpected error. BDB Error: %s\n",db_strerror(bdbres));
+ free(bdbdata->data);
+ return ISC_R_FAILURE;
+ }
+
+ /* loop and dump all data */
+ for (;;) {
+
+ /* loop through data until DB_NOTFOUND is returned */
+ bdbres = dbcursor->c_get(dbcursor, bdbkey, bdbdata,
+ DB_MULTIPLE_KEY | DB_NEXT);
+ /* if not successful did we encounter DB_NOTFOUND, or */
+ /* have a different problem. */
+ if (bdbres != 0) {
+ if (bdbres != DB_NOTFOUND) {
+ fprintf(stderr, "Unexpected error. BDB Error: %s\n",
+ db_strerror(bdbres));
+ free(bdbdata->data);
+ return ISC_R_FAILURE;
+ }
+ /* Hit DB_NOTFOUND which means end of data. */
+ break;
+ } /* end of if (bdbres !=0) */
+
+ for (DB_MULTIPLE_INIT(p, bdbdata);;) {
+ if (type == 'c')
+ DB_MULTIPLE_KEY_NEXT(p, bdbdata, retkey, retklen, retdata, retdlen);
+ else
+ DB_MULTIPLE_RECNO_NEXT(p, bdbdata, recNum, retdata, retdlen);
+
+ if (p == NULL)
+ break;
+ if (type == 'c')
+ printf("c %.*s %.*s\n",(int)retklen, retkey,(int)retdlen, retdata);
+ else
+ printf("d %.*s\n", (int)retdlen, retdata);
+ } /* end of for (DB_MULTIPLE_INIT....) */
+
+ } /* end of for (;;) */
+
+ /* free the buffer we created earlier */
+ free(bdbdata->data);
+
+ return ISC_R_SUCCESS;
+}
+
+/*%
+ * Perform listOrDelete operation
+ * if dlt == true, delete data
+ * else list data
+ */
+
+void
+operation_listOrDelete(isc_boolean_t dlt) {
+
+ int bdbres = 0;
+ DBC *curList[3];
+ DBT bdbkey, bdbdata;
+ db_recno_t recno;
+ int curIndex = 0;
+
+
+ /* verify that only allowed parameters were passed. */
+ if (dlt == isc_boolean_true) {
+ checkInvalidParam(zone, "z", "for delete operation");
+ checkInvalidParam(host, "h", "for delete operation");
+ checkInvalidOption(list_everything, isc_boolean_true, "e",
+ "for delete operation");
+ checkInvalidOption(create_allowed, isc_boolean_true, "n",
+ "for delete operation");
+ } else if (key != NULL || zone != NULL || host != NULL) {
+ checkInvalidParam(c_zone, "c", "for list when k, z or h are specified");
+ checkInvalidParam(c_ip, "i", "for list when k, z, or h are specified");
+ checkInvalidOption(list_everything, isc_boolean_true, "e",
+ "for list when k, z, or h are specified");
+ checkInvalidOption(create_allowed, isc_boolean_true, "n",
+ "for list operation");
+ } else if (c_ip != NULL || c_zone != NULL) {
+ checkInvalidOption(list_everything, isc_boolean_true, "e",
+ "for list when c or i are specified");
+ checkInvalidOption(create_allowed, isc_boolean_true, "n",
+ "for list operation");
+ }
+
+ memset(&bdbkey, 0, sizeof(bdbkey));
+ memset(&bdbdata, 0, sizeof(bdbdata));
+
+ /* Dump database in "dlzbdb" bulk format */
+ if (list_everything == isc_boolean_true) {
+ if (bulk_write('c', db.client, db.cursor, &bdbkey, &bdbdata)
+ != ISC_R_SUCCESS)
+ return;
+ memset(&bdbkey, 0, sizeof(bdbkey));
+ memset(&bdbdata, 0, sizeof(bdbdata));
+ bulk_write('d', db.data, db.cursor2, &bdbkey, &bdbdata);
+ return;
+ } /* end if (list_everything) */
+
+ /* set NULL the 2nd and 3rd positions in curList. */
+ /* that way later when add cursors to the join list */
+ /* it is already null terminated. */
+ curList[1] = curList[2] = NULL;
+
+ if (key != NULL) {
+ /* make sure other parameters weren't */
+ checkInvalidParam(zone, "z", "when k is specified");
+ checkInvalidParam(host, "h", "when k is specified");
+
+ recno = key_val;
+ bdbkey.data = &recno;
+ bdbkey.size = sizeof(recno);
+
+ if (dlt == isc_boolean_true) {
+ bdbres = db.data->del(db.data, NULL, &bdbkey, 0);
+ } else {
+ bdbdata.flags = DB_DBT_REALLOC;
+ bdbres = db.data->get(db.data, NULL, &bdbkey, &bdbdata, 0);
+
+ if (bdbres == 0) {
+ printf("KEY | DATA\n");
+ printf("%lu | %.*s\n", *(u_long *) bdbkey.data,
+ (int)bdbdata.size, (char *)bdbdata.data);
+ }
+ } /* closes else of if (dlt == isc_boolean_true) */
+ if (bdbres == DB_NOTFOUND) {
+ printf("Key not found in database");
+ }
+ } /* closes if (key != NULL) */
+
+ /* if zone is passed */
+ if (zone != NULL) {
+ /* create a cursor and make sure it worked */
+ bdbres = db.zone->cursor(db.zone, NULL, &db.cursor2, 0);
+ if (bdbres != 0) {
+ fprintf(stderr, "Unexpected error. BDB Error: %s\n",
+ db_strerror(bdbres));
+ return;
+ }
+
+ bdbkey.data = zone;
+ bdbkey.size = strlen(zone);
+ bdbres = db.cursor2->c_get(db.cursor2, &bdbkey, &bdbdata, DB_SET);
+ if (bdbres != 0) {
+ if (bdbres != DB_NOTFOUND) {
+ fprintf(stderr, "Unexpected error. BDB Error: %s\n",
+ db_strerror(bdbres));
+ } else {
+ printf("Zone not found in database");
+ }
+ return;
+ }
+
+ /* add cursor to cursor list for later use in join */
+ curList[curIndex++] = db.cursor2;
+ }
+
+ /* if host is passed */
+ if (host != NULL) {
+
+ /* create a cursor and make sure it worked. */
+ bdbres = db.host->cursor(db.host, NULL, &db.cursor3, 0);
+ if (bdbres != 0) {
+ fprintf(stderr, "Unexpected error. BDB Error: %s\n",
+ db_strerror(bdbres));
+ return;
+ }
+ bdbkey.data = host;
+ bdbkey.size = strlen(host);
+ bdbres = db.cursor3->c_get(db.cursor3, &bdbkey, &bdbdata, DB_SET);
+ if (bdbres != 0) {
+ if (bdbres != DB_NOTFOUND) {
+ fprintf(stderr, "Unexpected error. BDB Error: %s\n",
+ db_strerror(bdbres));
+ } else {
+ printf("Host not found in database");
+ }
+ return;
+ }
+
+ /* add cursor to cursor list for later use in join */
+ curList[curIndex++] = db.cursor3;
+ }
+
+
+ if (zone != NULL || host != NULL) {
+
+ /* join any cursors */
+ bdbres = db.data->join(db.data, curList, &db.cursor4, 0);
+ if (bdbres != 0) {
+ fprintf(stderr, "Unexpected error. BDB Error: %s\n",
+ db_strerror(bdbres));
+ return;
+ }
+
+ memset(&bdbkey, 0, sizeof(bdbkey));
+ bdbkey.flags = DB_DBT_REALLOC;
+ memset(&bdbdata, 0, sizeof(bdbdata));
+ bdbdata.flags = DB_DBT_REALLOC;
+
+ /* print a header to explain the output */
+ printf("KEY | DATA\n");
+ /* loop and list all results. */
+ while (bdbres == 0) {
+ /* get data */
+ bdbres = db.cursor4->c_get(db.cursor4, &bdbkey, &bdbdata, 0);
+ /* verify call had no errors */
+ if (bdbres != 0) {
+ break;
+ }
+ printf("%lu | %.*s\n", *(u_long *) bdbkey.data,
+ (int)bdbdata.size, (char *)bdbdata.data);
+ } /* closes while loop */
+ }
+
+ if (c_ip != NULL && c_zone == NULL) {
+ fprintf(stderr, "i may only be specified when c is also specified\n");
+ quit(2);
+ }
+ /* if client_zone was passed */
+ if (c_zone != NULL) {
+
+ /* create a cursor and make sure it worked. */
+ if (dlt == isc_boolean_true) {
+ /* open read-write cursor */
+ bdbres = db.client->cursor(db.client, NULL, &db.cursor,
+ DB_WRITECURSOR);
+ } else {
+ /* open read only cursor */
+ bdbres = db.client->cursor(db.client, NULL, &db.cursor, 0);
+ /* print a header to explain the output */
+ printf("CLIENT_ZONE | CLIENT_IP\n");
+ }
+
+ bdbkey.data = c_zone;
+ bdbkey.size = strlen(c_zone);
+
+ if (c_ip != NULL) {
+ bdbdata.data = c_ip;
+ bdbdata.size = strlen(c_ip);
+ bdbres = db.cursor->c_get(db.cursor, &bdbkey, &bdbdata, DB_GET_BOTH);
+ if (bdbres == DB_NOTFOUND) {
+ printf("Client zone & IP not found in database");
+ }
+ } else {
+ bdbdata.flags = DB_DBT_REALLOC;
+ bdbres = db.cursor->c_get(db.cursor, &bdbkey, &bdbdata, DB_SET);
+ if (bdbres == DB_NOTFOUND) {
+ printf("Client zone not found in database");
+ }
+ }
+
+ while (bdbres == 0) {
+ if (dlt == isc_boolean_false) {
+ printf("%.*s | %.*s\n", (int)bdbkey.size, (char *) bdbkey.data,
+ (int)bdbdata.size, (char *) bdbdata.data);
+ } else {
+ /* delete record. */
+ bdbres = db.cursor->c_del(db.cursor, 0);
+ if (bdbres != 0) {
+ fprintf(stderr, "Unexpected error. BDB Error: %s\n",
+ db_strerror(bdbres));
+ break;
+ }
+ }
+ if (c_ip != NULL) {
+ break;
+ }
+ bdbres = db.cursor->c_get(db.cursor, &bdbkey, &bdbdata, DB_NEXT_DUP);
+ if (bdbres != 0) {
+ break;
+ }
+ } /* end while loop */
+ }
+
+
+ if (bdbres != 0 && bdbres != DB_NOTFOUND) {
+ fprintf(stderr, "Unexpected error during list operation " \
+ "BDB error: %s", db_strerror(bdbres));
+ }
+
+ if (bdbkey.flags == DB_DBT_REALLOC && bdbkey.data != NULL) {
+ free(bdbkey.data);
+ }
+ if (bdbdata.flags == DB_DBT_REALLOC && bdbdata.data != NULL) {
+ free(bdbdata.data);
+ }
+}
+
+
+int
+main(int argc, char **argv) {
+
+ int ch;
+ char *endp;
+
+ /* there has to be at least 2 args, some operations require more */
+ if (argc < 2)
+ show_usage();
+
+ /* use the ISC commandline parser to get all the program arguments */
+ while ((ch= isc_commandline_parse(argc, argv, "ldesna:f:k:z:h:c:i:")) != -1) {
+ switch (ch) {
+ case 'n':
+ create_allowed = isc_boolean_true;
+ break;
+ case 'l':
+ checkOp(operation);
+ operation = list;
+ break;
+ case 'd':
+ checkOp(operation);
+ operation = dele;
+ break;
+ case 'a':
+ checkOp(operation);
+ operation = add;
+ a_data = isc_commandline_argument;
+ break;
+ case 'f':
+ checkOp(operation);
+ operation = bulk;
+ bulk_file = isc_commandline_argument;
+ break;
+ case 's':
+ checkOp(operation);
+ operation = bulk;
+ break;
+ case 'k':
+ checkParam(key, "k");
+ key = isc_commandline_argument;
+ key_val = strtoul(key, &endp, 10);
+ if (*endp != '\0' || key_val < 1) {
+ fprintf(stderr, "Error converting key to integer");
+ }
+ break;
+ case 'z':
+ checkParam(zone, "z");
+ zone = isc_commandline_argument;
+ break;
+ case 'h':
+ checkParam(host, "h");
+ host = isc_commandline_argument;
+ break;
+ case 'c':
+ checkParam(c_zone, "c");
+ c_zone = isc_commandline_argument;
+ break;
+ case 'i':
+ checkParam(c_ip, "i");
+ c_ip = isc_commandline_argument;
+ break;
+ case 'e':
+ checkOp(operation);
+ operation = list;
+ list_everything = isc_boolean_true;
+ break;
+ case '?':
+ show_usage();
+ break;
+ default:
+ /* should never reach this point */
+ fprintf(stderr, "unexpected error parsing command arguments\n");
+ quit(1);
+ break;
+ }
+ }
+
+ argc -= isc_commandline_index;
+ argv += isc_commandline_index;
+
+ /* argc & argv have been modified, so now only "extra" parameters are */
+ /* left in argc & argv. "Extra" parameters are any parameters that were */
+ /* not passed using a command line flag. Exactly 2 args should be left. */
+ /* The first should be the BDB environment path, the second should be the */
+ /* BDB database. The BDB database path can be either relative to the */
+ /* BDB environment path, or absolute. */
+ if (argc < 2) {
+ fprintf(stderr, "Both a Berkeley DB environment and file "\
+ "must be specified");
+ quit(2);
+ } else if (argc > 2) {
+ fprintf(stderr, "Too many parameters. Check command line for errors.");
+ quit(2);
+ }
+
+ /* get db_file to operate on */
+ db_envdir = argv[0];
+ db_file = argv[1];
+
+ if (openBDB() != ISC_R_SUCCESS) {
+ /* openBDB already prints error messages, don't do it here. */
+ bdb_cleanup();
+ quit(3);
+ }
+
+ switch(operation) {
+ case list:
+ operation_listOrDelete(isc_boolean_false);
+ break;
+ case dele:
+ operation_listOrDelete(isc_boolean_true);
+ break;
+ case add:
+ operation_add();
+ break;
+ case bulk:
+ operation_bulk();
+ break;
+ default:
+ fprintf(stderr, "\nNo operation was selected. "\
+ "Select an operation (l d a f)");
+ quit(2);
+ break;
+ }
+
+ quit(0);
+}
+#endif
+
--- /dev/null
+# Copyright (C) 2005 Internet Systems Consortium, Inc. ("ISC")
+#
+# 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 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.
+
+#
+# Shorthand. Note quoting: DLZ_DRIVER_DIR expanded in Makefile, not here.
+#
+dlzdir='${DLZ_DRIVER_DIR}'
+
+#
+# Private autoconf macro to simplify configuring drivers:
+#
+# DLZ_ADD_DRIVER(DEFINE, DRIVER, INCLUDES, LIBS)
+#
+# where:
+# DEFINE is FOO (to define -DDLZ_FOO)
+# DRIVER is dlz_foo_driver (sources without the .c)
+# INCLUDES is any necessary include definitions
+# LIBS is any necessary library definitions
+#
+AC_DEFUN(DLZ_ADD_DRIVER, [
+ USE_DLZ="$USE_DLZ -DDLZ_$1"
+ for i in $2
+ do
+ DLZ_DRIVER_SRCS="$DLZ_DRIVER_SRCS $dlzdir/$i.c"
+ DLZ_DRIVER_OBJS="$DLZ_DRIVER_OBJS $i.$O"
+ done
+ if test -n "$3"
+ then
+ DLZ_DRIVER_INCLUDES="$DLZ_DRIVER_INCLUDES $3"
+ fi
+ if test -n "$4"
+ then
+ DLZ_DRIVER_LIBS="$DLZ_DRIVER_LIBS $4"
+ fi
+])
+
+#
+# Check for the various DLZ drivers
+#
+
+#
+# Was --with-dlz-postgres specified?
+#
+
+AC_MSG_CHECKING(for Postgres DLZ driver)
+AC_ARG_WITH(dlz_postgres,
+[ --with-dlz-postgres[=PATH] Build with Postgres DLZ driver [yes|no|path].
+ (Required to use Postgres with DLZ)],
+ use_dlz_postgres="$withval", use_dlz_postgres="no")
+
+if test "$use_dlz_postgres" = "yes"
+then
+ # User did not specify a path - guess it
+ # Ask Postgres to tell us where it is
+
+ AC_PATH_PROGS(PG_CONFIG, pg_config, [not found])
+
+ if test "$PG_CONFIG" != "not found"
+ then
+ use_dlz_postgres=`$PG_CONFIG --includedir`
+ use_dlz_postgres_lib=`$PG_CONFIG --libdir`
+ fi
+fi
+
+if test "$use_dlz_postgres" = "yes"
+then
+ # User did not specify path and Postgres didn't say - guess it
+
+ pgdirs="/usr /usr/local /usr/local/pgsql /usr/pkg"
+ for d in $pgdirs
+ do
+ if test -f $d/include/libpq-fe.h
+ then
+ use_dlz_postgres=$d/include
+ use_dlz_postgres_lib=$d/lib
+ break
+ fi
+ done
+fi
+
+if test "$use_dlz_postgres" = "yes"
+then
+ # Still no joy, give up
+
+ AC_MSG_RESULT(not found)
+ AC_MSG_ERROR(
+[No pg_config and PostgreSQL was not found in any of $pgdirs; use --with-dlz-postgres=/path or put pg_config in your path])
+fi
+
+case "$use_dlz_postgres" in
+ no)
+ AC_MSG_RESULT(no)
+ ;;
+ *)
+ DLZ_ADD_DRIVER(POSTGRES, dlz_postgres_driver,
+ [-I$use_dlz_postgres],
+ [-L$use_dlz_postgres_lib -lpq])
+
+ AC_MSG_RESULT(
+[using PostgreSQL from $use_dlz_postgres_lib and $use_dlz_postgres])
+ ;;
+esac
+
+
+#
+# Was --with-dlz-mysql specified?
+#
+
+AC_MSG_CHECKING(for MySQL DLZ driver)
+AC_ARG_WITH(dlz_mysql,
+[ --with-dlz-mysql[=PATH] Build with MySQL DLZ driver [yes|no|path].
+ (Required to use MySQL with DLZ)],
+ use_dlz_mysql="$withval", use_dlz_mysql="no")
+
+if test "$use_dlz_mysql" = "yes"
+then
+ # User did not specify a path - guess it
+ mysqldirs="/usr /usr/local /usr/local/mysql /usr/pkg"
+ for d in $mysqldirs
+ do
+ if test -f $d/include/mysql/mysql.h
+ then
+ use_dlz_mysql=$d
+ break
+ fi
+ done
+fi
+
+if test "$use_dlz_mysql" = "yes"
+then
+ AC_MSG_RESULT(not found)
+ AC_MSG_ERROR(
+[MySQL was not found in any of $mysqldirs; use --with-dlz-mysql=/path])
+fi
+
+case "$use_dlz_mysql" in
+ no)
+ AC_MSG_RESULT(no)
+ ;;
+ *)
+ DLZ_ADD_DRIVER(MYSQL, dlz_mysql_driver,
+ [-I$use_dlz_mysql/include/mysql],
+ [-L$use_dlz_mysql/lib/mysql -lmysqlclient -lz -lcrypt -lm])
+
+ AC_MSG_RESULT(
+[using mysql from $use_dlz_mysql/lib/mysql and $use_dlz_mysql/include/mysql])
+ ;;
+esac
+
+
+#
+# Was --with-dlz-bdb specified?
+#
+
+AC_MSG_CHECKING(for Berkeley DB DLZ driver)
+AC_ARG_WITH(dlz_bdb,
+[ --with-dlz-bdb[=PATH] Build with Berkeley DB DLZ driver [yes|no|path].
+ (Required to use Berkeley DB with DLZ)],
+ use_dlz_bdb="$withval", use_dlz_bdb="no")
+
+case "$use_dlz_bdb" in
+ no)
+ AC_MSG_RESULT(no)
+ ;;
+ *)
+ if test "$use_dlz_bdb" = "yes"
+ then
+ # User did not specify a path - guess directories
+ bdbdirs="/usr/local /usr/pkg /usr"
+ elif test -d "$use_dlz_bdb"
+ then
+ # User specified directory and it exists
+ bdbdirs="$use_dlz_bdb"
+ else
+ AC_MSG_RESULT(not found)
+ AC_MSG_ERROR([path $use_dlz_bdb does not exist])
+ bdbdirs=""
+ fi
+
+ # Use path we were given or guessed. This is insanely
+ # complicated because we have to search for a bunch of
+ # platform-specific variations and have to check
+ # separately for include and library directories.
+
+ # Set both to yes, so we can check them later
+ dlz_bdb_inc="yes"
+ dlz_bdb_libs="yes"
+
+ for dd in $bdbdirs
+ do
+ # Skip nonexistant directories
+ if test ! -d "$dd"
+ then
+ continue
+ fi
+
+ # Check other locations for includes.
+ # Order is important (sigh).
+
+ bdb_incdirs="/ /db42/ /db41/ /db4/ /db/"
+ for d in $bdb_incdirs
+ do
+ if test -f "$dd/include${d}db.h"
+ then
+ dlz_bdb_inc="-I$dd/include${d}"
+ break
+ fi
+ done
+
+ # Give up on this directory if we couldn't
+ # find the include subdir
+
+ if test "$dlz_bdb_inc" = "yes"
+ then
+ continue
+ fi
+
+ # Look for libname other than libdb.so.
+ # Order is important (sigh).
+
+ bdb_libnames="db42 db-4.2 db41 db-4.1 db"
+ for d in $bdb_libnames
+ do
+ if test -f "$dd/lib/lib${d}.so"
+ then
+ if test "$dd" != "/usr"
+ then
+ dlz_bdb_libs="-L${dd}/lib "
+ fi
+ dlz_bdb_libs="${dlz_bdb_libs}-l${d}"
+ break
+ fi
+ done
+
+ # If we found both incdir and lib, we're done
+ if test "$dlz_bdb_libs" != "yes"
+ then
+ break
+ fi
+
+ # Otherwise, we're starting over
+
+ dlz_bdb_inc="yes"
+ dlz_bdb_libs="yes"
+ done
+
+ # Done searching, now make sure we got everything.
+
+ if test "$dlz_bdb_inc" = "yes"
+ then
+ AC_MSG_RESULT(not found)
+ AC_MSG_ERROR([could not find Berkeley DB include directory])
+ fi
+
+ if test "$dlz_bdb_libs" = "yes"
+ then
+ AC_MSG_RESULT(not found)
+ AC_MSG_ERROR([could not find Berkeley DB library])
+ fi
+
+ DLZ_ADD_DRIVER(BDB, dlz_bdb_driver dlz_bdbhpt_driver,
+ [$dlz_bdb_inc], [$dlz_bdb_libs])
+
+ AC_MSG_RESULT([using Berkeley DB: $dlz_bdb_inc $dlz_bdb_libs])
+
+ AC_CONFIG_FILES([contrib/dlz/bin/dlzbdb/Makefile])
+ ;;
+esac
+
+
+#
+# Was --with-dlz-filesystem specified?
+#
+
+AC_MSG_CHECKING(for file system DLZ driver)
+AC_ARG_WITH(dlz_filesystem,
+[ --with-dlz-filesystem[=PATH] Build with filesystem DLZ driver [yes|no].
+ (Required to use file system driver with DLZ)],
+ use_dlz_filesystem="$withval", use_dlz_filesystem="no")
+
+case "$use_dlz_filesystem" in
+ no)
+ AC_MSG_RESULT(no)
+ ;;
+ *)
+ DLZ_ADD_DRIVER(FILESYSTEM, dlz_filesystem_driver)
+
+ AC_MSG_RESULT(yes)
+ ;;
+esac
+
+
+#
+# Was --with-dlz-ldap specified?
+#
+
+AC_MSG_CHECKING(for LDAP DLZ driver)
+AC_ARG_WITH(dlz_ldap,
+[ --with-dlz-ldap[=PATH] Build with LDAP DLZ driver [yes|no|path].
+ (Required to use LDAP with DLZ)],
+ use_dlz_ldap="$withval", use_dlz_ldap="no")
+
+if test "$use_dlz_ldap" = "yes"
+then
+ # User did not specify a path - guess it
+ ldapdirs="/usr /usr/local /usr/pkg"
+ for d in $ldapdirs
+ do
+ if test -f $d/include/ldap.h
+ then
+ use_dlz_ldap=$d
+ break
+ fi
+ done
+fi
+
+if test "$use_dlz_ldap" = "yes"
+then
+ AC_MSG_RESULT(not found)
+ AC_MSG_ERROR(
+[LDAP headers were not found in any of $ldapdirs; use --with-dlz-ldap=/path])
+fi
+
+case "$use_dlz_ldap" in
+ no)
+ AC_MSG_RESULT(no)
+ ;;
+ *)
+ DLZ_ADD_DRIVER(LDAP, dlz_ldap_driver,
+ [-I$use_dlz_ldap/include],
+ [-L$use_dlz_ldap/lib -lldap -llber])
+
+ AC_MSG_RESULT(
+[using LDAP from $use_dlz_ldap/lib and $use_dlz_ldap/include])
+ ;;
+esac
+
+
+#
+# Was --with-dlz-odbc specified?
+#
+
+AC_MSG_CHECKING(for ODBC DLZ driver)
+AC_ARG_WITH(dlz_odbc,
+[ --with-dlz-odbc[=PATH] Build with ODBC DLZ driver [yes|no|path].
+ (Required to use ODBC with DLZ)],
+ use_dlz_odbc="$withval", use_dlz_odbc="no")
+
+if test "$use_dlz_odbc" = "yes"
+then
+ # User did not specify a path - guess it
+ odbcdirs="/usr /usr/local /usr/pkg"
+ for d in $odbcdirs
+ do
+ if test -f $d/include/sql.h -a -f $d/lib/libodbc.a
+ then
+ use_dlz_odbc=$d
+ break
+ fi
+ done
+fi
+
+case "$use_dlz_odbc" in
+ no)
+ AC_MSG_RESULT(no)
+ ;;
+ yes)
+ AC_MSG_RESULT(not found)
+ AC_MSG_ERROR(
+[ODBC headers were not found in any of $odbcdirs; use --with-dlz-odbc=/path])
+ ;;
+ *)
+ DLZ_ADD_DRIVER(ODBC, dlz_odbc_driver,
+ [-I$use_dlz_odbc/include],
+ [-L$use_dlz_odbc/lib -lodbc])
+
+ AC_MSG_RESULT([using ODBC from $use_dlz_odbc])
+ ;;
+esac
+
+
+#
+# Was --with-dlz-stub specified?
+#
+
+AC_MSG_CHECKING(for stub DLZ driver)
+AC_ARG_WITH(dlz_stub,
+[ --with-dlz-stub[=PATH] Build with stub DLZ driver [yes|no].
+ (Required to use stub driver with DLZ)],
+ use_dlz_stub="$withval", use_dlz_stub="no")
+
+case "$use_dlz_stub" in
+ no)
+ AC_MSG_RESULT(no)
+ ;;
+ *)
+
+ DLZ_ADD_DRIVER(STUB, dlz_stub_driver)
+
+ AC_MSG_RESULT(yes)
+ ;;
+esac
+
+
+# Add any additional DLZ drivers here.
+
+#
+# Finally, some generic stuff that applies to all drivers, assuming
+# we're compiling DLZ at all.
+#
+if test -n "$USE_DLZ"
+then
+ #
+ # Where to find DLZ driver header files.
+ #
+ DLZ_DRIVER_INCLUDES="-I$dlzdir/include $DLZ_DRIVER_INCLUDES"
+
+ #
+ # Initialization and shutdown wrappers, helper functions.
+ #
+ DLZ_DRIVER_SRCS="$dlzdir/dlz_drivers.c $dlzdir/sdlz_helper.c $DLZ_DRIVER_SRCS"
+ DLZ_DRIVER_OBJS="dlz_drivers.$O sdlz_helper.$O $DLZ_DRIVER_OBJS"
+fi
--- /dev/null
+/*
+ * 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) 1999-2001 Internet Software Consortium.
+ *
+ * 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 INTERNET SOFTWARE CONSORTIUM
+ * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+ * INTERNET SOFTWARE CONSORTIUM 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.
+ */
+
+#ifdef DLZ_BDB
+
+#include <config.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include <dns/log.h>
+#include <dns/sdlz.h>
+#include <dns/result.h>
+
+#include <isc/mem.h>
+#include <isc/print.h>
+#include <isc/result.h>
+#include <isc/util.h>
+
+#include <named/globals.h>
+
+#include <dlz/dlz_bdb_driver.h>
+
+#include <db.h>
+
+static dns_sdlzimplementation_t *dlz_bdb = NULL;
+
+/* should the bdb driver use threads. */
+#ifdef ISC_PLATFORM_USETHREADS
+#define bdb_threads DB_THREAD
+#else
+#define bdb_threads 0
+#endif
+
+/* BDB database names */
+#define dlz_data "dns_data"
+#define dlz_zone "dns_zone"
+#define dlz_host "dns_host"
+#define dlz_client "dns_client"
+
+/*%
+ * This structure contains all the Berkeley DB handles
+ * for this instance of the BDB driver.
+ */
+
+typedef struct bdb_instance {
+ DB_ENV *dbenv; /*%< BDB environment */
+ DB *data; /*%< dns_data database handle */
+ DB *zone; /*%< zone database handle */
+ DB *host; /*%< host database handle */
+ DB *client; /*%< client database handle */
+ isc_mem_t *mctx; /*%< memory context */
+
+} bdb_instance_t;
+
+typedef struct parsed_data {
+ char *zone;
+ char *host;
+ char *type;
+ int ttl;
+ char *data;
+} parsed_data_t;
+
+
+/* forward reference */
+
+static isc_result_t
+bdb_findzone(void *driverarg, void *dbdata, const char *name);
+
+/*%
+ * Parses the DBT from the Berkeley DB into a parsed_data record
+ * The parsed_data record should be allocated before and passed into the
+ * bdb_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
+bdb_parse_data(char *in, parsed_data_t *pd) {
+
+ char *endp, *ttlStr;
+ char *tmp = in;
+ char *lastchar = (char *) &tmp[strlen(tmp) + 1];
+
+ /*%
+ * String should be formated as:
+ * zone(a space)host(a space)ttl(a space)type(a space)remaining data
+ * examples:
+ * example.com www 10 A 127.0.0.1
+ * example.com mail 10 A 127.0.0.2
+ * example.com @ 10 MX 20 mail.example.com
+ */
+
+ /* save pointer to zone */
+ pd->zone = tmp;
+
+ /* find space after zone 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 host */
+ pd->host = 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 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 dns ttl */
+ 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 remainder of DNS data */
+ pd->data = tmp;
+
+ /* convert ttl string to integer */
+ pd->ttl = strtol(ttlStr, &endp, 10);
+ if (*endp != '\0' || pd->ttl < 0) {
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
+ "BDB driver ttl must be a postive number");
+ return ISC_R_FAILURE;
+ }
+
+ /* if we get this far everything should have worked. */
+ return ISC_R_SUCCESS;
+}
+
+/*
+ * DLZ methods
+ */
+
+static isc_result_t
+bdb_allowzonexfr(void *driverarg, void *dbdata, const char *name,
+ const char *client)
+{
+ isc_result_t result;
+ bdb_instance_t *db = (bdb_instance_t *) dbdata;
+ DBC *client_cursor = NULL;
+ DBT key, data;
+
+ /* check to see if we are authoritative for the zone first. */
+ result = bdb_findzone(driverarg, dbdata, name);
+ 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);
+
+ /* get a cursor to loop through zone data */
+ if (db->client->cursor(db->client, NULL, &client_cursor, 0) != 0) {
+ result = ISC_R_FAILURE;
+ goto xfr_cleanup;
+ }
+
+ switch(client_cursor->c_get(client_cursor, &key, &data, DB_GET_BOTH)) {
+ case DB_NOTFOUND:
+ case DB_SECONDARY_BAD:
+ 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);
+
+ /* get rid of zone_cursor */
+ if (client_cursor != NULL)
+ client_cursor->c_close(client_cursor);
+
+ return result;
+
+}
+
+static isc_result_t
+bdb_allnodes(const char *zone, void *driverarg, void *dbdata,
+ dns_sdlzallnodes_t *allnodes)
+{
+
+ isc_result_t result = ISC_R_NOTFOUND;
+ bdb_instance_t *db = (bdb_instance_t *) dbdata;
+ DBC *zone_cursor = NULL;
+ DBT key, data;
+ int flags;
+ int bdbres;
+ parsed_data_t pd;
+ char *tmp = NULL, *tmp_zone;
+
+ UNUSED(driverarg);
+
+ memset(&key, 0, sizeof(DBT));
+ memset(&data, 0, sizeof(DBT));
+
+ key.data = tmp_zone = strdup(zone);
+
+ if (key.data == NULL)
+ return (ISC_R_NOMEMORY);
+
+ key.size = strlen(key.data);
+
+ /* get a cursor to loop through zone data */
+ if (db->zone->cursor(db->zone, NULL, &zone_cursor, 0) != 0) {
+ result = ISC_R_FAILURE;
+ goto allnodes_cleanup;
+ }
+
+ flags = DB_SET;
+
+ while ((bdbres = zone_cursor->c_get(zone_cursor, &key, &data,
+ flags)) == 0) {
+
+ flags = DB_NEXT_DUP;
+
+ tmp = realloc(tmp, data.size + 1);
+ if (tmp == NULL)
+ goto allnodes_cleanup;
+
+ strncpy(tmp, data.data, data.size);
+ tmp[data.size] = '\0';
+
+ if (bdb_parse_data(tmp, &pd) != ISC_R_SUCCESS)
+ goto allnodes_cleanup;
+
+ result = dns_sdlz_putnamedrr(allnodes, pd.host, pd.type,
+ pd.ttl, pd.data);
+ if (result != ISC_R_SUCCESS)
+ goto allnodes_cleanup;
+
+ } /* end while loop */
+
+ allnodes_cleanup:
+
+ if (tmp != NULL)
+ free(tmp);
+
+ /* free any memory duplicate string in the key field */
+ if (tmp_zone != NULL)
+ free(tmp_zone);
+
+ /* get rid of zone_cursor */
+ if (zone_cursor != NULL)
+ zone_cursor->c_close(zone_cursor);
+
+ return result;
+
+}
+
+/*%
+ * Performs BDB cleanup.
+ * Used by bdb_create if there is an error starting up.
+ * Used by bdb_destroy when the driver is shutting down.
+ */
+
+static void
+bdb_cleanup(bdb_instance_t *db) {
+
+ isc_mem_t *mctx;
+
+ /* close databases */
+ if (db->data != NULL)
+ db->data->close(db->data, 0);
+ if (db->host != NULL)
+ db->host->close(db->host, 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);
+
+ /* cleanup memory */
+ if (db->mctx != NULL) {
+ /* save mctx for later */
+ mctx = db->mctx;
+ /* return, and detach the memory */
+ isc_mem_put(mctx, db, sizeof(bdb_instance_t));
+ isc_mem_detach(&mctx);
+ }
+}
+
+static isc_result_t
+bdb_findzone(void *driverarg, void *dbdata, const char *name)
+{
+
+ isc_result_t result;
+ bdb_instance_t *db = (bdb_instance_t *) dbdata;
+ DBC *zone_cursor = NULL;
+ DBT key, data;
+
+ UNUSED(driverarg);
+
+ memset(&key, 0, sizeof(DBT));
+ memset(&data, 0, sizeof(DBT));
+ data.flags = DB_DBT_MALLOC;
+
+ key.data = strdup(name);
+
+ if (key.data == NULL)
+ return (ISC_R_NOMEMORY);
+
+ key.size = strlen(key.data);
+
+ /* get a cursor to loop through zone data */
+ if (db->zone->cursor(db->zone, NULL, &zone_cursor, 0) != 0) {
+ result = ISC_R_NOTFOUND;
+ goto findzone_cleanup;
+ }
+
+ switch(zone_cursor->c_get(zone_cursor, &key, &data, DB_SET)) {
+ case DB_NOTFOUND:
+ case DB_SECONDARY_BAD:
+ result = ISC_R_NOTFOUND;
+ break;
+ case 0:
+ result = ISC_R_SUCCESS;
+ break;
+ default:
+ result = ISC_R_FAILURE;
+ }
+
+ findzone_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);
+
+ /* get rid of zone_cursor */
+ if (zone_cursor != NULL)
+ zone_cursor->c_close(zone_cursor);
+
+ return result;
+}
+
+static isc_result_t
+bdb_lookup(const char *zone, const char *name, void *driverarg,
+ void *dbdata, dns_sdlzlookup_t *lookup)
+{
+
+ isc_result_t result = ISC_R_NOTFOUND;
+ bdb_instance_t *db = (bdb_instance_t *) dbdata;
+ DBC *zone_cursor = NULL;
+ DBC *host_cursor = NULL;
+ DBC *join_cursor = NULL;
+ DBT key, data;
+ DBC *cur_arr[3];
+ int bdbres;
+ parsed_data_t pd;
+ char *tmp_zone, *tmp_host = NULL;
+ char *tmp = NULL;
+
+ UNUSED(driverarg);
+
+ memset(&key, 0, sizeof(DBT));
+ memset(&data, 0, sizeof(DBT));
+
+ /* set zone key */
+ key.data = tmp_zone = strdup(zone);
+ if (key.data == NULL) {
+ result = ISC_R_NOMEMORY;
+ goto lookup_cleanup;
+ }
+ key.size = strlen(key.data);
+
+ /* get a cursor to loop through zone data */
+ if (db->zone->cursor(db->zone, NULL, &zone_cursor, 0) != 0) {
+ result = ISC_R_FAILURE;
+ goto lookup_cleanup;
+ }
+
+ /* initialize zone_cursor with zone_key */
+ if (zone_cursor->c_get(zone_cursor, &key, &data, DB_SET) != 0) {
+ result = ISC_R_NOTFOUND;
+ goto lookup_cleanup;
+ }
+
+ /* set host key */
+ key.data = tmp_host = strdup(name);
+ if (key.data == NULL) {
+ result = ISC_R_NOMEMORY;
+ goto lookup_cleanup;
+ }
+ key.size = strlen(key.data);
+
+ /* get a cursor to loop through host data */
+ if (db->host->cursor(db->host, NULL, &host_cursor, 0) != 0) {
+ result = ISC_R_FAILURE;
+ goto lookup_cleanup;
+ }
+
+ /* initialize host_cursor with host_key */
+ if (host_cursor->c_get(host_cursor, &key, &data, DB_SET) != 0) {
+ result = ISC_R_NOTFOUND;
+ goto lookup_cleanup;
+ }
+
+ cur_arr[0] = zone_cursor;
+ cur_arr[1] = host_cursor;
+ cur_arr[2] = NULL;
+
+ db->data->join(db->data, cur_arr, &join_cursor, 0);
+
+ while ((bdbres = join_cursor->c_get(join_cursor, &key,
+ &data, 0)) == 0) {
+
+ tmp = realloc(tmp, data.size + 1);
+ if (tmp == NULL)
+ goto lookup_cleanup;
+
+ strncpy(tmp, data.data, data.size);
+ tmp[data.size] = '\0';
+
+ if (bdb_parse_data(tmp, &pd) != ISC_R_SUCCESS)
+ goto lookup_cleanup;
+
+ result = dns_sdlz_putrr(lookup, pd.type, pd.ttl, pd.data);
+
+ if (result != ISC_R_SUCCESS)
+ goto lookup_cleanup;
+ } /* end while loop */
+
+ lookup_cleanup:
+
+ if (tmp != NULL)
+ free(tmp);
+ if (tmp_zone != NULL)
+ free(tmp_zone);
+ if (tmp_host != NULL)
+ free(tmp_host);
+
+ /* get rid of the joined cusor */
+ if (join_cursor != NULL)
+ join_cursor->c_close(join_cursor);
+
+ /* get rid of zone_cursor */
+ if (zone_cursor != NULL)
+ zone_cursor->c_close(zone_cursor);
+
+ /* get rid of host_cursor */
+ if (host_cursor != NULL)
+ host_cursor->c_close(host_cursor);
+
+ return result;
+
+ return ISC_R_NOTFOUND;
+}
+
+
+/*% Initializes, sets flags and then opens Berkeley databases. */
+
+static isc_result_t
+bdb_opendb(DB_ENV *db_env, DBTYPE db_type, DB **db, const char *db_name,
+ char *db_file, int flags) {
+
+ int result;
+
+ /* Initialize the database. */
+ if ((result = db_create(db, db_env, 0)) != 0) {
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
+ "BDB could not initialize %s database. "
+ "BDB error: %s",
+ db_name, db_strerror(result));
+ return ISC_R_FAILURE;
+ }
+
+ /* set database flags. */
+ if ((result = (*db)->set_flags(*db, flags)) != 0) {
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
+ "BDB could not set flags for %s database. "
+ "BDB 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 | bdb_threads, 0)) != 0) {
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
+ "BDB could not open %s database in %s. "
+ "BDB error: %s",
+ db_name, db_file, db_strerror(result));
+ return ISC_R_FAILURE;
+ }
+
+ return ISC_R_SUCCESS;
+}
+
+static isc_result_t
+bdb_create(const char *dlzname, unsigned int argc, char *argv[],
+ void *driverarg, void **dbdata)
+{
+ isc_result_t result;
+ int bdbres;
+ bdb_instance_t *db = NULL;
+
+ UNUSED(dlzname);
+ UNUSED(driverarg);
+
+ /* verify we have 3 arg's passed to the driver */
+ if (argc != 3) {
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
+ "Berkeley DB driver requires at least "
+ "2 command line args.");
+ return (ISC_R_FAILURE);
+ }
+
+ /* allocate and zero memory for driver structure */
+ db = isc_mem_get(ns_g_mctx, sizeof(bdb_instance_t));
+ if (db == NULL) {
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
+ "Could not allocate memory for "
+ "database instance object.");
+ return (ISC_R_NOMEMORY);
+ }
+ memset(db, 0, sizeof(bdb_instance_t));
+
+ /* attach to the memory context */
+ isc_mem_attach(ns_g_mctx, &db->mctx);
+
+ /* create BDB environment
+ * Basically BDB allocates and assigns memory to db->dbenv
+ */
+ bdbres = db_env_create(&db->dbenv, 0);
+ if (bdbres != 0) {
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
+ "BDB environment could not be created. "
+ "BDB error: %s",
+ db_strerror(bdbres));
+ result = ISC_R_FAILURE;
+ goto init_cleanup;
+ }
+
+ /* open BDB environment */
+ bdbres = db->dbenv->open(db->dbenv, argv[1],
+ DB_INIT_CDB | DB_INIT_MPOOL |
+ bdb_threads | DB_CREATE,
+ 0);
+ if (bdbres != 0) {
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
+ "BDB environment at '%s' could not be opened. "
+ "BDB error: %s",
+ argv[1], db_strerror(bdbres));
+ result = ISC_R_FAILURE;
+ goto init_cleanup;
+ }
+
+ /* open dlz_data database. */
+ result = bdb_opendb(db->dbenv, DB_UNKNOWN, &db->data,
+ dlz_data, argv[2], 0);
+ if (result != ISC_R_SUCCESS)
+ goto init_cleanup;
+
+ /* open dlz_host database. */
+ result = bdb_opendb(db->dbenv, DB_UNKNOWN, &db->host,
+ dlz_host, argv[2],
+ DB_DUP | DB_DUPSORT);
+ if (result != ISC_R_SUCCESS)
+ goto init_cleanup;
+
+ /* open dlz_zone database. */
+ result = bdb_opendb(db->dbenv, DB_UNKNOWN, &db->zone,
+ dlz_zone, argv[2],
+ DB_DUP | DB_DUPSORT);
+ if (result != ISC_R_SUCCESS)
+ goto init_cleanup;
+
+ /* open dlz_client database. */
+ result = bdb_opendb(db->dbenv, DB_UNKNOWN, &db->client,
+ dlz_client, argv[2], DB_DUP | DB_DUPSORT);
+ if (result != ISC_R_SUCCESS)
+ goto init_cleanup;
+
+ /* associate the host secondary database with the primary database */
+ bdbres = db->data->associate(db->data, NULL, db->host, NULL, 0);
+ if (bdbres != 0) {
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
+ "BDB could not associate %s database with %s. "
+ "BDB error: %s",
+ dlz_host, dlz_data, db_strerror(bdbres));
+ result = ISC_R_FAILURE;
+ goto init_cleanup;
+ }
+
+ /* associate the zone secondary database with the primary database */
+ bdbres = db->data->associate(db->data, NULL, db->zone, NULL, 0);
+ if (bdbres != 0) {
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
+ "BDB could not associate %s database with %s. "
+ "BDB error: %s",
+ dlz_zone, dlz_data, db_strerror(bdbres));
+ result = ISC_R_FAILURE;
+ goto init_cleanup;
+ }
+
+ *dbdata = db;
+
+ return(ISC_R_SUCCESS);
+
+ init_cleanup:
+
+ bdb_cleanup(db);
+ return result;
+}
+
+static void
+bdb_destroy(void *driverarg, void *dbdata)
+{
+ UNUSED(driverarg);
+
+ bdb_cleanup((bdb_instance_t *) dbdata);
+}
+
+/* bdb_authority not needed as authority data is returned by lookup */
+static dns_sdlzmethods_t dlz_bdb_methods = {
+ bdb_create,
+ bdb_destroy,
+ bdb_findzone,
+ bdb_lookup,
+ NULL,
+ bdb_allnodes,
+ bdb_allowzonexfr
+};
+
+/*%
+ * Wrapper around dns_sdlzregister().
+ */
+isc_result_t
+dlz_bdb_init(void) {
+ isc_result_t result;
+
+ /*
+ * Write debugging message to log
+ */
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2),
+ "Registering DLZ bdb driver.");
+
+ result = dns_sdlzregister("bdb", &dlz_bdb_methods, NULL,
+ DNS_SDLZFLAG_RELATIVEOWNER |
+ DNS_SDLZFLAG_RELATIVERDATA |
+ DNS_SDLZFLAG_THREADSAFE,
+ ns_g_mctx, &dlz_bdb);
+ if (result != ISC_R_SUCCESS) {
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "dns_sdlzregister() failed: %s",
+ isc_result_totext(result));
+ result = ISC_R_UNEXPECTED;
+ }
+
+
+ return result;
+}
+
+/*%
+ * Wrapper around dns_sdlzunregister().
+ */
+void
+dlz_bdb_clear(void) {
+
+ /*
+ * Write debugging message to log
+ */
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2),
+ "Unregistering DLZ bdb driver.");
+
+ if (dlz_bdb != NULL)
+ dns_sdlzunregister(&dlz_bdb);
+}
+
+#endif
--- /dev/null
+/*
+ * 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) 1999-2001 Internet Software Consortium.
+ *
+ * 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 INTERNET SOFTWARE CONSORTIUM
+ * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+ * INTERNET SOFTWARE CONSORTIUM 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.
+ */
+
+#ifdef DLZ_BDB
+
+#include <config.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include <dns/log.h>
+#include <dns/sdlz.h>
+#include <dns/result.h>
+
+#include <isc/mem.h>
+#include <isc/print.h>
+#include <isc/result.h>
+#include <isc/util.h>
+
+#include <named/globals.h>
+
+#include <dlz/dlz_bdbhpt_driver.h>
+
+#include <db.h>
+
+static dns_sdlzimplementation_t *dlz_bdbhpt = NULL;
+
+/* 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"
+
+ /* This structure contains all the Berkeley DB handles
+ * for this instance of the bdbhpt 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 */
+ isc_mem_t *mctx; /*%< memory context */
+
+} bdbhpt_instance_t;
+
+typedef struct bdbhpt_parsed_data {
+ char *host;
+ char *type;
+ int ttl;
+ char *data;
+} bdbhpt_parsed_data_t;
+
+
+/* forward reference */
+
+static isc_result_t
+bdbhpt_findzone(void *driverarg, void *dbdata, const char *name);
+
+/*%
+ * 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(char *in, bdbhpt_parsed_data_t *pd) {
+
+ char *endp, *ttlStr;
+ char *tmp = in;
+ char *lastchar = (char *) &tmp[strlen(tmp)];
+
+ /*%
+ * String should be formated 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) {
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
+ "bdbhpt driver ttl must be a postive number");
+ return ISC_R_FAILURE;
+ }
+
+ /* if we get this far everything should have worked. */
+ return ISC_R_SUCCESS;
+}
+
+/*
+ * DLZ methods
+ */
+
+static isc_result_t
+bdbhpt_allowzonexfr(void *driverarg, 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. */
+ result = bdbhpt_findzone(driverarg, dbdata, name);
+ 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;
+
+}
+
+/*%
+ * 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).
+ */
+
+static isc_result_t
+bdbhpt_allnodes(const char *zone, void *driverarg, 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;
+
+ UNUSED(driverarg);
+
+ 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(tmp, &pd) != ISC_R_SUCCESS)
+ goto allnodes_cleanup;
+
+ result = dns_sdlz_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(xfr_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) {
+
+ isc_mem_t *mctx;
+
+ /* 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);
+
+ /* cleanup memory */
+ if (db->mctx != NULL) {
+ /* save mctx for later */
+ mctx = db->mctx;
+ /* return, and detach the memory */
+ isc_mem_put(mctx, db, sizeof(bdbhpt_instance_t));
+ isc_mem_detach(&mctx);
+ }
+}
+
+static isc_result_t
+bdbhpt_findzone(void *driverarg, void *dbdata, const char *name)
+{
+
+ isc_result_t result;
+ bdbhpt_instance_t *db = (bdbhpt_instance_t *) dbdata;
+ DBT key, data;
+
+ UNUSED(driverarg);
+
+ memset(&key, 0, sizeof(DBT));
+ memset(&data, 0, sizeof(DBT));
+ data.flags = DB_DBT_MALLOC;
+
+ 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;
+}
+
+static isc_result_t
+bdbhpt_lookup(const char *zone, const char *name, void *driverarg,
+ void *dbdata, dns_sdlzlookup_t *lookup)
+{
+
+ 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;
+
+ UNUSED(driverarg);
+
+ 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(tmp, &pd) != ISC_R_SUCCESS)
+ goto lookup_cleanup;
+
+ result = dns_sdlz_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;
+}
+
+/*% Initializes, sets flags and then opens Berkeley databases. */
+
+static isc_result_t
+bdbhpt_opendb(DB_ENV *db_env, DBTYPE db_type, DB **db, const char *db_name,
+ char *db_file, int flags) {
+
+ int result;
+
+ /* Initialize the database. */
+ if ((result = db_create(db, db_env, 0)) != 0) {
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
+ "bdbhpt could not initialize %s database. "
+ "bdbhpt error: %s",
+ db_name, db_strerror(result));
+ return ISC_R_FAILURE;
+ }
+
+ /* set database flags. */
+ if ((result = (*db)->set_flags(*db, flags)) != 0) {
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
+ "bdbhpt could not set flags for %s database. "
+ "bdbhpt 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) {
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
+ "bdbhpt could not open %s database in %s. "
+ "bdbhpt error: %s",
+ db_name, db_file, db_strerror(result));
+ return ISC_R_FAILURE;
+ }
+
+ return ISC_R_SUCCESS;
+}
+
+static isc_result_t
+bdbhpt_create(const char *dlzname, unsigned int argc, char *argv[],
+ void *driverarg, void **dbdata)
+{
+ isc_result_t result;
+ int bdbhptres;
+ int bdbFlags = 0;
+ bdbhpt_instance_t *db = NULL;
+
+ UNUSED(dlzname);
+ UNUSED(driverarg);
+
+ /* verify we have 4 arg's passed to the driver */
+ if (argc != 4) {
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
+ "bdbhpt driver requires at least "
+ "3 command line args.");
+ 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;
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(1),
+ "bdbhpt driver using transactional mode.");
+ break;
+ /*
+ * Concurrent mode. Lower safety (no rollback) -
+ * higher speed.
+ */
+ case 'C':
+ case 'c':
+ bdbFlags = DB_INIT_CDB | DB_INIT_MPOOL;
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(1),
+ "bdbhpt driver 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;
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(1),
+ "bdbhpt driver using private mode.");
+ break;
+ default:
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
+ "bdbhpt driver requires the operating mode "
+ "be set to P or C or T. You specified '%s'",
+ argv[1]);
+ return (ISC_R_FAILURE);
+ }
+
+ /* allocate and zero memory for driver structure */
+ db = isc_mem_get(ns_g_mctx, sizeof(bdbhpt_instance_t));
+ if (db == NULL) {
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
+ "Could not allocate memory for "
+ "database instance object.");
+ return (ISC_R_NOMEMORY);
+ }
+ memset(db, 0, sizeof(bdbhpt_instance_t));
+
+ /* attach to the memory context */
+ isc_mem_attach(ns_g_mctx, &db->mctx);
+
+ /*
+ * create bdbhpt environment
+ * Basically bdbhpt allocates and assigns memory to db->dbenv
+ */
+ bdbhptres = db_env_create(&db->dbenv, 0);
+ if (bdbhptres != 0) {
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
+ "bdbhpt environment could not be created. "
+ "bdbhpt 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) {
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
+ "bdbhpt environment at '%s' could not be opened."
+ " bdbhpt error: %s",
+ argv[2], db_strerror(bdbhptres));
+ result = ISC_R_FAILURE;
+ goto init_cleanup;
+ }
+
+ /* open dlz_data database. */
+ result = bdbhpt_opendb(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->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->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->dbenv, DB_UNKNOWN, &db->client,
+ dlz_client, argv[3], DB_DUP | DB_DUPSORT);
+ if (result != ISC_R_SUCCESS)
+ goto init_cleanup;
+
+ *dbdata = db;
+
+ return(ISC_R_SUCCESS);
+
+ init_cleanup:
+
+ bdbhpt_cleanup(db);
+ return result;
+}
+
+static void
+bdbhpt_destroy(void *driverarg, void *dbdata)
+{
+ UNUSED(driverarg);
+
+ bdbhpt_cleanup((bdbhpt_instance_t *) dbdata);
+}
+
+/*
+ * bdbhpt_authority not needed as authority data is returned by lookup
+ */
+static dns_sdlzmethods_t dlz_bdbhpt_methods = {
+ bdbhpt_create,
+ bdbhpt_destroy,
+ bdbhpt_findzone,
+ bdbhpt_lookup,
+ NULL,
+ bdbhpt_allnodes,
+ bdbhpt_allowzonexfr
+};
+
+/*%
+ * Wrapper around dns_sdlzregister().
+ */
+isc_result_t
+dlz_bdbhpt_init(void) {
+ isc_result_t result;
+
+ /*
+ * Write debugging message to log
+ */
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2),
+ "Registering DLZ bdbhpt driver.");
+
+ result = dns_sdlzregister("bdbhpt", &dlz_bdbhpt_methods, NULL,
+ DNS_SDLZFLAG_RELATIVEOWNER |
+ DNS_SDLZFLAG_RELATIVERDATA |
+ DNS_SDLZFLAG_THREADSAFE,
+ ns_g_mctx, &dlz_bdbhpt);
+ if (result != ISC_R_SUCCESS) {
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "dns_sdlzregister() failed: %s",
+ isc_result_totext(result));
+ result = ISC_R_UNEXPECTED;
+ }
+
+
+ return result;
+}
+
+/*%
+ * Wrapper around dns_sdlzunregister().
+ */
+void
+dlz_bdbhpt_clear(void) {
+
+ /*
+ * Write debugging message to log
+ */
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2),
+ "Unregistering DLZ bdbhpt driver.");
+
+ if (dlz_bdbhpt != NULL)
+ dns_sdlzunregister(&dlz_bdbhpt);
+}
+
+#endif
--- /dev/null
+/*
+ * Copyright (C) 2005 Internet Systems Consortium, Inc. ("ISC")
+ *
+ * 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 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.
+ */
+
+/* $Id: dlz_drivers.c,v 1.2 2005/09/05 00:10:55 marka Exp $ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <isc/result.h>
+
+/*
+ * Pull in declarations for this module's functions.
+ */
+
+#include <dlz/dlz_drivers.h>
+
+/*
+ * Pull in driver-specific stuff.
+ */
+
+#ifdef DLZ_STUB
+#include <dlz/dlz_stub_driver.h>
+#endif
+
+#ifdef DLZ_POSTGRES
+#include <dlz/dlz_postgres_driver.h>
+#endif
+
+#ifdef DLZ_MYSQL
+#include <dlz/dlz_mysql_driver.h>
+#endif
+
+#ifdef DLZ_FILESYSTEM
+#include <dlz/dlz_filesystem_driver.h>
+#endif
+
+#ifdef DLZ_BDB
+#include <dlz/dlz_bdb_driver.h>
+#include <dlz/dlz_bdbhpt_driver.h>
+#endif
+
+#ifdef DLZ_LDAP
+#include <dlz/dlz_ldap_driver.h>
+#endif
+
+#ifdef DLZ_ODBC
+#include <dlz/dlz_odbc_driver.h>
+#endif
+
+/*%
+ * Call init functions for all relevant DLZ drivers.
+ */
+
+isc_result_t
+dlz_drivers_init(void) {
+
+ isc_result_t result = ISC_R_SUCCESS;
+
+#ifdef DLZ_STUB
+ result = dlz_stub_init();
+ if (result != ISC_R_SUCCESS)
+ return (result);
+#endif
+
+#ifdef DLZ_POSTGRES
+ result = dlz_postgres_init();
+ if (result != ISC_R_SUCCESS)
+ return (result);
+#endif
+
+#ifdef DLZ_MYSQL
+ result = dlz_mysql_init();
+ if (result != ISC_R_SUCCESS)
+ return (result);
+#endif
+
+#ifdef DLZ_FILESYSTEM
+ result = dlz_fs_init();
+ if (result != ISC_R_SUCCESS)
+ return (result);
+#endif
+
+#ifdef DLZ_BDB
+ result = dlz_bdb_init();
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ result = dlz_bdbhpt_init();
+ if (result != ISC_R_SUCCESS)
+ return (result);
+#endif
+
+#ifdef DLZ_LDAP
+ result = dlz_ldap_init();
+ if (result != ISC_R_SUCCESS)
+ return (result);
+#endif
+
+#ifdef DLZ_ODBC
+ result = dlz_odbc_init();
+ if (result != ISC_R_SUCCESS)
+ return (result);
+#endif
+
+ return (result);
+}
+
+/*%
+ * Call shutdown functions for all relevant DLZ drivers.
+ */
+
+void
+dlz_drivers_clear(void) {
+
+#ifdef DLZ_STUB
+ dlz_stub_clear();
+#endif
+
+#ifdef DLZ_POSTGRES
+ dlz_postgres_clear();
+#endif
+
+#ifdef DLZ_MYSQL
+ dlz_mysql_clear();
+#endif
+
+#ifdef DLZ_FILESYSTEM
+ dlz_fs_clear();
+#endif
+
+#ifdef DLZ_BDB
+ dlz_bdb_clear();
+ dlz_bdbhpt_clear();
+#endif
+
+#ifdef DLZ_LDAP
+ dlz_ldap_clear();
+#endif
+
+#ifdef DLZ_ODBC
+ dlz_odbc_clear();
+#endif
+
+}
--- /dev/null
+/*
+ * 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) 1999-2001 Internet Software Consortium.
+ *
+ * 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 INTERNET SOFTWARE CONSORTIUM
+ * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+ * INTERNET SOFTWARE CONSORTIUM 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.
+ */
+
+#ifdef DLZ_FILESYSTEM
+
+#include <config.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include <sys/stat.h>
+
+#include <dns/log.h>
+#include <dns/sdlz.h>
+#include <dns/result.h>
+
+#include <isc/dir.h>
+#include <isc/mem.h>
+#include <isc/platform.h>
+#include <isc/print.h>
+#include <isc/result.h>
+#include <isc/util.h>
+
+#include <named/globals.h>
+
+#include <dlz/dlz_filesystem_driver.h>
+
+static dns_sdlzimplementation_t *dlz_fs = NULL;
+
+typedef struct config_data {
+ char *basedir;
+ int basedirsize;
+ char *datadir;
+ int datadirsize;
+ char *xfrdir;
+ int xfrdirsize;
+ int splitcnt;
+ char separator;
+ char pathsep;
+ isc_mem_t *mctx;
+} config_data_t;
+
+typedef struct dir_entry dir_entry_t;
+
+struct dir_entry {
+ char dirpath[ISC_DIR_PATHMAX];
+ ISC_LINK(dir_entry_t) link;
+};
+
+typedef ISC_LIST(dir_entry_t) dlist_t;
+
+/* forward reference */
+
+static void
+fs_destroy(void *driverarg, void *dbdata);
+
+/*
+ * Private methods
+ */
+
+static isc_boolean_t
+is_safe(const char *input)
+{
+ unsigned int i;
+ unsigned int len = strlen(input);
+
+ /* check that only allowed characters are in the domain name */
+ for (i=0; i < len; i++) {
+ /* '.' is allowed, but has special requirements */
+ if (input[i] == '.') {
+ /* '.' is not allowed as first char */
+ if (i == 0)
+ return ISC_FALSE;
+ /* '..', two dots together is not allowed. */
+ else if (input[i-1] == '.')
+ return ISC_FALSE;
+ /* '.' is not allowed as last char */
+ if (i == len)
+ return ISC_FALSE;
+ /* only 1 dot in ok location, continue at next char */
+ continue;
+ }
+ /* '-' is allowed, continue at next char */
+ if (input[i] == '-')
+ continue;
+ /* 0-9 is allowed, continue at next char */
+ if (input[i] >= '0' && input[i] <= '9')
+ continue;
+ /* A-Z uppercase is allowed, continue at next char */
+ if (input[i] >= 'A' && input[i] <= 'Z')
+ continue;
+ /* a-z lowercase is allowed, continue at next char */
+ if (input[i] >= 'a' && input[i] <= 'z')
+ continue;
+
+ /*
+ * colon needs to be allowed for IPV6 client
+ * addresses. Not dangerous in domain names, as not a
+ * special char.
+ */
+ if (input[i] == ':')
+ continue;
+
+ /*
+ * '@' needs to be allowed for in zone data. Not
+ * dangerous in domain names, as not a special char.
+ */
+ if (input[i] == '@')
+ continue;
+
+ /*
+ * if we reach this point we have encountered a
+ * disallowed char!
+ */
+ return ISC_FALSE;
+ }
+ /* everything ok. */
+ return ISC_TRUE;
+}
+
+static isc_result_t
+create_path_helper(char *out, const char *in, config_data_t *cd)
+{
+
+ char *tmpString;
+ char *tmpPtr;
+ int i;
+
+ tmpString = isc_mem_strdup(ns_g_mctx, in);
+ if (tmpString == NULL)
+ return (ISC_R_NOMEMORY);
+
+ /*
+ * don't forget is_safe guarantees '.' will NOT be the
+ * first/last char
+ */
+ while ((tmpPtr = strrchr(tmpString, '.')) != NULL) {
+ i = 0;
+ while (tmpPtr[i+1] != '\0') {
+ if (cd->splitcnt < 1)
+ strcat(out, (char *) &tmpPtr[i+1]);
+ else
+ strncat(out, (char *) &tmpPtr[i+1],
+ cd->splitcnt);
+ strncat(out, (char *) &cd->pathsep, 1);
+ if (cd->splitcnt == 0)
+ break;
+ if (strlen((char *) &tmpPtr[i+1]) <=
+ (unsigned int) cd->splitcnt)
+ break;
+ i += cd->splitcnt;
+ }
+ tmpPtr[0] = '\0';
+ }
+
+ /* handle the "first" label properly */
+ i=0;
+ tmpPtr = tmpString;
+ while (tmpPtr[i] != '\0') {
+ if (cd->splitcnt < 1)
+ strcat(out, (char *) &tmpPtr[i]);
+ else
+ strncat(out, (char *) &tmpPtr[i], cd->splitcnt);
+ strncat(out, (char *) &cd->pathsep, 1);
+ if (cd->splitcnt == 0)
+ break;
+ if (strlen((char *) &tmpPtr[i]) <=
+ (unsigned int) cd->splitcnt)
+ break;
+ i += cd->splitcnt;
+ }
+
+ isc_mem_free(ns_g_mctx, tmpString);
+ return (ISC_R_SUCCESS);
+}
+
+/*%
+ * Checks to make sure zone and host are safe. If safe, then
+ * hashes zone and host strings to build a path. If zone / host
+ * are not safe an error is returned.
+ */
+
+static isc_result_t
+create_path(const char *zone, const char *host, const char *client,
+ config_data_t *cd, char **path)
+{
+
+ char *tmpPath;
+ int pathsize;
+ int len;
+ isc_result_t result;
+
+ /* we require a zone & cd parameter */
+ REQUIRE(zone != NULL);
+ REQUIRE(cd != NULL);
+ /* require path to be a pointer to NULL */
+ REQUIRE(path != NULL && *path == NULL);
+ /*
+ * client and host may both be NULL, but they can't both be
+ * NON-NULL
+ */
+ REQUIRE( (host == NULL && client == NULL) ||
+ (host != NULL && client == NULL) ||
+ (host == NULL && client != NULL) );
+
+ /* if the requested zone is "unsafe", return error */
+ if (is_safe(zone) != ISC_TRUE)
+ return (ISC_R_FAILURE);
+
+ /* if host was passed, verify that it is safe */
+ if ((host != NULL) && (is_safe(host) != ISC_TRUE) )
+ return (ISC_R_FAILURE);
+
+ /* if host was passed, verify that it is safe */
+ if ((client != NULL) && (is_safe(client) != ISC_TRUE) )
+ return (ISC_R_FAILURE);
+
+ /* Determine how much memory the split up string will require */
+ if (host != NULL)
+ len = strlen(zone) + strlen(host);
+ else if (client != NULL)
+ len = strlen(zone) + strlen(client);
+ else
+ len = strlen(zone);
+
+ /*
+ * even though datadir and xfrdir will never be in the same
+ * string we only waste a few bytes by allocating for both,
+ * and then we are safe from buffer overruns.
+ */
+ pathsize = len + cd->basedirsize +
+ cd->datadirsize + cd->xfrdirsize + 4;
+
+ /* if we are splitting names, we will need extra space. */
+ if (cd->splitcnt > 0)
+ pathsize += len/cd->splitcnt;
+
+ tmpPath = isc_mem_allocate(ns_g_mctx , pathsize * sizeof(char));
+ if (tmpPath == NULL) {
+ /* write error message */
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
+ "Filesystem driver unable to "
+ "allocate memory in create_path().");
+ result = ISC_R_NOMEMORY;
+ goto cleanup_mem;
+ }
+
+ /*
+ * build path string.
+ * start out with base directory.
+ */
+ strcpy(tmpPath, cd->basedir);
+
+ /* add zone name - parsed properly */
+ if ((result = create_path_helper(tmpPath, zone, cd)) != ISC_R_SUCCESS)
+ goto cleanup_mem;
+
+ /*
+ * When neither client or host is passed we are building a
+ * path to see if a zone is supported. We require that a zone
+ * path have the "data dir" directory contained within it so
+ * that we know this zone is really supported. Otherwise,
+ * this zone may not really be supported because we are
+ * supporting a delagated sub zone.
+ *
+ * Example:
+ *
+ * We are supporting long.domain.com and using a splitcnt of
+ * 0. the base dir is "/base-dir/" and the data dir is
+ * "/.datadir" We want to see if we are authoritative for
+ * domain.com. Path /base-dir/com/domain/.datadir since
+ * /base-dir/com/domain/.datadir does not exist, we are not
+ * authoritative for the domain "domain.com". However we are
+ * authoritative for the domain "long.domain.com" because the
+ * path /base-dir/com/domain/long/.datadir does exist!
+ */
+
+ /* if client is passed append xfr dir, otherwise append data dir */
+ if (client != NULL) {
+ strcat(tmpPath, cd->xfrdir);
+ strncat(tmpPath, (char *) &cd->pathsep, 1);
+ strcat(tmpPath, client);
+ } else {
+ strcat(tmpPath, cd->datadir);
+ }
+
+ /* if host not null, add it. */
+ if (host != NULL) {
+ strncat(tmpPath, (char *) &cd->pathsep, 1);
+ if ((result = create_path_helper(tmpPath, host,
+ cd)) != ISC_R_SUCCESS)
+ goto cleanup_mem;
+ }
+
+ /* return the path we built. */
+ *path = tmpPath;
+
+ /* return success */
+ result = ISC_R_SUCCESS;
+
+ cleanup_mem:
+ /* cleanup memory */
+
+ /* free tmpPath memory */
+ if (tmpPath != NULL && result != ISC_R_SUCCESS)
+ isc_mem_free(ns_g_mctx, tmpPath);
+
+ /* free tmpPath memory */
+ return result;
+}
+
+static isc_result_t
+process_dir(isc_dir_t dir, void *passback, config_data_t *cd,
+ dlist_t *dir_list, unsigned int basedirlen)
+{
+
+ char tmp[ISC_DIR_PATHMAX + ISC_DIR_NAMEMAX];
+ int astPos;
+ struct stat sb;
+ isc_result_t result = ISC_R_FAILURE;
+ char *endp;
+ char *type;
+ char *ttlStr;
+ char *data;
+ char host[ISC_DIR_NAMEMAX];
+ char *tmpString;
+ char *tmpPtr;
+ int ttl;
+ int i;
+ int len;
+ dir_entry_t *direntry;
+ isc_boolean_t foundHost;
+
+ tmp[0] = '\0'; /* set 1st byte to '\0' so strcpy works right. */
+ host[0] = '\0';
+ foundHost = ISC_FALSE;
+
+ /* copy base directory name to tmp. */
+ strcpy(tmp, dir.dirname);
+
+ /* dir.dirname will always have '*' as the last char. */
+ astPos = strlen(dir.dirname) - 1;
+
+ /* if dir_list != NULL, were are performing a zone xfr */
+ if (dir_list != NULL) {
+ /* if splitcnt == 0, determine host from path. */
+ if (cd->splitcnt == 0) {
+ if (strlen(tmp) - 3 > basedirlen) {
+ tmp[astPos-1] = '\0';
+ tmpString = (char *) &tmp[basedirlen+1];
+ /* handle filesystem's special wildcard "-" */
+ if (strcmp(tmpString, "-") == 0) {
+ strcpy(host, "*");
+ } else {
+ /*
+ * not special wildcard -- normal name
+ */
+ while ((tmpPtr = strrchr(tmpString,
+ cd->pathsep))
+ != NULL) {
+ strcat(host, tmpPtr + 1);
+ strcat(host, ".");
+ tmpPtr[0] = '\0';
+ }
+ strcat(host, tmpString);
+ }
+
+ foundHost = ISC_TRUE;
+ /* set tmp again for use later */
+ strcpy(tmp, dir.dirname);
+ }
+ } else {
+ /*
+ * if splitcnt != 0 determine host from
+ * ".host" directory entry
+ */
+ while (isc_dir_read(&dir) == ISC_R_SUCCESS) {
+ if (strncasecmp(".host",
+ dir.entry.name, 5) == 0) {
+ /*
+ * handle filesystem's special
+ * wildcard "-"
+ */
+ if (strcmp((char *) &dir.entry.name[6],
+ "-") == 0)
+ strcpy(host, "*");
+ else
+ strcpy(host,
+ (char *)
+ &dir.entry.name[6]);
+ foundHost = ISC_TRUE;
+ break;
+ }
+ }
+ /* reset dir list for use later */
+ isc_dir_reset(&dir);
+ } /* end of else */
+ }
+
+ while (isc_dir_read(&dir) == ISC_R_SUCCESS) {
+
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(1),
+ "Filesystem driver Dir name:"
+ " '%s' Dir entry: '%s'\n",
+ dir.dirname, dir.entry.name);
+
+ /* skip any entries starting with "." */
+ if (dir.entry.name[0] == '.')
+ continue;
+
+ /*
+ * get rid of '*', set to NULL. Effectively trims
+ * string from previous loop to base directory only
+ * while still leaving memory for concat to be
+ * performed next.
+ */
+
+ tmp[astPos] = '\0';
+
+ /* add name to base directory name. */
+ strcat(tmp, dir.entry.name);
+
+ /* make sure we can stat entry */
+ if (stat(tmp, &sb) == 0 ) {
+ /* if entry is a directory */
+ if ((sb.st_mode & S_IFDIR) != 0) {
+ /*
+ * if dir list is NOT NULL, add dir to
+ * dir list
+ */
+ if (dir_list != NULL) {
+ direntry =
+ isc_mem_get(ns_g_mctx,
+ sizeof(dir_entry_t));
+ if (direntry == NULL)
+ return (ISC_R_NOMEMORY);
+ strcpy(direntry->dirpath, tmp);
+ ISC_LINK_INIT(direntry, link);
+ ISC_LIST_APPEND(*dir_list, direntry,
+ link);
+ result = ISC_R_SUCCESS;
+ }
+ continue;
+
+ /*
+ * if entry is a file be sure we do
+ * not add entry to DNS results if we
+ * are performing a zone xfr and we
+ * could not find a host entry.
+ */
+
+ } else if (dir_list != NULL &&
+ foundHost == ISC_FALSE) {
+ continue;
+ }
+ } else /* if we cannot stat entry, skip it. */
+ continue;
+
+ type = dir.entry.name;
+ ttlStr = strchr(type, cd->separator);
+ if (ttlStr == NULL) {
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
+ "Filesystem driver: "
+ "%s could not be parsed properly",
+ tmp);
+ return ISC_R_FAILURE;
+ }
+
+ /* replace separator char with NULL to split string */
+ ttlStr[0] = '\0';
+ /* start string after NULL of previous string */
+ ttlStr = (char *) &ttlStr[1];
+
+ data = strchr(ttlStr, cd->separator);
+ if (data == NULL) {
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
+ "Filesystem driver: "
+ "%s could not be parsed properly",
+ tmp);
+ return ISC_R_FAILURE;
+ }
+
+ /* replace separator char with NULL to split string */
+ data[0] = '\0';
+
+ /* start string after NULL of previous string */
+ data = (char *) &data[1];
+
+ /* replace all cd->separator chars with a space. */
+ len = strlen(data);
+
+ for (i=0; i < len; i++) {
+ if (data[i] == cd->separator)
+ data[i] = ' ';
+ }
+
+ /* convert text to int, make sure it worked right */
+ ttl = strtol(ttlStr, &endp, 10);
+ if (*endp != '\0' || ttl < 0) {
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
+ "Filesystem driver "
+ "ttl must be a postive number");
+ }
+
+ /* pass data back to Bind */
+ if (dir_list == NULL)
+ result = dns_sdlz_putrr((dns_sdlzlookup_t *) passback,
+ type, ttl, data);
+ else
+ result = dns_sdlz_putnamedrr((dns_sdlzallnodes_t *)
+ passback,
+ (char *) host,
+ type, ttl, data);
+
+ /* if error, return error right away */
+ if (result != ISC_R_SUCCESS)
+ return result;
+ } /* end of while loop */
+
+ return result;
+}
+
+/*
+ * SDLZ interface methods
+ */
+
+static isc_result_t
+fs_allowzonexfr(void *driverarg, void *dbdata, const char *name,
+ const char *client)
+{
+
+ isc_result_t result;
+ char *path;
+ struct stat sb;
+ config_data_t *cd;
+ path = NULL;
+
+ UNUSED(driverarg);
+
+ cd = (config_data_t *) dbdata;
+
+ if (create_path(name, NULL, client, cd, &path) != ISC_R_SUCCESS) {
+ return (ISC_R_NOTFOUND);
+ }
+
+ if (stat(path, &sb) != 0) {
+ result = ISC_R_NOTFOUND;
+ goto complete_AXFR;
+ }
+
+ if ((sb.st_mode & S_IFREG) != 0) {
+ result = ISC_R_SUCCESS;
+ goto complete_AXFR;
+ }
+
+ result = ISC_R_NOTFOUND;
+
+ complete_AXFR:
+ isc_mem_free(ns_g_mctx, path);
+ return result;
+}
+
+static isc_result_t
+fs_allnodes(const char *zone, void *driverarg, void *dbdata,
+ dns_sdlzallnodes_t *allnodes)
+{
+
+ isc_result_t result;
+ dlist_t *dir_list;
+ config_data_t *cd;
+ char *basepath;
+ unsigned int basepathlen;
+ struct stat sb;
+ isc_dir_t dir;
+ dir_entry_t *dir_entry;
+ dir_entry_t *next_de;
+
+ basepath = NULL;
+ dir_list = NULL;
+
+ UNUSED(driverarg);
+ UNUSED(allnodes);
+
+ cd = (config_data_t *) dbdata;
+
+ /* allocate memory for list */
+ dir_list = isc_mem_get(ns_g_mctx, sizeof(dlist_t));
+ if (dir_list == NULL) {
+ result = ISC_R_NOTFOUND;
+ goto complete_allnds;
+ }
+
+ /* initialize list */
+ ISC_LIST_INIT(*dir_list);
+
+ if (create_path(zone, NULL, NULL, cd, &basepath) != ISC_R_SUCCESS) {
+ return (ISC_R_NOTFOUND);
+ }
+
+ /* remove path separator at end of path so stat works properly */
+ basepathlen = strlen(basepath);
+
+ if (stat(basepath, &sb) != 0) {
+ result = ISC_R_NOTFOUND;
+ goto complete_allnds;
+ }
+
+ if ((sb.st_mode & S_IFDIR) == 0) {
+ result = ISC_R_NOTFOUND;
+ goto complete_allnds;
+ }
+
+ /* initialize and open directory */
+ isc_dir_init(&dir);
+ result = isc_dir_open(&dir, basepath);
+
+ /* if directory open failed, return error. */
+ if (result != ISC_R_SUCCESS) {
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
+ "Unable to open %s directory to read entries.",
+ basepath);
+ result = ISC_R_FAILURE;
+ goto complete_allnds;
+ }
+
+ /* process the directory */
+ result = process_dir(dir, allnodes, cd, dir_list, basepathlen);
+
+ /* close the directory */
+ isc_dir_close(&dir);
+
+ if (result != ISC_R_SUCCESS)
+ goto complete_allnds;
+
+ /* get first dir entry from list. */
+ dir_entry = ISC_LIST_HEAD(*dir_list);
+ while (dir_entry != NULL) {
+
+ result = isc_dir_open(&dir, dir_entry->dirpath);
+ /* if directory open failed, return error. */
+ if (result != ISC_R_SUCCESS) {
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
+ "Unable to open %s "
+ "directory to read entries.",
+ basepath);
+ result = ISC_R_FAILURE;
+ goto complete_allnds;
+ }
+
+ /* process the directory */
+ result = process_dir(dir, allnodes, cd, dir_list, basepathlen);
+
+ /* close the directory */
+ isc_dir_close(&dir);
+
+ if (result != ISC_R_SUCCESS)
+ goto complete_allnds;
+
+ dir_entry = ISC_LIST_NEXT(dir_entry, link);
+ } /* end while */
+
+ complete_allnds:
+ if (dir_list != NULL) {
+ /* clean up entries from list. */
+ dir_entry = ISC_LIST_HEAD(*dir_list);
+ while (dir_entry != NULL) {
+ next_de = ISC_LIST_NEXT(dir_entry, link);
+ isc_mem_put(ns_g_mctx, dir_entry, sizeof(dir_entry_t));
+ dir_entry = next_de;
+ } /* end while */
+ isc_mem_put(ns_g_mctx, dir_list, sizeof(dlist_t));
+ }
+
+ if (basepath != NULL)
+ isc_mem_free(ns_g_mctx, basepath);
+
+ return result;
+}
+
+static isc_result_t
+fs_findzone(void *driverarg, void *dbdata, const char *name)
+{
+
+ isc_result_t result;
+ char *path;
+ struct stat sb;
+ path = NULL;
+
+ UNUSED(driverarg);
+
+ if (create_path(name, NULL, NULL, (config_data_t *) dbdata,
+ &path) != ISC_R_SUCCESS) {
+ return (ISC_R_NOTFOUND);
+ }
+
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(1),
+ "Filesystem driver Findzone() Checking for path: '%s'\n",
+ path);
+
+ if (stat(path, &sb) != 0) {
+ result = ISC_R_NOTFOUND;
+ goto complete_FZ;
+ }
+
+ if ((sb.st_mode & S_IFDIR) != 0) {
+ result = ISC_R_SUCCESS;
+ goto complete_FZ;
+ }
+
+ result = ISC_R_NOTFOUND;
+
+ complete_FZ:
+
+ isc_mem_free(ns_g_mctx, path);
+ return result;
+}
+
+static isc_result_t
+fs_lookup(const char *zone, const char *name, void *driverarg,
+ void *dbdata, dns_sdlzlookup_t *lookup)
+{
+ isc_result_t result;
+ char *path;
+ struct stat sb;
+ isc_dir_t dir;
+ path = NULL;
+
+ UNUSED(driverarg);
+ UNUSED(lookup);
+
+ if (strcmp(name, "*") == 0)
+ /*
+ * handle filesystem's special wildcard "-"
+ */
+ result = create_path(zone, "-", NULL,
+ (config_data_t *) dbdata, &path);
+ else
+ result = create_path(zone, name, NULL,
+ (config_data_t *) dbdata, &path);
+
+ if ( result != ISC_R_SUCCESS) {
+ return (ISC_R_NOTFOUND);
+ }
+
+ /* remove path separator at end of path so stat works properly */
+ path[strlen(path)-1] = '\0';
+
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(1),
+ "Filesystem driver lookup() Checking for path: '%s'\n",
+ path);
+
+
+ if (stat(path, &sb) != 0) {
+ result = ISC_R_NOTFOUND;
+ goto complete_lkup;
+ }
+
+ if ((sb.st_mode & S_IFDIR) == 0) {
+ result = ISC_R_NOTFOUND;
+ goto complete_lkup;
+ }
+
+ /* initialize and open directory */
+ isc_dir_init(&dir);
+ result = isc_dir_open(&dir, path);
+
+ /* if directory open failed, return error. */
+ if (result != ISC_R_SUCCESS) {
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
+ "Unable to open %s directory to read entries.",
+ path);
+ result = ISC_R_FAILURE;
+ goto complete_lkup;
+ }
+
+ /* process any records in the directory */
+ result = process_dir(dir, lookup, (config_data_t *) dbdata, NULL, 0);
+
+ /* close the directory */
+ isc_dir_close(&dir);
+
+ complete_lkup:
+
+ isc_mem_free(ns_g_mctx, path);
+ return result;
+}
+
+static isc_result_t
+fs_create(const char *dlzname, unsigned int argc, char *argv[],
+ void *driverarg, void **dbdata)
+{
+ config_data_t *cd;
+ char *endp;
+ int len;
+ char pathsep;
+
+ UNUSED(driverarg);
+ UNUSED(dlzname);
+
+ /* we require 5 command line args. */
+ if (argc != 6) {
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
+ "Filesystem driver requires "
+ "6 command line args.");
+ return (ISC_R_FAILURE);
+ }
+
+ if (strlen(argv[5]) > 1) {
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
+ "Filesystem driver can only "
+ "accept a single character for separator.");
+ return (ISC_R_FAILURE);
+ }
+
+ /* verify base dir ends with '/' or '\' */
+ len = strlen(argv[1]);
+ if (argv[1][len-1] != '\\' && argv[1][len-1] != '/') {
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
+ "Base dir parameter for filesystem driver "
+ "should end with %s",
+ "either '/' or '\\' ");
+ return (ISC_R_FAILURE);
+ }
+
+ /* determine and save path separator for later */
+ if (argv[1][len-1] == '\\')
+ pathsep = '\\';
+ else
+ pathsep = '/';
+
+ /* allocate memory for our config data */
+ cd = isc_mem_get(ns_g_mctx, sizeof(config_data_t));
+ if (cd == NULL)
+ goto no_mem;
+
+ /* zero the memory */
+ memset(cd, 0, sizeof(config_data_t));
+
+ cd->pathsep = pathsep;
+
+ /* get and store our base directory */
+ cd->basedir = isc_mem_strdup(ns_g_mctx, argv[1]);
+ if (cd->basedir == NULL)
+ goto no_mem;
+ cd->basedirsize = strlen(cd->basedir);
+
+ /* get and store our data sub-dir */
+ cd->datadir = isc_mem_strdup(ns_g_mctx, argv[2]);
+ if (cd->datadir == NULL)
+ goto no_mem;
+ cd->datadirsize = strlen(cd->datadir);
+
+ /* get and store our zone xfr sub-dir */
+ cd->xfrdir = isc_mem_strdup(ns_g_mctx, argv[3]);
+ if (cd->xfrdir == NULL)
+ goto no_mem;
+ cd->xfrdirsize = strlen(cd->xfrdir);
+
+ /* get and store our directory split count */
+ cd->splitcnt = strtol(argv[4], &endp, 10);
+ if (*endp != '\0' || cd->splitcnt < 0) {
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
+ "Directory split count must be zero (0) "
+ "or a postive number");
+ }
+
+ /* get and store our separator character */
+ cd->separator = *argv[5];
+
+ /* attach config data to memory context */
+ isc_mem_attach(ns_g_mctx, &cd->mctx);
+
+ /* pass back config data */
+ *dbdata = cd;
+
+ /* return success */
+ return(ISC_R_SUCCESS);
+
+ /* handle no memory error */
+ no_mem:
+
+ /* if we allocated a config data object clean it up */
+ if (cd != NULL)
+ fs_destroy(NULL, cd);
+
+ /* write error message */
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
+ "Filesystem driver unable to "
+ "allocate memory for config data.");
+
+ /* return error */
+ return (ISC_R_NOMEMORY);
+}
+
+static void
+fs_destroy(void *driverarg, void *dbdata)
+{
+ isc_mem_t *mctx;
+ config_data_t *cd;
+
+ UNUSED(driverarg);
+
+ cd = (config_data_t *) dbdata;
+
+ /*
+ * free memory for each section of config data that was
+ * allocated
+ */
+ if (cd->basedir != NULL)
+ isc_mem_free(ns_g_mctx, cd->basedir);
+
+ if (cd->datadir != NULL)
+ isc_mem_free(ns_g_mctx, cd->datadir);
+
+ if (cd->xfrdir != NULL)
+ isc_mem_free(ns_g_mctx, cd->xfrdir);
+
+ /* hold memory context to use later */
+ mctx = cd->mctx;
+
+ /* free config data memory */
+ isc_mem_put(mctx, cd, sizeof(config_data_t));
+
+ /* detach memory from context */
+ isc_mem_detach(&mctx);
+}
+
+static dns_sdlzmethods_t dlz_fs_methods = {
+ fs_create,
+ fs_destroy,
+ fs_findzone,
+ fs_lookup,
+ NULL,
+ fs_allnodes,
+ fs_allowzonexfr
+};
+
+/*%
+ * Wrapper around dns_sdlzregister().
+ */
+isc_result_t
+dlz_fs_init(void)
+{
+ isc_result_t result;
+
+ /*
+ * Write debugging message to log
+ */
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2),
+ "Registering DLZ filesystem driver.");
+
+ result = dns_sdlzregister("filesystem", &dlz_fs_methods, NULL,
+ DNS_SDLZFLAG_RELATIVEOWNER |
+ DNS_SDLZFLAG_RELATIVERDATA,
+ ns_g_mctx, &dlz_fs);
+ if (result != ISC_R_SUCCESS) {
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "dns_sdlzregister() failed: %s",
+ isc_result_totext(result));
+ result = ISC_R_UNEXPECTED;
+ }
+
+ return result;
+}
+
+/*%
+ * Wrapper around dns_sdlzunregister().
+ */
+void
+dlz_fs_clear(void) {
+
+ /*
+ * Write debugging message to log
+ */
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2),
+ "Unregistering DLZ filesystem driver.");
+
+ if (dlz_fs != NULL)
+ dns_sdlzunregister(&dlz_fs);
+}
+
+#endif
--- /dev/null
+/*
+ * 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) 1999-2001 Internet Software Consortium.
+ *
+ * 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 INTERNET SOFTWARE CONSORTIUM
+ * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+ * INTERNET SOFTWARE CONSORTIUM 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.
+ */
+
+#ifdef DLZ_LDAP
+
+#include <config.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include <dns/log.h>
+#include <dns/sdlz.h>
+#include <dns/result.h>
+
+#include <isc/mem.h>
+#include <isc/platform.h>
+#include <isc/print.h>
+#include <isc/result.h>
+#include <isc/string.h>
+#include <isc/util.h>
+
+#include <named/globals.h>
+
+#include <dlz/sdlz_helper.h>
+#include <dlz/dlz_ldap_driver.h>
+
+/*
+ * Need older API functions from ldap.h.
+ */
+#define LDAP_DEPRECATED 1
+
+#include <ldap.h>
+
+#define SIMPLE "simple"
+#define KRB41 "krb41"
+#define KRB42 "krb42"
+#define V2 "v2"
+#define V3 "v3"
+
+static dns_sdlzimplementation_t *dlz_ldap = NULL;
+
+#define dbc_search_limit 30
+#define ALLNODES 1
+#define ALLOWXFR 2
+#define AUTHORITY 3
+#define FINDZONE 4
+#define LOOKUP 5
+
+/*%
+ * Structure to hold everthing needed by this "instance" of the LDAP
+ * driver remember, the driver code is only loaded once, but may have
+ * many separate instances.
+ */
+
+typedef struct {
+
+#ifdef ISC_PLATFORM_USETHREADS
+ db_list_t *db; /*%< handle to a list of DB */
+#else
+ dbinstance_t *db; /*%< handle to db */
+#endif
+ int method; /*%< security authentication method */
+ char *user; /*%< who is authenticating */
+ char *cred; /*%< password for simple authentication method */
+ int protocol; /*%< LDAP communication protocol version */
+ char *hosts; /*%< LDAP server hosts */
+
+} ldap_instance_t;
+
+/* forward references */
+
+static isc_result_t
+dlz_ldap_findzone(void *driverarg, void *dbdata, const char *name);
+
+static void
+dlz_ldap_destroy(void *driverarg, void *dbdata);
+
+/*
+ * Private methods
+ */
+
+/*% checks that the LDAP URL parameters make sense */
+
+static isc_result_t
+dlz_ldap_checkURL(char *URL, int attrCnt, const char *msg) {
+
+ isc_result_t result = ISC_R_SUCCESS;
+ int ldap_result;
+ LDAPURLDesc *ldap_url = NULL;
+
+ if (!ldap_is_ldap_url(URL)) {
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
+ "%s query is not a valid LDAP URL", msg);
+ result = ISC_R_FAILURE;
+ goto cleanup;
+ }
+
+ ldap_result = ldap_url_parse(URL, &ldap_url);
+ if (ldap_result != LDAP_SUCCESS || ldap_url == NULL) {
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
+ "parsing %s query failed", msg);
+ result = ISC_R_FAILURE;
+ goto cleanup;
+ }
+
+ if (ldap_count_values(ldap_url->lud_attrs) < attrCnt) {
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
+ "%s query must specify at least "
+ "%d attributes to return",
+ msg, attrCnt);
+ result = ISC_R_FAILURE;
+ goto cleanup;
+ }
+
+ if (ldap_url->lud_host != NULL) {
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
+ "%s query must not specify a host", msg);
+ result = ISC_R_FAILURE;
+ goto cleanup;
+ }
+
+ if (ldap_url->lud_port != 389) {
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
+ "%s query must not specify a port", msg);
+ result = ISC_R_FAILURE;
+ goto cleanup;
+ }
+
+ if (ldap_url->lud_dn == NULL || strlen (ldap_url->lud_dn) < 1) {
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
+ "%s query must specify a search base", msg);
+ result = ISC_R_FAILURE;
+ goto cleanup;
+ }
+
+ if (ldap_url->lud_exts != NULL || ldap_url->lud_crit_exts != 0) {
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
+ "%s uses extensions. "
+ "The driver does not support LDAP extensions.",
+ msg);
+ result = ISC_R_FAILURE;
+ goto cleanup;
+ }
+
+ cleanup:
+
+ if (ldap_url != NULL)
+ ldap_free_urldesc(ldap_url);
+
+ return result;
+}
+/*% Connects / reconnects to LDAP server */
+
+static isc_result_t
+dlz_ldap_connect(ldap_instance_t *dbi, dbinstance_t *dbc) {
+
+ isc_result_t result;
+ int ldap_result;
+
+ /* if we have a connection, get ride of it. */
+ if (dbc->dbconn != NULL) {
+ ldap_unbind_s((LDAP *) dbc->dbconn);
+ dbc->dbconn = NULL;
+ }
+
+ /* now connect / reconnect. */
+
+ /* initialize. */
+ dbc->dbconn = ldap_init(dbi->hosts, LDAP_PORT);
+ if (dbc->dbconn == NULL)
+ return ISC_R_NOMEMORY;
+
+ /* set protocol version. */
+ ldap_result = ldap_set_option((LDAP *) dbc->dbconn,
+ LDAP_OPT_PROTOCOL_VERSION,
+ &(dbi->protocol));
+ if (ldap_result != LDAP_SUCCESS) {
+ result = ISC_R_NOPERM;
+ goto cleanup;
+ }
+
+ /* "bind" to server. i.e. send username / pass */
+ ldap_result = ldap_bind_s((LDAP *) dbc->dbconn, dbi->user,
+ dbi->cred, dbi->method);
+ if (ldap_result != LDAP_SUCCESS) {
+ result = ISC_R_FAILURE;
+ goto cleanup;
+ }
+
+ return ISC_R_SUCCESS;
+
+ cleanup:
+
+ /* cleanup if failure. */
+ if (dbc->dbconn != NULL) {
+ ldap_unbind_s((LDAP *) dbc->dbconn);
+ dbc->dbconn = NULL;
+ }
+
+ return result;
+}
+
+#ifdef ISC_PLATFORM_USETHREADS
+
+
+/*%
+ * Properly cleans up a list of database instances.
+ * This function is only used when the driver is compiled for
+ * multithreaded operation.
+ */
+static void
+ldap_destroy_dblist(db_list_t *dblist)
+{
+
+ dbinstance_t *ndbi = NULL;
+ dbinstance_t *dbi = NULL;
+
+ /* get the first DBI in the list */
+ ndbi = ISC_LIST_HEAD(*dblist);
+
+ /* loop through the list */
+ while (ndbi != NULL) {
+ dbi = ndbi;
+ /* get the next DBI in the list */
+ ndbi = ISC_LIST_NEXT(dbi, link);
+ /* release DB connection */
+ if (dbi->dbconn != NULL)
+ ldap_unbind_s((LDAP *) dbi->dbconn);
+ /* release all memory that comprised a DBI */
+ destroy_sqldbinstance(dbi);
+ }
+ /* release memory for the list structure */
+ isc_mem_put(ns_g_mctx, dblist, sizeof(db_list_t));
+}
+
+/*%
+ * Loops through the list of DB instances, attempting to lock
+ * on the mutex. If successful, the DBI is reserved for use
+ * and the thread can perform queries against the database.
+ * If the lock fails, the next one in the list is tried.
+ * looping continues until a lock is obtained, or until
+ * the list has been searched dbc_search_limit times.
+ * This function is only used when the driver is compiled for
+ * multithreaded operation.
+ */
+
+static dbinstance_t *
+ldap_find_avail_conn(db_list_t *dblist)
+{
+ dbinstance_t *dbi = NULL;
+ dbinstance_t *head;
+ int count = 0;
+
+ /* get top of list */
+ head = dbi = ISC_LIST_HEAD(*dblist);
+
+ /* loop through list */
+ while (count < dbc_search_limit) {
+ /* try to lock on the mutex */
+ if (isc_mutex_trylock(&dbi->instance_lock) == ISC_R_SUCCESS)
+ return dbi; /* success, return the DBI for use. */
+
+ /* not successful, keep trying */
+ dbi = ISC_LIST_NEXT(dbi, link);
+
+ /* check to see if we have gone to the top of the list. */
+ if (dbi == NULL) {
+ count++;
+ dbi = head;
+ }
+ }
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_INFO,
+ "LDAP driver unable to find available connection "
+ "after searching %d times",
+ count);
+ return NULL;
+}
+
+#endif /* ISC_PLATFORM_USETHREADS */
+
+static isc_result_t
+ldap_process_results(LDAP *dbc, LDAPMessage *msg, char ** attrs,
+ void *ptr, isc_boolean_t allnodes)
+{
+ isc_result_t result = ISC_R_SUCCESS;
+ int i = 0;
+ int j;
+ int len;
+ char *attribute = NULL;
+ LDAPMessage *entry;
+ char *endp = NULL;
+ char *host = NULL;
+ char *type = NULL;
+ char *data = NULL;
+ char **vals = NULL;
+ int ttl;
+
+ /* make sure there are at least some attributes to process. */
+ REQUIRE(attrs != NULL || attrs[0] != NULL);
+
+ /* get the first entry to process */
+ entry = ldap_first_entry(dbc, msg);
+ if (entry == NULL) {
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_INFO,
+ "LDAP no entries to process.");
+ return ISC_R_FAILURE;
+ }
+
+ /* loop through all entries returned */
+ while (entry != NULL) {
+
+ /* reset for this loop */
+ ttl = 0;
+ len = 0;
+ i = 0;
+ attribute = attrs[i];
+
+ /* determine how much space we need for data string */
+ for (j=0; attrs[j] != NULL; j++) {
+ /* get the list of values for this attribute. */
+ vals = ldap_get_values(dbc, entry, attrs[j]);
+ /* skip empty attributes. */
+ if (vals == NULL || ldap_count_values(vals) < 1)
+ continue;
+ /*
+ * we only use the first value. this driver
+ * does not support multi-valued attributes.
+ */
+ len = len + strlen(vals[0]) + 1;
+ /* free vals for next loop */
+ ldap_value_free(vals);
+ } /* end for (j=0; attrs[j] != NULL, j++) loop */
+
+ /* allocate memory for data string */
+ data = isc_mem_allocate(ns_g_mctx, len + 1);
+ if (data == NULL) {
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
+ "LDAP driver unable to allocate memory "
+ "while processing results");
+ result = ISC_R_FAILURE;
+ goto cleanup;
+ }
+
+ /*
+ * Make sure data is null termed at the beginning so
+ * we can check if any data was stored to it later.
+ */
+ data[0] = '\0';
+
+ /* reset j to re-use below */
+ j = 0;
+
+ /* loop through the attributes in the order specified. */
+ while (attribute != NULL) {
+
+ /* get the list of values for this attribute. */
+ vals = ldap_get_values(dbc, entry, attribute);
+
+ /* skip empty attributes. */
+ if (vals == NULL || vals[0] == NULL) {
+ /* increment attibute pointer */
+ attribute = attrs[++i];
+ /* start loop over */
+ continue;
+ }
+
+ /*
+ * j initially = 0. Increment j each time we
+ * set a field that way next loop will set
+ * next field.
+ */
+ switch(j) {
+ case 0:
+ j++;
+ /*
+ * convert text to int, make sure it
+ * worked right
+ */
+ ttl = strtol(vals[0], &endp, 10);
+ if (*endp != '\0' || ttl < 0) {
+ isc_log_write(dns_lctx,
+ DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ,
+ ISC_LOG_ERROR,
+ "LDAP driver ttl must "
+ "be a postive number");
+ goto cleanup;
+ }
+ break;
+ case 1:
+ j++;
+ type = isc_mem_strdup(ns_g_mctx, vals[0]);
+ break;
+ case 2:
+ j++;
+ if (allnodes == isc_boolean_true) {
+ host = isc_mem_strdup(ns_g_mctx,
+ vals[0]);
+ } else {
+ strcpy(data, vals[0]);
+ }
+ break;
+ case 3:
+ j++;
+ if (allnodes == isc_boolean_true) {
+ strcpy(data, vals[0]);
+ } else {
+ strcat(data, " ");
+ strcat(data, vals[0]);
+ }
+ break;
+ default:
+ strcat(data, " ");
+ strcat(data, vals[0]);
+ break;
+ } /* end switch(j) */
+
+ /* free values */
+ ldap_value_free(vals);
+ vals = NULL;
+
+ /* increment attibute pointer */
+ attribute = attrs[++i];
+ } /* end while (attribute != NULL) */
+
+ if (type == NULL) {
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
+ "LDAP driver unable "
+ "to retrieve dns type");
+ result = ISC_R_FAILURE;
+ goto cleanup;
+ }
+ if (strlen(data) < 1) {
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
+ "LDAP driver unable "
+ "to retrieve dns data");
+ result = ISC_R_FAILURE;
+ goto cleanup;
+ }
+ if (allnodes == isc_boolean_true) {
+ if (strcasecmp(host, "~") == 0)
+ result = dns_sdlz_putnamedrr(
+ (dns_sdlzallnodes_t *) ptr,
+ "*", type, ttl, data);
+ else
+ result = dns_sdlz_putnamedrr(
+ (dns_sdlzallnodes_t *) ptr,
+ host, type, ttl, data);
+ }
+ else
+ result = dns_sdlz_putrr((dns_sdlzlookup_t *) ptr,
+ type, ttl, data);
+
+ if (result != ISC_R_SUCCESS) {
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
+ "LDAP driver failed "
+ "while sending data to Bind.");
+ goto cleanup;
+ }
+
+ /* free memory for type, data and host for next loop */
+ isc_mem_free(ns_g_mctx, type);
+ isc_mem_free(ns_g_mctx, data);
+ if (host != NULL)
+ isc_mem_free(ns_g_mctx, host);
+
+ /* get the next entry to process */
+ entry = ldap_next_entry(dbc, entry);
+ } /* end while (entry != NULL) */
+
+ cleanup:
+
+ /* de-allocate memory */
+ if (vals != NULL)
+ ldap_value_free(vals);
+ if (host != NULL)
+ isc_mem_free(ns_g_mctx, host);
+ if (type != NULL)
+ isc_mem_free(ns_g_mctx, type);
+ if (data != NULL)
+ isc_mem_free(ns_g_mctx, data);
+
+ return result;
+}
+
+/*%
+ * This function is the real core of the driver. Zone, record
+ * and client strings are passed in (or NULL is passed if the
+ * string is not available). The type of query we want to run
+ * is indicated by the query flag, and the dbdata object is passed
+ * passed in to. dbdata really holds either:
+ * 1) a list of database instances (in multithreaded mode) OR
+ * 2) a single database instance (in single threaded mode)
+ * The function will construct the query and obtain an available
+ * database instance (DBI). It will then run the query and hopefully
+ * obtain a result set.
+ */
+static isc_result_t
+ldap_get_results(const char *zone, const char *record,
+ const char *client, unsigned int query,
+ void *dbdata, void *ptr)
+{
+ isc_result_t result;
+ dbinstance_t *dbi = NULL;
+ char *querystring = NULL;
+ LDAPURLDesc *ldap_url = NULL;
+ int ldap_result = 0;
+ LDAPMessage *ldap_msg = NULL;
+ int i;
+ int entries;
+
+ /* get db instance / connection */
+#ifdef ISC_PLATFORM_USETHREADS
+
+ /* find an available DBI from the list */
+ dbi = ldap_find_avail_conn((db_list_t *)
+ ((ldap_instance_t *)dbdata)->db);
+
+#else /* ISC_PLATFORM_USETHREADS */
+
+ /*
+ * only 1 DBI - no need to lock instance lock either
+ * only 1 thread in the whole process, no possible contention.
+ */
+ dbi = (dbinstance_t *) ((ldap_instance_t *)dbdata)->db;
+
+#endif /* ISC_PLATFORM_USETHREADS */
+
+ /* if DBI is null, can't do anything else */
+ if (dbi == NULL)
+ return ISC_R_FAILURE;
+
+ /* set fields */
+ if (zone != NULL) {
+ dbi->zone = isc_mem_strdup(ns_g_mctx, zone);
+ if (dbi->zone == NULL) {
+ result = ISC_R_NOMEMORY;
+ goto cleanup;
+ }
+ } else {
+ dbi->zone = NULL;
+ }
+ if (record != NULL) {
+ dbi->record = isc_mem_strdup(ns_g_mctx, record);
+ if (dbi->record == NULL) {
+ result = ISC_R_NOMEMORY;
+ goto cleanup;
+ }
+ } else {
+ dbi->record = NULL;
+ }
+ if (client != NULL) {
+ dbi->client = isc_mem_strdup(ns_g_mctx, client);
+ if (dbi->client == NULL) {
+ result = ISC_R_NOMEMORY;
+ goto cleanup;
+ }
+ } else {
+ dbi->client = NULL;
+ }
+
+ /* what type of query are we going to run? */
+ switch(query) {
+ case ALLNODES:
+ /*
+ * if the query was not passed in from the config file
+ * then we can't run it. return not_implemented, so
+ * it's like the code for that operation was never
+ * built into the driver.... AHHH flexibility!!!
+ */
+ if (dbi->allnodes_q == NULL) {
+ result = ISC_R_NOTIMPLEMENTED;
+ goto cleanup;
+ } else {
+ querystring = build_querystring(ns_g_mctx,
+ dbi->allnodes_q);
+ }
+ break;
+ case ALLOWXFR:
+ /* same as comments as ALLNODES */
+ if (dbi->allowxfr_q == NULL) {
+ result = ISC_R_NOTIMPLEMENTED;
+ goto cleanup;
+ } else {
+ querystring = build_querystring(ns_g_mctx,
+ dbi->allowxfr_q);
+ }
+ break;
+ case AUTHORITY:
+ /* same as comments as ALLNODES */
+ if (dbi->authority_q == NULL) {
+ result = ISC_R_NOTIMPLEMENTED;
+ goto cleanup;
+ } else {
+ querystring = build_querystring(ns_g_mctx,
+ dbi->authority_q);
+ }
+ break;
+ case FINDZONE:
+ /* this is required. It's the whole point of DLZ! */
+ if (dbi->findzone_q == NULL) {
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2),
+ "No query specified for findzone. "
+ "Findzone requires a query");
+ result = ISC_R_FAILURE;
+ goto cleanup;
+ } else {
+ querystring = build_querystring(ns_g_mctx,
+ dbi->findzone_q);
+ }
+ break;
+ case LOOKUP:
+ /* this is required. It's also a major point of DLZ! */
+ if (dbi->lookup_q == NULL) {
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2),
+ "No query specified for lookup. "
+ "Lookup requires a query");
+ result = ISC_R_FAILURE;
+ goto cleanup;
+ } else {
+ querystring = build_querystring(ns_g_mctx,
+ dbi->lookup_q);
+ }
+ break;
+ default:
+ /*
+ * this should never happen. If it does, the code is
+ * screwed up!
+ */
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "Incorrect query flag passed to "
+ "ldap_get_results");
+ result = ISC_R_UNEXPECTED;
+ goto cleanup;
+ }
+
+ /* if the querystring is null, Bummer, outta RAM. UPGRADE TIME!!! */
+ if (querystring == NULL) {
+ result = ISC_R_NOMEMORY;
+ goto cleanup;
+ }
+
+ /*
+ * output the full query string during debug so we can see
+ * what lame error the query has.
+ */
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(1),
+ "\nQuery String: %s\n", querystring);
+
+ /* break URL down into it's component parts, if error cleanup */
+ ldap_result = ldap_url_parse(querystring, &ldap_url);
+ if (ldap_result != LDAP_SUCCESS || ldap_url == NULL) {
+ result = ISC_R_FAILURE;
+ goto cleanup;
+ }
+
+ for (i=0; i < 3; i++) {
+
+ /*
+ * dbi->dbconn may be null if trying to reconnect on a
+ * previous query failed.
+ */
+ if (dbi->dbconn == NULL) {
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_INFO,
+ "LDAP driver attempting to re-connect");
+
+ result = dlz_ldap_connect((ldap_instance_t *) dbdata,
+ dbi);
+ if (result != ISC_R_SUCCESS) {
+ result = ISC_R_FAILURE;
+ continue;
+ }
+ }
+
+ /* perform ldap search syncronously */
+ ldap_result = ldap_search_s((LDAP *) dbi->dbconn,
+ ldap_url->lud_dn,
+ ldap_url->lud_scope,
+ ldap_url->lud_filter,
+ ldap_url->lud_attrs, 0, &ldap_msg);
+
+ /*
+ * check return code. No such object is ok, just
+ * didn't find what we wanted
+ */
+ switch(ldap_result) {
+ case LDAP_NO_SUCH_OBJECT:
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(1),
+ "No object found matching "
+ "query requirements");
+ result = ISC_R_NOTFOUND;
+ goto cleanup;
+ break;
+ case LDAP_SUCCESS: /* on success do nothing */
+ result = ISC_R_SUCCESS;
+ i = 3;
+ break;
+ case LDAP_SERVER_DOWN:
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_INFO,
+ "LDAP driver attempting to re-connect");
+ result = dlz_ldap_connect((ldap_instance_t *) dbdata,
+ dbi);
+ if (result != ISC_R_SUCCESS)
+ result = ISC_R_FAILURE;
+ break;
+ default:
+ /*
+ * other errors not ok. Log error message and
+ * get out
+ */
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
+ "LDAP error: %s",
+ ldap_err2string(ldap_result));
+ result = ISC_R_FAILURE;
+ goto cleanup;
+ break;
+ } /* close switch(ldap_result) */
+ } /* end for (int i=0 i < 3; i++) */
+
+ if (result != ISC_R_SUCCESS)
+ goto cleanup;
+
+ switch(query) {
+ case ALLNODES:
+ result = ldap_process_results((LDAP *) dbi->dbconn, ldap_msg,
+ ldap_url->lud_attrs,
+ ptr, isc_boolean_true);
+ break;
+ case AUTHORITY:
+ case LOOKUP:
+ result = ldap_process_results((LDAP *) dbi->dbconn, ldap_msg,
+ ldap_url->lud_attrs,
+ ptr, isc_boolean_false);
+ break;
+ case ALLOWXFR:
+ entries = ldap_count_entries((LDAP *) dbi->dbconn, ldap_msg);
+ if (entries == 0)
+ result = ISC_R_NOPERM;
+ else if (entries > 0)
+ result = ISC_R_SUCCESS;
+ else
+ result = ISC_R_FAILURE;
+ break;
+ case FINDZONE:
+ entries = ldap_count_entries((LDAP *) dbi->dbconn, ldap_msg);
+ if (entries == 0)
+ result = ISC_R_NOTFOUND;
+ else if (entries > 0)
+ result = ISC_R_SUCCESS;
+ else
+ result = ISC_R_FAILURE;
+ break;
+ default:
+ /*
+ * this should never happen. If it does, the code is
+ * screwed up!
+ */
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "Incorrect query flag passed to "
+ "ldap_get_results");
+ result = ISC_R_UNEXPECTED;
+ }
+
+
+ cleanup:
+ /* it's always good to cleanup after yourself */
+
+ /* if we retrieved results, free them */
+ if (ldap_msg != NULL)
+ ldap_msgfree(ldap_msg);
+
+ if (ldap_url != NULL)
+ ldap_free_urldesc(ldap_url);
+
+ /* cleanup */
+ if (dbi->zone != NULL)
+ isc_mem_free(ns_g_mctx, dbi->zone);
+ if (dbi->record != NULL)
+ isc_mem_free(ns_g_mctx, dbi->record);
+ if (dbi->client != NULL)
+ isc_mem_free(ns_g_mctx, dbi->client);
+
+#ifdef ISC_PLATFORM_USETHREADS
+
+ /* release the lock so another thread can use this dbi */
+ isc_mutex_unlock(&dbi->instance_lock);
+
+#endif /* ISC_PLATFORM_USETHREADS */
+
+ /* release query string */
+ if (querystring != NULL)
+ isc_mem_free(ns_g_mctx, querystring );
+
+ /* return result */
+ return result;
+}
+
+/*
+ * DLZ methods
+ */
+
+static isc_result_t
+dlz_ldap_allowzonexfr(void *driverarg, void *dbdata, const char *name,
+ const char *client)
+{
+ isc_result_t result;
+
+ UNUSED(driverarg);
+
+ /* check to see if we are authoritative for the zone first */
+ result = dlz_ldap_findzone(driverarg, dbdata, name);
+ if (result != ISC_R_SUCCESS) {
+ return result;
+ }
+
+ /* get all the zone data */
+ return ldap_get_results(name, NULL, client, ALLOWXFR, dbdata, NULL);
+}
+
+static isc_result_t
+dlz_ldap_allnodes(const char *zone, void *driverarg, void *dbdata,
+ dns_sdlzallnodes_t *allnodes)
+{
+ UNUSED(driverarg);
+ return ldap_get_results(zone, NULL, NULL, ALLNODES, dbdata, allnodes);
+}
+
+static isc_result_t
+dlz_ldap_authority(const char *zone, void *driverarg, void *dbdata,
+ dns_sdlzlookup_t *lookup)
+{
+ UNUSED(driverarg);
+ return ldap_get_results(zone, NULL, NULL, AUTHORITY, dbdata, lookup);
+}
+
+static isc_result_t
+dlz_ldap_findzone(void *driverarg, void *dbdata, const char *name)
+{
+ UNUSED(driverarg);
+ return ldap_get_results(name, NULL, NULL, FINDZONE, dbdata, NULL);
+}
+
+static isc_result_t
+dlz_ldap_lookup(const char *zone, const char *name, void *driverarg,
+ void *dbdata, dns_sdlzlookup_t *lookup)
+{
+ UNUSED(driverarg);
+ if (strcmp(name, "*") == 0)
+ return ldap_get_results(zone, "~", NULL,
+ LOOKUP, dbdata, lookup);
+ else
+ return ldap_get_results(zone, name, NULL,
+ LOOKUP, dbdata, lookup);
+}
+
+
+static isc_result_t
+dlz_ldap_create(const char *dlzname, unsigned int argc, char *argv[],
+ void *driverarg, void **dbdata)
+{
+
+ isc_result_t result;
+ ldap_instance_t *ldap_inst = NULL;
+ dbinstance_t *dbi = NULL;
+ int protocol;
+ int method;
+
+#ifdef ISC_PLATFORM_USETHREADS
+ /* if multi-threaded, we need a few extra variables. */
+ int dbcount;
+ char *endp;
+/* db_list_t *dblist = NULL; */
+ int i;
+
+#endif /* ISC_PLATFORM_USETHREADS */
+
+ UNUSED(dlzname);
+ UNUSED(driverarg);
+
+#ifdef ISC_PLATFORM_USETHREADS
+ /* if debugging, let user know we are multithreaded. */
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(1),
+ "LDAP driver running multithreaded");
+#else /* ISC_PLATFORM_USETHREADS */
+ /* if debugging, let user know we are single threaded. */
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(1),
+ "LDAP driver running single threaded");
+#endif /* ISC_PLATFORM_USETHREADS */
+
+ if (argc < 9) {
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
+ "LDAP driver requires at least "
+ "8 command line args.");
+ return (ISC_R_FAILURE);
+ }
+
+ /* no more than 13 arg's should be passed to the driver */
+ if (argc > 12) {
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
+ "LDAP driver cannot accept more than "
+ "11 command line args.");
+ return (ISC_R_FAILURE);
+ }
+
+ /* determine protocol version. */
+ if (strncasecmp(argv[2], V2, strlen(V2)) == 0) {
+ protocol = 2;
+ } else if (strncasecmp(argv[2], V3, strlen(V3)) == 0) {
+ protocol = 3;
+ } else {
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
+ "LDAP driver protocol must be either %s or %s",
+ V2, V3);
+ return (ISC_R_FAILURE);
+ }
+
+ /* determine connection method. */
+ if (strncasecmp(argv[3], SIMPLE, strlen(SIMPLE)) == 0) {
+ method = LDAP_AUTH_SIMPLE;
+ } else if (strncasecmp(argv[3], KRB41, strlen(KRB41)) == 0) {
+ method = LDAP_AUTH_KRBV41;
+ } else if (strncasecmp(argv[3], KRB42, strlen(KRB42)) == 0) {
+ method = LDAP_AUTH_KRBV42;
+ } else {
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
+ "LDAP driver authentication method must be "
+ "one of %s, %s or %s",
+ SIMPLE, KRB41, KRB42);
+ return (ISC_R_FAILURE);
+ }
+
+ /* multithreaded build can have multiple DB connections */
+#ifdef ISC_PLATFORM_USETHREADS
+
+ /* check how many db connections we should create */
+ dbcount = strtol(argv[1], &endp, 10);
+ if (*endp != '\0' || dbcount < 0) {
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
+ "LDAP driver database connection count "
+ "must be positive.");
+ return (ISC_R_FAILURE);
+ }
+#endif
+
+ /* check that LDAP URL parameters make sense */
+ switch(argc) {
+ case 12:
+ result = dlz_ldap_checkURL(argv[11], 0, "allow zone transfer");
+ if (result != ISC_R_SUCCESS)
+ return result;
+ case 11:
+ result = dlz_ldap_checkURL(argv[10], 3, "all nodes");
+ if (result != ISC_R_SUCCESS)
+ return result;
+ case 10:
+ if (strlen(argv[9]) > 0) {
+ result = dlz_ldap_checkURL(argv[9], 3, "authority");
+ if (result != ISC_R_SUCCESS)
+ return result;
+ }
+ case 9:
+ result = dlz_ldap_checkURL(argv[8], 3, "lookup");
+ if (result != ISC_R_SUCCESS)
+ return result;
+ result = dlz_ldap_checkURL(argv[7], 0, "find zone");
+ if (result != ISC_R_SUCCESS)
+ return result;
+ break;
+ default:
+ /* not really needed, should shut up compiler. */
+ result = ISC_R_FAILURE;
+ }
+
+ /* allocate memory for LDAP instance */
+ ldap_inst = isc_mem_get(ns_g_mctx, sizeof(ldap_instance_t));
+ if (ldap_inst == NULL)
+ return (ISC_R_NOMEMORY);
+ memset(ldap_inst, 0, sizeof(ldap_instance_t));
+
+ /* store info needed to automatically re-connect. */
+ ldap_inst->protocol = protocol;
+ ldap_inst->method = method;
+ ldap_inst->hosts = isc_mem_strdup(ns_g_mctx, argv[6]);
+ if (ldap_inst->hosts == NULL) {
+ result = ISC_R_NOMEMORY;
+ goto cleanup;
+ }
+ ldap_inst->user = isc_mem_strdup(ns_g_mctx, argv[4]);
+ if (ldap_inst->user == NULL) {
+ result = ISC_R_NOMEMORY;
+ goto cleanup;
+ }
+ ldap_inst->cred = isc_mem_strdup(ns_g_mctx, argv[5]);
+ if (ldap_inst->cred == NULL) {
+ result = ISC_R_NOMEMORY;
+ goto cleanup;
+ }
+
+#ifdef ISC_PLATFORM_USETHREADS
+ /* allocate memory for database connection list */
+ ldap_inst->db = isc_mem_get(ns_g_mctx, sizeof(db_list_t));
+ if (ldap_inst->db == NULL) {
+ result = ISC_R_NOMEMORY;
+ goto cleanup;
+ }
+
+ /* initialize DB connection list */
+ ISC_LIST_INIT(*(ldap_inst->db));
+
+ /*
+ * create the appropriate number of database instances (DBI)
+ * append each new DBI to the end of the list
+ */
+ for (i = 0; i < dbcount; i++) {
+
+#endif /* ISC_PLATFORM_USETHREADS */
+
+ /* how many queries were passed in from config file? */
+ switch(argc) {
+ case 9:
+ result = build_sqldbinstance(ns_g_mctx, NULL, NULL,
+ NULL, argv[7], argv[8],
+ NULL, &dbi);
+ break;
+ case 10:
+ result = build_sqldbinstance(ns_g_mctx, NULL, NULL,
+ argv[9], argv[7], argv[8],
+ NULL, &dbi);
+ break;
+ case 11:
+ result = build_sqldbinstance(ns_g_mctx, argv[10], NULL,
+ argv[9], argv[7], argv[8],
+ NULL, &dbi);
+ break;
+ case 12:
+ result = build_sqldbinstance(ns_g_mctx, argv[10],
+ argv[11], argv[9],
+ argv[7], argv[8],
+ NULL, &dbi);
+ break;
+ default:
+ /* not really needed, should shut up compiler. */
+ result = ISC_R_FAILURE;
+ }
+
+ if (result == ISC_R_SUCCESS) {
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2),
+ "LDAP driver created "
+ "database instance object.");
+ } else { /* unsuccessful?, log err msg and cleanup. */
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
+ "LDAP driver could not create "
+ "database instance object.");
+ goto cleanup;
+ }
+
+#ifdef ISC_PLATFORM_USETHREADS
+ /* when multithreaded, build a list of DBI's */
+ ISC_LINK_INIT(dbi, link);
+ ISC_LIST_APPEND(*(ldap_inst->db), dbi, link);
+#else
+ /*
+ * when single threaded, hold onto the one connection
+ * instance.
+ */
+ ldap_inst->db = dbi;
+
+#endif
+ /* attempt to connect */
+ result = dlz_ldap_connect(ldap_inst, dbi);
+
+ /*
+ * if db connection cannot be created, log err msg and
+ * cleanup.
+ */
+ switch(result) {
+ /* success, do nothing */
+ case ISC_R_SUCCESS:
+ break;
+ /*
+ * no memory means ldap_init could not
+ * allocate memory
+ */
+ case ISC_R_NOMEMORY:
+#ifdef ISC_PLATFORM_USETHREADS
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
+ "LDAP driver could not allocate memory "
+ "for connection number %u",
+ i+1);
+#else
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
+ "LDAP driver could not allocate memory "
+ "for connection");
+#endif
+ goto cleanup;
+ break;
+ /*
+ * no perm means ldap_set_option could not set
+ * protocol version
+ */
+ case ISC_R_NOPERM:
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
+ "LDAP driver could not "
+ "set protocol version.");
+ result = ISC_R_FAILURE;
+ goto cleanup;
+ break;
+ /* failure means couldn't connect to ldap server */
+ case ISC_R_FAILURE:
+#ifdef ISC_PLATFORM_USETHREADS
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
+ "LDAP driver could not "
+ "bind connection number %u to server.",
+ i+1);
+#else
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
+ "LDAP driver could not "
+ "bind connection to server.");
+#endif
+ goto cleanup;
+ break;
+ /*
+ * default should never happen. If it does,
+ * major errors.
+ */
+ default:
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "dlz_ldap_create() failed: %s",
+ isc_result_totext(result));
+ result = ISC_R_UNEXPECTED;
+ goto cleanup;
+ break;
+ } /* end switch(result) */
+
+
+#ifdef ISC_PLATFORM_USETHREADS
+
+ /* set DBI = null for next loop through. */
+ dbi = NULL;
+ } /* end for loop */
+
+#endif /* ISC_PLATFORM_USETHREADS */
+
+
+ /* set dbdata to the ldap_instance we created. */
+ *dbdata = ldap_inst;
+
+ /* hey, we got through all of that ok, return success. */
+ return(ISC_R_SUCCESS);
+
+ cleanup:
+
+ dlz_ldap_destroy(NULL, ldap_inst);
+
+ return(ISC_R_FAILURE);
+}
+
+void
+dlz_ldap_destroy(void *driverarg, void *dbdata)
+{
+
+ UNUSED(driverarg);
+
+ if (dbdata != NULL) {
+
+#ifdef ISC_PLATFORM_USETHREADS
+
+ /* cleanup the list of DBI's */
+ ldap_destroy_dblist((db_list_t *)
+ ((ldap_instance_t *)dbdata)->db);
+
+#else /* ISC_PLATFORM_USETHREADS */
+
+ /* release connection */
+ if (((ldap_instance_t *)dbdata)->db->dbconn != NULL)
+ ldap_unbind_s((LDAP *)
+ ((ldap_instance_t *)dbdata)->db->dbconn);
+
+ /* destroy single DB instance */
+ destroy_sqldbinstance(((ldap_instance_t *)dbdata)->db);
+
+#endif /* ISC_PLATFORM_USETHREADS */
+
+ if (((ldap_instance_t *)dbdata)->hosts != NULL)
+ isc_mem_free(ns_g_mctx,
+ ((ldap_instance_t *)dbdata)->hosts);
+
+ if (((ldap_instance_t *)dbdata)->user != NULL)
+ isc_mem_free(ns_g_mctx,
+ ((ldap_instance_t *)dbdata)->user);
+
+ if (((ldap_instance_t *)dbdata)->cred != NULL)
+ isc_mem_free(ns_g_mctx,
+ ((ldap_instance_t *)dbdata)->cred);
+
+ isc_mem_put(ns_g_mctx, dbdata, sizeof(ldap_instance_t));
+ }
+}
+
+static dns_sdlzmethods_t dlz_ldap_methods = {
+ dlz_ldap_create,
+ dlz_ldap_destroy,
+ dlz_ldap_findzone,
+ dlz_ldap_lookup,
+ dlz_ldap_authority,
+ dlz_ldap_allnodes,
+ dlz_ldap_allowzonexfr
+};
+
+/*%
+ * Wrapper around dns_sdlzregister().
+ */
+isc_result_t
+dlz_ldap_init(void) {
+ isc_result_t result;
+
+ /*
+ * Write debugging message to log
+ */
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2),
+ "Registering DLZ ldap driver.");
+
+ result = dns_sdlzregister("ldap", &dlz_ldap_methods, NULL,
+ DNS_SDLZFLAG_RELATIVEOWNER |
+ DNS_SDLZFLAG_RELATIVERDATA,
+ ns_g_mctx, &dlz_ldap);
+ if (result != ISC_R_SUCCESS) {
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "dns_sdlzregister() failed: %s",
+ isc_result_totext(result));
+ result = ISC_R_UNEXPECTED;
+ }
+
+
+ return result;
+}
+
+/*%
+ * Wrapper around dns_sdlzunregister().
+ */
+void
+dlz_ldap_clear(void) {
+
+ /*
+ * Write debugging message to log
+ */
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2),
+ "Unregistering DLZ ldap driver.");
+
+ if (dlz_ldap != NULL)
+ dns_sdlzunregister(&dlz_ldap);
+}
+
+#endif
--- /dev/null
+/*
+ * 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) 1999-2001 Internet Software Consortium.
+ *
+ * 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 INTERNET SOFTWARE CONSORTIUM
+ * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+ * INTERNET SOFTWARE CONSORTIUM 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.
+ */
+
+#ifdef DLZ_MYSQL
+
+#include <config.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include <dns/log.h>
+#include <dns/sdlz.h>
+#include <dns/result.h>
+
+#include <isc/mem.h>
+#include <isc/platform.h>
+#include <isc/print.h>
+#include <isc/result.h>
+#include <isc/string.h>
+#include <isc/util.h>
+
+#include <named/globals.h>
+
+#include <dlz/sdlz_helper.h>
+#include <dlz/dlz_mysql_driver.h>
+
+#include <mysql.h>
+
+static dns_sdlzimplementation_t *dlz_mysql = NULL;
+
+#define dbc_search_limit 30
+#define ALLNODES 1
+#define ALLOWXFR 2
+#define AUTHORITY 3
+#define FINDZONE 4
+#define COUNTZONE 5
+#define LOOKUP 6
+
+#define safeGet(in) in == NULL ? "" : in
+
+/*
+ * Private methods
+ */
+
+/*%
+ * Allocates memory for a new string, and then constructs the new
+ * string by "escaping" the input string. The new string is
+ * safe to be used in queries. This is necessary because we cannot
+ * be sure of what types of strings are passed to us, and we don't
+ * want special characters in the string causing problems.
+ */
+
+static char *
+mysqldrv_escape_string(MYSQL *mysql, const char *instr) {
+
+ char *outstr;
+ unsigned int len;
+
+ if (instr == NULL)
+ return NULL;
+
+ len = strlen(instr);
+
+ outstr = isc_mem_allocate(ns_g_mctx ,(2 * len * sizeof(char)) + 1);
+ if (outstr == NULL)
+ return NULL;
+
+ mysql_real_escape_string(mysql, outstr, instr, len);
+
+ return outstr;
+}
+
+/*%
+ * This function is the real core of the driver. Zone, record
+ * and client strings are passed in (or NULL is passed if the
+ * string is not available). The type of query we want to run
+ * is indicated by the query flag, and the dbdata object is passed
+ * passed in to. dbdata really holds a single database instance.
+ * The function will construct and run the query, hopefully getting
+ * a result set.
+ */
+
+static isc_result_t
+mysql_get_resultset(const char *zone, const char *record,
+ const char *client, unsigned int query,
+ void *dbdata, MYSQL_RES **rs)
+{
+ isc_result_t result;
+ dbinstance_t *dbi = NULL;
+ char *querystring = NULL;
+ unsigned int i = 0;
+ unsigned int j = 0;
+ int qres = 0;
+
+ if (query != COUNTZONE)
+ REQUIRE(*rs == NULL);
+ else
+ REQUIRE(rs == NULL);
+
+ /* get db instance / connection */
+ dbi = (dbinstance_t *) dbdata;
+
+ /* if DBI is null, can't do anything else */
+ if (dbi == NULL) {
+ result = ISC_R_FAILURE;
+ goto cleanup;
+ }
+
+ /* what type of query are we going to run? */
+ switch(query) {
+ case ALLNODES:
+ /*
+ * if the query was not passed in from the config file
+ * then we can't run it. return not_implemented, so
+ * it's like the code for that operation was never
+ * built into the driver.... AHHH flexibility!!!
+ */
+ if (dbi->allnodes_q == NULL) {
+ result = ISC_R_NOTIMPLEMENTED;
+ goto cleanup;
+ }
+ break;
+ case ALLOWXFR:
+ /* same as comments as ALLNODES */
+ if (dbi->allowxfr_q == NULL) {
+ result = ISC_R_NOTIMPLEMENTED;
+ goto cleanup;
+ }
+ break;
+ case AUTHORITY:
+ /* same as comments as ALLNODES */
+ if (dbi->authority_q == NULL) {
+ result = ISC_R_NOTIMPLEMENTED;
+ goto cleanup;
+ }
+ break;
+ case FINDZONE:
+ /* this is required. It's the whole point of DLZ! */
+ if (dbi->findzone_q == NULL) {
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2),
+ "No query specified for findzone. "
+ "Findzone requires a query");
+ result = ISC_R_FAILURE;
+ goto cleanup;
+ }
+ break;
+ case COUNTZONE:
+ /* same as comments as ALLNODES */
+ if (dbi->countzone_q == NULL) {
+ result = ISC_R_NOTIMPLEMENTED;
+ goto cleanup;
+ }
+ break;
+ case LOOKUP:
+ /* this is required. It's also a major point of DLZ! */
+ if (dbi->lookup_q == NULL) {
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2),
+ "No query specified for lookup. "
+ "Lookup requires a query");
+ result = ISC_R_FAILURE;
+ goto cleanup;
+ }
+ break;
+ default:
+ /*
+ * this should never happen. If it does, the code is
+ * screwed up!
+ */
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "Incorrect query flag passed to "
+ "mysql_get_resultset");
+ result = ISC_R_UNEXPECTED;
+ goto cleanup;
+ }
+
+
+ /*
+ * was a zone string passed? If so, make it safe for use in
+ * queries.
+ */
+ if (zone != NULL) {
+ dbi->zone = mysqldrv_escape_string((MYSQL *) dbi->dbconn,
+ zone);
+ if (dbi->zone == NULL) {
+ result = ISC_R_NOMEMORY;
+ goto cleanup;
+ }
+ } else { /* no string passed, set the string pointer to NULL */
+ dbi->zone = NULL;
+ }
+
+ /*
+ * was a record string passed? If so, make it safe for use in
+ * queries.
+ */
+ if (record != NULL) {
+ dbi->record = mysqldrv_escape_string((MYSQL *) dbi->dbconn,
+ record);
+ if (dbi->record == NULL) {
+ result = ISC_R_NOMEMORY;
+ goto cleanup;
+ }
+ } else { /* no string passed, set the string pointer to NULL */
+ dbi->record = NULL;
+ }
+
+ /*
+ * was a client string passed? If so, make it safe for use in
+ * queries.
+ */
+ if (client != NULL) {
+ dbi->client = mysqldrv_escape_string((MYSQL *) dbi->dbconn,
+ client);
+ if (dbi->client == NULL) {
+ result = ISC_R_NOMEMORY;
+ goto cleanup;
+ }
+ } else { /* no string passed, set the string pointer to NULL */
+ dbi->client = NULL;
+ }
+
+ /*
+ * what type of query are we going to run? this time we build
+ * the actual query to run.
+ */
+ switch(query) {
+ case ALLNODES:
+ querystring = build_querystring(ns_g_mctx, dbi->allnodes_q);
+ break;
+ case ALLOWXFR:
+ querystring = build_querystring(ns_g_mctx, dbi->allowxfr_q);
+ break;
+ case AUTHORITY:
+ querystring = build_querystring(ns_g_mctx, dbi->authority_q);
+ break;
+ case FINDZONE:
+ querystring = build_querystring(ns_g_mctx, dbi->findzone_q);
+ break;
+ case COUNTZONE:
+ querystring = build_querystring(ns_g_mctx, dbi->countzone_q);
+ break;
+ case LOOKUP:
+ querystring = build_querystring(ns_g_mctx, dbi->lookup_q);
+ break;
+ default:
+ /*
+ * this should never happen. If it does, the code is
+ * screwed up!
+ */
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "Incorrect query flag passed to "
+ "mysql_get_resultset");
+ result = ISC_R_UNEXPECTED;
+ goto cleanup;
+ }
+
+ /* if the querystring is null, Bummer, outta RAM. UPGRADE TIME!!! */
+ if (querystring == NULL) {
+ result = ISC_R_NOMEMORY;
+ goto cleanup;
+ }
+
+ /*
+ * output the full query string during debug so we can see
+ * what lame error the query has.
+ */
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(1),
+ "\nQuery String: %s\n", querystring);
+
+ /* attempt query up to 3 times. */
+ for (i=0; i < 3; i++) {
+ qres = mysql_query((MYSQL *) dbi->dbconn, querystring);
+ if (qres == 0)
+ break;
+ for (j=0; mysql_ping((MYSQL *) dbi->dbconn) != 0 && j < 4; j++)
+ ;
+ }
+
+ if (qres == 0) {
+ result = ISC_R_SUCCESS;
+ if (query != COUNTZONE) {
+ *rs = mysql_store_result((MYSQL *) dbi->dbconn);
+ if (*rs == NULL)
+ result = ISC_R_FAILURE;
+ }
+ } else {
+ result = ISC_R_FAILURE;
+ }
+
+
+ cleanup:
+ /* it's always good to cleanup after yourself */
+
+ /* if we couldn't even get DBI, just return NULL */
+ if (dbi == NULL)
+ return ISC_R_FAILURE;
+
+ /* free dbi->zone string */
+ if (dbi->zone != NULL)
+ isc_mem_free(ns_g_mctx, dbi->zone);
+
+ /* free dbi->record string */
+ if (dbi->record != NULL)
+ isc_mem_free(ns_g_mctx, dbi->record);
+
+ /* free dbi->client string */
+ if (dbi->client != NULL)
+ isc_mem_free(ns_g_mctx, dbi->client);
+
+ /* release query string */
+ if (querystring != NULL)
+ isc_mem_free(ns_g_mctx, querystring);
+
+ /* return result */
+ return result;
+}
+
+/*%
+ * The processing of result sets for lookup and authority are
+ * exactly the same. So that functionality has been moved
+ * into this function to minimize code.
+ */
+
+static isc_result_t
+mysql_process_rs(dns_sdlzlookup_t *lookup, MYSQL_RES *rs)
+{
+ isc_result_t result = ISC_R_NOTFOUND;
+ MYSQL_ROW row;
+ unsigned int fields;
+ unsigned int j;
+ unsigned int len;
+ char *tmpString;
+ char *endp;
+ int ttl;
+
+ row = mysql_fetch_row(rs); /* get a row from the result set */
+ fields = mysql_num_fields(rs); /* how many columns in result set */
+ while (row != NULL) {
+ switch(fields) {
+ case 1:
+ /*
+ * one column in rs, it's the data field. use
+ * default type of A record, and default TTL
+ * of 86400
+ */
+ result = dns_sdlz_putrr(lookup, "a", 86400,
+ safeGet(row[0]));
+ break;
+ case 2:
+ /*
+ * two columns, data field, and data type.
+ * use default TTL of 86400.
+ */
+ result = dns_sdlz_putrr(lookup, safeGet(row[0]), 86400,
+ safeGet(row[1]));
+ break;
+ case 3:
+ /*
+ * three columns, all data no defaults.
+ * convert text to int, make sure it worked
+ * right.
+ */
+ ttl = strtol(safeGet(row[0]), &endp, 10);
+ if (*endp != '\0' || ttl < 0) {
+ isc_log_write(dns_lctx,
+ DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
+ "mysql driver ttl must be "
+ "a postive number");
+ }
+ result = dns_sdlz_putrr(lookup, safeGet(row[1]), ttl,
+ safeGet(row[2]));
+ break;
+ default:
+ /*
+ * more than 3 fields, concatenate the last
+ * ones together. figure out how long to make
+ * string.
+ */
+ for (j=2, len=0; j < fields; j++) {
+ len += strlen(safeGet(row[j])) + 1;
+ }
+ /*
+ * allocate string memory, allow for NULL to
+ * term string
+ */
+ tmpString = isc_mem_allocate(ns_g_mctx, len + 1);
+ if (tmpString == NULL) {
+ /* major bummer, need more ram */
+ isc_log_write(dns_lctx,
+ DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
+ "mysql driver unable "
+ "to allocate memory for "
+ "temporary string");
+ mysql_free_result(rs);
+ return (ISC_R_FAILURE); /* Yeah, I'd say! */
+ }
+ /* copy field to tmpString */
+ strcpy(tmpString, safeGet(row[2]));
+
+
+ /*
+ * concat the rest of fields together, space
+ * between each one.
+ */
+ for (j=3; j < fields; j++) {
+ strcat(tmpString, " ");
+ strcat(tmpString, safeGet(row[j]));
+ }
+ /* convert text to int, make sure it worked right */
+ ttl = strtol(safeGet(row[0]), &endp, 10);
+ if (*endp != '\0' || ttl < 0) {
+ isc_log_write(dns_lctx,
+ DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
+ "mysql driver ttl must be "
+ "a postive number");
+ }
+ /* ok, now tell Bind about it. */
+ result = dns_sdlz_putrr(lookup, safeGet(row[1]),
+ ttl, tmpString);
+ /* done, get rid of this thing. */
+ isc_mem_free(ns_g_mctx, tmpString);
+ }
+ /* I sure hope we were successful */
+ if (result != ISC_R_SUCCESS) {
+ /* nope, get rid of the Result set, and log a msg */
+ mysql_free_result(rs);
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
+ "dns_sdlz_putrr returned error. "
+ "Error code was: %s",
+ isc_result_totext(result));
+ return (ISC_R_FAILURE);
+ }
+ row = mysql_fetch_row(rs); /* get next row */
+ }
+
+ /* free result set memory */
+ mysql_free_result(rs);
+
+ /* return result code */
+ return result;
+}
+
+/*
+ * SDLZ interface methods
+ */
+
+/*% determine if the zone is supported by (in) the database */
+
+static isc_result_t
+mysql_findzone(void *driverarg, void *dbdata, const char *name)
+{
+ isc_result_t result;
+ MYSQL_RES *rs = NULL;
+ my_ulonglong rows;
+
+ UNUSED(driverarg);
+
+ /* run the query and get the result set from the database. */
+ result = mysql_get_resultset(name, NULL, NULL, FINDZONE, dbdata, &rs);
+ /* if we didn't get a result set, log an err msg. */
+ if (result != ISC_R_SUCCESS || rs == NULL) {
+ if (rs != NULL)
+ mysql_free_result(rs);
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
+ "mysql driver unable to return "
+ "result set for findzone query");
+ return (ISC_R_FAILURE);
+ }
+ /* count how many rows in result set */
+ rows = mysql_num_rows(rs);
+ /* get rid of result set, we are done with it. */
+ mysql_free_result(rs);
+
+ /* if we returned any rows, zone is supported. */
+ if (rows > 0) {
+ mysql_get_resultset(name, NULL, NULL, COUNTZONE, dbdata, NULL);
+ return (ISC_R_SUCCESS);
+ }
+
+ /* no rows returned, zone is not supported. */
+ return (ISC_R_NOTFOUND);
+}
+
+/*% Determine if the client is allowed to perform a zone transfer */
+static isc_result_t
+mysql_allowzonexfr(void *driverarg, void *dbdata, const char *name,
+ const char *client)
+{
+ isc_result_t result;
+ MYSQL_RES *rs = NULL;
+ my_ulonglong rows;
+
+ UNUSED(driverarg);
+
+ /* first check if the zone is supported by the database. */
+ result = mysql_findzone(driverarg, dbdata, name);
+ if (result != ISC_R_SUCCESS)
+ return (ISC_R_NOTFOUND);
+
+ /*
+ * if we get to this point we know the zone is supported by
+ * the database the only questions now are is the zone
+ * transfer is allowed for this client and did the config file
+ * have an allow zone xfr query.
+ *
+ * Run our query, and get a result set from the database.
+ */
+ result = mysql_get_resultset(name, NULL, client, ALLOWXFR,
+ dbdata, &rs);
+ /* if we get "not implemented", send it along. */
+ if (result == ISC_R_NOTIMPLEMENTED)
+ return result;
+ /* if we didn't get a result set, log an err msg. */
+ if (result != ISC_R_SUCCESS || rs == NULL) {
+ if (rs != NULL)
+ mysql_free_result(rs);
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
+ "mysql driver unable to return "
+ "result set for allow xfr query");
+ return (ISC_R_FAILURE);
+ }
+ /* count how many rows in result set */
+ rows = mysql_num_rows(rs);
+ /* get rid of result set, we are done with it. */
+ mysql_free_result(rs);
+
+ /* if we returned any rows, zone xfr is allowed. */
+ if (rows > 0)
+ return (ISC_R_SUCCESS);
+
+ /* no rows returned, zone xfr not allowed */
+ return (ISC_R_NOPERM);
+}
+
+/*%
+ * If the client is allowed to perform a zone transfer, the next order of
+ * business is to get all the nodes in the zone, so bind can respond to the
+ * query.
+ */
+static isc_result_t
+mysql_allnodes(const char *zone, void *driverarg, void *dbdata,
+ dns_sdlzallnodes_t *allnodes)
+{
+ isc_result_t result;
+ MYSQL_RES *rs = NULL;
+ MYSQL_ROW row;
+ unsigned int fields;
+ unsigned int j;
+ unsigned int len;
+ char *tmpString;
+ char *endp;
+ int ttl;
+
+ UNUSED(driverarg);
+
+ /* run the query and get the result set from the database. */
+ result = mysql_get_resultset(zone, NULL, NULL, ALLNODES, dbdata, &rs);
+ /* if we get "not implemented", send it along */
+ if (result == ISC_R_NOTIMPLEMENTED)
+ return result;
+ /* if we didn't get a result set, log an err msg. */
+ if (result != ISC_R_SUCCESS) {
+ if (rs != NULL)
+ mysql_free_result(rs);
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
+ "mysql driver unable to return "
+ "result set for all nodes query");
+ return (ISC_R_FAILURE);
+ }
+
+ result = ISC_R_NOTFOUND;
+
+ row = mysql_fetch_row(rs); /* get a row from the result set */
+ fields = mysql_num_fields(rs); /* how many columns in result set */
+ while (row != NULL) {
+ if (fields < 4) { /* gotta have at least 4 columns */
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
+ "mysql driver too few fields returned "
+ "by all nodes query");
+ }
+ /* convert text to int, make sure it worked right */
+ ttl = strtol(safeGet(row[0]), &endp, 10);
+ if (*endp != '\0' || ttl < 0) {
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
+ "mysql driver ttl must be "
+ "a postive number");
+ }
+ if (fields == 4) {
+ /* tell Bind about it. */
+ result = dns_sdlz_putnamedrr(allnodes, safeGet(row[0]),
+ safeGet(row[1]), ttl,
+ safeGet(row[3]));
+ } else {
+ /*
+ * more than 4 fields, concatenate the last
+ * ones together. figure out how long to make
+ * string.
+ */
+ for (j=3, len=0; j < fields; j++) {
+ len += strlen(safeGet(row[j])) + 1;
+ }
+ /* allocate memory, allow for NULL to term string */
+ tmpString = isc_mem_allocate(ns_g_mctx, len + 1);
+ if (tmpString == NULL) { /* we need more ram. */
+ isc_log_write(dns_lctx,
+ DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
+ "mysql driver unable "
+ "to allocate memory for "
+ "temporary string");
+ mysql_free_result(rs);
+ return (ISC_R_FAILURE);
+ }
+ /* copy this field to tmpString */
+ strcpy(tmpString, safeGet(row[3]));
+ /* concatonate the rest, with spaces between */
+ for (j=4; j < fields; j++) {
+ strcat(tmpString, " ");
+ strcat(tmpString, safeGet(row[j]));
+ }
+ /* tell Bind about it. */
+ result = dns_sdlz_putnamedrr(allnodes, safeGet(row[2]),
+ safeGet(row[1]),
+ ttl, tmpString);
+ isc_mem_free(ns_g_mctx, tmpString);
+ }
+ /* if we weren't successful, log err msg */
+ if (result != ISC_R_SUCCESS) {
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
+ "dns_sdlz_putnamedrr returned error. "
+ "Error code was: %s",
+ isc_result_totext(result));
+ result = ISC_R_FAILURE;
+ break;
+ }
+ /* get next row from the result set */
+ row = mysql_fetch_row(rs);
+ }
+
+ /* free result set memory */
+ mysql_free_result(rs);
+
+ return result;
+}
+
+/*% if the lookup function does not return SOA or NS records for the zone,
+ * use this function to get that information for Bind.
+ */
+
+static isc_result_t
+mysql_authority(const char *zone, void *driverarg, void *dbdata,
+ dns_sdlzlookup_t *lookup)
+{
+ isc_result_t result;
+ MYSQL_RES *rs = NULL;
+
+ UNUSED(driverarg);
+
+ /* run the query and get the result set from the database. */
+ result = mysql_get_resultset(zone, NULL, NULL, AUTHORITY, dbdata, &rs);
+ /* if we get "not implemented", send it along */
+ if (result == ISC_R_NOTIMPLEMENTED)
+ return result;
+ /* if we didn't get a result set, log an err msg. */
+ if (result != ISC_R_SUCCESS) {
+ if (rs != NULL)
+ mysql_free_result(rs);
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
+ "mysql driver unable to return "
+ "result set for authority query");
+ return (ISC_R_FAILURE);
+ }
+ /*
+ * lookup and authority result sets are processed in the same
+ * manner mysql_process_rs does the job for both functions.
+ */
+ return mysql_process_rs(lookup, rs);
+}
+
+/*% if zone is supported, lookup up a (or multiple) record(s) in it */
+static isc_result_t
+mysql_lookup(const char *zone, const char *name, void *driverarg,
+ void *dbdata, dns_sdlzlookup_t *lookup)
+{
+ isc_result_t result;
+ MYSQL_RES *rs = NULL;
+
+ UNUSED(driverarg);
+
+ /* run the query and get the result set from the database. */
+ result = mysql_get_resultset(zone, name, NULL, LOOKUP, dbdata, &rs);
+ /* if we didn't get a result set, log an err msg. */
+ if (result != ISC_R_SUCCESS) {
+ if (rs != NULL)
+ mysql_free_result(rs);
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
+ "mysql driver unable to return "
+ "result set for lookup query");
+ return (ISC_R_FAILURE);
+ }
+ /*
+ * lookup and authority result sets are processed in the same manner
+ * mysql_process_rs does the job for both functions.
+ */
+ return mysql_process_rs(lookup, rs);
+}
+
+/*%
+ * create an instance of the driver. Remember, only 1 copy of the driver's
+ * code is ever loaded, the driver has to remember which context it's
+ * operating in. This is done via use of the dbdata arguement which is
+ * passed into all query functions.
+ */
+static isc_result_t
+mysql_create(const char *dlzname, unsigned int argc, char *argv[],
+ void *driverarg, void **dbdata)
+{
+ isc_result_t result;
+ dbinstance_t *dbi = NULL;
+ char *tmp = NULL;
+ char *dbname = NULL;
+ char *host = NULL;
+ char *user = NULL;
+ char *pass = NULL;
+ char *socket = NULL;
+ int port;
+ MYSQL *dbc;
+ char *endp;
+ int j;
+ unsigned int flags = 0;
+
+ UNUSED(driverarg);
+ UNUSED(dlzname);
+
+ /* verify we have at least 4 arg's passed to the driver */
+ if (argc < 4) {
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
+ "mysql driver requires "
+ "at least 4 command line args.");
+ return (ISC_R_FAILURE);
+ }
+
+ /* no more than 8 arg's should be passed to the driver */
+ if (argc > 8) {
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
+ "mysql driver cannot accept "
+ "more than 7 command line args.");
+ return (ISC_R_FAILURE);
+ }
+
+ /* parse connection string and get paramters. */
+
+ /* get db name - required */
+ dbname = getParameterValue(argv[1], "dbname=");
+ if (dbname == NULL) {
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
+ "mysql driver requires a dbname parameter.");
+ result = ISC_R_FAILURE;
+ goto full_cleanup;
+ }
+
+ /* get db port. Not required, but must be > 0 if specified */
+ tmp = getParameterValue(argv[1], "port=");
+ if (tmp == NULL) {
+ port = 0;
+ } else {
+ port = strtol(tmp, &endp, 10);
+ if (*endp != '\0' || port < 0) {
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
+ "Mysql driver port "
+ "must be a positive number.");
+ isc_mem_free(ns_g_mctx, tmp);
+ result = ISC_R_FAILURE;
+ goto full_cleanup;
+ }
+ isc_mem_free(ns_g_mctx, tmp);
+ }
+
+ /* how many queries were passed in from config file? */
+ switch(argc) {
+ case 4:
+ result = build_sqldbinstance(ns_g_mctx, NULL, NULL, NULL,
+ argv[2], argv[3], NULL, &dbi);
+ break;
+ case 5:
+ result = build_sqldbinstance(ns_g_mctx, NULL, NULL, argv[4],
+ argv[2], argv[3], NULL, &dbi);
+ break;
+ case 6:
+ result = build_sqldbinstance(ns_g_mctx, argv[5], NULL, argv[4],
+ argv[2], argv[3], NULL, &dbi);
+ break;
+ case 7:
+ result = build_sqldbinstance(ns_g_mctx, argv[5],
+ argv[6], argv[4],
+ argv[2], argv[3], NULL, &dbi);
+ break;
+ case 8:
+ result = build_sqldbinstance(ns_g_mctx, argv[5],
+ argv[6], argv[4],
+ argv[2], argv[3], argv[7], &dbi);
+ break;
+ default:
+ /* not really needed, should shut up compiler. */
+ result = ISC_R_FAILURE;
+ }
+
+ /* unsuccessful?, log err msg and cleanup. */
+ if (result != ISC_R_SUCCESS) {
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
+ "mysql driver could not create "
+ "database instance object.");
+ result = ISC_R_FAILURE;
+ goto full_cleanup;
+ }
+
+ /* create and set db connection */
+ dbi->dbconn = mysql_init(NULL);
+
+ /* if db connection cannot be created, log err msg and cleanup. */
+ if (dbi->dbconn == NULL) {
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
+ "mysql driver could not allocate "
+ "memory for database connection");
+ result = ISC_R_FAILURE;
+ goto full_cleanup;
+ }
+
+ tmp = getParameterValue(argv[1], "compress=");
+ if (tmp != NULL) {
+ if (strcasecmp(tmp, "true") == 0)
+ flags = CLIENT_COMPRESS;
+ isc_mem_free(ns_g_mctx, tmp);
+ }
+
+ tmp = getParameterValue(argv[1], "ssl=");
+ if (tmp != NULL) {
+ if (strcasecmp(tmp, "true") == 0)
+ flags = flags | CLIENT_SSL;
+ isc_mem_free(ns_g_mctx, tmp);
+ }
+
+ tmp = getParameterValue(argv[1], "space=");
+ if (tmp != NULL) {
+ if (strcasecmp(tmp, "ignore") == 0)
+ flags = flags | CLIENT_IGNORE_SPACE;
+ isc_mem_free(ns_g_mctx, tmp);
+ }
+
+ dbc = NULL;
+ host = getParameterValue(argv[1], "host=");
+ user = getParameterValue(argv[1], "user=");
+ pass = getParameterValue(argv[1], "pass=");
+ socket = getParameterValue(argv[1], "socket=");
+
+ for (j=0; dbc == NULL && j < 4; j++)
+ dbc = mysql_real_connect((MYSQL *) dbi->dbconn, host,
+ user, pass, dbname, port, socket,
+ flags);
+
+ /* let user know if we couldn't connect. */
+ if (dbc == NULL) {
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
+ "mysql driver failed to create "
+ "database connection after 4 attempts");
+ result = ISC_R_FAILURE;
+ goto full_cleanup;
+ }
+
+ /* return db connection via dbdata */
+ *dbdata = dbi;
+
+ result = ISC_R_SUCCESS;
+ goto cleanup;
+
+ full_cleanup:
+
+ destroy_sqldbinstance(dbi);
+
+ cleanup:
+
+ if (dbname != NULL)
+ isc_mem_free(ns_g_mctx, dbname);
+ if (host != NULL)
+ isc_mem_free(ns_g_mctx, host);
+ if (user != NULL)
+ isc_mem_free(ns_g_mctx, user);
+ if (pass != NULL)
+ isc_mem_free(ns_g_mctx, pass);
+ if (socket != NULL)
+ isc_mem_free(ns_g_mctx, socket);
+
+
+ return result;
+}
+
+/*%
+ * destroy the driver. Remember, only 1 copy of the driver's
+ * code is ever loaded, the driver has to remember which context it's
+ * operating in. This is done via use of the dbdata arguement.
+ * so we really only need to clean it up since we are not using driverarg.
+ */
+
+static void
+mysql_destroy(void *driverarg, void *dbdata)
+{
+ dbinstance_t *dbi;
+
+ UNUSED(driverarg);
+
+ dbi = (dbinstance_t *) dbdata;
+
+ /* release DB connection */
+ if (dbi->dbconn != NULL)
+ mysql_close((MYSQL *) dbi->dbconn);
+
+ /* destroy DB instance */
+ destroy_sqldbinstance(dbi);
+}
+
+/* pointers to all our runtime methods. */
+/* this is used during driver registration */
+/* i.e. in dlz_mysql_init below. */
+static dns_sdlzmethods_t dlz_mysql_methods = {
+ mysql_create,
+ mysql_destroy,
+ mysql_findzone,
+ mysql_lookup,
+ mysql_authority,
+ mysql_allnodes,
+ mysql_allowzonexfr
+};
+
+/*%
+ * Wrapper around dns_sdlzregister().
+ */
+isc_result_t
+dlz_mysql_init(void) {
+ isc_result_t result;
+
+ /*
+ * Write debugging message to log
+ */
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2),
+ "Registering DLZ mysql driver.");
+
+ /* Driver is always threadsafe. Because of the way MySQL handles
+ * threads the MySQL driver can only be used when bind is run single
+ * threaded. Using MySQL with Bind running multi-threaded is not
+ * allowed. When using the MySQL driver "-n1" should always be
+ * passed to Bind to guarantee single threaded operation.
+ */
+ result = dns_sdlzregister("mysql", &dlz_mysql_methods, NULL,
+ DNS_SDLZFLAG_RELATIVEOWNER |
+ DNS_SDLZFLAG_RELATIVERDATA |
+ DNS_SDLZFLAG_THREADSAFE,
+ ns_g_mctx, &dlz_mysql);
+ /* if we can't register the driver, there are big problems. */
+ if (result != ISC_R_SUCCESS) {
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "dns_sdlzregister() failed: %s",
+ isc_result_totext(result));
+ result = ISC_R_UNEXPECTED;
+ }
+
+
+ return result;
+}
+
+/*%
+ * Wrapper around dns_sdlzunregister().
+ */
+void
+dlz_mysql_clear(void) {
+
+ /*
+ * Write debugging message to log
+ */
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2),
+ "Unregistering DLZ mysql driver.");
+
+ /* unregister the driver. */
+ if (dlz_mysql != NULL)
+ dns_sdlzunregister(&dlz_mysql);
+}
+
+#endif
--- /dev/null
+/*
+ * 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) 1999-2001 Internet Software Consortium.
+ *
+ * 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 INTERNET SOFTWARE CONSORTIUM
+ * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+ * INTERNET SOFTWARE CONSORTIUM 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.
+ */
+
+#ifdef DLZ_ODBC
+
+#include <config.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include <dns/log.h>
+#include <dns/sdlz.h>
+#include <dns/result.h>
+
+#include <isc/mem.h>
+#include <isc/platform.h>
+#include <isc/print.h>
+#include <isc/result.h>
+#include <isc/string.h>
+#include <isc/util.h>
+
+#include <named/globals.h>
+
+#include <dlz/sdlz_helper.h>
+#include <dlz/dlz_odbc_driver.h>
+
+#include <sql.h>
+#include <sqlext.h>
+#include <sqltypes.h>
+
+static dns_sdlzimplementation_t *dlz_odbc = NULL;
+
+#define dbc_search_limit 30
+#define ALLNODES 1
+#define ALLOWXFR 2
+#define AUTHORITY 3
+#define FINDZONE 4
+#define LOOKUP 5
+
+#define sqlOK(a) ((a == SQL_SUCCESS || a == SQL_SUCCESS_WITH_INFO) ? -1 : 0)
+
+/*
+ * Private Structures
+ */
+
+/*
+ * structure to hold ODBC connection & statement
+ */
+
+typedef struct{
+ SQLHDBC dbc;
+ SQLHSTMT stmnt;
+} odbc_db_t;
+
+/*
+ * Structure to hold everthing needed by this "instance" of the odbc driver
+ * remember, the driver code is only loaded once, but may have many separate
+ * instances
+ */
+
+typedef struct {
+
+#ifdef ISC_PLATFORM_USETHREADS
+
+ db_list_t *db; /* handle to a list of DB */
+
+#else
+
+ dbinstance_t *db; /* handle to db */
+
+#endif
+
+ SQLHENV sql_env; /* handle to SQL environment */
+ SQLCHAR *dsn;
+ SQLCHAR *user;
+ SQLCHAR *pass;
+} odbc_instance_t;
+
+/* forward reference */
+
+static size_t
+odbc_makesafe(char *to, const char *from, size_t length);
+
+/*
+ * Private methods
+ */
+
+static SQLSMALLINT
+safeLen(void *a) {
+ if (a == NULL)
+ return 0;
+ return strlen((char *) a);
+}
+
+/*% propertly cleans up an odbc_instance_t */
+
+static void
+destroy_odbc_instance(odbc_instance_t *odbc_inst) {
+
+#ifdef ISC_PLATFORM_USETHREADS
+
+ dbinstance_t *ndbi = NULL;
+ dbinstance_t *dbi = NULL;
+
+ /* get the first DBI in the list */
+ ndbi = ISC_LIST_HEAD(*odbc_inst->db);
+
+ /* loop through the list */
+ while (ndbi != NULL) {
+ dbi = ndbi;
+ /* get the next DBI in the list */
+ ndbi = ISC_LIST_NEXT(dbi, link);
+
+ /* if we have a connection / statement object in memory */
+ if (dbi->dbconn != NULL) {
+ /* free statement handle */
+ if (((odbc_db_t *) (dbi->dbconn))->stmnt != NULL) {
+ SQLFreeHandle(SQL_HANDLE_STMT,
+ ((odbc_db_t *)
+ (dbi->dbconn))->stmnt);
+ ((odbc_db_t *) (dbi->dbconn))->stmnt = NULL;
+ }
+
+ /* disconnect from database & free connection handle */
+ if (((odbc_db_t *) (dbi->dbconn))->dbc != NULL) {
+ SQLDisconnect(((odbc_db_t *)
+ dbi->dbconn)->dbc);
+ SQLFreeHandle(SQL_HANDLE_DBC,
+ ((odbc_db_t *)
+ (dbi->dbconn))->dbc);
+ ((odbc_db_t *) (dbi->dbconn))->dbc = NULL;
+ }
+
+ /* free memory that held connection & statement. */
+ isc_mem_free(ns_g_mctx, dbi->dbconn);
+ }
+ /* release all memory that comprised a DBI */
+ destroy_sqldbinstance(dbi);
+ }
+ /* release memory for the list structure */
+ isc_mem_put(ns_g_mctx, odbc_inst->db, sizeof(db_list_t));
+
+#else /* ISC_PLATFORM_USETHREADS */
+
+ /* free statement handle */
+ if (((odbc_db_t *) (odbc_inst->db->dbconn))->stmnt != NULL) {
+ SQLFreeHandle(SQL_HANDLE_STMT,
+ ((odbc_db_t *) (odbc_inst->db->dbconn))->stmnt);
+ ((odbc_db_t *) (odbc_inst->db->dbconn))->stmnt = NULL;
+ }
+
+ /* disconnect from database, free connection handle */
+ if (((odbc_db_t *) (odbc_inst->db->dbconn))->dbc != NULL) {
+ SQLDisconnect(((odbc_db_t *) (odbc_inst->db->dbconn))->dbc);
+ SQLFreeHandle(SQL_HANDLE_DBC,
+ ((odbc_db_t *) (odbc_inst->db->dbconn))->dbc);
+ ((odbc_db_t *) (odbc_inst->db->dbconn))->dbc = NULL;
+ }
+ /* free mem for the odbc_db_t structure held in db */
+ if (((odbc_db_t *) odbc_inst->db->dbconn) != NULL) {
+ isc_mem_free(ns_g_mctx, odbc_inst->db->dbconn);
+ odbc_inst->db->dbconn = NULL;
+ }
+
+ if (odbc_inst->db != NULL)
+ destroy_sqldbinstance(odbc_inst->db);
+
+#endif /* ISC_PLATFORM_USETHREADS */
+
+
+ /* free sql environment */
+ if (odbc_inst->sql_env != NULL)
+ SQLFreeHandle(SQL_HANDLE_ENV, odbc_inst->sql_env);
+
+ /* free ODBC instance strings */
+ if (odbc_inst->dsn != NULL)
+ isc_mem_free(ns_g_mctx, odbc_inst->dsn);
+ if (odbc_inst->pass != NULL)
+ isc_mem_free(ns_g_mctx, odbc_inst->pass);
+ if (odbc_inst->user != NULL)
+ isc_mem_free(ns_g_mctx, odbc_inst->user);
+
+ /* free memory for odbc_inst */
+ if (odbc_inst != NULL)
+ isc_mem_put(ns_g_mctx, odbc_inst, sizeof(odbc_instance_t));
+
+}
+
+/*% Connects to database, and creates ODBC statements */
+
+static isc_result_t
+odbc_connect(odbc_instance_t *dbi, odbc_db_t **dbc) {
+
+ odbc_db_t *ndb = *dbc;
+ SQLRETURN sqlRes;
+ isc_result_t result = ISC_R_SUCCESS;
+
+ if (ndb != NULL) {
+ /*
+ * if db != null, we have to do some cleanup
+ * if statement handle != null free it
+ */
+ if (ndb->stmnt != NULL) {
+ SQLFreeHandle(SQL_HANDLE_STMT, ndb->stmnt);
+ ndb->stmnt = NULL;
+ }
+
+ /* if connection handle != null free it */
+ if (ndb->dbc != NULL) {
+ SQLFreeHandle(SQL_HANDLE_DBC, ndb->dbc);
+ ndb->dbc = NULL;
+ }
+ } else {
+ ndb = isc_mem_allocate(ns_g_mctx, sizeof(odbc_db_t));
+ if (ndb == NULL) {
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
+ "Odbc driver unable to allocate memory");
+ return ISC_R_NOMEMORY;
+ }
+ memset(ndb, 0, sizeof(odbc_db_t));
+ }
+
+ sqlRes = SQLAllocHandle(SQL_HANDLE_DBC, dbi->sql_env, &(ndb->dbc));
+ if (!sqlOK(sqlRes)) {
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
+ "Odbc driver unable to allocate memory");
+ result = ISC_R_NOMEMORY;
+ goto cleanup;
+ }
+
+ sqlRes = SQLConnect(ndb->dbc, dbi->dsn, safeLen(dbi->dsn), dbi->user,
+ safeLen(dbi->user), dbi->pass, safeLen(dbi->pass));
+ if (!sqlOK(sqlRes)) {
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
+ "Odbc driver unable to connect");
+ result = ISC_R_FAILURE;
+ goto cleanup;
+ }
+
+ sqlRes = SQLAllocHandle(SQL_HANDLE_STMT, ndb->dbc, &(ndb->stmnt));
+ if (!sqlOK(sqlRes)) {
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
+ "Odbc driver unable to allocate memory");
+ result = ISC_R_NOMEMORY;
+ goto cleanup;
+ }
+
+ *dbc = ndb;
+
+ return ISC_R_SUCCESS;
+
+ cleanup:
+
+ if (ndb != NULL) {
+
+ /* if statement handle != null free it */
+ if (ndb->stmnt != NULL) {
+ SQLFreeHandle(SQL_HANDLE_STMT, ndb->stmnt);
+ ndb->stmnt = NULL;
+ }
+
+ /* if connection handle != null free it */
+ if (ndb->dbc != NULL) {
+ SQLDisconnect(ndb->dbc);
+ SQLFreeHandle(SQL_HANDLE_DBC, ndb->dbc);
+ ndb->dbc = NULL;
+ }
+ /* free memory holding ndb */
+ isc_mem_free(ns_g_mctx, ndb);
+ }
+
+ return result;
+}
+
+/*%
+ * Loops through the list of DB instances, attempting to lock
+ * on the mutex. If successful, the DBI is reserved for use
+ * and the thread can perform queries against the database.
+ * If the lock fails, the next one in the list is tried.
+ * looping continues until a lock is obtained, or until
+ * the list has been searched dbc_search_limit times.
+ * This function is only used when the driver is compiled for
+ * multithreaded operation.
+ */
+
+#ifdef ISC_PLATFORM_USETHREADS
+
+static dbinstance_t *
+odbc_find_avail_conn(db_list_t *dblist)
+{
+ dbinstance_t *dbi = NULL;
+ dbinstance_t *head;
+ int count = 0;
+
+ /* get top of list */
+ head = dbi = ISC_LIST_HEAD(*dblist);
+
+ /* loop through list */
+ while (count < dbc_search_limit) {
+ /* try to lock on the mutex */
+ if (isc_mutex_trylock(&dbi->instance_lock) == ISC_R_SUCCESS)
+ return dbi; /* success, return the DBI for use. */
+
+ /* not successful, keep trying */
+ dbi = ISC_LIST_NEXT(dbi, link);
+
+ /* check to see if we have gone to the top of the list. */
+ if (dbi == NULL) {
+ count++;
+ dbi = head;
+ }
+ }
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_INFO,
+ "Odbc driver unable to find available "
+ "connection after searching %d times",
+ count);
+ return NULL;
+}
+
+#endif /* ISC_PLATFORM_USETHREADS */
+
+/*% Allocates memory for a new string, and then constructs the new
+ * string by "escaping" the input string. The new string is
+ * safe to be used in queries. This is necessary because we cannot
+ * be sure of what types of strings are passed to us, and we don't
+ * want special characters in the string causing problems.
+ */
+
+static char *
+odbc_escape_string(const char *instr) {
+
+ char *outstr;
+ unsigned int len;
+
+ if (instr == NULL)
+ return NULL;
+
+ len = strlen(instr);
+
+ outstr = isc_mem_allocate(ns_g_mctx ,(2 * len * sizeof(char)) + 1);
+ if (outstr == NULL)
+ return NULL;
+
+ odbc_makesafe(outstr, instr, len);
+
+ return outstr;
+}
+
+/* ---------------
+ * Escaping arbitrary strings to get valid SQL strings/identifiers.
+ *
+ * Replaces "\\" with "\\\\" and "'" with "''".
+ * length is the length of the buffer pointed to by
+ * from. The buffer at to must be at least 2*length + 1 characters
+ * long. A terminating NUL character is written.
+ *
+ * NOTICE!!!
+ * This function was borrowed directly from PostgreSQL's libpq.
+ *
+ * The copyright statements from the original file containing this
+ * function are included below:
+ * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ * ---------------
+ */
+
+static size_t
+odbc_makesafe(char *to, const char *from, size_t length)
+{
+ const char *source = from;
+ char *target = to;
+ unsigned int remaining = length;
+
+ while (remaining > 0)
+ {
+ switch (*source)
+ {
+ case '\\':
+ *target = '\\';
+ target++;
+ *target = '\\';
+ /* target and remaining are updated below. */
+ break;
+
+ case '\'':
+ *target = '\'';
+ target++;
+ *target = '\'';
+ /* target and remaining are updated below. */
+ break;
+
+ default:
+ *target = *source;
+ /* target and remaining are updated below. */
+ }
+ source++;
+ target++;
+ remaining--;
+ }
+
+ /* Write the terminating NUL character. */
+ *target = '\0';
+
+ return target - to;
+}
+
+/*%
+ * This function is the real core of the driver. Zone, record
+ * and client strings are passed in (or NULL is passed if the
+ * string is not available). The type of query we want to run
+ * is indicated by the query flag, and the dbdata object is passed
+ * passed in to. dbdata really holds either:
+ * 1) a list of database instances (in multithreaded mode) OR
+ * 2) a single database instance (in single threaded mode)
+ * The function will construct the query and obtain an available
+ * database instance (DBI). It will then run the query and hopefully
+ * obtain a result set. The data base instance that is used is returned
+ * to the caller so they can get the data from the result set from it.
+ * If successfull, it will be the responsibility of the caller to close
+ * the cursor, and unlock the mutex of the DBI when they are done with it.
+ * If not successfull, this function will perform all the cleanup.
+ */
+
+
+static isc_result_t
+odbc_get_resultset(const char *zone, const char *record,
+ const char *client, unsigned int query,
+ void *dbdata, dbinstance_t **r_dbi)
+{
+
+ isc_result_t result;
+ dbinstance_t *dbi = NULL;
+ char *querystring = NULL;
+ unsigned int j = 0;
+ SQLRETURN sqlRes;
+
+ REQUIRE(*r_dbi == NULL);
+
+ /* get db instance / connection */
+#ifdef ISC_PLATFORM_USETHREADS
+
+ /* find an available DBI from the list */
+ dbi = odbc_find_avail_conn(((odbc_instance_t *) dbdata)->db);
+
+#else /* ISC_PLATFORM_USETHREADS */
+
+ /*
+ * only 1 DBI - no need to lock instance lock either
+ * only 1 thread in the whole process, no possible contention.
+ */
+ dbi = (dbinstance_t *) ((odbc_instance_t *) dbdata)->db;
+
+#endif /* ISC_PLATFORM_USETHREADS */
+
+ /* if DBI is null, can't do anything else */
+ if (dbi == NULL) {
+ result = ISC_R_FAILURE;
+ goto cleanup;
+ }
+
+ /* what type of query are we going to run? */
+ switch(query) {
+ case ALLNODES:
+ /*
+ * if the query was not passed in from the config file
+ * then we can't run it. return not_implemented, so
+ * it's like the code for that operation was never
+ * built into the driver.... AHHH flexibility!!!
+ */
+ if (dbi->allnodes_q == NULL) {
+ result = ISC_R_NOTIMPLEMENTED;
+ goto cleanup;
+ }
+ break;
+ case ALLOWXFR:
+ /* same as comments as ALLNODES */
+ if (dbi->allowxfr_q == NULL) {
+ result = ISC_R_NOTIMPLEMENTED;
+ goto cleanup;
+ }
+ break;
+ case AUTHORITY:
+ /* same as comments as ALLNODES */
+ if (dbi->authority_q == NULL) {
+ result = ISC_R_NOTIMPLEMENTED;
+ goto cleanup;
+ }
+ break;
+ case FINDZONE:
+ /* this is required. It's the whole point of DLZ! */
+ if (dbi->findzone_q == NULL) {
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2),
+ "No query specified for findzone. "
+ "Findzone requires a query");
+ result = ISC_R_FAILURE;
+ goto cleanup;
+ }
+ break;
+ case LOOKUP:
+ /* this is required. It's also a major point of DLZ! */
+ if (dbi->lookup_q == NULL) {
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2),
+ "No query specified for lookup. "
+ "Lookup requires a query");
+ result = ISC_R_FAILURE;
+ goto cleanup;
+ }
+ break;
+ default:
+ /*
+ * this should never happen. If it does, the code is
+ * screwed up!
+ */
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "Incorrect query flag passed to "
+ "odbc_get_resultset");
+ result = ISC_R_UNEXPECTED;
+ goto cleanup;
+ }
+
+
+ /*
+ * was a zone string passed? If so, make it safe for use in
+ * queries.
+ */
+ if (zone != NULL) {
+ dbi->zone = odbc_escape_string(zone);
+ if (dbi->zone == NULL) {
+ result = ISC_R_NOMEMORY;
+ goto cleanup;
+ }
+ } else { /* no string passed, set the string pointer to NULL */
+ dbi->zone = NULL;
+ }
+
+ /*
+ * was a record string passed? If so, make it safe for use in
+ * queries.
+ */
+ if (record != NULL) {
+ dbi->record = odbc_escape_string(record);
+ if (dbi->record == NULL) {
+ result = ISC_R_NOMEMORY;
+ goto cleanup;
+ }
+ } else { /* no string passed, set the string pointer to NULL */
+ dbi->record = NULL;
+ }
+
+ /*
+ * was a client string passed? If so, make it safe for use in
+ * queries.
+ */
+ if (client != NULL) {
+ dbi->client = odbc_escape_string(client);
+ if (dbi->client == NULL) {
+ result = ISC_R_NOMEMORY;
+ goto cleanup;
+ }
+ } else { /* no string passed, set the string pointer to NULL */
+ dbi->client = NULL;
+ }
+
+ /*
+ * what type of query are we going to run?
+ * this time we build the actual query to run.
+ */
+ switch(query) {
+ case ALLNODES:
+ querystring = build_querystring(ns_g_mctx, dbi->allnodes_q);
+ break;
+ case ALLOWXFR:
+ querystring = build_querystring(ns_g_mctx, dbi->allowxfr_q);
+ break;
+ case AUTHORITY:
+ querystring = build_querystring(ns_g_mctx, dbi->authority_q);
+ break;
+ case FINDZONE:
+ querystring = build_querystring(ns_g_mctx, dbi->findzone_q);
+ break;
+ case LOOKUP:
+ querystring = build_querystring(ns_g_mctx, dbi->lookup_q);
+ break;
+ default:
+ /*
+ * this should never happen. If it does, the code is
+ * screwed up!
+ */
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "Incorrect query flag passed to "
+ "odbc_get_resultset");
+ result = ISC_R_UNEXPECTED;
+ goto cleanup;
+ }
+
+ /* if the querystring is null, Bummer, outta RAM. UPGRADE TIME!!! */
+ if (querystring == NULL) {
+ result = ISC_R_NOMEMORY;
+ goto cleanup;
+ }
+
+ /* output the full query string during debug so we can see */
+ /* what lame error the query has. */
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(1),
+ "\nQuery String: %s\n", querystring);
+
+ /* attempt query up to 3 times. */
+ for (j=0; j < 3; j++) {
+ /* try to get result set */
+ sqlRes = SQLExecDirect(((odbc_db_t *) dbi->dbconn)->stmnt,
+ (SQLCHAR *) querystring,
+ (SQLINTEGER) strlen(querystring));
+
+ /* if error, reset DB connection */
+ if (!sqlOK(sqlRes)) {
+ /* close cursor */
+ SQLCloseCursor(((odbc_db_t *) dbi->dbconn)->stmnt);
+ /* attempt to reconnect */
+ result = odbc_connect((odbc_instance_t *) dbdata,
+ (odbc_db_t **) &(dbi->dbconn));
+ /* check if we reconnected */
+ if (result != ISC_R_SUCCESS)
+ break;
+ /* incase this is the last time through the loop */
+ result = ISC_R_FAILURE;
+ } else {
+ result = ISC_R_SUCCESS;
+ /* return dbi */
+ *r_dbi = dbi;
+ /* result set ok, break loop */
+ break;
+ }
+ } /* end for loop */
+
+ cleanup: /* it's always good to cleanup after yourself */
+
+ /* if we couldn't even allocate DBI, just return NULL */
+ if (dbi == NULL)
+ return ISC_R_FAILURE;
+
+ /* free dbi->zone string */
+ if (dbi->zone != NULL)
+ isc_mem_free(ns_g_mctx, dbi->zone);
+
+ /* free dbi->record string */
+ if (dbi->record != NULL)
+ isc_mem_free(ns_g_mctx, dbi->record);
+
+ /* free dbi->client string */
+ if (dbi->client != NULL)
+ isc_mem_free(ns_g_mctx, dbi->client);
+
+#ifdef ISC_PLATFORM_USETHREADS
+
+ /* if we are done using this dbi, release the lock */
+ if (result != ISC_R_SUCCESS)
+ isc_mutex_unlock(&dbi->instance_lock);
+
+#endif /* ISC_PLATFORM_USETHREADS */
+
+ /* release query string */
+ if (querystring != NULL)
+ isc_mem_free(ns_g_mctx, querystring );
+
+ /* return result */
+ return result;
+
+}
+
+/*%
+ * Gets a single field from the ODBC statement. The memory for the
+ * returned data is dynamically allocated. If this method is successful
+ * it is the reponsibility of the caller to free the memory using
+ * isc_mem_free(ns_g_mctx, *ptr);
+ */
+
+static isc_result_t
+odbc_getField(SQLHSTMT *stmnt, SQLSMALLINT field, char **data) {
+
+ SQLINTEGER size;
+
+ REQUIRE(data != NULL && *data == NULL);
+
+ if (sqlOK(SQLColAttribute(stmnt, field, SQL_DESC_DISPLAY_SIZE,
+ NULL, 0, NULL, &size)) && size > 0) {
+ *data = isc_mem_allocate(ns_g_mctx, size + 1);
+ if (data != NULL) {
+ if (sqlOK(SQLGetData(stmnt, field, SQL_C_CHAR,
+ *data, size + 1,&size)))
+ return ISC_R_SUCCESS;
+ isc_mem_free(ns_g_mctx, *data);
+ }
+ }
+ return ISC_R_FAILURE;
+}
+
+/*%
+ * Gets multiple fields from the ODBC statement. The memory for the
+ * returned data is dynamically allocated. If this method is successful
+ * it is the reponsibility of the caller to free the memory using
+ * isc_mem_free(ns_g_mctx, *ptr);
+ */
+
+static isc_result_t
+odbc_getManyFields(SQLHSTMT *stmnt, SQLSMALLINT startField,
+ SQLSMALLINT endField, char **retData) {
+
+ isc_result_t result;
+ SQLINTEGER size;
+ int totSize = 0;
+ SQLSMALLINT i;
+ int j = 0;
+ char *data;
+
+ REQUIRE(retData != NULL && *retData == NULL);
+ REQUIRE(startField > 0 && startField <= endField);
+
+ /* determine how large the data is */
+ for (i=startField; i <= endField; i++)
+ if (sqlOK(SQLColAttribute(stmnt, i, SQL_DESC_DISPLAY_SIZE,
+ NULL, 0, NULL, &size)) && size > 0) {
+ /* always allow for a " " (space) character */
+ totSize += (size + 1);
+ /* after the data item */
+ }
+
+ if (totSize < 1)
+ return ISC_R_FAILURE;
+
+ /* allow for a "\n" at the end of the string/ */
+ data = isc_mem_allocate(ns_g_mctx, ++totSize);
+ if (data == NULL)
+ return ISC_R_NOMEMORY;
+
+ result = ISC_R_FAILURE;
+
+ /* get the data and concat all fields into a large string */
+ for (i=startField; i <= endField; i++) {
+ if (sqlOK(SQLGetData(stmnt, i, SQL_C_CHAR, &(data[j]),
+ totSize - j, &size))) {
+ if (size > 0) {
+ j += size;
+ data[j++] = ' ';
+ data[j] = '\0';
+ result = ISC_R_SUCCESS;
+ }
+ } else {
+ isc_mem_free(ns_g_mctx, data);
+ return ISC_R_FAILURE;
+ }
+ }
+
+ if (result != ISC_R_SUCCESS) {
+ isc_mem_free(ns_g_mctx, data);
+ return result;
+ }
+
+ *retData = data;
+ return ISC_R_SUCCESS;
+
+}
+
+/*%
+ * The processing of result sets for lookup and authority are
+ * exactly the same. So that functionality has been moved
+ * into this function to minimize code.
+ */
+
+static isc_result_t
+odbc_process_rs(dns_sdlzlookup_t *lookup, dbinstance_t *dbi)
+{
+
+
+ isc_result_t result;
+ SQLSMALLINT fields;
+ SQLHSTMT *stmnt;
+ char *ttl_s;
+ char *type;
+ char *data;
+ char *endp;
+ int ttl;
+
+ REQUIRE(dbi != NULL);
+
+ stmnt = ((odbc_db_t *) (dbi->dbconn))->stmnt;
+
+ /* get number of columns */
+ if (!sqlOK(SQLNumResultCols(stmnt, &fields))) {
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
+ "Odbc driver unable to process result set");
+ result = ISC_R_FAILURE;
+ goto process_rs_cleanup;
+ }
+
+ /* get things ready for processing */
+ result = ISC_R_FAILURE;
+
+ while (sqlOK(SQLFetch(stmnt))) {
+
+ /* set to null for next pass through */
+ data = type = ttl_s = NULL;
+
+ switch(fields) {
+ case 1:
+ /*
+ * one column in rs, it's the data field. use
+ * default type of A record, and default TTL
+ * of 86400. attempt to get data, & tell bind
+ * about it.
+ */
+ if ((result = odbc_getField(stmnt, 1,
+ &data)) == ISC_R_SUCCESS) {
+ result = dns_sdlz_putrr(lookup, "a",
+ 86400, data);
+ }
+ break;
+ case 2:
+ /*
+ * two columns, data field, and data type.
+ * use default TTL of 86400. attempt to get
+ * DNS type & data, then tell bind about it.
+ */
+ if ((result = odbc_getField(stmnt, 1,
+ &type)) == ISC_R_SUCCESS &&
+ (result = odbc_getField(stmnt, 2,
+ &data)) == ISC_R_SUCCESS) {
+ result = dns_sdlz_putrr(lookup, type,
+ 86400, data);
+ }
+ break;
+ default:
+ /*
+ * 3 fields or more, concatenate the last ones
+ * together. attempt to get DNS ttl, type,
+ * data then tell Bind about them.
+ */
+ if ((result = odbc_getField(stmnt, 1, &ttl_s))
+ == ISC_R_SUCCESS &&
+ (result = odbc_getField(stmnt, 2, &type))
+ == ISC_R_SUCCESS &&
+ (result = odbc_getManyFields(stmnt, 3,
+ fields, &data))
+ == ISC_R_SUCCESS) {
+ /* try to convert ttl string to int */
+ ttl = strtol(ttl_s, &endp, 10);
+ /* failure converting ttl. */
+ if (*endp != '\0' || ttl < 0) {
+ isc_log_write(dns_lctx,
+ DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ,
+ ISC_LOG_ERROR,
+ "Odbc driver ttl must "
+ "be a postive number");
+ result = ISC_R_FAILURE;
+ } else {
+ /*
+ * successful converting TTL,
+ * tell Bind everything
+ */
+ result = dns_sdlz_putrr(lookup, type,
+ ttl, data);
+ }
+ } /* closes bid if () */
+ } /* closes switch(fields) */
+
+ /* clean up mem */
+ if (ttl_s != NULL)
+ isc_mem_free(ns_g_mctx, ttl_s);
+ if (type != NULL)
+ isc_mem_free(ns_g_mctx, type);
+ if (data != NULL)
+ isc_mem_free(ns_g_mctx, data);
+
+ /* I sure hope we were successful */
+ if (result != ISC_R_SUCCESS) {
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
+ "dns_sdlz_putrr returned error. "
+ "Error code was: %s",
+ isc_result_totext(result));
+ result = ISC_R_FAILURE;
+ goto process_rs_cleanup;
+ }
+ } /* closes while loop */
+
+ process_rs_cleanup:
+
+ /* close cursor */
+ SQLCloseCursor(((odbc_db_t *) (dbi->dbconn))->stmnt);
+
+#ifdef ISC_PLATFORM_USETHREADS
+
+ /* free lock on dbi so someone else can use it. */
+ isc_mutex_unlock(&dbi->instance_lock);
+
+#endif
+
+ return result;
+}
+
+/*
+ * SDLZ interface methods
+ */
+
+/*% determine if the zone is supported by (in) the database */
+
+static isc_result_t
+odbc_findzone(void *driverarg, void *dbdata, const char *name)
+{
+
+ isc_result_t result;
+ dbinstance_t *dbi = NULL;
+
+ UNUSED(driverarg);
+
+ /* run the query and get the result set from the database. */
+ /* if result != ISC_R_SUCCESS cursor and mutex already cleaned up. */
+ /* so we don't have to do it here. */
+ result = odbc_get_resultset(name, NULL, NULL, FINDZONE, dbdata, &dbi);
+
+ /* Check that we got a result set with data */
+ if (result == ISC_R_SUCCESS &&
+ !sqlOK(SQLFetch(((odbc_db_t *) (dbi->dbconn))->stmnt))) {
+ result = ISC_R_NOTFOUND;
+ }
+
+ if (dbi != NULL) {
+ /* get rid of result set, we are done with it. */
+ SQLCloseCursor(((odbc_db_t *) (dbi->dbconn))->stmnt);
+
+#ifdef ISC_PLATFORM_USETHREADS
+
+ /* free lock on dbi so someone else can use it. */
+ isc_mutex_unlock(&dbi->instance_lock);
+#endif
+ }
+
+ return result;
+}
+
+/*% Determine if the client is allowed to perform a zone transfer */
+static isc_result_t
+odbc_allowzonexfr(void *driverarg, void *dbdata, const char *name,
+ const char *client)
+{
+ isc_result_t result;
+ dbinstance_t *dbi = NULL;
+
+ UNUSED(driverarg);
+
+ /* first check if the zone is supported by the database. */
+ result = odbc_findzone(driverarg, dbdata, name);
+ if (result != ISC_R_SUCCESS)
+ return (ISC_R_NOTFOUND);
+
+ /*
+ * if we get to this point we know the zone is supported by
+ * the database. the only questions now are is the zone
+ * transfer is allowed for this client and did the config file
+ * have an allow zone xfr query
+ *
+ * Run our query, and get a result set from the database. if
+ * result != ISC_R_SUCCESS cursor and mutex already cleaned
+ * up, so we don't have to do it here.
+ */
+ result = odbc_get_resultset(name, NULL, client, ALLOWXFR,
+ dbdata, &dbi);
+
+ /* if we get "not implemented", send it along. */
+ if (result == ISC_R_NOTIMPLEMENTED)
+ return result;
+
+ /* Check that we got a result set with data */
+ if (result == ISC_R_SUCCESS &&
+ !sqlOK(SQLFetch(((odbc_db_t *) (dbi->dbconn))->stmnt))) {
+ result = ISC_R_NOPERM;
+ }
+
+ if (dbi != NULL) {
+ /* get rid of result set, we are done with it. */
+ SQLCloseCursor(((odbc_db_t *) (dbi->dbconn))->stmnt);
+
+#ifdef ISC_PLATFORM_USETHREADS
+
+ /* free lock on dbi so someone else can use it. */
+ isc_mutex_unlock(&dbi->instance_lock);
+#endif
+
+ }
+
+ return result;
+}
+
+/*%
+ * If the client is allowed to perform a zone transfer, the next order of
+ * business is to get all the nodes in the zone, so bind can respond to the
+ * query.
+ */
+
+static isc_result_t
+odbc_allnodes(const char *zone, void *driverarg, void *dbdata,
+ dns_sdlzallnodes_t *allnodes)
+{
+
+ isc_result_t result;
+ dbinstance_t *dbi = NULL;
+ SQLHSTMT *stmnt;
+ SQLSMALLINT fields;
+ char *data;
+ char *type;
+ char *ttl_s;
+ int ttl;
+ char *host;
+ char *endp;
+
+ UNUSED(driverarg);
+
+ /* run the query and get the result set from the database. */
+ result = odbc_get_resultset(zone, NULL, NULL, ALLNODES, dbdata, &dbi);
+
+ /* if we get "not implemented", send it along */
+ if (result == ISC_R_NOTIMPLEMENTED)
+ return result;
+
+ /* if we didn't get a result set, log an err msg. */
+ if (result != ISC_R_SUCCESS) {
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
+ "Odbc driver unable to return "
+ "result set for all nodes query");
+ return (ISC_R_FAILURE);
+ }
+
+ stmnt = ((odbc_db_t *) (dbi->dbconn))->stmnt;
+
+ /* get number of columns */
+ if (!sqlOK(SQLNumResultCols(stmnt, &fields))) {
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
+ "Odbc driver unable to process result set");
+ result = ISC_R_FAILURE;
+ goto allnodes_cleanup;
+ }
+
+ if (fields < 4) { /* gotta have at least 4 columns */
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
+ "Odbc driver too few fields returned by "
+ "all nodes query");
+ result = ISC_R_FAILURE;
+ goto allnodes_cleanup;
+ }
+
+ /* get things ready for processing */
+ result = ISC_R_FAILURE;
+
+ while (sqlOK(SQLFetch(stmnt))) {
+
+ /* set to null for next pass through */
+ data = host = type = ttl_s = NULL;
+
+ /*
+ * attempt to get DNS ttl, type, host, data then tell
+ * Bind about them
+ */
+ if ((result = odbc_getField(stmnt, 1,
+ &ttl_s)) == ISC_R_SUCCESS &&
+ (result = odbc_getField(stmnt, 2,
+ &type)) == ISC_R_SUCCESS &&
+ (result = odbc_getField(stmnt, 3,
+ &host)) == ISC_R_SUCCESS &&
+ (result = odbc_getManyFields(stmnt, 4, fields,
+ &data)) == ISC_R_SUCCESS) {
+ /* convert ttl string to int */
+ ttl = strtol(ttl_s, &endp, 10);
+ /* failure converting ttl. */
+ if (*endp != '\0' || ttl < 0) {
+ isc_log_write(dns_lctx,
+ DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
+ "Odbc driver ttl must be "
+ "a postive number");
+ result = ISC_R_FAILURE;
+ } else {
+ /* successful converting TTL, tell Bind */
+ result = dns_sdlz_putnamedrr(allnodes, host,
+ type, ttl, data);
+ }
+ } /* closes big if () */
+
+ /* clean up mem */
+ if (ttl_s != NULL)
+ isc_mem_free(ns_g_mctx, ttl_s);
+ if (type != NULL)
+ isc_mem_free(ns_g_mctx, type);
+ if (host != NULL)
+ isc_mem_free(ns_g_mctx, host);
+ if (data != NULL)
+ isc_mem_free(ns_g_mctx, data);
+
+ /* if we weren't successful, log err msg */
+ if (result != ISC_R_SUCCESS) {
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
+ "dns_sdlz_putnamedrr returned error. "
+ "Error code was: %s",
+ isc_result_totext(result));
+ result = ISC_R_FAILURE;
+ goto allnodes_cleanup;
+ }
+ } /* closes while loop */
+
+ allnodes_cleanup:
+
+ /* close cursor */
+ SQLCloseCursor(((odbc_db_t *) (dbi->dbconn))->stmnt);
+
+#ifdef ISC_PLATFORM_USETHREADS
+
+ /* free lock on dbi so someone else can use it. */
+ isc_mutex_unlock(&dbi->instance_lock);
+
+#endif
+
+ return result;
+}
+
+/*%
+ * if the lookup function does not return SOA or NS records for the zone,
+ * use this function to get that information for Bind.
+ */
+
+static isc_result_t
+odbc_authority(const char *zone, void *driverarg, void *dbdata,
+ dns_sdlzlookup_t *lookup)
+{
+ isc_result_t result;
+ dbinstance_t *dbi = NULL;
+
+ UNUSED(driverarg);
+
+ /* run the query and get the result set from the database. */
+ result = odbc_get_resultset(zone, NULL, NULL, AUTHORITY, dbdata, &dbi);
+ /* if we get "not implemented", send it along */
+ if (result == ISC_R_NOTIMPLEMENTED)
+ return result;
+ /* if we didn't get a result set, log an err msg. */
+ if (result != ISC_R_SUCCESS) {
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
+ "Odbc driver unable to return "
+ "result set for authority query");
+ return (ISC_R_FAILURE);
+ }
+ /* lookup and authority result sets are processed in the same manner */
+ /* odbc_process_rs does the job for both functions. */
+ return odbc_process_rs(lookup, dbi);
+}
+
+/*% if zone is supported, lookup up a (or multiple) record(s) in it */
+
+static isc_result_t
+odbc_lookup(const char *zone, const char *name, void *driverarg,
+ void *dbdata, dns_sdlzlookup_t *lookup)
+{
+ isc_result_t result;
+ dbinstance_t *dbi = NULL;
+
+ UNUSED(driverarg);
+
+ /* run the query and get the result set from the database. */
+ result = odbc_get_resultset(zone, name, NULL, LOOKUP, dbdata, &dbi);
+ /* if we didn't get a result set, log an err msg. */
+ if (result != ISC_R_SUCCESS) {
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
+ "Odbc driver unable to return "
+ "result set for lookup query");
+ return (ISC_R_FAILURE);
+ }
+ /* lookup and authority result sets are processed in the same manner */
+ /* odbc_process_rs does the job for both functions. */
+ return odbc_process_rs(lookup, dbi);
+}
+
+/*%
+ * create an instance of the driver. Remember, only 1 copy of the driver's
+ * code is ever loaded, the driver has to remember which context it's
+ * operating in. This is done via use of the dbdata arguement which is
+ * passed into all query functions.
+ */
+static isc_result_t
+odbc_create(const char *dlzname, unsigned int argc, char *argv[],
+ void *driverarg, void **dbdata)
+{
+ isc_result_t result;
+ odbc_instance_t *odbc_inst = NULL;
+ dbinstance_t *db = NULL;
+ SQLRETURN sqlRes;
+
+#ifdef ISC_PLATFORM_USETHREADS
+ /* if multi-threaded, we need a few extra variables. */
+ int dbcount;
+ int i;
+ char *endp;
+
+#endif /* ISC_PLATFORM_USETHREADS */
+
+ UNUSED(dlzname);
+ UNUSED(driverarg);
+
+#ifdef ISC_PLATFORM_USETHREADS
+ /* if debugging, let user know we are multithreaded. */
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(1),
+ "Odbc driver running multithreaded");
+#else /* ISC_PLATFORM_USETHREADS */
+ /* if debugging, let user know we are single threaded. */
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(1),
+ "Odbc driver running single threaded");
+#endif /* ISC_PLATFORM_USETHREADS */
+
+ /* verify we have at least 5 arg's passed to the driver */
+ if (argc < 5) {
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
+ "Odbc driver requires at least "
+ "4 command line args.");
+ return (ISC_R_FAILURE);
+ }
+
+ /* no more than 8 arg's should be passed to the driver */
+ if (argc > 8) {
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
+ "Odbc driver cannot accept more than "
+ "7 command line args.");
+ return (ISC_R_FAILURE);
+ }
+
+ /* multithreaded build can have multiple DB connections */
+#ifdef ISC_PLATFORM_USETHREADS
+
+ /* check how many db connections we should create */
+ dbcount = strtol(argv[1], &endp, 10);
+ if (*endp != '\0' || dbcount < 0) {
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
+ "Odbc driver database connection count "
+ "must be positive.");
+ return (ISC_R_FAILURE);
+ }
+
+#endif /* ISC_PLATFORM_USETHREADS */
+
+ /* allocate memory for odbc instance */
+ odbc_inst = isc_mem_get(ns_g_mctx, sizeof(odbc_instance_t));
+ if (odbc_inst == NULL)
+ return (ISC_R_NOMEMORY);
+ memset(odbc_inst, 0, sizeof(odbc_instance_t));
+
+ /* parse connection string and get paramters. */
+
+ /* get odbc database dsn - required */
+ odbc_inst->dsn = (SQLCHAR *) getParameterValue(argv[2],
+ "dsn=");
+ if (odbc_inst->dsn == NULL) {
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
+ "odbc driver requires a dns parameter.");
+ result = ISC_R_FAILURE;
+ goto cleanup;
+ }
+ /* get odbc database username */
+ /* if no username was passed, set odbc_inst.user = NULL; */
+ odbc_inst->user = (SQLCHAR *) getParameterValue(argv[2],
+ "user=");
+
+ /* get odbc database password */
+ /* if no password was passed, set odbc_inst.pass = NULL; */
+ odbc_inst->pass = (SQLCHAR *) getParameterValue(argv[2], "pass=");
+
+ /* create odbc environment & set environment to ODBC V3 */
+ if (odbc_inst->sql_env == NULL) {
+ /* create environment handle */
+ sqlRes = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE,
+ &(odbc_inst->sql_env));
+ if (!sqlOK(sqlRes)) {
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_INFO,
+ "Odbc driver unable to allocate memory");
+ result = ISC_R_NOMEMORY;
+ goto cleanup;
+ }
+ /*set ODBC version = 3 */
+ sqlRes = SQLSetEnvAttr(odbc_inst->sql_env,
+ SQL_ATTR_ODBC_VERSION,
+ (void *) SQL_OV_ODBC3, 0);
+ if (!sqlOK(sqlRes)) {
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_INFO,
+ "Unable to configure ODBC environment");
+ result = ISC_R_NOMEMORY;
+ goto cleanup;
+ }
+ }
+
+#ifdef ISC_PLATFORM_USETHREADS
+
+ /* allocate memory for database connection list */
+ odbc_inst->db = isc_mem_get(ns_g_mctx, sizeof(db_list_t));
+ if (odbc_inst->db == NULL) {
+ result = ISC_R_NOMEMORY;
+ goto cleanup;
+ }
+
+
+ /* initialize DB connection list */
+ ISC_LIST_INIT(*odbc_inst->db);
+
+ /* create the appropriate number of database instances (DBI) */
+ /* append each new DBI to the end of the list */
+ for (i=0; i < dbcount; i++) {
+
+#endif /* ISC_PLATFORM_USETHREADS */
+
+ /* how many queries were passed in from config file? */
+ switch(argc) {
+ case 5:
+ result = build_sqldbinstance(ns_g_mctx, NULL, NULL,
+ NULL, argv[3], argv[4],
+ NULL, &db);
+ break;
+ case 6:
+ result = build_sqldbinstance(ns_g_mctx, NULL, NULL,
+ argv[5], argv[3], argv[4],
+ NULL, &db);
+ break;
+ case 7:
+ result = build_sqldbinstance(ns_g_mctx, argv[6], NULL,
+ argv[5], argv[3], argv[4],
+ NULL, &db);
+ break;
+ case 8:
+ result = build_sqldbinstance(ns_g_mctx, argv[6],
+ argv[7], argv[5], argv[3],
+ argv[4], NULL, &db);
+ break;
+ default:
+ /* not really needed, should shut up compiler. */
+ result = ISC_R_FAILURE;
+ }
+
+ /* unsuccessful?, log err msg and cleanup. */
+ if (result != ISC_R_SUCCESS) {
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
+ "Odbc driver could not create "
+ "database instance object.");
+ goto cleanup;
+ }
+
+#ifdef ISC_PLATFORM_USETHREADS
+
+ /* when multithreaded, build a list of DBI's */
+ ISC_LINK_INIT(db, link);
+ ISC_LIST_APPEND(*odbc_inst->db, db, link);
+
+#endif
+
+ result = odbc_connect(odbc_inst, (odbc_db_t **) &(db->dbconn));
+
+ if (result != ISC_R_SUCCESS) {
+
+#ifdef ISC_PLATFORM_USETHREADS
+
+ /*
+ * if multi threaded, let user know which
+ * connection failed. user could be
+ * attempting to create 10 db connections and
+ * for some reason the db backend only allows
+ * 9.
+ */
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
+ "Odbc driver failed to create database "
+ "connection number %u after 3 attempts",
+ i+1);
+#else
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
+ "Odbc driver failed to create database "
+ "connection after 3 attempts");
+#endif
+ goto cleanup;
+ }
+
+#ifdef ISC_PLATFORM_USETHREADS
+
+ /* set DB = null for next loop through. */
+ db = NULL;
+
+ } /* end for loop */
+
+#else
+ /* tell odbc_inst about the db connection we just created. */
+ odbc_inst->db = db;
+
+#endif
+
+ /* set dbdata to the odbc_instance we created. */
+ *dbdata = odbc_inst;
+
+ /* hey, we got through all of that ok, return success. */
+ return(ISC_R_SUCCESS);
+
+ cleanup:
+
+ destroy_odbc_instance(odbc_inst);
+
+ return result;
+}
+
+/*%
+ * destroy an instance of the driver. Remember, only 1 copy of the driver's
+ * code is ever loaded, the driver has to remember which context it's
+ * operating in. This is done via use of the dbdata arguement.
+ * so we really only need to clean it up since we are not using driverarg.
+ */
+
+static void
+odbc_destroy(void *driverarg, void *dbdata)
+{
+ UNUSED(driverarg);
+
+ destroy_odbc_instance((odbc_instance_t *) dbdata);
+}
+
+
+/* pointers to all our runtime methods. */
+/* this is used during driver registration */
+/* i.e. in dlz_odbc_init below. */
+static dns_sdlzmethods_t dlz_odbc_methods = {
+ odbc_create,
+ odbc_destroy,
+ odbc_findzone,
+ odbc_lookup,
+ odbc_authority,
+ odbc_allnodes,
+ odbc_allowzonexfr
+};
+
+/*%
+ * Wrapper around dns_sdlzregister().
+ */
+isc_result_t
+dlz_odbc_init(void) {
+ isc_result_t result;
+
+ /*
+ * Write debugging message to log
+ */
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2),
+ "Registering DLZ odbc driver.");
+
+ /*
+ * Driver is always threadsafe. When multithreaded all
+ * functions use multithreaded code. When not multithreaded,
+ * all functions can only be entered once, but only 1 thread
+ * of operation is available in Bind. So everything is still
+ * threadsafe.
+ */
+ result = dns_sdlzregister("odbc", &dlz_odbc_methods, NULL,
+ DNS_SDLZFLAG_RELATIVEOWNER |
+ DNS_SDLZFLAG_RELATIVERDATA |
+ DNS_SDLZFLAG_THREADSAFE,
+ ns_g_mctx, &dlz_odbc);
+ /* if we can't register the driver, there are big problems. */
+ if (result != ISC_R_SUCCESS) {
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "dns_sdlzregister() failed: %s",
+ isc_result_totext(result));
+ result = ISC_R_UNEXPECTED;
+ }
+
+
+ return result;
+}
+
+/*%
+ * Wrapper around dns_sdlzunregister().
+ */
+void
+dlz_odbc_clear(void) {
+
+ /*
+ * Write debugging message to log
+ */
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2),
+ "Unregistering DLZ odbc driver.");
+
+ /* unregister the driver. */
+ if (dlz_odbc != NULL)
+ dns_sdlzunregister(&dlz_odbc);
+}
+
+#endif
--- /dev/null
+/*
+ * 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) 1999-2001 Internet Software Consortium.
+ *
+ * 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 INTERNET SOFTWARE CONSORTIUM
+ * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+ * INTERNET SOFTWARE CONSORTIUM 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.
+ */
+
+#ifdef DLZ_POSTGRES
+
+#include <config.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include <dns/log.h>
+#include <dns/sdlz.h>
+#include <dns/result.h>
+
+#include <isc/mem.h>
+#include <isc/platform.h>
+#include <isc/print.h>
+#include <isc/result.h>
+#include <isc/string.h>
+#include <isc/util.h>
+
+#include <named/globals.h>
+
+#include <dlz/sdlz_helper.h>
+#include <dlz/dlz_postgres_driver.h>
+
+/* temporarily include time. */
+#include <time.h>
+
+#include <libpq-fe.h>
+
+static dns_sdlzimplementation_t *dlz_postgres = NULL;
+
+#define dbc_search_limit 30
+#define ALLNODES 1
+#define ALLOWXFR 2
+#define AUTHORITY 3
+#define FINDZONE 4
+#define LOOKUP 5
+
+/*
+ * Private methods
+ */
+
+/* ---------------
+ * Escaping arbitrary strings to get valid SQL strings/identifiers.
+ *
+ * Replaces "\\" with "\\\\" and "'" with "''".
+ * length is the length of the buffer pointed to by
+ * from. The buffer at to must be at least 2*length + 1 characters
+ * long. A terminating NUL character is written.
+ *
+ * NOTICE!!!
+ * This function was borrowed directly from PostgreSQL's libpq.
+ * The function was originally called PQescapeString and renamed
+ * to postgres_makesafe to avoid a naming collision.
+ * PQescapeString is a new function made available in Postgres 7.2.
+ * For some reason the function is not properly exported on Win32
+ * builds making the function unavailable on Windows. Also, since
+ * this function is new it would require building this driver with
+ * the libpq 7.2. By borrowing this function the Windows problem
+ * is solved, and the dependence on libpq 7.2 is removed. Libpq is
+ * still required of course, but an older version should work now too.
+ *
+ * The copyright statements from the original file containing this
+ * function are included below:
+ * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ * ---------------
+ */
+
+static size_t
+postgres_makesafe(char *to, const char *from, size_t length)
+{
+ const char *source = from;
+ char *target = to;
+ unsigned int remaining = length;
+
+ while (remaining > 0)
+ {
+ switch (*source)
+ {
+ case '\\':
+ *target = '\\';
+ target++;
+ *target = '\\';
+ /* target and remaining are updated below. */
+ break;
+
+ case '\'':
+ *target = '\'';
+ target++;
+ *target = '\'';
+ /* target and remaining are updated below. */
+ break;
+
+ default:
+ *target = *source;
+ /* target and remaining are updated below. */
+ }
+ source++;
+ target++;
+ remaining--;
+ }
+
+ /* Write the terminating NUL character. */
+ *target = '\0';
+
+ return target - to;
+}
+
+#ifdef ISC_PLATFORM_USETHREADS
+
+/*%
+ * Properly cleans up a list of database instances.
+ * This function is only used when the driver is compiled for
+ * multithreaded operation.
+ */
+static void
+postgres_destroy_dblist(db_list_t *dblist)
+{
+
+ dbinstance_t *ndbi = NULL;
+ dbinstance_t *dbi = NULL;
+
+ /* get the first DBI in the list */
+ ndbi = ISC_LIST_HEAD(*dblist);
+
+ /* loop through the list */
+ while (ndbi != NULL) {
+ dbi = ndbi;
+ /* get the next DBI in the list */
+ ndbi = ISC_LIST_NEXT(dbi, link);
+ /* release DB connection */
+ if (dbi->dbconn != NULL)
+ PQfinish((PGconn *) dbi->dbconn);
+ /* release all memory that comprised a DBI */
+ destroy_sqldbinstance(dbi);
+ }
+ /* release memory for the list structure */
+ isc_mem_put(ns_g_mctx, dblist, sizeof(db_list_t));
+}
+
+/*%
+ * Loops through the list of DB instances, attempting to lock
+ * on the mutex. If successful, the DBI is reserved for use
+ * and the thread can perform queries against the database.
+ * If the lock fails, the next one in the list is tried.
+ * looping continues until a lock is obtained, or until
+ * the list has been searched dbc_search_limit times.
+ * This function is only used when the driver is compiled for
+ * multithreaded operation.
+ */
+
+static dbinstance_t *
+postgres_find_avail_conn(db_list_t *dblist)
+{
+ dbinstance_t *dbi = NULL;
+ dbinstance_t *head;
+ int count = 0;
+
+ /* get top of list */
+ head = dbi = ISC_LIST_HEAD(*dblist);
+
+ /* loop through list */
+ while (count < dbc_search_limit) {
+ /* try to lock on the mutex */
+ if (isc_mutex_trylock(&dbi->instance_lock) == ISC_R_SUCCESS)
+ return dbi; /* success, return the DBI for use. */
+
+ /* not successful, keep trying */
+ dbi = ISC_LIST_NEXT(dbi, link);
+
+ /* check to see if we have gone to the top of the list. */
+ if (dbi == NULL) {
+ count++;
+ dbi = head;
+ }
+ }
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_INFO,
+ "Postgres driver unable to find available connection "
+ "after searching %d times",
+ count);
+ return NULL;
+}
+
+#endif /* ISC_PLATFORM_USETHREADS */
+
+/*%
+ * Allocates memory for a new string, and then constructs the new
+ * string by "escaping" the input string. The new string is
+ * safe to be used in queries. This is necessary because we cannot
+ * be sure of what types of strings are passed to us, and we don't
+ * want special characters in the string causing problems.
+ */
+
+static char *
+postgres_escape_string(const char *instr) {
+
+ char *outstr;
+ unsigned int len;
+
+ if (instr == NULL)
+ return NULL;
+
+ len = strlen(instr);
+
+ outstr = isc_mem_allocate(ns_g_mctx ,(2 * len * sizeof(char)) + 1);
+ if (outstr == NULL)
+ return NULL;
+
+ postgres_makesafe(outstr, instr, len);
+ /* PQescapeString(outstr, instr, len); */
+
+ return outstr;
+}
+
+/*%
+ * This function is the real core of the driver. Zone, record
+ * and client strings are passed in (or NULL is passed if the
+ * string is not available). The type of query we want to run
+ * is indicated by the query flag, and the dbdata object is passed
+ * passed in to. dbdata really holds either:
+ * 1) a list of database instances (in multithreaded mode) OR
+ * 2) a single database instance (in single threaded mode)
+ * The function will construct the query and obtain an available
+ * database instance (DBI). It will then run the query and hopefully
+ * obtain a result set. Postgres is nice, in that once the result
+ * set is returned, we can make the db connection available for another
+ * thread to use, while this thread continues on. So, the DBI is made
+ * available ASAP by unlocking the instance_lock after we have cleaned
+ * it up properly.
+ */
+static isc_result_t
+postgres_get_resultset(const char *zone, const char *record,
+ const char *client, unsigned int query,
+ void *dbdata, PGresult **rs)
+{
+ isc_result_t result;
+ dbinstance_t *dbi = NULL;
+ char *querystring = NULL;
+ unsigned int i = 0;
+ unsigned int j = 0;
+
+ /* temporarily get a unique thread # */
+ unsigned int dlz_thread_num = 1+(int) (1000.0*rand()/(RAND_MAX+1.0));
+
+ REQUIRE(*rs == NULL);
+
+ /* temporary logging message */
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
+ "%d Getting DBI", dlz_thread_num);
+
+ /* get db instance / connection */
+#ifdef ISC_PLATFORM_USETHREADS
+
+ /* find an available DBI from the list */
+ dbi = postgres_find_avail_conn((db_list_t *) dbdata);
+
+#else /* ISC_PLATFORM_USETHREADS */
+
+ /*
+ * only 1 DBI - no need to lock instance lock either
+ * only 1 thread in the whole process, no possible contention.
+ */
+ dbi = (dbinstance_t *) dbdata;
+
+#endif /* ISC_PLATFORM_USETHREADS */
+
+ /* temporary logging message */
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
+ "%d Got DBI - checking query", dlz_thread_num);
+
+ /* if DBI is null, can't do anything else */
+ if (dbi == NULL) {
+ result = ISC_R_FAILURE;
+ goto cleanup;
+ }
+
+ /* what type of query are we going to run? */
+ switch(query) {
+ case ALLNODES:
+ /*
+ * if the query was not passed in from the config file
+ * then we can't run it. return not_implemented, so
+ * it's like the code for that operation was never
+ * built into the driver.... AHHH flexibility!!!
+ */
+ if (dbi->allnodes_q == NULL) {
+ result = ISC_R_NOTIMPLEMENTED;
+ goto cleanup;
+ }
+ break;
+ case ALLOWXFR:
+ /* same as comments as ALLNODES */
+ if (dbi->allowxfr_q == NULL) {
+ result = ISC_R_NOTIMPLEMENTED;
+ goto cleanup;
+ }
+ break;
+ case AUTHORITY:
+ /* same as comments as ALLNODES */
+ if (dbi->authority_q == NULL) {
+ result = ISC_R_NOTIMPLEMENTED;
+ goto cleanup;
+ }
+ break;
+ case FINDZONE:
+ /* this is required. It's the whole point of DLZ! */
+ if (dbi->findzone_q == NULL) {
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2),
+ "No query specified for findzone. "
+ "Findzone requires a query");
+ result = ISC_R_FAILURE;
+ goto cleanup;
+ }
+ break;
+ case LOOKUP:
+ /* this is required. It's also a major point of DLZ! */
+ if (dbi->lookup_q == NULL) {
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2),
+ "No query specified for lookup. "
+ "Lookup requires a query");
+ result = ISC_R_FAILURE;
+ goto cleanup;
+ }
+ break;
+ default:
+ /*
+ * this should never happen. If it does, the code is
+ * screwed up!
+ */
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "Incorrect query flag passed to "
+ "postgres_get_resultset");
+ result = ISC_R_UNEXPECTED;
+ goto cleanup;
+ }
+
+ /* temporary logging message */
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
+ "%d checked query", dlz_thread_num);
+
+ /*
+ * was a zone string passed? If so, make it safe for use in
+ * queries.
+ */
+ if (zone != NULL) {
+ dbi->zone = postgres_escape_string(zone);
+ if (dbi->zone == NULL) {
+ result = ISC_R_NOMEMORY;
+ goto cleanup;
+ }
+ } else { /* no string passed, set the string pointer to NULL */
+ dbi->zone = NULL;
+ }
+
+ /* temporary logging message */
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
+ "%d did zone", dlz_thread_num);
+
+ /*
+ * was a record string passed? If so, make it safe for use in
+ * queries.
+ */
+ if (record != NULL) {
+ dbi->record = postgres_escape_string(record);
+ if (dbi->record == NULL) {
+ result = ISC_R_NOMEMORY;
+ goto cleanup;
+ }
+ } else { /* no string passed, set the string pointer to NULL */
+ dbi->record = NULL;
+ }
+
+
+ /* temporary logging message */
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
+ "%d did record", dlz_thread_num);
+
+ /*
+ * was a client string passed? If so, make it safe for use in
+ * queries.
+ */
+ if (client != NULL) {
+ dbi->client = postgres_escape_string(client);
+ if (dbi->client == NULL) {
+ result = ISC_R_NOMEMORY;
+ goto cleanup;
+ }
+ } else { /* no string passed, set the string pointer to NULL */
+ dbi->client = NULL;
+ }
+
+ /* temporary logging message */
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
+ "%d did client", dlz_thread_num);
+
+ /*
+ * what type of query are we going to run?
+ * this time we build the actual query to run.
+ */
+ switch(query) {
+ case ALLNODES:
+ querystring = build_querystring(ns_g_mctx, dbi->allnodes_q);
+ break;
+ case ALLOWXFR:
+ querystring = build_querystring(ns_g_mctx, dbi->allowxfr_q);
+ break;
+ case AUTHORITY:
+ querystring = build_querystring(ns_g_mctx, dbi->authority_q);
+ break;
+ case FINDZONE:
+ querystring = build_querystring(ns_g_mctx, dbi->findzone_q);
+ break;
+ case LOOKUP:
+ querystring = build_querystring(ns_g_mctx, dbi->lookup_q);
+ break;
+ default:
+ /*
+ * this should never happen. If it does, the code is
+ * screwed up!
+ */
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "Incorrect query flag passed to "
+ "postgres_get_resultset");
+ result = ISC_R_UNEXPECTED;
+ goto cleanup;
+ }
+
+ /* temporary logging message */
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
+ "%d built query", dlz_thread_num);
+
+ /* if the querystring is null, Bummer, outta RAM. UPGRADE TIME!!! */
+ if (querystring == NULL) {
+ result = ISC_R_NOMEMORY;
+ goto cleanup;
+ }
+
+ /* temporary logging message */
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
+ "%d query is '%s'", dlz_thread_num, querystring);
+
+ /*
+ * output the full query string during debug so we can see
+ * what lame error the query has.
+ */
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(1),
+ "\nQuery String: %s\n", querystring);
+
+ /* attempt query up to 3 times. */
+ for (j=0; j < 3; j++) {
+ /* temporary logging message */
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
+ "%d executing query for %d time",
+ dlz_thread_num, j);
+ /* try to get result set */
+ *rs = PQexec((PGconn *)dbi->dbconn, querystring );
+ result = ISC_R_SUCCESS;
+ /*
+ * if result set is null, reset DB connection, max 3
+ * attempts.
+ */
+ for (i=0; *rs == NULL && i < 3; i++) {
+ /* temporary logging message */
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
+ "%d resetting connection",
+ dlz_thread_num);
+ result = ISC_R_FAILURE;
+ PQreset((PGconn *) dbi->dbconn);
+ /* connection ok, break inner loop */
+ if (PQstatus((PGconn *) dbi->dbconn) == CONNECTION_OK)
+ break;
+ }
+ /* result set ok, break outter loop */
+ if (PQresultStatus(*rs) == PGRES_TUPLES_OK) {
+ /* temporary logging message */
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
+ "%d rs ok", dlz_thread_num);
+ break;
+ } else {
+ /* we got a result set object, but it's not right. */
+ /* temporary logging message */
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
+ "%d clearing rs", dlz_thread_num);
+ PQclear(*rs); /* get rid of it */
+ /* in case this was the last attempt */
+ result = ISC_R_FAILURE;
+ }
+ }
+
+ cleanup:
+ /* it's always good to cleanup after yourself */
+
+ /* temporary logging message */
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
+ "%d cleaning up", dlz_thread_num);
+
+ /* if we couldn't even allocate DBI, just return NULL */
+ if (dbi == NULL)
+ return ISC_R_FAILURE;
+
+ /* free dbi->zone string */
+ if (dbi->zone != NULL)
+ isc_mem_free(ns_g_mctx, dbi->zone);
+
+ /* free dbi->record string */
+ if (dbi->record != NULL)
+ isc_mem_free(ns_g_mctx, dbi->record);
+
+ /* free dbi->client string */
+ if (dbi->client != NULL)
+ isc_mem_free(ns_g_mctx, dbi->client);
+
+#ifdef ISC_PLATFORM_USETHREADS
+
+ /* temporary logging message */
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
+ "%d unlocking mutex", dlz_thread_num);
+
+ /* release the lock so another thread can use this dbi */
+ isc_mutex_unlock(&dbi->instance_lock);
+
+#endif /* ISC_PLATFORM_USETHREADS */
+
+ /* release query string */
+ if (querystring != NULL)
+ isc_mem_free(ns_g_mctx, querystring );
+
+ /* temporary logging message */
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
+ "%d returning", dlz_thread_num);
+
+ /* return result */
+ return result;
+}
+
+/*%
+ * The processing of result sets for lookup and authority are
+ * exactly the same. So that functionality has been moved
+ * into this function to minimize code.
+ */
+
+static isc_result_t
+postgres_process_rs(dns_sdlzlookup_t *lookup, PGresult *rs)
+{
+ isc_result_t result;
+ unsigned int i;
+ unsigned int rows;
+ unsigned int fields;
+ unsigned int j;
+ unsigned int len;
+ char *tmpString;
+ char *endp;
+ int ttl;
+
+ rows = PQntuples(rs); /* how many rows in result set */
+ fields = PQnfields(rs); /* how many columns in result set */
+ for (i=0; i < rows; i++) {
+ switch(fields) {
+ case 1:
+ /*
+ * one column in rs, it's the data field. use
+ * default type of A record, and default TTL
+ * of 86400
+ */
+ result = dns_sdlz_putrr(lookup, "a", 86400,
+ PQgetvalue(rs, i, 0));
+ break;
+ case 2:
+ /* two columns, data field, and data type.
+ * use default TTL of 86400.
+ */
+ result = dns_sdlz_putrr(lookup, PQgetvalue(rs, i, 0),
+ 86400, PQgetvalue(rs, i, 1));
+ break;
+ case 3:
+ /* three columns, all data no defaults.
+ * convert text to int, make sure it worked
+ * right.
+ */
+ ttl = strtol(PQgetvalue(rs, i, 0), &endp, 10);
+ if (*endp != '\0' || ttl < 0) {
+ isc_log_write(dns_lctx,
+ DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
+ "Postgres driver ttl must be "
+ "a positive number");
+ }
+ result = dns_sdlz_putrr(lookup, PQgetvalue(rs, i, 1),
+ ttl, PQgetvalue(rs, i, 2));
+ break;
+ default:
+ /*
+ * more than 3 fields, concatenate the last
+ * ones together. figure out how long to make
+ * string
+ */
+ for (j=2, len=0; j < fields; j++) {
+ len += strlen(PQgetvalue(rs, i, j)) + 1;
+ }
+ /*
+ * allocate string memory, allow for NULL to
+ * term string
+ */
+ tmpString = isc_mem_allocate(ns_g_mctx, len + 1);
+ if (tmpString == NULL) {
+ /* major bummer, need more ram */
+ isc_log_write(dns_lctx,
+ DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
+ "Postgres driver unable to "
+ "allocate memory for "
+ "temporary string");
+ PQclear(rs);
+ return (ISC_R_FAILURE); /* Yeah, I'd say! */
+ }
+ /* copy field to tmpString */
+ strcpy(tmpString, PQgetvalue(rs, i, 2));
+ /*
+ * concat the rest of fields together, space
+ * between each one.
+ */
+ for (j=3; j < fields; j++) {
+ strcat(tmpString, " ");
+ strcat(tmpString, PQgetvalue(rs, i, j));
+ }
+ /* convert text to int, make sure it worked right */
+ ttl = strtol(PQgetvalue(rs, i, 0), &endp, 10);
+ if (*endp != '\0' || ttl < 0) {
+ isc_log_write(dns_lctx,
+ DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
+ "Postgres driver ttl must be "
+ "a postive number");
+ }
+ /* ok, now tell Bind about it. */
+ result = dns_sdlz_putrr(lookup, PQgetvalue(rs, i, 1),
+ ttl, tmpString);
+ /* done, get rid of this thing. */
+ isc_mem_free(ns_g_mctx, tmpString);
+ }
+ /* I sure hope we were successful */
+ if (result != ISC_R_SUCCESS) {
+ /* nope, get rid of the Result set, and log a msg */
+ PQclear(rs);
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
+ "dns_sdlz_putrr returned error. "
+ "Error code was: %s",
+ isc_result_totext(result));
+ return (ISC_R_FAILURE);
+ }
+ }
+
+ /* free result set memory */
+ PQclear(rs);
+
+ /* if we did return results, we are successful */
+ if (rows > 0)
+ return (ISC_R_SUCCESS);
+
+ /* empty result set, no data found */
+ return (ISC_R_NOTFOUND);
+}
+
+/*
+ * SDLZ interface methods
+ */
+
+/*% determine if the zone is supported by (in) the database */
+
+static isc_result_t
+postgres_findzone(void *driverarg, void *dbdata, const char *name)
+{
+ isc_result_t result;
+ PGresult *rs = NULL;
+ unsigned int rows;
+ UNUSED(driverarg);
+
+ /* run the query and get the result set from the database. */
+ result = postgres_get_resultset(name, NULL, NULL,
+ FINDZONE, dbdata, &rs);
+ /* if we didn't get a result set, log an err msg. */
+ if (result != ISC_R_SUCCESS) {
+ if (rs != NULL)
+ PQclear(rs);
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
+ "Postgres driver unable to return "
+ "result set for findzone query");
+ return (ISC_R_FAILURE);
+ }
+ /* count how many rows in result set */
+ rows = PQntuples(rs);
+ /* get rid of result set, we are done with it. */
+ PQclear(rs);
+
+ /* if we returned any rows, zone is supported. */
+ if (rows > 0)
+ return (ISC_R_SUCCESS);
+
+ /* no rows returned, zone is not supported. */
+ return (ISC_R_NOTFOUND);
+}
+
+/*% Determine if the client is allowed to perform a zone transfer */
+static isc_result_t
+postgres_allowzonexfr(void *driverarg, void *dbdata, const char *name,
+ const char *client)
+{
+ isc_result_t result;
+ PGresult *rs = NULL;
+ unsigned int rows;
+ UNUSED(driverarg);
+
+ /* first check if the zone is supported by the database. */
+ result = postgres_findzone(driverarg, dbdata, name);
+ if (result != ISC_R_SUCCESS)
+ return (ISC_R_NOTFOUND);
+
+ /*
+ * if we get to this point we know the zone is supported by
+ * the database the only questions now are is the zone
+ * transfer is allowed for this client and did the config file
+ * have an allow zone xfr query.
+ *
+ * Run our query, and get a result set from the database.
+ */
+ result = postgres_get_resultset(name, NULL, client,
+ ALLOWXFR, dbdata, &rs);
+ /* if we get "not implemented", send it along. */
+ if (result == ISC_R_NOTIMPLEMENTED)
+ return result;
+ /* if we didn't get a result set, log an err msg. */
+ if (result != ISC_R_SUCCESS) {
+ if (rs != NULL)
+ PQclear(rs);
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
+ "Postgres driver unable to return "
+ "result set for allow xfr query");
+ return (ISC_R_FAILURE);
+ }
+ /* count how many rows in result set */
+ rows = PQntuples(rs);
+ /* get rid of result set, we are done with it. */
+ PQclear(rs);
+
+ /* if we returned any rows, zone xfr is allowed. */
+ if (rows > 0)
+ return (ISC_R_SUCCESS);
+
+ /* no rows returned, zone xfr not allowed */
+ return (ISC_R_NOPERM);
+}
+
+/*%
+ * If the client is allowed to perform a zone transfer, the next order of
+ * business is to get all the nodes in the zone, so bind can respond to the
+ * query.
+ */
+static isc_result_t
+postgres_allnodes(const char *zone, void *driverarg, void *dbdata,
+ dns_sdlzallnodes_t *allnodes)
+{
+ isc_result_t result;
+ PGresult *rs = NULL;
+ unsigned int i;
+ unsigned int rows;
+ unsigned int fields;
+ unsigned int j;
+ unsigned int len;
+ char *tmpString;
+ char *endp;
+ int ttl;
+
+ UNUSED(driverarg);
+
+ /* run the query and get the result set from the database. */
+ result = postgres_get_resultset(zone, NULL, NULL,
+ ALLNODES, dbdata, &rs);
+ /* if we get "not implemented", send it along */
+ if (result == ISC_R_NOTIMPLEMENTED)
+ return result;
+ /* if we didn't get a result set, log an err msg. */
+ if (result != ISC_R_SUCCESS) {
+ if (rs != NULL)
+ PQclear(rs);
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
+ "Postgres driver unable to return "
+ "result set for all nodes query");
+ return (ISC_R_FAILURE);
+ }
+
+ rows = PQntuples(rs); /* how many rows in result set */
+ fields = PQnfields(rs); /* how many columns in result set */
+ for (i=0; i < rows; i++) {
+ if (fields < 4) { /* gotta have at least 4 columns */
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
+ "Postgres driver too few fields "
+ "returned by all nodes query");
+ }
+ /* convert text to int, make sure it worked right */
+ ttl = strtol(PQgetvalue(rs, i, 0), &endp, 10);
+ if (*endp != '\0' || ttl < 0) {
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
+ "Postgres driver ttl must be "
+ "a postive number");
+ }
+ if (fields == 4) {
+ /* tell Bind about it. */
+ result = dns_sdlz_putnamedrr(allnodes,
+ PQgetvalue(rs, i, 2),
+ PQgetvalue(rs, i, 1),
+ ttl,
+ PQgetvalue(rs, i, 3));
+ } else {
+ /*
+ * more than 4 fields, concatonat the last
+ * ones together. figure out how long to make
+ * string
+ */
+ for (j=3, len=0; j < fields; j++) {
+ len += strlen(PQgetvalue(rs, i, j)) + 1;
+ }
+ /* allocate memory, allow for NULL to term string */
+ tmpString = isc_mem_allocate(ns_g_mctx, len + 1);
+ if (tmpString == NULL) { /* we need more ram. */
+ isc_log_write(dns_lctx,
+ DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
+ "Postgres driver unable to "
+ "allocate memory for "
+ "temporary string");
+ PQclear(rs);
+ return (ISC_R_FAILURE);
+ }
+ /* copy this field to tmpString */
+ strcpy(tmpString, PQgetvalue(rs, i, 3));
+ /* concatonate the rest, with spaces between */
+ for (j=4; j < fields; j++) {
+ strcat(tmpString, " ");
+ strcat(tmpString, PQgetvalue(rs, i, j));
+ }
+ /* tell Bind about it. */
+ result = dns_sdlz_putnamedrr(allnodes,
+ PQgetvalue(rs, i, 2),
+ PQgetvalue(rs, i, 1),
+ ttl, tmpString);
+ isc_mem_free(ns_g_mctx, tmpString);
+ }
+ /* if we weren't successful, log err msg */
+ if (result != ISC_R_SUCCESS) {
+ PQclear(rs);
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
+ "dns_sdlz_putnamedrr returned error. "
+ "Error code was: %s",
+ isc_result_totext(result));
+ return (ISC_R_FAILURE);
+ }
+ }
+
+ /* free result set memory */
+ PQclear(rs);
+
+ /* if we did return results, we are successful */
+ if (rows > 0)
+ return (ISC_R_SUCCESS);
+
+ /* empty result set, no data found */
+ return (ISC_R_NOTFOUND);
+}
+
+/*%
+ * if the lookup function does not return SOA or NS records for the zone,
+ * use this function to get that information for Bind.
+ */
+
+static isc_result_t
+postgres_authority(const char *zone, void *driverarg, void *dbdata,
+ dns_sdlzlookup_t *lookup)
+{
+ isc_result_t result;
+ PGresult *rs = NULL;
+
+ UNUSED(driverarg);
+
+ /* run the query and get the result set from the database. */
+ result = postgres_get_resultset(zone, NULL, NULL,
+ AUTHORITY, dbdata, &rs);
+ /* if we get "not implemented", send it along */
+ if (result == ISC_R_NOTIMPLEMENTED)
+ return result;
+ /* if we didn't get a result set, log an err msg. */
+ if (result != ISC_R_SUCCESS) {
+ if (rs != NULL)
+ PQclear(rs);
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
+ "Postgres driver unable to return "
+ "result set for authority query");
+ return (ISC_R_FAILURE);
+ }
+ /*
+ * lookup and authority result sets are processed in the same
+ * manner postgres_process_rs does the job for both
+ * functions.
+ */
+ return postgres_process_rs(lookup, rs);
+}
+
+/*% if zone is supported, lookup up a (or multiple) record(s) in it */
+static isc_result_t
+postgres_lookup(const char *zone, const char *name, void *driverarg,
+ void *dbdata, dns_sdlzlookup_t *lookup)
+{
+ isc_result_t result;
+ PGresult *rs = NULL;
+
+ UNUSED(driverarg);
+
+ /* run the query and get the result set from the database. */
+ result = postgres_get_resultset(zone, name, NULL, LOOKUP, dbdata, &rs);
+ /* if we didn't get a result set, log an err msg. */
+ if (result != ISC_R_SUCCESS) {
+ if (rs != NULL)
+ PQclear(rs);
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
+ "Postgres driver unable to "
+ "return result set for lookup query");
+ return (ISC_R_FAILURE);
+ }
+ /*
+ * lookup and authority result sets are processed in the same
+ * manner postgres_process_rs does the job for both functions.
+ */
+ return postgres_process_rs(lookup, rs);
+}
+
+/*%
+ * create an instance of the driver. Remember, only 1 copy of the driver's
+ * code is ever loaded, the driver has to remember which context it's
+ * operating in. This is done via use of the dbdata arguement which is
+ * passed into all query functions.
+ */
+static isc_result_t
+postgres_create(const char *dlzname, unsigned int argc, char *argv[],
+ void *driverarg, void **dbdata)
+{
+ isc_result_t result;
+ dbinstance_t *dbi = NULL;
+ unsigned int j;
+
+#ifdef ISC_PLATFORM_USETHREADS
+ /* if multi-threaded, we need a few extra variables. */
+ int dbcount;
+ db_list_t *dblist = NULL;
+ int i;
+ char *endp;
+
+#endif /* ISC_PLATFORM_USETHREADS */
+
+ UNUSED(driverarg);
+ UNUSED(dlzname);
+
+/* seed random # generator */
+ srand( (unsigned)time( NULL ) );
+
+
+#ifdef ISC_PLATFORM_USETHREADS
+ /* if debugging, let user know we are multithreaded. */
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(1),
+ "Postgres driver running multithreaded");
+#else /* ISC_PLATFORM_USETHREADS */
+ /* if debugging, let user know we are single threaded. */
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(1),
+ "Postgres driver running single threaded");
+#endif /* ISC_PLATFORM_USETHREADS */
+
+ /* verify we have at least 5 arg's passed to the driver */
+ if (argc < 5) {
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
+ "Postgres driver requires at least "
+ "4 command line args.");
+ return (ISC_R_FAILURE);
+ }
+
+ /* no more than 8 arg's should be passed to the driver */
+ if (argc > 8) {
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
+ "Postgres driver cannot accept more than "
+ "7 command line args.");
+ return (ISC_R_FAILURE);
+ }
+
+ /* multithreaded build can have multiple DB connections */
+#ifdef ISC_PLATFORM_USETHREADS
+
+ /* check how many db connections we should create */
+ dbcount = strtol(argv[1], &endp, 10);
+ if (*endp != '\0' || dbcount < 0) {
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
+ "Postgres driver database connection count "
+ "must be positive.");
+ return (ISC_R_FAILURE);
+ }
+
+ /* allocate memory for database connection list */
+ dblist = isc_mem_get(ns_g_mctx, sizeof(db_list_t));
+ if (dblist == NULL)
+ return (ISC_R_NOMEMORY);
+
+ /* initialize DB connection list */
+ ISC_LIST_INIT(*dblist);
+
+ /*
+ * create the appropriate number of database instances (DBI)
+ * append each new DBI to the end of the list
+ */
+ for (i=0; i < dbcount; i++) {
+
+#endif /* ISC_PLATFORM_USETHREADS */
+
+ /* how many queries were passed in from config file? */
+ switch(argc) {
+ case 5:
+ result = build_sqldbinstance(ns_g_mctx, NULL, NULL,
+ NULL, argv[3], argv[4],
+ NULL, &dbi);
+ break;
+ case 6:
+ result = build_sqldbinstance(ns_g_mctx, NULL, NULL,
+ argv[5], argv[3], argv[4],
+ NULL, &dbi);
+ break;
+ case 7:
+ result = build_sqldbinstance(ns_g_mctx, argv[6], NULL,
+ argv[5], argv[3], argv[4],
+ NULL, &dbi);
+ break;
+ case 8:
+ result = build_sqldbinstance(ns_g_mctx, argv[6],
+ argv[7], argv[5], argv[3],
+ argv[4], NULL, &dbi);
+ break;
+ default:
+ /* not really needed, should shut up compiler. */
+ result = ISC_R_FAILURE;
+ }
+
+
+ if (result == ISC_R_SUCCESS) {
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2),
+ "Postgres driver created database "
+ "instance object.");
+ } else { /* unsuccessful?, log err msg and cleanup. */
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
+ "Postgres driver could not create "
+ "database instance object.");
+ goto cleanup;
+ }
+
+#ifdef ISC_PLATFORM_USETHREADS
+
+ /* when multithreaded, build a list of DBI's */
+ ISC_LINK_INIT(dbi, link);
+ ISC_LIST_APPEND(*dblist, dbi, link);
+
+#endif
+
+ /* create and set db connection */
+ dbi->dbconn = PQconnectdb(argv[2]);
+ /*
+ * if db connection cannot be created, log err msg and
+ * cleanup.
+ */
+ if (dbi->dbconn == NULL) {
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
+ "Postgres driver could not allocate "
+ "memory for database connection");
+ goto cleanup;
+ }
+
+ /* if we cannot connect the first time, try 3 more times. */
+ for (j = 0;
+ PQstatus((PGconn *) dbi->dbconn) != CONNECTION_OK &&
+ j < 3;
+ j++)
+ PQreset((PGconn *) dbi->dbconn);
+
+
+#ifdef ISC_PLATFORM_USETHREADS
+
+ /*
+ * if multi threaded, let user know which connection
+ * failed. user could be attempting to create 10 db
+ * connections and for some reason the db backend only
+ * allows 9
+ */
+ if (PQstatus((PGconn *) dbi->dbconn) != CONNECTION_OK) {
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
+ "Postgres driver failed to create "
+ "database connection number %u "
+ "after 4 attempts",
+ i + 1);
+ goto cleanup;
+ }
+
+ /* set DBI = null for next loop through. */
+ dbi = NULL;
+ } /* end for loop */
+
+ /* set dbdata to the list we created. */
+ *dbdata = dblist;
+
+#else /* ISC_PLATFORM_USETHREADS */
+ /* if single threaded, just let user know we couldn't connect. */
+ if (PQstatus((PGconn *) dbi->dbconn) != CONNECTION_OK) {
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
+ "Postgres driver failed to create database "
+ "connection after 4 attempts");
+ goto cleanup;
+ }
+
+ /*
+ * single threaded build can only use 1 db connection, return
+ * it via dbdata
+ */
+ *dbdata = dbi;
+
+#endif /* ISC_PLATFORM_USETHREADS */
+
+ /* hey, we got through all of that ok, return success. */
+ return(ISC_R_SUCCESS);
+
+ cleanup:
+
+#ifdef ISC_PLATFORM_USETHREADS
+ /*
+ * if multithreaded, we could fail because only 1 connection
+ * couldn't be made. We should cleanup the other successful
+ * connections properly.
+ */
+ postgres_destroy_dblist(dblist);
+
+#else /* ISC_PLATFORM_USETHREADS */
+ if (dbi != NULL)
+ destroy_sqldbinstance(dbi);
+
+#endif /* ISC_PLATFORM_USETHREADS */
+ return(ISC_R_FAILURE);
+}
+
+/*%
+ * destroy an instance of the driver. Remember, only 1 copy of the driver's
+ * code is ever loaded, the driver has to remember which context it's
+ * operating in. This is done via use of the dbdata arguement.
+ * so we really only need to clean it up since we are not using driverarg.
+ */
+static void
+postgres_destroy(void *driverarg, void *dbdata)
+{
+
+#ifdef ISC_PLATFORM_USETHREADS
+
+ UNUSED(driverarg);
+ /* cleanup the list of DBI's */
+ postgres_destroy_dblist((db_list_t *) dbdata);
+
+#else /* ISC_PLATFORM_USETHREADS */
+
+ dbinstance_t *dbi;
+
+ UNUSED(driverarg);
+
+ dbi = (dbinstance_t *) dbdata;
+
+ /* release DB connection */
+ if (dbi->dbconn != NULL)
+ PQfinish((PGconn *) dbi->dbconn);
+
+ /* destroy single DB instance */
+ destroy_sqldbinstance(dbi);
+
+#endif /* ISC_PLATFORM_USETHREADS */
+}
+
+/* pointers to all our runtime methods. */
+/* this is used during driver registration */
+/* i.e. in dlz_postgres_init below. */
+static dns_sdlzmethods_t dlz_postgres_methods = {
+ postgres_create,
+ postgres_destroy,
+ postgres_findzone,
+ postgres_lookup,
+ postgres_authority,
+ postgres_allnodes,
+ postgres_allowzonexfr
+};
+
+/*%
+ * Wrapper around dns_sdlzregister().
+ */
+isc_result_t
+dlz_postgres_init(void) {
+ isc_result_t result;
+
+ /*
+ * Write debugging message to log
+ */
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2),
+ "Registering DLZ postgres driver.");
+
+ /*
+ * Driver is always threadsafe. When multithreaded all
+ * functions use multithreaded code. When not multithreaded,
+ * all functions can only be entered once, but only 1 thread
+ * of operation is available in Bind. So everything is still
+ * threadsafe.
+ */
+ result = dns_sdlzregister("postgres", &dlz_postgres_methods, NULL,
+ DNS_SDLZFLAG_RELATIVEOWNER |
+ DNS_SDLZFLAG_RELATIVERDATA |
+ DNS_SDLZFLAG_THREADSAFE,
+ ns_g_mctx, &dlz_postgres);
+ /* if we can't register the driver, there are big problems. */
+ if (result != ISC_R_SUCCESS) {
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "dns_sdlzregister() failed: %s",
+ isc_result_totext(result));
+ result = ISC_R_UNEXPECTED;
+ }
+
+
+ return result;
+}
+
+/*%
+ * Wrapper around dns_sdlzunregister().
+ */
+void
+dlz_postgres_clear(void) {
+
+ /*
+ * Write debugging message to log
+ */
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2),
+ "Unregistering DLZ postgres driver.");
+
+ /* unregister the driver. */
+ if (dlz_postgres != NULL)
+ dns_sdlzunregister(&dlz_postgres);
+}
+
+#endif
--- /dev/null
+/*
+ * 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) 1999-2001 Internet Software Consortium.
+ *
+ * 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 INTERNET SOFTWARE CONSORTIUM
+ * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+ * INTERNET SOFTWARE CONSORTIUM 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.
+ */
+
+#ifdef DLZ_STUB
+
+#include <config.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include <dns/log.h>
+#include <dns/sdlz.h>
+#include <dns/result.h>
+
+#include <isc/mem.h>
+#include <isc/print.h>
+#include <isc/result.h>
+#include <isc/util.h>
+
+#include <named/globals.h>
+
+#include <dlz/dlz_stub_driver.h>
+
+static dns_sdlzimplementation_t *dlz_stub = NULL;
+
+typedef struct config_data {
+ char *myzone;
+ char *myname;
+ char *myip;
+ isc_mem_t *mctx;
+} config_data_t;
+
+/*
+ * SDLZ methods
+ */
+
+static isc_result_t
+stub_dlz_allnodes(const char *zone, void *driverarg, void *dbdata,
+ dns_sdlzallnodes_t *allnodes)
+{
+ config_data_t *cd;
+ isc_result_t result;
+
+ UNUSED(zone);
+ UNUSED(driverarg);
+
+ cd = (config_data_t *) dbdata;
+
+ result = dns_sdlz_putnamedrr(allnodes, cd->myname, "soa", 86400,
+ "web root.localhost. "
+ "0 28800 7200 604800 86400");
+ if (result != ISC_R_SUCCESS)
+ return (ISC_R_FAILURE);
+ result = dns_sdlz_putnamedrr(allnodes, "ns", "ns", 86400, cd->myname);
+ if (result != ISC_R_SUCCESS)
+ return (ISC_R_FAILURE);
+ result = dns_sdlz_putnamedrr(allnodes, cd->myname, "a", 1, cd->myip);
+ if (result != ISC_R_SUCCESS)
+ return (ISC_R_FAILURE);
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+stub_dlz_allowzonexfr(void *driverarg, void *dbdata, const char *name,
+ const char *client)
+{
+ UNUSED(driverarg);
+ UNUSED(dbdata);
+ UNUSED(name);
+ UNUSED(client);
+ return ISC_R_SUCCESS;
+}
+
+static isc_result_t
+stub_dlz_authority(const char *zone, void *driverarg, void *dbdata,
+ dns_sdlzlookup_t *lookup)
+{
+ isc_result_t result;
+ config_data_t *cd;
+
+ UNUSED(driverarg);
+
+ cd = (config_data_t *) dbdata;
+
+ if (strcmp(zone, cd->myzone) == 0) {
+ result = dns_sdlz_putsoa(lookup, cd->myname,
+ "root.localhost.", 0);
+ if (result != ISC_R_SUCCESS)
+ return (ISC_R_FAILURE);
+
+ result = dns_sdlz_putrr(lookup, "ns", 86400, cd->myname);
+ if (result != ISC_R_SUCCESS)
+ return (ISC_R_FAILURE);
+
+ return (ISC_R_SUCCESS);
+ }
+ return (ISC_R_NOTFOUND);
+}
+
+static isc_result_t
+stub_dlz_findzonedb(void *driverarg, void *dbdata, const char *name)
+{
+
+ config_data_t *cd;
+
+ UNUSED(driverarg);
+
+ cd = (config_data_t *) dbdata;
+
+ /* Write info message to log */
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2),
+ "dlz_stub findzone looking for '%s'", name);
+
+ if (strcmp(cd->myzone, name) == 0)
+ return (ISC_R_SUCCESS);
+ else
+ return (ISC_R_SUCCESS);
+}
+
+
+static isc_result_t
+stub_dlz_lookup(const char *zone, const char *name, void *driverarg,
+ void *dbdata, dns_sdlzlookup_t *lookup)
+{
+ isc_result_t result;
+ config_data_t *cd;
+
+ UNUSED(zone);
+ UNUSED(driverarg);
+
+ cd = (config_data_t *) dbdata;
+
+ if (strcmp(name, cd->myname) == 0) {
+ result = dns_sdlz_putrr(lookup, "a", 1, cd->myip);
+ if (result != ISC_R_SUCCESS)
+ return (ISC_R_FAILURE);
+
+ return (ISC_R_SUCCESS);
+ }
+ return (ISC_R_FAILURE);
+
+}
+
+
+static isc_result_t
+stub_dlz_create(const char *dlzname, unsigned int argc, char *argv[],
+ void *driverarg, void **dbdata)
+{
+
+ config_data_t *cd;
+
+ UNUSED(driverarg);
+
+ if (argc < 4)
+ return (ISC_R_FAILURE);
+ /*
+ * Write info message to log
+ */
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_INFO,
+ "Loading '%s' using DLZ_stub driver. "
+ "Zone: %s, Name: %s IP: %s",
+ dlzname, argv[1], argv[2], argv[3]);
+
+ cd = isc_mem_get(ns_g_mctx, sizeof(config_data_t));
+ if ((cd) == NULL) {
+ return (ISC_R_NOMEMORY);
+ }
+
+ memset(cd, 0, sizeof(config_data_t));
+
+ cd->myzone = isc_mem_strdup(ns_g_mctx, argv[1]);
+ if (cd->myzone == NULL) {
+ isc_mem_put(ns_g_mctx, cd, sizeof(config_data_t));
+ return (ISC_R_NOMEMORY);
+ }
+
+ cd->myname = isc_mem_strdup(ns_g_mctx, argv[2]);
+ if (cd->myname == NULL) {
+ isc_mem_put(ns_g_mctx, cd, sizeof(config_data_t));
+ isc_mem_free(ns_g_mctx, cd->myzone);
+ return (ISC_R_NOMEMORY);
+ }
+
+ cd->myip = isc_mem_strdup(ns_g_mctx, argv[3]);
+ if (cd->myip == NULL) {
+ isc_mem_put(ns_g_mctx, cd, sizeof(config_data_t));
+ isc_mem_free(ns_g_mctx, cd->myname);
+ isc_mem_free(ns_g_mctx, cd->myzone);
+ return (ISC_R_NOMEMORY);
+ }
+
+ isc_mem_attach(ns_g_mctx, &cd->mctx);
+
+ *dbdata = cd;
+
+ return(ISC_R_SUCCESS);
+}
+
+static void
+stub_dlz_destroy(void *driverarg, void *dbdata)
+{
+ config_data_t *cd;
+ isc_mem_t *mctx;
+
+ UNUSED(driverarg);
+
+ cd = (config_data_t *) dbdata;
+
+ /*
+ * Write debugging message to log
+ */
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2),
+ "Unloading DLZ_stub driver.");
+
+ isc_mem_free(ns_g_mctx, cd->myzone);
+ isc_mem_free(ns_g_mctx, cd->myname);
+ isc_mem_free(ns_g_mctx, cd->myip);
+ mctx = cd->mctx;
+ isc_mem_put(mctx, cd, sizeof(config_data_t));
+ isc_mem_detach(&mctx);
+}
+
+static dns_sdlzmethods_t dlz_stub_methods = {
+ stub_dlz_create,
+ stub_dlz_destroy,
+ stub_dlz_findzonedb,
+ stub_dlz_lookup,
+ stub_dlz_authority,
+ stub_dlz_allnodes,
+ stub_dlz_allowzonexfr
+};
+
+/*%
+ * Wrapper around dns_sdlzregister().
+ */
+isc_result_t
+dlz_stub_init(void) {
+ isc_result_t result;
+
+ /*
+ * Write debugging message to log
+ */
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2),
+ "Registering DLZ_stub driver.");
+
+ result = dns_sdlzregister("dlz_stub", &dlz_stub_methods, NULL,
+ DNS_SDLZFLAG_RELATIVEOWNER |
+ DNS_SDLZFLAG_RELATIVERDATA,
+ ns_g_mctx, &dlz_stub);
+ if (result != ISC_R_SUCCESS) {
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "dns_sdlzregister() failed: %s",
+ isc_result_totext(result));
+ result = ISC_R_UNEXPECTED;
+ }
+
+
+ return result;
+}
+
+/*
+ * Wrapper around dns_sdlzunregister().
+ */
+void
+dlz_stub_clear(void) {
+
+ /*
+ * Write debugging message to log
+ */
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2),
+ "Unregistering DLZ_stub driver.");
+
+ if (dlz_stub != NULL)
+ dns_sdlzunregister(&dlz_stub);
+}
+
+#endif
--- /dev/null
+/*
+ * 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.
+ */
+
+#ifndef DLZ_BDB_DRIVER_H
+#define DLZ_BDB_DRIVER_H
+
+isc_result_t
+dlz_bdb_init(void);
+
+void
+dlz_bdb_clear(void);
+
+#endif
--- /dev/null
+/*
+ * 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.
+ */
+
+#ifndef DLZ_BDBHPT_DRIVER_H
+#define DLZ_BDBHPT_DRIVER_H
+
+isc_result_t
+dlz_bdbhpt_init(void);
+
+void
+dlz_bdbhpt_clear(void);
+
+#endif
--- /dev/null
+/*
+ * Copyright (C) 2005 Internet Systems Consortium, Inc. ("ISC")
+ *
+ * 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 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.
+ */
+
+/* $Id: dlz_drivers.h,v 1.2 2005/09/05 00:10:58 marka Exp $ */
+
+#ifndef DLZ_DRIVERS_H
+#define DLZ_DRIVERS_H 1
+
+/*! \file */
+
+isc_result_t
+dlz_drivers_init(void);
+
+void
+dlz_drivers_clear(void);
+
+#endif /* DLZ_DRIVERS_H */
--- /dev/null
+/*
+ * 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.
+ */
+
+#ifndef DLZ_FILESYSTEM_DRIVER_H
+#define DLZ_FILESYSTEM_DRIVER_H
+
+isc_result_t
+dlz_fs_init(void);
+
+void
+dlz_fs_clear(void);
+
+#endif
--- /dev/null
+/*
+ * 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.
+ */
+
+#ifndef DLZ_LDAP_DRIVER_H
+#define DLZ_LDAP_DRIVER_H
+
+isc_result_t
+dlz_ldap_init(void);
+
+void
+dlz_ldap_clear(void);
+
+#endif
--- /dev/null
+/*
+ * 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.
+ */
+
+#ifndef DLZ_MYSQL_DRIVER_H
+#define DLZ_MYSQL_DRIVER_H
+
+isc_result_t
+dlz_mysql_init(void);
+
+void
+dlz_mysql_clear(void);
+
+#endif
--- /dev/null
+/*
+ * 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.
+ */
+
+#ifndef DLZ_ODBC_DRIVER_H
+#define DLZ_ODBC_DRIVER_H
+
+isc_result_t
+dlz_odbc_init(void);
+
+void
+dlz_odbc_clear(void);
+
+#endif
--- /dev/null
+/*
+ * 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.
+ */
+
+#ifndef DLZ_POSTGRES_DRIVER_H
+#define DLZ_POSTGRES_DRIVER_H
+
+isc_result_t
+dlz_postgres_init(void);
+
+void
+dlz_postgres_clear(void);
+
+#endif
--- /dev/null
+/*
+ * 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.
+ */
+
+#ifndef DLZ_STUB_DRIVER_H
+#define DLZ_STUB_DRIVER_H
+
+isc_result_t
+dlz_stub_init(void);
+
+void
+dlz_stub_clear(void);
+
+#endif
--- /dev/null
+/*
+ * 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.
+ */
+
+#ifndef SDLZHELPER_H
+#define SDLZHELPER_H
+
+/*
+ * Types
+ */
+#define SDLZH_REQUIRE_CLIENT 0x01
+#define SDLZH_REQUIRE_QUERY 0x02
+#define SDLZH_REQUIRE_RECORD 0x04
+#define SDLZH_REQUIRE_ZONE 0x08
+
+typedef struct query_segment query_segment_t;
+typedef ISC_LIST(query_segment_t) query_list_t;
+typedef struct dbinstance dbinstance_t;
+typedef ISC_LIST(dbinstance_t) db_list_t;
+typedef struct driverinstance driverinstance_t;
+
+/*%
+ * a query segment is all the text between our special tokens
+ * special tokens are %zone%, %record%, %client%
+ */
+struct query_segment {
+ void *sql;
+ unsigned int strlen;
+ isc_boolean_t direct;
+ ISC_LINK(query_segment_t) link;
+};
+
+/*%
+ * a database instance contains everything we need for running
+ * a query against the database. Using it each separate thread
+ * can dynamically construct a query and execute it against the
+ * database. The "instance_lock" and locking code in the driver's
+ * make sure no two threads try to use the same DBI at a time.
+ */
+struct dbinstance {
+ void *dbconn;
+ query_list_t *allnodes_q;
+ query_list_t *allowxfr_q;
+ query_list_t *authority_q;
+ query_list_t *findzone_q;
+ query_list_t *lookup_q;
+ query_list_t *countzone_q;
+ char *query_buf;
+ char *zone;
+ char *record;
+ char *client;
+ isc_mem_t *mctx;
+ isc_mutex_t instance_lock;
+ ISC_LINK(dbinstance_t) link;
+};
+
+/*
+ * Method declarations
+ */
+
+/* see the code in sdlz_helper.c for more information on these methods */
+
+char *
+sdlzh_build_querystring(isc_mem_t *mctx, query_list_t *querylist);
+
+isc_result_t
+sdlzh_build_sqldbinstance(isc_mem_t *mctx, const char *allnodes_str,
+ const char *allowxfr_str, const char *authority_str,
+ const char *findzone_str, const char *lookup_str,
+ const char *countzone_str, dbinstance_t **dbi);
+
+void
+sdlzh_destroy_sqldbinstance(dbinstance_t *dbi);
+
+char *
+sdlzh_get_parameter_value(isc_mem_t *mctx, const char *input, const char* key);
+
+/* Compatability with existing DLZ drivers */
+
+#define build_querystring sdlzh_build_querystring
+#define build_sqldbinstance sdlzh_build_sqldbinstance
+#define destroy_sqldbinstance sdlzh_destroy_sqldbinstance
+
+#define getParameterValue(x,y) sdlzh_get_parameter_value(ns_g_mctx, (x), (y))
+
+#endif /* SDLZHELPER_H */
--- /dev/null
+# Copyright (C) 2005 Internet Systems Consortium, Inc. ("ISC")
+#
+# 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 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.
+
+# $Id: rules.in,v 1.2 2005/09/05 00:10:57 marka Exp $
+
+dlz_drivers.@O@: ${DLZ_DRIVER_DIR}/dlz_drivers.c ${DLZ_DRIVER_DIR}/include/dlz/dlz_drivers.h
+ ${LIBTOOL_MODE_COMPILE} ${CC} ${ALL_CFLAGS} -c ${DLZ_DRIVER_DIR}/dlz_drivers.c
+
+sdlz_helper.@O@: ${DLZ_DRIVER_DIR}/sdlz_helper.c ${DLZ_DRIVER_DIR}/include/dlz/sdlz_helper.h
+ ${LIBTOOL_MODE_COMPILE} ${CC} ${ALL_CFLAGS} -c ${DLZ_DRIVER_DIR}/sdlz_helper.c
+
+
+dlz_bdb_driver.@O@: ${DLZ_DRIVER_DIR}/dlz_bdb_driver.c ${DLZ_DRIVER_DIR}/include/dlz/dlz_bdb_driver.h
+ ${LIBTOOL_MODE_COMPILE} ${CC} ${ALL_CFLAGS} -c ${DLZ_DRIVER_DIR}/dlz_bdb_driver.c
+
+dlz_bdbhpt_driver.@O@: ${DLZ_DRIVER_DIR}/dlz_bdbhpt_driver.c ${DLZ_DRIVER_DIR}/include/dlz/dlz_bdbhpt_driver.h
+ ${LIBTOOL_MODE_COMPILE} ${CC} ${ALL_CFLAGS} -c ${DLZ_DRIVER_DIR}/dlz_bdbhpt_driver.c
+
+dlz_filesystem_driver.@O@: ${DLZ_DRIVER_DIR}/dlz_filesystem_driver.c ${DLZ_DRIVER_DIR}/include/dlz/dlz_filesystem_driver.h
+ ${LIBTOOL_MODE_COMPILE} ${CC} ${ALL_CFLAGS} -c ${DLZ_DRIVER_DIR}/dlz_filesystem_driver.c
+
+dlz_ldap_driver.@O@: ${DLZ_DRIVER_DIR}/dlz_ldap_driver.c ${DLZ_DRIVER_DIR}/include/dlz/dlz_ldap_driver.h
+ ${LIBTOOL_MODE_COMPILE} ${CC} ${ALL_CFLAGS} -c ${DLZ_DRIVER_DIR}/dlz_ldap_driver.c
+
+dlz_mysql_driver.@O@: ${DLZ_DRIVER_DIR}/dlz_mysql_driver.c ${DLZ_DRIVER_DIR}/include/dlz/dlz_mysql_driver.h
+ ${LIBTOOL_MODE_COMPILE} ${CC} ${ALL_CFLAGS} -c ${DLZ_DRIVER_DIR}/dlz_mysql_driver.c
+
+dlz_odbc_driver.@O@: ${DLZ_DRIVER_DIR}/dlz_odbc_driver.c ${DLZ_DRIVER_DIR}/include/dlz/dlz_odbc_driver.h
+ ${LIBTOOL_MODE_COMPILE} ${CC} ${ALL_CFLAGS} -c ${DLZ_DRIVER_DIR}/dlz_odbc_driver.c
+
+dlz_postgres_driver.@O@: ${DLZ_DRIVER_DIR}/dlz_postgres_driver.c ${DLZ_DRIVER_DIR}/include/dlz/dlz_postgres_driver.h
+ ${LIBTOOL_MODE_COMPILE} ${CC} ${ALL_CFLAGS} -c ${DLZ_DRIVER_DIR}/dlz_postgres_driver.c
+
+dlz_stub_driver.@O@: ${DLZ_DRIVER_DIR}/dlz_stub_driver.c ${DLZ_DRIVER_DIR}/include/dlz/dlz_stub_driver.h
+ ${LIBTOOL_MODE_COMPILE} ${CC} ${ALL_CFLAGS} -c ${DLZ_DRIVER_DIR}/dlz_stub_driver.c
+
--- /dev/null
+/*
+ * 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) 1999-2001 Internet Software Consortium.
+ *
+ * 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 INTERNET SOFTWARE CONSORTIUM
+ * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+ * INTERNET SOFTWARE CONSORTIUM 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.
+ */
+
+#ifdef DLZ
+
+#include <config.h>
+
+#include <dns/log.h>
+#include <dns/result.h>
+
+#include <isc/mem.h>
+#include <isc/result.h>
+#include <isc/string.h>
+#include <isc/util.h>
+
+#include <dlz/sdlz_helper.h>
+
+/*
+ * sdlz helper methods
+ */
+
+/*%
+ * properly destroys a querylist by de-allocating the
+ * memory for each query segment, and then the list itself
+ */
+
+static void
+destroy_querylist(isc_mem_t *mctx, query_list_t **querylist)
+{
+ query_segment_t *tseg = NULL;
+ query_segment_t *nseg = NULL;
+
+ REQUIRE(mctx != NULL);
+
+ /* if query list is null, nothing to do */
+ if (*querylist == NULL)
+ return;
+
+ /* start at the top of the list */
+ nseg = ISC_LIST_HEAD(**querylist);
+ while (nseg != NULL) { /* loop, until end of list */
+ tseg = nseg;
+ /*
+ * free the query segment's text string but only if it
+ * was really a query segment, and not a pointer to
+ * %zone%, or %record%, or %client%
+ */
+ if (tseg->sql != NULL && tseg->direct == isc_boolean_true)
+ isc_mem_free(mctx, tseg->sql);
+ /* get the next query segment, before we destroy this one. */
+ nseg = ISC_LIST_NEXT(nseg, link);
+ /* deallocate this query segment. */
+ isc_mem_put(mctx, tseg, sizeof(query_segment_t));
+ }
+ /* deallocate the query segment list */
+ isc_mem_put(mctx, *querylist, sizeof(query_list_t));
+}
+
+/*% constructs a query list by parsing a string into query segments */
+static isc_result_t
+build_querylist(isc_mem_t *mctx, const char *query_str, char **zone,
+ char **record, char **client, query_list_t **querylist,
+ unsigned int flags)
+{
+ isc_result_t result;
+ isc_boolean_t foundzone = isc_boolean_false;
+ isc_boolean_t foundrecord = isc_boolean_false;
+ isc_boolean_t foundclient = isc_boolean_false;
+ char *temp_str = NULL;
+ char *right_str = NULL;
+ query_list_t *tql;
+ query_segment_t *tseg = NULL;
+
+ REQUIRE(querylist != NULL && *querylist == NULL);
+ REQUIRE(mctx != NULL);
+
+ /* if query string is null, or zero length */
+ if (query_str == NULL || strlen(query_str) < 1) {
+ if ((flags & SDLZH_REQUIRE_QUERY) == 0)
+ /* we don't need it were ok. */
+ return (ISC_R_SUCCESS);
+ else
+ /* we did need it, PROBLEM!!! */
+ return (ISC_R_FAILURE);
+ }
+
+ /* allocate memory for query list */
+ tql = isc_mem_get(mctx, sizeof(query_list_t));
+ /* couldn't allocate memory. Problem!! */
+ if (tql == NULL)
+ return (ISC_R_NOMEMORY);
+
+ /* initialize the query segment list */
+ ISC_LIST_INIT(*tql);
+
+ /* make a copy of query_str so we can chop it up */
+ temp_str = right_str = isc_mem_strdup(mctx, query_str);
+ /* couldn't make a copy, problem!! */
+ if (right_str == NULL) {
+ result = ISC_R_NOMEMORY;
+ goto cleanup;
+ }
+
+ /* loop through the string and chop it up */
+ while (right_str != NULL) {
+ /* allocate memory for tseg */
+ tseg = isc_mem_get(mctx, sizeof(query_segment_t));
+ if (tseg == NULL) { /* no memory, clean everything up. */
+ result = ISC_R_NOMEMORY;
+ goto cleanup;
+ }
+ tseg->sql = NULL;
+ tseg->direct = isc_boolean_false;
+ /* initialize the query segment link */
+ ISC_LINK_INIT(tseg, link);
+ /* append the query segment to the list */
+ ISC_LIST_APPEND(*tql, tseg, link);
+
+ /*
+ * split string at the first "%". set query segment to
+ * left portion
+ */
+ tseg->sql = isc_mem_strdup(mctx,
+ isc_string_separate(&right_str,
+ "%"));
+ if (tseg->sql == NULL) {
+ /* no memory, clean everything up. */
+ result = ISC_R_NOMEMORY;
+ goto cleanup;
+ }
+ /* tseg->sql points directly to a string. */
+ tseg->direct = isc_boolean_true;
+ tseg->strlen = strlen(tseg->sql);
+
+ /* check if we encountered "%zone%" token */
+ if (strcasecmp(tseg->sql, "zone") == 0) {
+ /*
+ * we don't really need, or want the "zone"
+ * text, so get rid of it.
+ */
+ isc_mem_free(mctx, tseg->sql);
+ /* set tseg->sql to in-direct zone string */
+ tseg->sql = (char**) zone;
+ tseg->strlen = 0;
+ /* tseg->sql points in-directly to a string */
+ tseg->direct = isc_boolean_false;
+ foundzone = isc_boolean_true;
+ /* check if we encountered "%record%" token */
+ } else if (strcasecmp(tseg->sql, "record") == 0) {
+ /*
+ * we don't really need, or want the "record"
+ * text, so get rid of it.
+ */
+ isc_mem_free(mctx, tseg->sql);
+ /* set tseg->sql to in-direct record string */
+ tseg->sql = (char**) record;
+ tseg->strlen = 0;
+ /* tseg->sql points in-directly poinsts to a string */
+ tseg->direct = isc_boolean_false;
+ foundrecord = isc_boolean_true;
+ /* check if we encountered "%client%" token */
+ } else if (strcasecmp(tseg->sql, "client") == 0) {
+ /*
+ * we don't really need, or want the "client"
+ * text, so get rid of it.
+ */
+ isc_mem_free(mctx, tseg->sql);
+ /* set tseg->sql to in-direct record string */
+ tseg->sql = (char**) client;
+ tseg->strlen = 0;
+ /* tseg->sql points in-directly poinsts to a string */
+ tseg->direct = isc_boolean_false;
+ foundclient = isc_boolean_true;
+ }
+ }
+
+ /* we don't need temp_str any more */
+ isc_mem_free(mctx, temp_str);
+ /*
+ * add checks later to verify zone and record are found if
+ * necessary.
+ */
+
+ /* if this query requires %client%, make sure we found it */
+ if (((flags & SDLZH_REQUIRE_CLIENT) != 0) && (!foundclient) ) {
+ /* Write error message to log */
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
+ "Required token %%client%% not found.");
+ result = ISC_R_FAILURE;
+ goto flag_fail;
+ }
+
+ /* if this query requires %record%, make sure we found it */
+ if (((flags & SDLZH_REQUIRE_RECORD) != 0) && (!foundrecord) ) {
+ /* Write error message to log */
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
+ "Required token %%record%% not found.");
+ result = ISC_R_FAILURE;
+ goto flag_fail;
+ }
+
+ /* if this query requires %zone%, make sure we found it */
+ if (((flags & SDLZH_REQUIRE_ZONE) != 0) && (!foundzone) ) {
+ /* Write error message to log */
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
+ "Required token %%zone%% not found.");
+ result = ISC_R_FAILURE;
+ goto flag_fail;
+ }
+
+ /* pass back the query list */
+ *querylist = (query_list_t *) tql;
+
+ /* return success */
+ return (ISC_R_SUCCESS);
+
+ cleanup:
+ /* get rid of temp_str */
+ if (temp_str != NULL)
+ isc_mem_free(mctx, temp_str);
+
+ flag_fail:
+ /* get rid of what was build of the query list */
+ if (tql != NULL)
+ destroy_querylist(mctx, &tql);
+ return result;
+}
+
+/*%
+ * build a query string from query segments, and dynamic segments
+ * dynamic segments replace where the tokens %zone%, %record%, %client%
+ * used to be in our queries from named.conf
+ */
+char *
+sdlzh_build_querystring(isc_mem_t *mctx, query_list_t *querylist)
+{
+ query_segment_t *tseg = NULL;
+ unsigned int length = 0;
+ char *qs = NULL;
+
+ REQUIRE(mctx != NULL);
+ REQUIRE(querylist != NULL);
+
+ /* start at the top of the list */
+ tseg = ISC_LIST_HEAD(*querylist);
+ while (tseg != NULL) {
+ /*
+ * if this is a query segment, use the
+ * precalculated string length
+ */
+ if (tseg->direct == isc_boolean_true)
+ length += tseg->strlen;
+ else /* calculate string length for dynamic segments. */
+ length += strlen(* (char**) tseg->sql);
+ /* get the next segment */
+ tseg = ISC_LIST_NEXT(tseg, link);
+ }
+
+ /* allocate memory for the string */
+ qs = isc_mem_allocate(mctx, length + 1);
+ /* couldn't allocate memory, We need more ram! */
+ if (qs == NULL)
+ return NULL;
+
+ /* start at the top of the list again */
+ tseg = ISC_LIST_HEAD(*querylist);
+ /* copy the first item in the list to the query string */
+ if (tseg->direct == isc_boolean_true) /* query segment */
+ strcpy(qs, tseg->sql);
+ else
+ strcpy(qs, * (char**) tseg->sql); /* dynamic segment */
+
+ /* concatonate the rest of the segments */
+ while ((tseg = ISC_LIST_NEXT(tseg, link)) != NULL) {
+ if (tseg->direct == isc_boolean_true)
+ /* query segments */
+ strcat(qs, tseg->sql);
+ else
+ /* dynamic segments */
+ strcat(qs, * (char**) tseg->sql);
+ }
+
+ return qs;
+}
+
+/*% constructs a sql dbinstance (DBI) */
+isc_result_t
+sdlzh_build_sqldbinstance(isc_mem_t *mctx, const char *allnodes_str,
+ const char *allowxfr_str, const char *authority_str,
+ const char *findzone_str, const char *lookup_str,
+ const char *countzone_str, dbinstance_t **dbi)
+{
+
+ isc_result_t result;
+ dbinstance_t *db = NULL;
+
+ REQUIRE(dbi != NULL && *dbi == NULL);
+ REQUIRE(mctx != NULL);
+
+ /* allocate and zero memory for driver structure */
+ db = isc_mem_get(mctx, sizeof(dbinstance_t));
+ if (db == NULL) {
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
+ "Could not allocate memory for "
+ "database instance object.");
+ return (ISC_R_NOMEMORY);
+ }
+ memset(db, 0, sizeof(dbinstance_t));
+ db->dbconn = NULL;
+ db->client = NULL;
+ db->record = NULL;
+ db->zone = NULL;
+ db->mctx = NULL;
+ db->query_buf = NULL;
+ db->allnodes_q = NULL;
+ db->allowxfr_q = NULL;
+ db->authority_q = NULL;
+ db->findzone_q = NULL;
+ db->countzone_q = NULL;
+ db->lookup_q = NULL;
+
+ /* attach to the memory context */
+ isc_mem_attach(mctx, &db->mctx);
+
+ /* initialize the reference count mutex */
+ result = isc_mutex_init(&db->instance_lock);
+ if (result != ISC_R_SUCCESS) {
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "isc_mutex_init() failed: %s",
+ isc_result_totext(result));
+ goto cleanup;
+ }
+
+ /* build the all nodes query list */
+ result = build_querylist(mctx, allnodes_str, &db->zone,
+ &db->record, &db->client,
+ &db->allnodes_q, SDLZH_REQUIRE_ZONE);
+ /* if unsuccessful, log err msg and cleanup */
+ if (result != ISC_R_SUCCESS) {
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
+ "Could not build all nodes query list");
+ goto cleanup;
+ }
+
+ /* build the allow zone transfer query list */
+ result = build_querylist(mctx, allowxfr_str, &db->zone,
+ &db->record, &db->client,
+ &db->allowxfr_q,
+ SDLZH_REQUIRE_ZONE | SDLZH_REQUIRE_CLIENT);
+ /* if unsuccessful, log err msg and cleanup */
+ if (result != ISC_R_SUCCESS) {
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
+ "Could not build allow xfr query list");
+ goto cleanup;
+ }
+
+ /* build the authority query, query list */
+ result = build_querylist(mctx, authority_str, &db->zone,
+ &db->record, &db->client,
+ &db->authority_q, SDLZH_REQUIRE_ZONE);
+ /* if unsuccessful, log err msg and cleanup */
+ if (result != ISC_R_SUCCESS) {
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
+ "Could not build authority query list");
+ goto cleanup;
+ }
+
+ /* build findzone query, query list */
+ result = build_querylist(mctx, findzone_str, &db->zone,
+ &db->record, &db->client,
+ &db->findzone_q, SDLZH_REQUIRE_ZONE);
+ /* if unsuccessful, log err msg and cleanup */
+ if (result != ISC_R_SUCCESS) {
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
+ "Could not build find zone query list");
+ goto cleanup;
+ }
+
+ /* build countzone query, query list */
+ result = build_querylist(mctx, countzone_str, &db->zone,
+ &db->record, &db->client,
+ &db->countzone_q, SDLZH_REQUIRE_ZONE);
+ /* if unsuccessful, log err msg and cleanup */
+ if (result != ISC_R_SUCCESS) {
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
+ "Could not build count zone query list");
+ goto cleanup;
+ }
+
+ /* build lookup query, query list */
+ result = build_querylist(mctx, lookup_str, &db->zone,
+ &db->record, &db->client,
+ &db->lookup_q, SDLZH_REQUIRE_RECORD);
+ /* if unsuccessful, log err msg and cleanup */
+ if (result != ISC_R_SUCCESS) {
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
+ "Could not build lookup query list");
+ goto cleanup;
+ }
+
+ /* pass back the db instance */
+ *dbi = (dbinstance_t *) db;
+
+ /* return success */
+ return (ISC_R_SUCCESS);
+
+ cleanup:
+ /* destroy whatever was build of the db instance */
+ destroy_sqldbinstance(db);
+ /* return failure */
+ return (ISC_R_FAILURE);
+}
+
+void
+sdlzh_destroy_sqldbinstance(dbinstance_t *dbi)
+{
+ isc_mem_t *mctx;
+
+ /* save mctx for later */
+ mctx = dbi->mctx;
+
+ /* destroy any query lists we created */
+ destroy_querylist(mctx, &dbi->allnodes_q);
+ destroy_querylist(mctx, &dbi->allowxfr_q);
+ destroy_querylist(mctx, &dbi->authority_q);
+ destroy_querylist(mctx, &dbi->findzone_q);
+ destroy_querylist(mctx, &dbi->countzone_q);
+ destroy_querylist(mctx, &dbi->lookup_q);
+
+ /* get rid of the mutex */
+ isc_mutex_destroy(&dbi->instance_lock);
+
+ /* return, and detach the memory */
+ isc_mem_put(mctx, dbi, sizeof(dbinstance_t));
+ isc_mem_detach(&mctx);
+}
+
+char *
+sdlzh_get_parameter_value(isc_mem_t *mctx, const char *input, const char* key)
+{
+ int keylen;
+ char *keystart;
+ char value[255];
+ int i;
+
+ if (key == NULL || input == NULL || strlen(input) < 1)
+ return NULL;
+
+ keylen = strlen(key);
+
+ if (keylen < 1)
+ return NULL;
+
+ keystart = strstr(input, key);
+
+ if (keystart == NULL)
+ return NULL;
+
+ REQUIRE(mctx != NULL);
+
+ for (i = 0; i < 255; i++) {
+ value[i] = keystart[keylen + i];
+ if (value[i] == ' ' || value[i] == '\0') {
+ value[i] = '\0';
+ break;
+ }
+ }
+
+ return isc_mem_strdup(mctx, value);
+}
+
+#endif
# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
# PERFORMANCE OF THIS SOFTWARE.
-# $Id: Makefile.in,v 1.151 2005/07/18 23:59:36 marka Exp $
+# $Id: Makefile.in,v 1.152 2005/09/05 00:11:01 marka Exp $
srcdir = @srcdir@
VPATH = @srcdir@
DNSOBJS = acache.@O@ acl.@O@ adb.@O@ byaddr.@O@ \
cache.@O@ callbacks.@O@ compress.@O@ \
db.@O@ dbiterator.@O@ dbtable.@O@ diff.@O@ dispatch.@O@ \
- dnssec.@O@ ds.@O@ forward.@O@ journal.@O@ keytable.@O@ \
+ dlz.@O@ dnssec.@O@ ds.@O@ forward.@O@ journal.@O@ keytable.@O@ \
lib.@O@ log.@O@ lookup.@O@ \
master.@O@ masterdump.@O@ message.@O@ \
name.@O@ ncache.@O@ nsec.@O@ order.@O@ peer.@O@ portlist.@O@ \
rbt.@O@ rbtdb.@O@ rbtdb64.@O@ rcode.@O@ rdata.@O@ \
rdatalist.@O@ \
rdataset.@O@ rdatasetiter.@O@ rdataslab.@O@ request.@O@ \
- resolver.@O@ result.@O@ rootns.@O@ sdb.@O@ soa.@O@ ssu.@O@ \
+ resolver.@O@ result.@O@ rootns.@O@ sdb.@O@ sdlz.@O@ \
+ soa.@O@ ssu.@O@ \
stats.@O@ tcpmsg.@O@ time.@O@ timer.@O@ tkey.@O@ \
tsig.@O@ ttl.@O@ validator.@O@ \
version.@O@ view.@O@ xfrin.@O@ zone.@O@ zonekey.@O@ zt.@O@
DNSSRCS = acache.c acl.c adb.c byaddr.c \
cache.c callbacks.c compress.c \
db.c dbiterator.c dbtable.c diff.c dispatch.c \
- dnssec.c ds.c forward.c journal.c keytable.c \
+ dlz.c dnssec.c ds.c forward.c journal.c keytable.c \
lib.c log.c lookup.c \
master.c masterdump.c message.c \
name.c ncache.c nsec.c order.c peer.c portlist.c \
rbt.c rbtdb.c rbtdb64.c rcode.c rdata.c \
rdatalist.c \
rdataset.c rdatasetiter.c rdataslab.c request.c \
- resolver.c result.c rootns.c sdb.c soa.c ssu.c \
+ resolver.c result.c rootns.c sdb.c sdlz.c \
+ soa.c ssu.c \
stats.c tcpmsg.c time.c timer.c tkey.c \
tsig.c ttl.c validator.c \
version.c view.c xfrin.c zone.c zonekey.c zt.c ${OTHERSRCS}
--- /dev/null
+/*
+ * 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) 1999-2001 Internet Software Consortium.
+ *
+ * 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 INTERNET SOFTWARE CONSORTIUM
+ * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+ * INTERNET SOFTWARE CONSORTIUM 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.
+ */
+
+/* $Id: dlz.c,v 1.2 2005/09/05 00:11:01 marka Exp $ */
+
+/*! \file */
+
+/***
+ *** Imports
+ ***/
+
+#include <config.h>
+
+#include <dns/fixedname.h>
+#include <dns/log.h>
+#include <dns/master.h>
+#include <dns/dlz.h>
+
+
+#include <isc/buffer.h>
+#include <isc/magic.h>
+#include <isc/mem.h>
+#include <isc/once.h>
+#include <isc/rwlock.h>
+#include <isc/string.h>
+#include <isc/util.h>
+
+/***
+ *** Supported DLZ DB Implementations Registry
+ ***/
+
+static ISC_LIST(dns_dlzimplementation_t) dlz_implementations;
+static isc_rwlock_t dlz_implock;
+static isc_once_t once = ISC_ONCE_INIT;
+
+static void
+dlz_initialize(void) {
+ RUNTIME_CHECK(isc_rwlock_init(&dlz_implock, 0, 0) == ISC_R_SUCCESS);
+ ISC_LIST_INIT(dlz_implementations);
+}
+
+/*%
+ * Searches the dlz_implementations list for a driver matching name.
+ */
+static inline dns_dlzimplementation_t *
+dlz_impfind(const char *name) {
+ dns_dlzimplementation_t *imp;
+
+ for (imp = ISC_LIST_HEAD(dlz_implementations);
+ imp != NULL;
+ imp = ISC_LIST_NEXT(imp, link))
+ if (strcasecmp(name, imp->name) == 0)
+ return (imp);
+ return (NULL);
+}
+
+/***
+ *** Basic DLZ Methods
+ ***/
+
+isc_result_t
+dns_dlzallowzonexfr(dns_view_t *view, dns_name_t *name,
+ isc_sockaddr_t *clientaddr, dns_db_t **dbp)
+{
+ isc_result_t result;
+ dns_dlzallowzonexfr_t allowzonexfr;
+ dns_dlzdb_t *dlzdatabase;
+
+ /*
+ * Performs checks to make sure data is as we expect it to be.
+ */
+ REQUIRE(DNS_DLZ_VALID(view->dlzdatabase));
+ REQUIRE(name != NULL);
+ REQUIRE(dbp != NULL && *dbp == NULL);
+
+ /* ask driver if the zone is supported */
+ dlzdatabase = view->dlzdatabase;
+ allowzonexfr = dlzdatabase->implementation->methods->allowzonexfr;
+ result = (*allowzonexfr)(dlzdatabase->implementation->driverarg,
+ dlzdatabase->dbdata, dlzdatabase->mctx,
+ view->rdclass, name, clientaddr, dbp);
+
+ if (result == ISC_R_NOTIMPLEMENTED)
+ return (ISC_R_NOTFOUND);
+ return (result);
+}
+
+isc_result_t
+dns_dlzcreate(isc_mem_t *mctx, const char *dlzname, const char *drivername,
+ unsigned int argc, char *argv[], dns_dlzdb_t **dbp)
+{
+ dns_dlzimplementation_t *impinfo;
+ isc_result_t result;
+
+ /*
+ * initialize the dlz_implementations list, this is guaranteed
+ * to only really happen once.
+ */
+ RUNTIME_CHECK(isc_once_do(&once, dlz_initialize) == ISC_R_SUCCESS);
+
+ /*
+ * Performs checks to make sure data is as we expect it to be.
+ */
+ REQUIRE(dbp != NULL && *dbp == NULL);
+ REQUIRE(dlzname != NULL);
+ REQUIRE(drivername != NULL);
+ REQUIRE(mctx != NULL);
+
+ /* write log message */
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_INFO,
+ "Loading '%s' using driver %s", dlzname, drivername);
+
+ /* lock the dlz_implementations list so we can search it. */
+ RWLOCK(&dlz_implock, isc_rwlocktype_read);
+
+ /* search for the driver implementation */
+ impinfo = dlz_impfind(drivername);
+ if (impinfo == NULL) {
+ RWUNLOCK(&dlz_implock, isc_rwlocktype_read);
+
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
+ "unsupported DLZ database driver '%s'."
+ " %s not loaded.",
+ drivername, dlzname);
+
+ return (ISC_R_NOTFOUND);
+ }
+
+ /* Allocate memory to hold the DLZ database driver */
+ (*dbp) = isc_mem_get(mctx, sizeof(dns_dlzdb_t));
+ if ((*dbp) == NULL) {
+ RWUNLOCK(&dlz_implock, isc_rwlocktype_read);
+ return (ISC_R_NOMEMORY);
+ }
+
+ /* Make sure memory region is set to all 0's */
+ memset((*dbp), 0, sizeof(dns_dlzdb_t));
+
+ (*dbp)->implementation = impinfo;
+
+ /* Create a new database using implementation 'drivername'. */
+ result = ((impinfo->methods->create)(mctx, dlzname, argc, argv,
+ impinfo->driverarg,
+ &(*dbp)->dbdata));
+
+ /* mark the DLZ driver as valid */
+ if (result == ISC_R_SUCCESS) {
+ RWUNLOCK(&dlz_implock, isc_rwlocktype_read);
+ (*dbp)->magic = DNS_DLZ_MAGIC;
+ isc_mem_attach(mctx, &(*dbp)->mctx);
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2),
+ "DLZ driver loaded successfully.");
+ return (ISC_R_SUCCESS);
+ } else {
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
+ "DLZ driver failed to load.");
+ }
+
+ /* impinfo->methods->create failed. */
+ RWUNLOCK(&dlz_implock, isc_rwlocktype_read);
+ isc_mem_put(mctx, (*dbp), sizeof(dns_dlzdb_t));
+ return (result);
+}
+
+void
+dns_dlzdestroy(dns_dlzdb_t **dbp) {
+ isc_mem_t *mctx;
+ dns_dlzdestroy_t destroy;
+
+ /* Write debugging message to log */
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2),
+ "Unloading DLZ driver.");
+
+ /*
+ * Perform checks to make sure data is as we expect it to be.
+ */
+ REQUIRE(dbp != NULL && DNS_DLZ_VALID(*dbp));
+
+ /* call the drivers destroy method */
+ if ((*dbp) != NULL) {
+ mctx = (*dbp)->mctx;
+ destroy = (*dbp)->implementation->methods->destroy;
+ (*destroy)((*dbp)->implementation->driverarg,(*dbp)->dbdata);
+ /* return memory */
+ isc_mem_put(mctx, (*dbp), sizeof(dns_dlzdb_t));
+ isc_mem_detach(&mctx);
+ }
+
+ *dbp = NULL;
+}
+
+
+isc_result_t
+dns_dlzfindzone(dns_view_t *view, dns_name_t *name, unsigned int minlabels,
+ dns_db_t **dbp)
+{
+ dns_fixedname_t fname;
+ dns_name_t *zonename;
+ unsigned int namelabels;
+ unsigned int i;
+ isc_result_t result;
+ dns_dlzfindzone_t findzone;
+ dns_dlzdb_t *dlzdatabase;
+
+ /*
+ * Performs checks to make sure data is as we expect it to be.
+ */
+ REQUIRE(DNS_DLZ_VALID(view->dlzdatabase));
+ REQUIRE(name != NULL);
+ REQUIRE(dbp != NULL && *dbp == NULL);
+
+ /* setup a "fixed" dns name */
+ dns_fixedname_init(&fname);
+ zonename = dns_fixedname_name(&fname);
+
+ /* count the number of labels in the name */
+ namelabels = dns_name_countlabels(name);
+
+ /*
+ * loop through starting with the longest domain name and
+ * trying shorter names portions of the name until we find a
+ * match, have an error, or are below the 'minlabels'
+ * threshold. minlabels is 0, if the standard database didn't
+ * have a zone name match. Otherwise minlables is the number
+ * of labels in that name. We need to beat that for a
+ * "better" match for the DLZ database to be authoritative
+ * instead of the standard database.
+ */
+ for (i = namelabels; i > minlabels && i > 1; i--) {
+ if (i == namelabels) {
+ result = dns_name_copy(name, zonename, NULL);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ } else
+ dns_name_split(name, i, NULL, zonename);
+
+ /* ask SDLZ driver if the zone is supported */
+ dlzdatabase = view->dlzdatabase;
+ findzone = dlzdatabase->implementation->methods->findzone;
+ result = (*findzone)(dlzdatabase->implementation->driverarg,
+ dlzdatabase->dbdata, dlzdatabase->mctx,
+ view->rdclass, zonename, dbp);
+ if (result != ISC_R_NOTFOUND)
+ return (result);
+ }
+ return (ISC_R_NOTFOUND);
+}
+
+/*%
+ * Registers a DLZ driver. This basically just adds the dlz
+ * driver to the list of available drivers in the dlz_implementations list.
+ */
+isc_result_t
+dns_dlzregister(const char *drivername, const dns_dlzmethods_t *methods,
+ void *driverarg, isc_mem_t *mctx,
+ dns_dlzimplementation_t **dlzimp)
+{
+
+ dns_dlzimplementation_t *dlz_imp;
+
+ /* Write debugging message to log */
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2),
+ "Registering DLZ driver '%s'", drivername);
+
+ /*
+ * Performs checks to make sure data is as we expect it to be.
+ */
+ REQUIRE(drivername != NULL);
+ REQUIRE(methods != NULL);
+ REQUIRE(methods->create != NULL);
+ REQUIRE(methods->destroy != NULL);
+ REQUIRE(methods->findzone != NULL);
+ REQUIRE(mctx != NULL);
+ REQUIRE(dlzimp != NULL && *dlzimp == NULL);
+
+ /*
+ * initialize the dlz_implementations list, this is guaranteed
+ * to only really happen once.
+ */
+ RUNTIME_CHECK(isc_once_do(&once, dlz_initialize) == ISC_R_SUCCESS);
+
+ /* lock the dlz_implementations list so we can modify it. */
+ RWLOCK(&dlz_implock, isc_rwlocktype_write);
+
+ /*
+ * check that another already registered driver isn't using
+ * the same name
+ */
+ dlz_imp = dlz_impfind(drivername);
+ if (dlz_imp != NULL) {
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2),
+ "DLZ Driver '%s' already registered",
+ drivername);
+ RWUNLOCK(&dlz_implock, isc_rwlocktype_write);
+ return (ISC_R_EXISTS);
+ }
+
+ /*
+ * Allocate memory for a dlz_implementation object. Error if
+ * we cannot.
+ */
+ dlz_imp = isc_mem_get(mctx, sizeof(dns_dlzimplementation_t));
+ if (dlz_imp == NULL) {
+ RWUNLOCK(&dlz_implock, isc_rwlocktype_write);
+ return (ISC_R_NOMEMORY);
+ }
+
+ /* Make sure memory region is set to all 0's */
+ memset(dlz_imp, 0, sizeof(dns_dlzimplementation_t));
+
+ /* Store the data passed into this method */
+ dlz_imp->name = drivername;
+ dlz_imp->methods = methods;
+ dlz_imp->mctx = NULL;
+ dlz_imp->driverarg = driverarg;
+
+ /* attach the new dlz_implementation object to a memory context */
+ isc_mem_attach(mctx, &dlz_imp->mctx);
+
+ /*
+ * prepare the dlz_implementation object to be put in a list,
+ * and append it to the list
+ */
+ ISC_LINK_INIT(dlz_imp, link);
+ ISC_LIST_APPEND(dlz_implementations, dlz_imp, link);
+
+ /* Unlock the dlz_implementations list. */
+ RWUNLOCK(&dlz_implock, isc_rwlocktype_write);
+
+ /* Pass back the dlz_implementation that we created. */
+ *dlzimp = dlz_imp;
+
+ return (ISC_R_SUCCESS);
+}
+
+/*%
+ * Helper function for dns_dlzstrtoargv().
+ * Pardon the gratuitous recursion.
+ */
+static isc_result_t
+dns_dlzstrtoargvsub(isc_mem_t *mctx, char *s, unsigned int *argcp,
+ char ***argvp, unsigned int n)
+{
+ isc_result_t result;
+
+ restart:
+ /* Discard leading whitespace. */
+ while (*s == ' ' || *s == '\t')
+ s++;
+
+ if (*s == '\0') {
+ /* We have reached the end of the string. */
+ *argcp = n;
+ *argvp = isc_mem_get(mctx, n * sizeof(char *));
+ if (*argvp == NULL)
+ return (ISC_R_NOMEMORY);
+ } else {
+ char *p = s;
+ while (*p != ' ' && *p != '\t' && *p != '\0' && *p != '{') {
+ if (*p == '\n') {
+ *p = ' ';
+ goto restart;
+ }
+ p++;
+ }
+
+ /* do "grouping", items between { and } are one arg */
+ if (*p == '{') {
+ char *t = p;
+ /*
+ * shift all characters to left by 1 to get rid of '{'
+ */
+ while (*t != '\0') {
+ t++;
+ *(t-1) = *t;
+ }
+ while (*p != '\0' && *p != '}') {
+ p++;
+ }
+ /* get rid of '}' character */
+ if (*p == '}') {
+ *p = '\0';
+ p++;
+ }
+ /* normal case, no "grouping" */
+ } else if (*p != '\0')
+ *p++ = '\0';
+
+ result = dns_dlzstrtoargvsub(mctx, p, argcp, argvp, n + 1);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ (*argvp)[n] = s;
+ }
+ return (ISC_R_SUCCESS);
+}
+
+/*%
+ * Tokenize the string "s" into whitespace-separated words,
+ * return the number of words in '*argcp' and an array
+ * of pointers to the words in '*argvp'. The caller
+ * must free the array using isc_mem_put(). The string
+ * is modified in-place.
+ */
+isc_result_t
+dns_dlzstrtoargv(isc_mem_t *mctx, char *s,
+ unsigned int *argcp, char ***argvp)
+{
+ return(dns_dlzstrtoargvsub(mctx, s, argcp, argvp, 0));
+}
+
+/*%
+ * Unregisters a DLZ driver. This basically just removes the dlz
+ * driver from the list of available drivers in the dlz_implementations list.
+ */
+void
+dns_dlzunregister(dns_dlzimplementation_t **dlzimp) {
+ dns_dlzimplementation_t *dlz_imp;
+ isc_mem_t *mctx;
+
+ /* Write debugging message to log */
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2),
+ "Unregistering DLZ driver.");
+
+ /*
+ * Performs checks to make sure data is as we expect it to be.
+ */
+ REQUIRE(dlzimp != NULL && *dlzimp != NULL);
+
+ /*
+ * initialize the dlz_implementations list, this is guaranteed
+ * to only really happen once.
+ */
+ RUNTIME_CHECK(isc_once_do(&once, dlz_initialize) == ISC_R_SUCCESS);
+
+ dlz_imp = *dlzimp;
+
+ /* lock the dlz_implementations list so we can modify it. */
+ RWLOCK(&dlz_implock, isc_rwlocktype_write);
+
+ /* remove the dlz_implementation object from the list */
+ ISC_LIST_UNLINK(dlz_implementations, dlz_imp, link);
+ mctx = dlz_imp->mctx;
+
+ /*
+ * return the memory back to the available memory pool and
+ * remove it from the memory context.
+ */
+ isc_mem_put(mctx, dlz_imp, sizeof(dns_dlzimplementation_t));
+ isc_mem_detach(&mctx);
+
+ /* Unlock the dlz_implementations list. */
+ RWUNLOCK(&dlz_implock, isc_rwlocktype_write);
+}
--- /dev/null
+/*
+ * 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) 1999-2001 Internet Software Consortium.
+ *
+ * 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 INTERNET SOFTWARE CONSORTIUM
+ * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+ * INTERNET SOFTWARE CONSORTIUM 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.
+ */
+
+/* $Id: dlz.h,v 1.2 2005/09/05 00:11:02 marka Exp $ */
+
+/*! \file */
+
+#ifndef DLZ_H
+#define DLZ_H 1
+
+/*****
+ ***** Module Info
+ *****/
+
+/*
+ * DLZ Interface
+ *
+ * The DLZ interface allows zones to be looked up using a driver instead of
+ * Bind's default in memory zone table.
+ *
+ *
+ * Reliability:
+ * No anticipated impact.
+ *
+ * Resources:
+ *
+ * Security:
+ * No anticipated impact.
+ *
+ * Standards:
+ * None.
+ */
+
+/*****
+ ***** Imports
+ *****/
+
+#include <dns/name.h>
+#include <dns/types.h>
+#include <dns/view.h>
+
+#include <isc/lang.h>
+
+ISC_LANG_BEGINDECLS
+
+/***
+ *** Types
+ ***/
+
+#define DNS_DLZ_MAGIC ISC_MAGIC('D','L','Z','D')
+#define DNS_DLZ_VALID(dlz) ISC_MAGIC_VALID(dlz, DNS_DLZ_MAGIC)
+
+typedef isc_result_t
+(*dns_dlzallowzonexfr_t)(void *driverarg, void *dbdata, isc_mem_t *mctx,
+ dns_rdataclass_t rdclass, dns_name_t *name,
+ isc_sockaddr_t *clientaddr,
+ dns_db_t **dbp);
+
+/*%<
+ * Method prototype. Drivers implementing the DLZ interface MUST
+ * supply an allow zone transfer method. This method is called when
+ * the DNS server is performing a zone transfer query. The driver's
+ * method should return ISC_R_SUCCESS and a database pointer to the
+ * name server if the zone is supported by the database, and zone
+ * transfer is allowed. Otherwise it will return ISC_R_NOTFOUND if
+ * the zone is not supported by the database, or ISC_R_NOPERM if zone
+ * transfers are not allowed. If an error occurs it should return a
+ * result code indicating the type of error.
+ */
+
+typedef isc_result_t
+(*dns_dlzcreate_t)(isc_mem_t *mctx, const char *dlzname, unsigned int argc,
+ char *argv[], void *driverarg, void **dbdata);
+
+/*%<
+ * Method prototype. Drivers implementing the DLZ interface MUST
+ * supply a create method. This method is called when the DNS server
+ * is starting up and creating drivers for use later.
+ */
+
+typedef void
+(*dns_dlzdestroy_t)(void *driverarg, void **dbdata);
+
+/*%<
+ * Method prototype. Drivers implementing the DLZ interface MUST
+ * supply a destroy method. This method is called when the DNS server
+ * is shuting down and no longer needs the driver.
+ */
+
+typedef isc_result_t
+(*dns_dlzfindzone_t)(void *driverarg, void *dbdata, isc_mem_t *mctx,
+ dns_rdataclass_t rdclass, dns_name_t *name,
+ dns_db_t **dbp);
+
+/*%<
+
+ * Method prototype. Drivers implementing the DLZ interface MUST
+ * supply a find zone method. This method is called when the DNS
+ * server is performing a query. The find zone method will be called
+ * with the longest possible name first, and continue to be called
+ * with successively shorter domain names, until any of the following
+ * occur:
+ *
+ * \li 1) a match is found, and the function returns (ISC_R_SUCCESS)
+ *
+ * \li 2) a problem occurs, and the functions returns anything other
+ * than (ISC_R_NOTFOUND)
+ * \li 3) we run out of domain name labels. I.E. we have tried the
+ * shortest domain name
+ * \li 4) the number of labels in the domain name is less than
+ * min_lables for dns_dlzfindzone
+ *
+ * The driver's find zone method should return ISC_R_SUCCESS and a
+ * database pointer to the name server if the zone is supported by the
+ * database. Otherwise it will return ISC_R_NOTFOUND, and a null
+ * pointer if the zone is not supported. If an error occurs it should
+ * return a result code indicating the type of error.
+ */
+
+/*% the methods supplied by a DLZ driver */
+typedef struct dns_dlzmethods {
+ dns_dlzcreate_t create;
+ dns_dlzdestroy_t destroy;
+ dns_dlzfindzone_t findzone;
+ dns_dlzallowzonexfr_t allowzonexfr;
+} dns_dlzmethods_t;
+
+/*% information about a DLZ driver */
+struct dns_dlzimplementation {
+ const char *name;
+ const dns_dlzmethods_t *methods;
+ isc_mem_t *mctx;
+ void *driverarg;
+ ISC_LINK(dns_dlzimplementation_t) link;
+};
+
+/*% an instance of a DLZ driver */
+struct dns_dlzdb {
+ unsigned int magic;
+ isc_mem_t *mctx;
+ dns_dlzimplementation_t *implementation;
+ void *dbdata;
+};
+
+
+/***
+ *** Method declarations
+ ***/
+
+isc_result_t
+dns_dlzallowzonexfr(dns_view_t *view, dns_name_t *name,
+ isc_sockaddr_t *clientaddr, dns_db_t **dbp);
+
+/*%<
+ * This method is called when the DNS server is performing a zone
+ * transfer query. It will call the DLZ driver's allow zone tranfer
+ * method.
+ */
+
+isc_result_t
+dns_dlzcreate(isc_mem_t *mctx, const char *dlzname,
+ const char *drivername, unsigned int argc,
+ char *argv[], dns_dlzdb_t **dbp);
+
+/*%<
+ * This method is called when the DNS server is starting up and
+ * creating drivers for use later. It will search the DLZ driver list
+ * for 'drivername' and return a DLZ driver via dbp if a match is
+ * found. If the DLZ driver supplies a create method, this function
+ * will call it.
+ */
+
+void
+dns_dlzdestroy(dns_dlzdb_t **dbp);
+
+/*%<
+ * This method is called when the DNS server is shuting down and no
+ * longer needs the driver. If the DLZ driver supplies a destroy
+ * methods, this function will call it.
+ */
+
+isc_result_t
+dns_dlzfindzone(dns_view_t *view, dns_name_t *name,
+ unsigned int minlabels, dns_db_t **dbp);
+
+/*%<
+ * This method is called when the DNS server is performing a query.
+ * It will call the DLZ driver's find zone method.
+ */
+
+isc_result_t
+dns_dlzregister(const char *drivername, const dns_dlzmethods_t *methods,
+ void *driverarg, isc_mem_t *mctx,
+ dns_dlzimplementation_t **dlzimp);
+
+/*%<
+ * Register a dynamically loadable zones (DLZ) driver for the database
+ * type 'drivername', implemented by the functions in '*methods'.
+ *
+ * dlzimp must point to a NULL dlz_implementation_t pointer. That is,
+ * dlzimp != NULL && *dlzimp == NULL. It will be assigned a value that
+ * will later be used to identify the driver when deregistering it.
+ */
+
+isc_result_t
+dns_dlzstrtoargv(isc_mem_t *mctx, char *s, unsigned int *argcp, char ***argvp);
+
+/*%<
+ * This method is called when the name server is starting up to parse
+ * the DLZ driver command line from named.conf. Basically it splits
+ * up a string into and argc / argv. The primary difference of this
+ * method is items between braces { } are considered only 1 word. for
+ * example the command line "this is { one grouped phrase } and this
+ * isn't" would be parsed into:
+ *
+ * \li argv[0]: "this"
+ * \li argv[1]: "is"
+ * \li argv{2]: " one grouped phrase "
+ * \li argv[3]: "and"
+ * \li argv[4]: "this"
+ * \li argv{5}: "isn't"
+ *
+ * braces should NOT be nested, more than one grouping in the command
+ * line is allowed. Notice, argv[2] has an extra space at the
+ * beginning and end. Extra spaces are not stripped between a
+ * grouping. You can do so in your driver if needed, or be sure not
+ * to put extra spaces before / after the braces.
+ */
+
+void
+dns_dlzunregister(dns_dlzimplementation_t **dlzimp);
+
+/*%<
+ * Removes the dlz driver from the list of registered dlz drivers.
+ * There must be no active dlz drivers of this type when this function
+ * is called.
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* DLZ_H */
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: log.h,v 1.36 2005/04/29 00:22:59 marka Exp $ */
+/* $Id: log.h,v 1.37 2005/09/05 00:11:02 marka Exp $ */
/*! \file
* \author Principal Authors: DCL */
#define DNS_LOGMODULE_DIFF (&dns_modules[23])
#define DNS_LOGMODULE_HINTS (&dns_modules[24])
#define DNS_LOGMODULE_ACACHE (&dns_modules[25])
+#define DNS_LOGMODULE_DLZ (&dns_modules[26])
ISC_LANG_BEGINDECLS
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: name.h,v 1.116 2005/05/19 04:59:04 marka Exp $ */
+/* $Id: name.h,v 1.117 2005/09/05 00:11:03 marka Exp $ */
#ifndef DNS_NAME_H
#define DNS_NAME_H 1
* \li ISC_FALSE 'name' does not have a dedicated buffer.
*/
-
/***
*** Properties
***/
* Requires:
*\li 'name' is a valid name.
*
- * \li 'suffixlabels' cannot exceed the number of labels in 'name'.
+ *\li 'suffixlabels' cannot exceed the number of labels in 'name'.
*
- *\li 'prefix' is a valid name or NULL, and cannot be read-only.
+ * \li 'prefix' is a valid name or NULL, and cannot be read-only.
*
*\li 'suffix' is a valid name or NULL, and cannot be read-only.
*
--- /dev/null
+/*
+ * 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) 1999-2001 Internet Software Consortium.
+ *
+ * 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 INTERNET SOFTWARE CONSORTIUM
+ * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+ * INTERNET SOFTWARE CONSORTIUM 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.
+ */
+
+/* $Id: sdlz.h,v 1.2 2005/09/05 00:11:03 marka Exp $ */
+
+/*! \file */
+
+#ifndef SDLZ_H
+#define SDLZ_H 1
+
+#include <dns/dlz.h>
+
+ISC_LANG_BEGINDECLS
+
+#define DNS_SDLZFLAG_THREADSAFE 0x00000001U
+#define DNS_SDLZFLAG_RELATIVEOWNER 0x00000002U
+#define DNS_SDLZFLAG_RELATIVERDATA 0x00000004U
+
+ /* A simple DLZ database. */
+typedef struct dns_sdlz_db dns_sdlz_db_t;
+
+ /* A simple DLZ database lookup in progress. */
+typedef struct dns_sdlzlookup dns_sdlzlookup_t;
+
+ /* A simple DLZ database traversal in progress. */
+typedef struct dns_sdlzallnodes dns_sdlzallnodes_t;
+
+
+typedef isc_result_t
+(*dns_sdlzallnodesfunc_t)(const char *zone, void *driverarg, void *dbdata,
+ dns_sdlzallnodes_t *allnodes);
+
+/*%<
+ * Method prototype. Drivers implementing the SDLZ interface may
+ * supply an all nodes method. This method is called when the DNS
+ * server is performing a zone transfer query, after the allow zone
+ * transfer method has been called. This method is only called if the
+ * allow zone transfer method returned ISC_R_SUCCESS. This method and
+ * the allow zone transfer method are both required for zone transfers
+ * to be supported. If the driver generates data dynamically (instead
+ * of searching in a database for it) it should not implement this
+ * function as a zone transfer would be meaningless. A SDLZ driver
+ * does not have to implement an all nodes method.
+ */
+
+typedef isc_result_t
+(*dns_sdlzallowzonexfr_t)(void *driverarg, void *dbdata, const char *name,
+ const char *client);
+
+/*%<
+ * Method prototype. Drivers implementing the SDLZ interface may
+ * supply an allow zone transfer method. This method is called when
+ * the DNS server is performing a zone transfer query, before the all
+ * nodes method can be called. This method and the all node method
+ * are both required for zone transfers to be supported. If the
+ * driver generates data dynamically (instead of searching in a
+ * database for it) it should not implement this function as a zone
+ * transfer would be meaningless. A SDLZ driver does not have to
+ * implement an allow zone transfer method.
+ *
+ * This method should return ISC_R_SUCCESS if the zone is supported by
+ * the database and a zone transfer is allowed for the specified
+ * client. If the zone is supported by the database, but zone
+ * transfers are not allowed for the specified client this method
+ * should return ISC_R_NOPERM.. Lastly the method should return
+ * ISC_R_NOTFOUND if the zone is not supported by the database. If an
+ * error occurs it should return a result code indicating the type of
+ * error.
+ */
+
+typedef isc_result_t
+(*dns_sdlzauthorityfunc_t)(const char *zone, void *driverarg, void *dbdata,
+ dns_sdlzlookup_t *lookup);
+
+/*%<
+ * Method prototype. Drivers implementing the SDLZ interface may
+ * supply an authority method. This method is called when the DNS
+ * server is performing a query, after both the find zone and lookup
+ * methods have been called. This method is required if the lookup
+ * function does not supply authority information for the dns
+ * record. A SDLZ driver does not have to implement an authority
+ * method.
+ */
+
+typedef isc_result_t
+(*dns_sdlzcreate_t)(const char *dlzname, unsigned int argc, char *argv[],
+ void *driverarg, void **dbdata);
+
+/*%<
+ * Method prototype. Drivers implementing the SDLZ interface may
+ * supply a create method. This method is called when the DNS server
+ * is starting up and creating drivers for use later. A SDLZ driver
+ * does not have to implement a create method.
+ */
+
+typedef void
+(*dns_sdlzdestroy_t)(void *driverarg, void *dbdata);
+
+/*%<
+ * Method prototype. Drivers implementing the SDLZ interface may
+ * supply a destroy method. This method is called when the DNS server
+ * is shuting down and no longer needs the driver. A SDLZ driver does
+ * not have to implement a destroy method.
+ */
+
+typedef isc_result_t
+(*dns_sdlzfindzone_t)(void *driverarg, void *dbdata, const char *name);
+
+/*%<
+ * Method prototype. Drivers implementing the SDLZ interface MUST
+ * supply a find zone method. This method is called when the DNS
+ * server is performing a query to to determine if 'name' is a
+ * supported dns zone. The find zone method will be called with the
+ * longest possible name first, and continue to be called with
+ * successively shorter domain names, until any of the following
+ * occur:
+ *
+ * \li 1) the function returns (ISC_R_SUCCESS) indicating a zone name
+ * match.
+ *
+ * \li 2) a problem occurs, and the functions returns anything other than
+ * (ISC_R_NOTFOUND)
+ *
+ * \li 3) we run out of domain name labels. I.E. we have tried the
+ * shortest domain name
+ *
+ * \li 4) the number of labels in the domain name is less than min_lables
+ * for dns_dlzfindzone
+ *
+ * The driver's find zone method should return ISC_R_SUCCESS if the
+ * zone is supported by the database. Otherwise it should return
+ * ISC_R_NOTFOUND, if the zone is not supported. If an error occurs
+ * it should return a result code indicating the type of error.
+ */
+
+typedef isc_result_t
+(*dns_sdlzlookupfunc_t)(const char *zone, const char *name, void *driverarg,
+ void *dbdata, dns_sdlzlookup_t *lookup);
+
+/*%<
+ * Method prototype. Drivers implementing the SDLZ interface MUST
+ * supply a lookup method. This method is called when the DNS server
+ * is performing a query, after the find zone and before any other
+ * methods have been called. This function returns record DNS record
+ * information using the dns_sdlz_putrr and dns_sdlz_putsoa functions.
+ * If this function supplies authority information for the DNS record
+ * the authority method is not required. If it does not, the
+ * authority function is required. A SDLZ driver must implement a
+ * lookup method.
+ */
+
+typedef struct dns_sdlzmethods {
+ dns_sdlzcreate_t create;
+ dns_sdlzdestroy_t destroy;
+ dns_sdlzfindzone_t findzone;
+ dns_sdlzlookupfunc_t lookup;
+ dns_sdlzauthorityfunc_t authority;
+ dns_sdlzallnodesfunc_t allnodes;
+ dns_sdlzallowzonexfr_t allowzonexfr;
+} dns_sdlzmethods_t;
+
+isc_result_t
+dns_sdlzregister(const char *drivername, const dns_sdlzmethods_t *methods,
+ void *driverarg, unsigned int flags, isc_mem_t *mctx,
+ dns_sdlzimplementation_t **sdlzimp);
+/*%<
+ * Register a dynamically loadable zones (dlz) driver for the database
+ * type 'drivername', implemented by the functions in '*methods'.
+ *
+ * sdlzimp must point to a NULL dns_sdlzimplementation_t pointer.
+ * That is, sdlzimp != NULL && *sdlzimp == NULL. It will be assigned
+ * a value that will later be used to identify the driver when
+ * deregistering it.
+ */
+
+void
+dns_sdlzunregister(dns_sdlzimplementation_t **sdlzimp);
+
+/*%<
+ * Removes the sdlz driver from the list of registered sdlz drivers.
+ * There must be no active sdlz drivers of this type when this
+ * function is called.
+ */
+
+isc_result_t
+dns_sdlz_putnamedrr(dns_sdlzallnodes_t *allnodes, const char *name,
+ const char *type, dns_ttl_t ttl, const char *data);
+/*%<
+ * Add a single resource record to the allnodes structure to be later
+ * parsed into a zone transfer response.
+ */
+
+isc_result_t
+dns_sdlz_putrr(dns_sdlzlookup_t *lookup, const char *type, dns_ttl_t ttl,
+ const char *data);
+/*%<
+ * Add a single resource record to the lookup structure to be later
+ * parsed into a query response.
+ */
+
+isc_result_t
+dns_sdlz_putsoa(dns_sdlzlookup_t *lookup, const char *mname, const char *rname,
+ isc_uint32_t serial);
+/*%<
+ * This function may optionally be called from the 'authority'
+ * callback to simplify construction of the SOA record for 'zone'. It
+ * will provide a SOA listing 'mname' as as the master server and
+ * 'rname' as the responsible person mailbox. It is the
+ * responsibility of the driver to increment the serial number between
+ * responses if necessary. All other SOA fields will have reasonable
+ * default values.
+ */
+
+
+ISC_LANG_ENDDECLS
+
+#endif /* SDLZ_H */
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: types.h,v 1.116 2005/06/20 01:03:54 marka Exp $ */
+/* $Id: types.h,v 1.117 2005/09/05 00:11:03 marka Exp $ */
#ifndef DNS_TYPES_H
#define DNS_TYPES_H 1
typedef void dns_dbnode_t;
typedef struct dns_dbtable dns_dbtable_t;
typedef void dns_dbversion_t;
+typedef struct dns_dlzimplementation dns_dlzimplementation_t;
+typedef struct dns_dlzdb dns_dlzdb_t;
+typedef struct dns_sdlzimplementation dns_sdlzimplementation_t;
typedef struct dns_decompress dns_decompress_t;
typedef struct dns_dispatch dns_dispatch_t;
typedef struct dns_dispatchevent dns_dispatchevent_t;
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: view.h,v 1.96 2005/07/18 05:58:59 marka Exp $ */
+/* $Id: view.h,v 1.97 2005/09/05 00:11:04 marka Exp $ */
#ifndef DNS_VIEW_H
#define DNS_VIEW_H 1
dns_rdataclass_t rdclass;
char * name;
dns_zt_t * zonetable;
+ dns_dlzdb_t * dlzdatabase;
dns_resolver_t * resolver;
dns_adb_t * adb;
dns_requestmgr_t * requestmgr;
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: log.c,v 1.39 2005/04/29 00:22:48 marka Exp $ */
+/* $Id: log.c,v 1.40 2005/09/05 00:11:01 marka Exp $ */
/*! \file */
{ "dns/diff", 0 },
{ "dns/hints", 0 },
{ "dns/acache", 0 },
+ { "dns/dlz", 0 },
{ NULL, 0 }
};
--- /dev/null
+/*
+ * 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) 1999-2001 Internet Software Consortium.
+ *
+ * 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 INTERNET SOFTWARE CONSORTIUM
+ * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+ * INTERNET SOFTWARE CONSORTIUM 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.
+ */
+
+/* $Id: sdlz.c,v 1.2 2005/09/05 00:11:02 marka Exp $ */
+
+/*! \file */
+
+#include <config.h>
+#include <string.h>
+
+#include <isc/buffer.h>
+#include <isc/lex.h>
+#include <isc/log.h>
+#include <isc/rwlock.h>
+#include <isc/string.h>
+#include <isc/util.h>
+#include <isc/magic.h>
+#include <isc/mem.h>
+#include <isc/once.h>
+#include <isc/print.h>
+#include <isc/region.h>
+
+#include <dns/callbacks.h>
+#include <dns/db.h>
+#include <dns/dbiterator.h>
+#include <dns/dlz.h>
+#include <dns/fixedname.h>
+#include <dns/log.h>
+#include <dns/rdata.h>
+#include <dns/rdatalist.h>
+#include <dns/rdataset.h>
+#include <dns/rdatasetiter.h>
+#include <dns/rdatatype.h>
+#include <dns/result.h>
+#include <dns/master.h>
+#include <dns/sdlz.h>
+#include <dns/types.h>
+
+#include "rdatalist_p.h"
+
+/*
+ * Private Types
+ */
+
+struct dns_sdlzimplementation {
+ const dns_sdlzmethods_t *methods;
+ isc_mem_t *mctx;
+ void *driverarg;
+ unsigned int flags;
+ isc_mutex_t driverlock;
+ dns_dlzimplementation_t *dlz_imp;
+};
+
+struct dns_sdlz_db {
+ /* Unlocked */
+ dns_db_t common;
+ void *dbdata;
+ dns_sdlzimplementation_t *dlzimp;
+ isc_mutex_t refcnt_lock;
+ /* Locked */
+ unsigned int references;
+};
+
+struct dns_sdlzlookup {
+ /* Unlocked */
+ unsigned int magic;
+ dns_sdlz_db_t *sdlz;
+ ISC_LIST(dns_rdatalist_t) lists;
+ ISC_LIST(isc_buffer_t) buffers;
+ dns_name_t *name;
+ ISC_LINK(dns_sdlzlookup_t) link;
+ isc_mutex_t lock;
+ dns_rdatacallbacks_t callbacks;
+ /* Locked */
+ unsigned int references;
+};
+
+typedef struct dns_sdlzlookup dns_sdlznode_t;
+
+struct dns_sdlzallnodes {
+ dns_dbiterator_t common;
+ ISC_LIST(dns_sdlznode_t) nodelist;
+ dns_sdlznode_t *current;
+ dns_sdlznode_t *origin;
+};
+
+typedef dns_sdlzallnodes_t sdlz_dbiterator_t;
+
+typedef struct sdlz_rdatasetiter {
+ dns_rdatasetiter_t common;
+ dns_rdatalist_t *current;
+} sdlz_rdatasetiter_t;
+
+
+#define SDLZDB_MAGIC ISC_MAGIC('D', 'L', 'Z', 'S')
+
+/*
+ * Note that "impmagic" is not the first four bytes of the struct, so
+ * ISC_MAGIC_VALID cannot be used.
+ */
+
+#define VALID_SDLZDB(sdlzdb) ((sdlzdb) != NULL && \
+ (sdlzdb)->common.impmagic == SDLZDB_MAGIC)
+
+#define SDLZLOOKUP_MAGIC ISC_MAGIC('D','L','Z','L')
+#define VALID_SDLZLOOKUP(sdlzl) ISC_MAGIC_VALID(sdlzl, SDLZLOOKUP_MAGIC)
+#define VALID_SDLZNODE(sdlzn) VALID_SDLZLOOKUP(sdlzn)
+
+/* These values are taken from RFC 1537 */
+#define SDLZ_DEFAULT_REFRESH (60 * 60 * 8)
+#define SDLZ_DEFAULT_RETRY (60 * 60 * 2)
+#define SDLZ_DEFAULT_EXPIRE (60 * 60 * 24 * 7)
+#define SDLZ_DEFAULT_MINIMUM (60 * 60 * 24)
+
+/* This is a reasonable value */
+#define SDLZ_DEFAULT_TTL (60 * 60 * 24)
+
+static int dummy;
+
+#define MAYBE_LOCK(imp) \
+ do { \
+ unsigned int flags = imp->flags; \
+ if ((flags & DNS_SDLZFLAG_THREADSAFE) == 0) \
+ LOCK(&imp->driverlock); \
+ } while (0)
+
+#define MAYBE_UNLOCK(imp) \
+ do { \
+ unsigned int flags = imp->flags; \
+ if ((flags & DNS_SDLZFLAG_THREADSAFE) == 0) \
+ UNLOCK(&imp->driverlock); \
+ } while (0)
+
+/*
+ * Forward references. Try to keep these to a minimum.
+ */
+
+static void list_tordataset(dns_rdatalist_t *rdatalist,
+ dns_db_t *db, dns_dbnode_t *node,
+ dns_rdataset_t *rdataset);
+
+static void detachnode(dns_db_t *db, dns_dbnode_t **targetp);
+
+static void dbiterator_destroy(dns_dbiterator_t **iteratorp);
+static isc_result_t dbiterator_first(dns_dbiterator_t *iterator);
+static isc_result_t dbiterator_last(dns_dbiterator_t *iterator);
+static isc_result_t dbiterator_seek(dns_dbiterator_t *iterator,
+ dns_name_t *name);
+static isc_result_t dbiterator_prev(dns_dbiterator_t *iterator);
+static isc_result_t dbiterator_next(dns_dbiterator_t *iterator);
+static isc_result_t dbiterator_current(dns_dbiterator_t *iterator,
+ dns_dbnode_t **nodep,
+ dns_name_t *name);
+static isc_result_t dbiterator_pause(dns_dbiterator_t *iterator);
+static isc_result_t dbiterator_origin(dns_dbiterator_t *iterator,
+ dns_name_t *name);
+
+static dns_dbiteratormethods_t dbiterator_methods = {
+ dbiterator_destroy,
+ dbiterator_first,
+ dbiterator_last,
+ dbiterator_seek,
+ dbiterator_prev,
+ dbiterator_next,
+ dbiterator_current,
+ dbiterator_pause,
+ dbiterator_origin
+};
+
+/*
+ * Utility functions
+ */
+
+/*% Converts the input string to lowercase, in place. */
+
+static void
+dns_sdlz_tolower(char *str) {
+
+ unsigned int len = strlen(str);
+ unsigned int i;
+
+ for (i = 0; i < len; i++) {
+ if (str[i] >= 'A' && str[i] <= 'Z')
+ str[i] += 32;
+ }
+
+}
+
+static inline unsigned int
+initial_size(const char *data) {
+ unsigned int len = (strlen(data) / 64) + 1;
+ return (len * 64 + 64);
+}
+
+/*
+ * Rdataset Iterator Methods. These methods were "borrowed" from the SDB
+ * driver interface. See the SDB driver interface documentation for more info.
+ */
+
+static void
+rdatasetiter_destroy(dns_rdatasetiter_t **iteratorp) {
+ sdlz_rdatasetiter_t *sdlziterator =
+ (sdlz_rdatasetiter_t *)(*iteratorp);
+
+ detachnode(sdlziterator->common.db, &sdlziterator->common.node);
+ isc_mem_put(sdlziterator->common.db->mctx, sdlziterator,
+ sizeof(sdlz_rdatasetiter_t));
+ *iteratorp = NULL;
+}
+
+static isc_result_t
+rdatasetiter_first(dns_rdatasetiter_t *iterator) {
+ sdlz_rdatasetiter_t *sdlziterator = (sdlz_rdatasetiter_t *)iterator;
+ dns_sdlznode_t *sdlznode = (dns_sdlznode_t *)iterator->node;
+
+ if (ISC_LIST_EMPTY(sdlznode->lists))
+ return (ISC_R_NOMORE);
+ sdlziterator->current = ISC_LIST_HEAD(sdlznode->lists);
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+rdatasetiter_next(dns_rdatasetiter_t *iterator) {
+ sdlz_rdatasetiter_t *sdlziterator = (sdlz_rdatasetiter_t *)iterator;
+
+ sdlziterator->current = ISC_LIST_NEXT(sdlziterator->current, link);
+ if (sdlziterator->current == NULL)
+ return (ISC_R_NOMORE);
+ else
+ return (ISC_R_SUCCESS);
+}
+
+static void
+rdatasetiter_current(dns_rdatasetiter_t *iterator, dns_rdataset_t *rdataset) {
+ sdlz_rdatasetiter_t *sdlziterator = (sdlz_rdatasetiter_t *)iterator;
+
+ list_tordataset(sdlziterator->current, iterator->db, iterator->node,
+ rdataset);
+}
+
+static dns_rdatasetitermethods_t rdatasetiter_methods = {
+ rdatasetiter_destroy,
+ rdatasetiter_first,
+ rdatasetiter_next,
+ rdatasetiter_current
+};
+
+/*
+ * DB routines. These methods were "borrowed" from the SDB driver interface.
+ * See the SDB driver interface documentation for more info.
+ */
+
+static void
+attach(dns_db_t *source, dns_db_t **targetp) {
+ dns_sdlz_db_t *sdlz = (dns_sdlz_db_t *) source;
+
+ REQUIRE(VALID_SDLZDB(sdlz));
+
+ LOCK(&sdlz->refcnt_lock);
+ REQUIRE(sdlz->references > 0);
+ sdlz->references++;
+ UNLOCK(&sdlz->refcnt_lock);
+
+ *targetp = source;
+}
+
+static void
+destroy(dns_sdlz_db_t *sdlz) {
+ isc_mem_t *mctx;
+ mctx = sdlz->common.mctx;
+
+ sdlz->common.magic = 0;
+ sdlz->common.impmagic = 0;
+
+ isc_mutex_destroy(&sdlz->refcnt_lock);
+
+ dns_name_free(&sdlz->common.origin, mctx);
+
+ isc_mem_put(mctx, sdlz, sizeof(dns_sdlz_db_t));
+ isc_mem_detach(&mctx);
+}
+
+static void
+detach(dns_db_t **dbp) {
+ dns_sdlz_db_t *sdlz = (dns_sdlz_db_t *)(*dbp);
+ isc_boolean_t need_destroy = ISC_FALSE;
+
+ REQUIRE(VALID_SDLZDB(sdlz));
+ LOCK(&sdlz->refcnt_lock);
+ REQUIRE(sdlz->references > 0);
+ sdlz->references--;
+ if (sdlz->references == 0)
+ need_destroy = ISC_TRUE;
+ UNLOCK(&sdlz->refcnt_lock);
+
+ if (need_destroy)
+ destroy(sdlz);
+
+ *dbp = NULL;
+}
+
+static isc_result_t
+beginload(dns_db_t *db, dns_addrdatasetfunc_t *addp, dns_dbload_t **dbloadp) {
+ UNUSED(db);
+ UNUSED(addp);
+ UNUSED(dbloadp);
+ return (ISC_R_NOTIMPLEMENTED);
+}
+
+static isc_result_t
+endload(dns_db_t *db, dns_dbload_t **dbloadp) {
+ UNUSED(db);
+ UNUSED(dbloadp);
+ return (ISC_R_NOTIMPLEMENTED);
+}
+
+static isc_result_t
+dump(dns_db_t *db, dns_dbversion_t *version, const char *filename,
+ dns_masterformat_t masterformat)
+{
+ UNUSED(db);
+ UNUSED(version);
+ UNUSED(filename);
+ UNUSED(masterformat);
+ return (ISC_R_NOTIMPLEMENTED);
+}
+
+static void
+currentversion(dns_db_t *db, dns_dbversion_t **versionp) {
+ REQUIRE(versionp != NULL && *versionp == NULL);
+
+ UNUSED(db);
+
+ *versionp = (void *) &dummy;
+ return;
+}
+
+static isc_result_t
+newversion(dns_db_t *db, dns_dbversion_t **versionp) {
+ UNUSED(db);
+ UNUSED(versionp);
+
+ return (ISC_R_NOTIMPLEMENTED);
+}
+
+static void
+attachversion(dns_db_t *db, dns_dbversion_t *source,
+ dns_dbversion_t **targetp)
+{
+ REQUIRE(source != NULL && source == (void *) &dummy);
+
+ UNUSED(db);
+ UNUSED(source);
+ UNUSED(targetp);
+ *targetp = source;
+}
+
+static void
+closeversion(dns_db_t *db, dns_dbversion_t **versionp, isc_boolean_t commit) {
+ REQUIRE(versionp != NULL && *versionp == (void *) &dummy);
+ REQUIRE(commit == ISC_FALSE);
+
+ UNUSED(db);
+ UNUSED(commit);
+
+ *versionp = NULL;
+}
+
+static isc_result_t
+createnode(dns_sdlz_db_t *sdlz, dns_sdlznode_t **nodep) {
+ dns_sdlznode_t *node;
+ isc_result_t result;
+
+ node = isc_mem_get(sdlz->common.mctx, sizeof(dns_sdlznode_t));
+ if (node == NULL)
+ return (ISC_R_NOMEMORY);
+
+ node->sdlz = NULL;
+ attach((dns_db_t *)sdlz, (dns_db_t **)&node->sdlz);
+ ISC_LIST_INIT(node->lists);
+ ISC_LIST_INIT(node->buffers);
+ ISC_LINK_INIT(node, link);
+ node->name = NULL;
+ result = isc_mutex_init(&node->lock);
+ if (result != ISC_R_SUCCESS) {
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "isc_mutex_init() failed: %s",
+ isc_result_totext(result));
+ isc_mem_put(sdlz->common.mctx, node, sizeof(dns_sdlznode_t));
+ return (ISC_R_UNEXPECTED);
+ }
+ dns_rdatacallbacks_init(&node->callbacks);
+ node->references = 1;
+ node->magic = SDLZLOOKUP_MAGIC;
+
+ *nodep = node;
+ return (ISC_R_SUCCESS);
+}
+
+static void
+destroynode(dns_sdlznode_t *node) {
+ dns_rdatalist_t *list;
+ dns_rdata_t *rdata;
+ isc_buffer_t *b;
+ dns_sdlz_db_t *sdlz;
+ dns_db_t *db;
+ isc_mem_t *mctx;
+
+ sdlz = node->sdlz;
+ mctx = sdlz->common.mctx;
+
+ while (!ISC_LIST_EMPTY(node->lists)) {
+ list = ISC_LIST_HEAD(node->lists);
+ while (!ISC_LIST_EMPTY(list->rdata)) {
+ rdata = ISC_LIST_HEAD(list->rdata);
+ ISC_LIST_UNLINK(list->rdata, rdata, link);
+ isc_mem_put(mctx, rdata, sizeof(dns_rdata_t));
+ }
+ ISC_LIST_UNLINK(node->lists, list, link);
+ isc_mem_put(mctx, list, sizeof(dns_rdatalist_t));
+ }
+
+ while (!ISC_LIST_EMPTY(node->buffers)) {
+ b = ISC_LIST_HEAD(node->buffers);
+ ISC_LIST_UNLINK(node->buffers, b, link);
+ isc_buffer_free(&b);
+ }
+
+ if (node->name != NULL) {
+ dns_name_free(node->name, mctx);
+ isc_mem_put(mctx, node->name, sizeof(dns_name_t));
+ }
+ DESTROYLOCK(&node->lock);
+ node->magic = 0;
+ isc_mem_put(mctx, node, sizeof(dns_sdlznode_t));
+ db = &sdlz->common;
+ detach(&db);
+}
+
+static isc_result_t
+findnode(dns_db_t *db, dns_name_t *name, isc_boolean_t create,
+ dns_dbnode_t **nodep)
+{
+ dns_sdlz_db_t *sdlz = (dns_sdlz_db_t *)db;
+ dns_sdlznode_t *node = NULL;
+ isc_result_t result;
+ isc_buffer_t b;
+ char namestr[DNS_NAME_MAXTEXT + 1];
+ isc_buffer_t b2;
+ char zonestr[DNS_NAME_MAXTEXT + 1];
+ isc_boolean_t isorigin;
+ dns_sdlzauthorityfunc_t authority;
+
+ REQUIRE(VALID_SDLZDB(sdlz));
+ REQUIRE(create == ISC_FALSE);
+ REQUIRE(nodep != NULL && *nodep == NULL);
+
+ UNUSED(name);
+ UNUSED(create);
+
+ isc_buffer_init(&b, namestr, sizeof(namestr));
+ if ((sdlz->dlzimp->flags & DNS_SDLZFLAG_RELATIVEOWNER) != 0) {
+ dns_name_t relname;
+ unsigned int labels;
+
+ labels = dns_name_countlabels(name) -
+ dns_name_countlabels(&db->origin);
+ dns_name_init(&relname, NULL);
+ dns_name_getlabelsequence(name, 0, labels, &relname);
+ result = dns_name_totext(&relname, ISC_TRUE, &b);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ } else {
+ result = dns_name_totext(name, ISC_TRUE, &b);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ }
+ isc_buffer_putuint8(&b, 0);
+
+ isc_buffer_init(&b2, zonestr, sizeof(zonestr));
+ result = dns_name_totext(&sdlz->common.origin, ISC_TRUE, &b2);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ isc_buffer_putuint8(&b2, 0);
+
+ result = createnode(sdlz, &node);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+ isorigin = dns_name_equal(name, &sdlz->common.origin);
+
+ /* make sure strings are always lowercase */
+ dns_sdlz_tolower(zonestr);
+ dns_sdlz_tolower(namestr);
+
+ MAYBE_LOCK(sdlz->dlzimp);
+
+ /* try to lookup the host (namestr) */
+ result = sdlz->dlzimp->methods->lookup(zonestr, namestr,
+ sdlz->dlzimp->driverarg,
+ sdlz->dbdata, node);
+
+ /*
+ * if the host (namestr) was not found, try to lookup a
+ * "wildcard" host.
+ */
+ if (result != ISC_R_SUCCESS) {
+ result = sdlz->dlzimp->methods->lookup(zonestr, "*",
+ sdlz->dlzimp->driverarg,
+ sdlz->dbdata, node);
+ }
+
+ MAYBE_UNLOCK(sdlz->dlzimp);
+
+ if (result != ISC_R_SUCCESS && !isorigin) {
+ destroynode(node);
+ return (result);
+ }
+
+ if (isorigin && sdlz->dlzimp->methods->authority != NULL) {
+ MAYBE_LOCK(sdlz->dlzimp);
+ authority = sdlz->dlzimp->methods->authority;
+ result = (*authority)(zonestr, sdlz->dlzimp->driverarg,
+ sdlz->dbdata, node);
+ MAYBE_UNLOCK(sdlz->dlzimp);
+ if (result != ISC_R_SUCCESS &&
+ result != ISC_R_NOTIMPLEMENTED) {
+ destroynode(node);
+ return (result);
+ }
+ }
+
+ *nodep = node;
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+findzonecut(dns_db_t *db, dns_name_t *name, unsigned int options,
+ isc_stdtime_t now, dns_dbnode_t **nodep, dns_name_t *foundname,
+ dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset)
+{
+ UNUSED(db);
+ UNUSED(name);
+ UNUSED(options);
+ UNUSED(now);
+ UNUSED(nodep);
+ UNUSED(foundname);
+ UNUSED(rdataset);
+ UNUSED(sigrdataset);
+
+ return (ISC_R_NOTIMPLEMENTED);
+}
+
+static void
+attachnode(dns_db_t *db, dns_dbnode_t *source, dns_dbnode_t **targetp) {
+ dns_sdlz_db_t *sdlz = (dns_sdlz_db_t *)db;
+ dns_sdlznode_t *node = (dns_sdlznode_t *)source;
+
+ REQUIRE(VALID_SDLZDB(sdlz));
+
+ UNUSED(sdlz);
+
+ LOCK(&node->lock);
+ INSIST(node->references > 0);
+ node->references++;
+ INSIST(node->references != 0); /* Catch overflow. */
+ UNLOCK(&node->lock);
+
+ *targetp = source;
+}
+
+static void
+detachnode(dns_db_t *db, dns_dbnode_t **targetp) {
+ dns_sdlz_db_t *sdlz = (dns_sdlz_db_t *)db;
+ dns_sdlznode_t *node;
+ isc_boolean_t need_destroy = ISC_FALSE;
+
+ REQUIRE(VALID_SDLZDB(sdlz));
+ REQUIRE(targetp != NULL && *targetp != NULL);
+
+ UNUSED(sdlz);
+
+ node = (dns_sdlznode_t *)(*targetp);
+
+ LOCK(&node->lock);
+ INSIST(node->references > 0);
+ node->references--;
+ if (node->references == 0)
+ need_destroy = ISC_TRUE;
+ UNLOCK(&node->lock);
+
+ if (need_destroy)
+ destroynode(node);
+
+ *targetp = NULL;
+}
+
+static isc_result_t
+expirenode(dns_db_t *db, dns_dbnode_t *node, isc_stdtime_t now) {
+ UNUSED(db);
+ UNUSED(node);
+ UNUSED(now);
+ INSIST(0);
+ return (ISC_R_UNEXPECTED);
+}
+
+static void
+printnode(dns_db_t *db, dns_dbnode_t *node, FILE *out) {
+ UNUSED(db);
+ UNUSED(node);
+ UNUSED(out);
+ return;
+}
+
+static isc_result_t
+createiterator(dns_db_t *db, isc_boolean_t relative_names,
+ dns_dbiterator_t **iteratorp)
+{
+ dns_sdlz_db_t *sdlz = (dns_sdlz_db_t *)db;
+ sdlz_dbiterator_t *sdlziter;
+ isc_result_t result;
+ isc_buffer_t b;
+ char zonestr[DNS_NAME_MAXTEXT + 1];
+
+ REQUIRE(VALID_SDLZDB(sdlz));
+
+ if (sdlz->dlzimp->methods->allnodes == NULL)
+ return (ISC_R_NOTIMPLEMENTED);
+
+ isc_buffer_init(&b, zonestr, sizeof(zonestr));
+ result = dns_name_totext(&sdlz->common.origin, ISC_TRUE, &b);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ isc_buffer_putuint8(&b, 0);
+
+ sdlziter = isc_mem_get(sdlz->common.mctx, sizeof(sdlz_dbiterator_t));
+ if (sdlziter == NULL)
+ return (ISC_R_NOMEMORY);
+
+ sdlziter->common.methods = &dbiterator_methods;
+ sdlziter->common.db = NULL;
+ dns_db_attach(db, &sdlziter->common.db);
+ sdlziter->common.relative_names = relative_names;
+ sdlziter->common.magic = DNS_DBITERATOR_MAGIC;
+ ISC_LIST_INIT(sdlziter->nodelist);
+ sdlziter->current = NULL;
+ sdlziter->origin = NULL;
+
+ /* make sure strings are always lowercase */
+ dns_sdlz_tolower(zonestr);
+
+ MAYBE_LOCK(sdlz->dlzimp);
+ result = sdlz->dlzimp->methods->allnodes(zonestr,
+ sdlz->dlzimp->driverarg,
+ sdlz->dbdata, sdlziter);
+ MAYBE_UNLOCK(sdlz->dlzimp);
+ if (result != ISC_R_SUCCESS) {
+ dns_dbiterator_t *iter = &sdlziter->common;
+ dbiterator_destroy(&iter);
+ return (result);
+ }
+
+ if (sdlziter->origin != NULL) {
+ ISC_LIST_UNLINK(sdlziter->nodelist, sdlziter->origin, link);
+ ISC_LIST_PREPEND(sdlziter->nodelist, sdlziter->origin, link);
+ }
+
+ *iteratorp = (dns_dbiterator_t *)sdlziter;
+
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+findrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
+ dns_rdatatype_t type, dns_rdatatype_t covers,
+ isc_stdtime_t now, dns_rdataset_t *rdataset,
+ dns_rdataset_t *sigrdataset)
+{
+ dns_rdatalist_t *list;
+ dns_sdlznode_t *sdlznode = (dns_sdlznode_t *)node;
+
+ REQUIRE(VALID_SDLZNODE(node));
+
+ UNUSED(db);
+ UNUSED(version);
+ UNUSED(covers);
+ UNUSED(now);
+ UNUSED(sigrdataset);
+
+ if (type == dns_rdatatype_sig)
+ return (ISC_R_NOTIMPLEMENTED);
+
+ list = ISC_LIST_HEAD(sdlznode->lists);
+ while (list != NULL) {
+ if (list->type == type)
+ break;
+ list = ISC_LIST_NEXT(list, link);
+ }
+ if (list == NULL)
+ return (ISC_R_NOTFOUND);
+
+ list_tordataset(list, db, node, rdataset);
+
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+find(dns_db_t *db, dns_name_t *name, dns_dbversion_t *version,
+ dns_rdatatype_t type, unsigned int options, isc_stdtime_t now,
+ dns_dbnode_t **nodep, dns_name_t *foundname,
+ dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset)
+{
+ dns_sdlz_db_t *sdlz = (dns_sdlz_db_t *)db;
+ dns_dbnode_t *node = NULL;
+ dns_fixedname_t fname;
+ dns_rdataset_t xrdataset;
+ dns_name_t *xname;
+ unsigned int nlabels, olabels;
+ isc_result_t result;
+ unsigned int i;
+
+ REQUIRE(VALID_SDLZDB(sdlz));
+ REQUIRE(nodep == NULL || *nodep == NULL);
+ REQUIRE(version == NULL || version == (void *) &dummy);
+
+ UNUSED(options);
+ UNUSED(sdlz);
+
+ if (!dns_name_issubdomain(name, &db->origin))
+ return (DNS_R_NXDOMAIN);
+
+ olabels = dns_name_countlabels(&db->origin);
+ nlabels = dns_name_countlabels(name);
+
+ dns_fixedname_init(&fname);
+ xname = dns_fixedname_name(&fname);
+
+ if (rdataset == NULL)
+ rdataset = &xrdataset;
+
+ result = DNS_R_NXDOMAIN;
+
+ for (i = olabels; i <= nlabels; i++) {
+ /*
+ * Unless this is an explicit lookup at the origin, don't
+ * look at the origin.
+ */
+ if (i == olabels && i != nlabels)
+ continue;
+
+ /*
+ * Look up the next label.
+ */
+ dns_name_getlabelsequence(name, nlabels - i, i, xname);
+ result = findnode(db, xname, ISC_FALSE, &node);
+ if (result != ISC_R_SUCCESS) {
+ result = DNS_R_NXDOMAIN;
+ continue;
+ }
+
+ /*
+ * Look for a DNAME at the current label, unless this is
+ * the qname.
+ */
+ if (i < nlabels) {
+ result = findrdataset(db, node, version,
+ dns_rdatatype_dname,
+ 0, now, rdataset, sigrdataset);
+ if (result == ISC_R_SUCCESS) {
+ result = DNS_R_DNAME;
+ break;
+ }
+ }
+
+ /*
+ * Look for an NS at the current label, unless this is the
+ * origin or glue is ok.
+ */
+ if (i != olabels && (options & DNS_DBFIND_GLUEOK) == 0) {
+ result = findrdataset(db, node, version,
+ dns_rdatatype_ns,
+ 0, now, rdataset, sigrdataset);
+ if (result == ISC_R_SUCCESS) {
+ if (i == nlabels && type == dns_rdatatype_any)
+ {
+ result = DNS_R_ZONECUT;
+ dns_rdataset_disassociate(rdataset);
+ if (sigrdataset != NULL)
+ dns_rdataset_disassociate
+ (sigrdataset);
+ } else
+ result = DNS_R_DELEGATION;
+ break;
+ }
+ }
+
+ /*
+ * If the current name is not the qname, add another label
+ * and try again.
+ */
+ if (i < nlabels) {
+ destroynode(node);
+ node = NULL;
+ continue;
+ }
+
+ /*
+ * If we're looking for ANY, we're done.
+ */
+ if (type == dns_rdatatype_any) {
+ result = ISC_R_SUCCESS;
+ break;
+ }
+
+ /*
+ * Look for the qtype.
+ */
+ result = findrdataset(db, node, version, type,
+ 0, now, rdataset, sigrdataset);
+ if (result == ISC_R_SUCCESS)
+ break;
+
+ /*
+ * Look for a CNAME
+ */
+ if (type != dns_rdatatype_cname) {
+ result = findrdataset(db, node, version,
+ dns_rdatatype_cname,
+ 0, now, rdataset, sigrdataset);
+ if (result == ISC_R_SUCCESS) {
+ result = DNS_R_CNAME;
+ break;
+ }
+ }
+
+ result = DNS_R_NXRRSET;
+ break;
+ }
+
+ if (rdataset == &xrdataset && dns_rdataset_isassociated(rdataset))
+ dns_rdataset_disassociate(rdataset);
+
+ if (foundname != NULL) {
+ isc_result_t xresult;
+
+ xresult = dns_name_copy(xname, foundname, NULL);
+ if (xresult != ISC_R_SUCCESS) {
+ destroynode(node);
+ if (dns_rdataset_isassociated(rdataset))
+ dns_rdataset_disassociate(rdataset);
+ return (DNS_R_BADDB);
+ }
+ }
+
+ if (nodep != NULL)
+ *nodep = node;
+ else if (node != NULL)
+ detachnode(db, &node);
+
+ return (result);
+}
+
+static isc_result_t
+allrdatasets(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
+ isc_stdtime_t now, dns_rdatasetiter_t **iteratorp)
+{
+ sdlz_rdatasetiter_t *iterator;
+
+ REQUIRE(version == NULL || version == &dummy);
+
+ UNUSED(version);
+ UNUSED(now);
+
+ iterator = isc_mem_get(db->mctx, sizeof(sdlz_rdatasetiter_t));
+ if (iterator == NULL)
+ return (ISC_R_NOMEMORY);
+
+ iterator->common.magic = DNS_RDATASETITER_MAGIC;
+ iterator->common.methods = &rdatasetiter_methods;
+ iterator->common.db = db;
+ iterator->common.node = NULL;
+ attachnode(db, node, &iterator->common.node);
+ iterator->common.version = version;
+ iterator->common.now = now;
+
+ *iteratorp = (dns_rdatasetiter_t *)iterator;
+
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
+ isc_stdtime_t now, dns_rdataset_t *rdataset, unsigned int options,
+ dns_rdataset_t *addedrdataset)
+{
+ UNUSED(db);
+ UNUSED(node);
+ UNUSED(version);
+ UNUSED(now);
+ UNUSED(rdataset);
+ UNUSED(options);
+ UNUSED(addedrdataset);
+
+ return (ISC_R_NOTIMPLEMENTED);
+}
+
+static isc_result_t
+subtractrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
+ dns_rdataset_t *rdataset, unsigned int options,
+ dns_rdataset_t *newrdataset)
+{
+ UNUSED(db);
+ UNUSED(node);
+ UNUSED(version);
+ UNUSED(rdataset);
+ UNUSED(options);
+ UNUSED(newrdataset);
+
+ return (ISC_R_NOTIMPLEMENTED);
+}
+
+static isc_result_t
+deleterdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
+ dns_rdatatype_t type, dns_rdatatype_t covers)
+{
+ UNUSED(db);
+ UNUSED(node);
+ UNUSED(version);
+ UNUSED(type);
+ UNUSED(covers);
+
+ return (ISC_R_NOTIMPLEMENTED);
+}
+
+static isc_boolean_t
+issecure(dns_db_t *db) {
+ UNUSED(db);
+
+ return (ISC_FALSE);
+}
+
+static unsigned int
+nodecount(dns_db_t *db) {
+ UNUSED(db);
+
+ return (0);
+}
+
+static isc_boolean_t
+ispersistent(dns_db_t *db) {
+ UNUSED(db);
+ return (ISC_TRUE);
+}
+
+static void
+overmem(dns_db_t *db, isc_boolean_t overmem) {
+ UNUSED(db);
+ UNUSED(overmem);
+}
+
+static void
+settask(dns_db_t *db, isc_task_t *task) {
+ UNUSED(db);
+ UNUSED(task);
+}
+
+
+static dns_dbmethods_t sdlzdb_methods = {
+ attach,
+ detach,
+ beginload,
+ endload,
+ dump,
+ currentversion,
+ newversion,
+ attachversion,
+ closeversion,
+ findnode,
+ find,
+ findzonecut,
+ attachnode,
+ detachnode,
+ expirenode,
+ printnode,
+ createiterator,
+ findrdataset,
+ allrdatasets,
+ addrdataset,
+ subtractrdataset,
+ deleterdataset,
+ issecure,
+ nodecount,
+ ispersistent,
+ overmem,
+ settask,
+ NULL,
+ NULL,
+ NULL,
+ NULL
+};
+
+/*
+ * Database Iterator Methods. These methods were "borrowed" from the SDB
+ * driver interface. See the SDB driver interface documentation for more info.
+ */
+
+static void
+dbiterator_destroy(dns_dbiterator_t **iteratorp) {
+ sdlz_dbiterator_t *sdlziter = (sdlz_dbiterator_t *)(*iteratorp);
+ dns_sdlz_db_t *sdlz = (dns_sdlz_db_t *)sdlziter->common.db;
+
+ while (!ISC_LIST_EMPTY(sdlziter->nodelist)) {
+ dns_sdlznode_t *node;
+ node = ISC_LIST_HEAD(sdlziter->nodelist);
+ ISC_LIST_UNLINK(sdlziter->nodelist, node, link);
+ destroynode(node);
+ }
+
+ dns_db_detach(&sdlziter->common.db);
+ isc_mem_put(sdlz->common.mctx, sdlziter, sizeof(sdlz_dbiterator_t));
+
+ *iteratorp = NULL;
+}
+
+static isc_result_t
+dbiterator_first(dns_dbiterator_t *iterator) {
+ sdlz_dbiterator_t *sdlziter = (sdlz_dbiterator_t *)iterator;
+
+ sdlziter->current = ISC_LIST_HEAD(sdlziter->nodelist);
+ if (sdlziter->current == NULL)
+ return (ISC_R_NOMORE);
+ else
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+dbiterator_last(dns_dbiterator_t *iterator) {
+ sdlz_dbiterator_t *sdlziter = (sdlz_dbiterator_t *)iterator;
+
+ sdlziter->current = ISC_LIST_TAIL(sdlziter->nodelist);
+ if (sdlziter->current == NULL)
+ return (ISC_R_NOMORE);
+ else
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+dbiterator_seek(dns_dbiterator_t *iterator, dns_name_t *name) {
+ sdlz_dbiterator_t *sdlziter = (sdlz_dbiterator_t *)iterator;
+
+ sdlziter->current = ISC_LIST_HEAD(sdlziter->nodelist);
+ while (sdlziter->current != NULL)
+ if (dns_name_equal(sdlziter->current->name, name))
+ return (ISC_R_SUCCESS);
+ return (ISC_R_NOTFOUND);
+}
+
+static isc_result_t
+dbiterator_prev(dns_dbiterator_t *iterator) {
+ sdlz_dbiterator_t *sdlziter = (sdlz_dbiterator_t *)iterator;
+
+ sdlziter->current = ISC_LIST_PREV(sdlziter->current, link);
+ if (sdlziter->current == NULL)
+ return (ISC_R_NOMORE);
+ else
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+dbiterator_next(dns_dbiterator_t *iterator) {
+ sdlz_dbiterator_t *sdlziter = (sdlz_dbiterator_t *)iterator;
+
+ sdlziter->current = ISC_LIST_NEXT(sdlziter->current, link);
+ if (sdlziter->current == NULL)
+ return (ISC_R_NOMORE);
+ else
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+dbiterator_current(dns_dbiterator_t *iterator, dns_dbnode_t **nodep,
+ dns_name_t *name)
+{
+ sdlz_dbiterator_t *sdlziter = (sdlz_dbiterator_t *)iterator;
+
+ attachnode(iterator->db, sdlziter->current, nodep);
+ if (name != NULL)
+ return (dns_name_copy(sdlziter->current->name, name, NULL));
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+dbiterator_pause(dns_dbiterator_t *iterator) {
+ UNUSED(iterator);
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+dbiterator_origin(dns_dbiterator_t *iterator, dns_name_t *name) {
+ UNUSED(iterator);
+ return (dns_name_copy(dns_rootname, name, NULL));
+}
+
+/*
+ * Rdataset Methods. These methods were "borrowed" from the SDB driver
+ * interface. See the SDB driver interface documentation for more info.
+ */
+
+static void
+disassociate(dns_rdataset_t *rdataset) {
+ dns_dbnode_t *node = rdataset->private5;
+ dns_sdlznode_t *sdlznode = (dns_sdlznode_t *) node;
+ dns_db_t *db = (dns_db_t *) sdlznode->sdlz;
+
+ detachnode(db, &node);
+ isc__rdatalist_disassociate(rdataset);
+}
+
+static void
+rdataset_clone(dns_rdataset_t *source, dns_rdataset_t *target) {
+ dns_dbnode_t *node = source->private5;
+ dns_sdlznode_t *sdlznode = (dns_sdlznode_t *) node;
+ dns_db_t *db = (dns_db_t *) sdlznode->sdlz;
+ dns_dbnode_t *tempdb = NULL;
+
+ isc__rdatalist_clone(source, target);
+ attachnode(db, node, &tempdb);
+ source->private5 = tempdb;
+}
+
+static dns_rdatasetmethods_t rdataset_methods = {
+ disassociate,
+ isc__rdatalist_first,
+ isc__rdatalist_next,
+ isc__rdatalist_current,
+ rdataset_clone,
+ isc__rdatalist_count,
+ isc__rdatalist_addnoqname,
+ isc__rdatalist_getnoqname,
+ NULL,
+ NULL,
+ NULL
+};
+
+static void
+list_tordataset(dns_rdatalist_t *rdatalist,
+ dns_db_t *db, dns_dbnode_t *node,
+ dns_rdataset_t *rdataset)
+{
+ /*
+ * The sdlz rdataset is an rdatalist with some additions.
+ * - private1 & private2 are used by the rdatalist.
+ * - private3 & private 4 are unused.
+ * - private5 is the node.
+ */
+
+ /* This should never fail. */
+ RUNTIME_CHECK(dns_rdatalist_tordataset(rdatalist, rdataset) ==
+ ISC_R_SUCCESS);
+
+ rdataset->methods = &rdataset_methods;
+ dns_db_attachnode(db, node, &rdataset->private5);
+}
+
+/*
+ * SDLZ core methods. This is the core of the new DLZ functionality.
+ */
+
+/*%
+ * Build a 'bind' database driver structure to be returned by
+ * either the find zone or the allow zone transfer method.
+ * This method is only available in this source file, it is
+ * not made available anywhere else.
+ */
+
+static isc_result_t
+dns_sdlzcreateDBP(isc_mem_t *mctx, void *driverarg, void *dbdata,
+ dns_name_t *name, dns_rdataclass_t rdclass, dns_db_t **dbp)
+{
+ isc_result_t result;
+ dns_sdlz_db_t *sdlzdb;
+ dns_sdlzimplementation_t *imp;
+
+ /* check that things are as we expect */
+ REQUIRE(dbp != NULL && *dbp == NULL);
+ REQUIRE(name != NULL);
+
+ imp = (dns_sdlzimplementation_t *) driverarg;
+
+ /* allocate and zero memory for driver structure */
+ sdlzdb = isc_mem_get(mctx, sizeof(dns_sdlz_db_t));
+ if (sdlzdb == NULL)
+ return (ISC_R_NOMEMORY);
+ memset(sdlzdb, 0, sizeof(dns_sdlz_db_t));
+
+ /* initialize and set origin */
+ dns_name_init(&sdlzdb->common.origin, NULL);
+ result = dns_name_dupwithoffsets(name, mctx, &sdlzdb->common.origin);
+ if (result != ISC_R_SUCCESS)
+ goto mem_cleanup;
+
+ /* initialize the reference count mutex */
+ result = isc_mutex_init(&sdlzdb->refcnt_lock);
+ if (result != ISC_R_SUCCESS)
+ goto name_cleanup;
+
+ /* set the rest of the database structure attributes */
+ sdlzdb->dlzimp = imp;
+ sdlzdb->common.methods = &sdlzdb_methods;
+ sdlzdb->common.attributes = 0;
+ sdlzdb->common.rdclass = rdclass;
+ sdlzdb->common.mctx = NULL;
+ sdlzdb->dbdata = dbdata;
+ sdlzdb->references = 1;
+
+ /* attach to the memory context */
+ isc_mem_attach(mctx, &sdlzdb->common.mctx);
+
+ /* mark structure as valid */
+ sdlzdb->common.magic = DNS_DB_MAGIC;
+ sdlzdb->common.impmagic = SDLZDB_MAGIC;
+ *dbp = (dns_db_t *) sdlzdb;
+
+ return (result);
+
+ /*
+ * reference count mutex could not be initialized, clean up
+ * name memory
+ */
+ name_cleanup:
+ dns_name_free(&sdlzdb->common.origin, mctx);
+ mem_cleanup:
+ isc_mem_put(mctx, sdlzdb, sizeof(dns_sdlz_db_t));
+ return (result);
+}
+
+static isc_result_t
+dns_sdlzallowzonexfr(void *driverarg, void *dbdata, isc_mem_t *mctx,
+ dns_rdataclass_t rdclass, dns_name_t *name,
+ isc_sockaddr_t *clientaddr, dns_db_t **dbp)
+{
+ isc_buffer_t b;
+ isc_buffer_t b2;
+ char namestr[DNS_NAME_MAXTEXT + 1];
+ char clientstr[(sizeof "xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255.255.255.255")
+ + 1];
+ isc_netaddr_t netaddr;
+ isc_result_t result;
+ dns_sdlzimplementation_t *imp;
+
+ /*
+ * Perform checks to make sure data is as we expect it to be.
+ */
+ REQUIRE(driverarg != NULL);
+ REQUIRE(name != NULL);
+ REQUIRE(clientaddr != NULL);
+ REQUIRE(dbp != NULL && *dbp == NULL);
+
+ imp = (dns_sdlzimplementation_t *) driverarg;
+
+ /* Convert DNS name to ascii text */
+ isc_buffer_init(&b, namestr, sizeof(namestr));
+ result = dns_name_totext(name, ISC_TRUE, &b);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ isc_buffer_putuint8(&b, 0);
+
+ /* convert client address to ascii text */
+ isc_buffer_init(&b2, clientstr, sizeof(clientstr));
+ isc_netaddr_fromsockaddr(&netaddr, clientaddr);
+ result = isc_netaddr_totext(&netaddr, &b2);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ isc_buffer_putuint8(&b2, 0);
+
+ /* make sure strings are always lowercase */
+ dns_sdlz_tolower(namestr);
+ dns_sdlz_tolower(clientstr);
+
+ /* Call SDLZ driver's find zone method */
+ if (imp->methods->allowzonexfr != NULL) {
+ MAYBE_LOCK(imp);
+ result = imp->methods->allowzonexfr(imp->driverarg, dbdata,
+ namestr, clientstr);
+ MAYBE_UNLOCK(imp);
+ /*
+ * if zone is supported and transfers allowed build a 'bind'
+ * database driver
+ */
+ if (result == ISC_R_SUCCESS)
+ result = dns_sdlzcreateDBP(mctx, driverarg, dbdata,
+ name, rdclass, dbp);
+ return (result);
+ }
+
+ return (ISC_R_NOTIMPLEMENTED);
+}
+
+static isc_result_t
+dns_sdlzcreate(isc_mem_t *mctx, const char *dlzname, unsigned int argc,
+ char *argv[], void *driverarg, void **dbdata)
+{
+ dns_sdlzimplementation_t *imp;
+ isc_result_t result = ISC_R_NOTFOUND;
+
+ /* Write debugging message to log */
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2),
+ "Loading SDLZ driver.");
+
+ /*
+ * Performs checks to make sure data is as we expect it to be.
+ */
+ REQUIRE(driverarg != NULL);
+ REQUIRE(dlzname != NULL);
+ REQUIRE(dbdata != NULL);
+ UNUSED(mctx);
+
+ imp = driverarg;
+
+ /* If the create method exists, call it. */
+ if (imp->methods->create != NULL) {
+ MAYBE_LOCK(imp);
+ result = imp->methods->create(dlzname, argc, argv,
+ imp->driverarg, dbdata);
+ MAYBE_UNLOCK(imp);
+ }
+
+ /* Write debugging message to log */
+ if (result == ISC_R_SUCCESS) {
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2),
+ "SDLZ driver loaded successfully.");
+ } else {
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
+ "SDLZ driver failed to load.");
+ }
+
+ return (result);
+}
+
+static void
+dns_sdlzdestroy(void *driverdata, void **dbdata)
+{
+
+ dns_sdlzimplementation_t *imp;
+
+ /* Write debugging message to log */
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2),
+ "Unloading SDLZ driver.");
+
+ imp = driverdata;
+
+ /* If the destroy method exists, call it. */
+ if (imp->methods->destroy != NULL) {
+ MAYBE_LOCK(imp);
+ imp->methods->destroy(imp->driverarg, dbdata);
+ MAYBE_UNLOCK(imp);
+ }
+}
+
+static isc_result_t
+dns_sdlzfindzone(void *driverarg, void *dbdata, isc_mem_t *mctx,
+ dns_rdataclass_t rdclass, dns_name_t *name, dns_db_t **dbp)
+{
+ isc_buffer_t b;
+ char namestr[DNS_NAME_MAXTEXT + 1];
+ isc_result_t result;
+ dns_sdlzimplementation_t *imp;
+
+ /*
+ * Perform checks to make sure data is as we expect it to be.
+ */
+ REQUIRE(driverarg != NULL);
+ REQUIRE(name != NULL);
+ REQUIRE(dbp != NULL && *dbp == NULL);
+
+ imp = (dns_sdlzimplementation_t *) driverarg;
+
+ /* Convert DNS name to ascii text */
+ isc_buffer_init(&b, namestr, sizeof(namestr));
+ result = dns_name_totext(name, ISC_TRUE, &b);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ isc_buffer_putuint8(&b, 0);
+
+ /* make sure strings are always lowercase */
+ dns_sdlz_tolower(namestr);
+
+ /* Call SDLZ driver's find zone method */
+ MAYBE_LOCK(imp);
+ result = imp->methods->findzone(imp->driverarg, dbdata, namestr);
+ MAYBE_UNLOCK(imp);
+
+ /*
+ * if zone is supported build a 'bind' database driver
+ * structure to return
+ */
+ if (result == ISC_R_SUCCESS)
+ result = dns_sdlzcreateDBP(mctx, driverarg, dbdata, name,
+ rdclass, dbp);
+
+ return (result);
+}
+
+static dns_dlzmethods_t sdlzmethods = {
+ dns_sdlzcreate,
+ dns_sdlzdestroy,
+ dns_sdlzfindzone,
+ dns_sdlzallowzonexfr
+};
+
+/*
+ * Public functions.
+ */
+
+isc_result_t
+dns_sdlz_putrr(dns_sdlzlookup_t *lookup, const char *type, dns_ttl_t ttl,
+ const char *data)
+{
+ dns_rdatalist_t *rdatalist;
+ dns_rdata_t *rdata;
+ dns_rdatatype_t typeval;
+ isc_consttextregion_t r;
+ isc_buffer_t b;
+ isc_buffer_t *rdatabuf;
+ isc_lex_t *lex;
+ isc_result_t result;
+ unsigned int size;
+ isc_mem_t *mctx;
+ dns_name_t *origin;
+
+ REQUIRE(VALID_SDLZLOOKUP(lookup));
+ REQUIRE(type != NULL);
+ REQUIRE(data != NULL);
+
+ mctx = lookup->sdlz->common.mctx;
+
+ r.base = type;
+ r.length = strlen(type);
+ result = dns_rdatatype_fromtext(&typeval, (void *) &r);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+ rdatalist = ISC_LIST_HEAD(lookup->lists);
+ while (rdatalist != NULL) {
+ if (rdatalist->type == typeval)
+ break;
+ rdatalist = ISC_LIST_NEXT(rdatalist, link);
+ }
+
+ if (rdatalist == NULL) {
+ rdatalist = isc_mem_get(mctx, sizeof(dns_rdatalist_t));
+ if (rdatalist == NULL)
+ return (ISC_R_NOMEMORY);
+ rdatalist->rdclass = lookup->sdlz->common.rdclass;
+ rdatalist->type = typeval;
+ rdatalist->covers = 0;
+ rdatalist->ttl = ttl;
+ ISC_LIST_INIT(rdatalist->rdata);
+ ISC_LINK_INIT(rdatalist, link);
+ ISC_LIST_APPEND(lookup->lists, rdatalist, link);
+ } else
+ if (rdatalist->ttl != ttl)
+ return (DNS_R_BADTTL);
+
+ rdata = isc_mem_get(mctx, sizeof(dns_rdata_t));
+ if (rdata == NULL)
+ return (ISC_R_NOMEMORY);
+ dns_rdata_init(rdata);
+
+ if ((lookup->sdlz->dlzimp->flags & DNS_SDLZFLAG_RELATIVERDATA) != 0)
+ origin = &lookup->sdlz->common.origin;
+ else
+ origin = dns_rootname;
+
+ lex = NULL;
+ result = isc_lex_create(mctx, 64, &lex);
+ if (result != ISC_R_SUCCESS)
+ goto failure;
+
+ size = initial_size(data);
+ do {
+ isc_buffer_init(&b, data, strlen(data));
+ isc_buffer_add(&b, strlen(data));
+
+ result = isc_lex_openbuffer(lex, &b);
+ if (result != ISC_R_SUCCESS)
+ goto failure;
+
+ rdatabuf = NULL;
+ result = isc_buffer_allocate(mctx, &rdatabuf, size);
+ if (result != ISC_R_SUCCESS)
+ goto failure;
+
+ result = dns_rdata_fromtext(rdata, rdatalist->rdclass,
+ rdatalist->type, lex,
+ origin, ISC_FALSE,
+ mctx, rdatabuf,
+ &lookup->callbacks);
+ if (result != ISC_R_SUCCESS)
+ isc_buffer_free(&rdatabuf);
+ size *= 2;
+ } while (result == ISC_R_NOSPACE);
+
+ if (result != ISC_R_SUCCESS)
+ goto failure;
+
+ ISC_LIST_APPEND(rdatalist->rdata, rdata, link);
+ ISC_LIST_APPEND(lookup->buffers, rdatabuf, link);
+
+ if (lex != NULL)
+ isc_lex_destroy(&lex);
+
+ return (ISC_R_SUCCESS);
+
+ failure:
+ if (rdatabuf != NULL)
+ isc_buffer_free(&rdatabuf);
+ if (lex != NULL)
+ isc_lex_destroy(&lex);
+ isc_mem_put(mctx, rdata, sizeof(dns_rdata_t));
+
+ return (result);
+}
+
+isc_result_t
+dns_sdlz_putnamedrr(dns_sdlzallnodes_t *allnodes, const char *name,
+ const char *type, dns_ttl_t ttl, const char *data)
+{
+ dns_name_t *newname, *origin;
+ dns_fixedname_t fnewname;
+ dns_sdlz_db_t *sdlz = (dns_sdlz_db_t *)allnodes->common.db;
+ dns_sdlznode_t *sdlznode;
+ isc_mem_t *mctx = sdlz->common.mctx;
+ isc_buffer_t b;
+ isc_result_t result;
+
+ dns_fixedname_init(&fnewname);
+ newname = dns_fixedname_name(&fnewname);
+
+ if ((sdlz->dlzimp->flags & DNS_SDLZFLAG_RELATIVERDATA) != 0)
+ origin = &sdlz->common.origin;
+ else
+ origin = dns_rootname;
+ isc_buffer_init(&b, name, strlen(name));
+ isc_buffer_add(&b, strlen(name));
+
+ result = dns_name_fromtext(newname, &b, origin, ISC_FALSE, NULL);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+ if (allnodes->common.relative_names) {
+ /* All names are relative to the root */
+ unsigned int nlabels = dns_name_countlabels(newname);
+ dns_name_getlabelsequence(newname, 0, nlabels - 1, newname);
+ }
+
+ sdlznode = ISC_LIST_HEAD(allnodes->nodelist);
+ if (sdlznode == NULL || !dns_name_equal(sdlznode->name, newname)) {
+ sdlznode = NULL;
+ result = createnode(sdlz, &sdlznode);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ sdlznode->name = isc_mem_get(mctx, sizeof(dns_name_t));
+ if (sdlznode->name == NULL) {
+ destroynode(sdlznode);
+ return (ISC_R_NOMEMORY);
+ }
+ dns_name_init(sdlznode->name, NULL);
+ result = dns_name_dup(newname, mctx, sdlznode->name);
+ if (result != ISC_R_SUCCESS) {
+ isc_mem_put(mctx, sdlznode->name, sizeof(dns_name_t));
+ destroynode(sdlznode);
+ return (result);
+ }
+ ISC_LIST_PREPEND(allnodes->nodelist, sdlznode, link);
+ if (allnodes->origin == NULL &&
+ dns_name_equal(newname, &sdlz->common.origin))
+ allnodes->origin = sdlznode;
+ }
+ return (dns_sdlz_putrr(sdlznode, type, ttl, data));
+
+}
+
+isc_result_t
+dns_sdlz_putsoa(dns_sdlzlookup_t *lookup, const char *mname, const char *rname,
+ isc_uint32_t serial)
+{
+ char str[2 * DNS_NAME_MAXTEXT + 5 * (sizeof("2147483647")) + 7];
+ int n;
+
+ REQUIRE(mname != NULL);
+ REQUIRE(rname != NULL);
+
+ n = snprintf(str, sizeof str, "%s %s %u %u %u %u %u",
+ mname, rname, serial,
+ SDLZ_DEFAULT_REFRESH, SDLZ_DEFAULT_RETRY,
+ SDLZ_DEFAULT_EXPIRE, SDLZ_DEFAULT_MINIMUM);
+ if (n >= (int)sizeof(str) || n < 0)
+ return (ISC_R_NOSPACE);
+ return (dns_sdlz_putrr(lookup, "SOA", SDLZ_DEFAULT_TTL, str));
+}
+
+isc_result_t
+dns_sdlzregister(const char *drivername, const dns_sdlzmethods_t *methods,
+ void *driverarg, unsigned int flags, isc_mem_t *mctx,
+ dns_sdlzimplementation_t **sdlzimp)
+{
+
+ dns_sdlzimplementation_t *imp;
+ isc_result_t result;
+
+ /*
+ * Performs checks to make sure data is as we expect it to be.
+ */
+ REQUIRE(drivername != NULL);
+ REQUIRE(methods != NULL);
+ REQUIRE(methods->findzone != NULL);
+ REQUIRE(methods->lookup != NULL);
+ REQUIRE(mctx != NULL);
+ REQUIRE(sdlzimp != NULL && *sdlzimp == NULL);
+ REQUIRE((flags & ~(DNS_SDLZFLAG_RELATIVEOWNER |
+ DNS_SDLZFLAG_RELATIVERDATA |
+ DNS_SDLZFLAG_THREADSAFE)) == 0);
+
+ /* Write debugging message to log */
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2),
+ "Registering SDLZ driver '%s'", drivername);
+
+ /*
+ * Allocate memory for a sdlz_implementation object. Error if
+ * we cannot.
+ */
+ imp = isc_mem_get(mctx, sizeof(dns_sdlzimplementation_t));
+ if (imp == NULL)
+ return (ISC_R_NOMEMORY);
+
+ /* Make sure memory region is set to all 0's */
+ memset(imp, 0, sizeof(dns_sdlzimplementation_t));
+
+ /* Store the data passed into this method */
+ imp->methods = methods;
+ imp->driverarg = driverarg;
+ imp->flags = flags;
+ imp->mctx = NULL;
+
+ /* attach the new sdlz_implementation object to a memory context */
+ isc_mem_attach(mctx, &imp->mctx);
+
+ /*
+ * initialize the driver lock, error if we cannot
+ * (used if a driver does not support multiple threads)
+ */
+ result = isc_mutex_init(&imp->driverlock);
+ if (result != ISC_R_SUCCESS) {
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "isc_mutex_init() failed: %s",
+ isc_result_totext(result));
+ goto cleanup_mctx;
+ }
+
+ imp->dlz_imp = NULL;
+
+ /*
+ * register the DLZ driver. Pass in our "extra" sdlz information as
+ * a driverarg. (that's why we stored the passed in driver arg in our
+ * sdlz_implementation structure) Also, store the dlz_implementation
+ * structure in our sdlz_implementation.
+ */
+ result = dns_dlzregister(drivername, &sdlzmethods, imp, mctx,
+ &imp->dlz_imp);
+
+ /* if registration fails, cleanup and get outta here. */
+ if (result != ISC_R_SUCCESS)
+ goto cleanup_mutex;
+
+ *sdlzimp = imp;
+
+ return (ISC_R_SUCCESS);
+
+ cleanup_mutex:
+ /* destroy the driver lock, we don't need it anymore */
+ DESTROYLOCK(&imp->driverlock);
+
+ cleanup_mctx:
+ /*
+ * return the memory back to the available memory pool and
+ * remove it from the memory context.
+ */
+ isc_mem_put(mctx, imp, sizeof(dns_sdlzimplementation_t));
+ isc_mem_detach(&mctx);
+ return (result);
+}
+
+void
+dns_sdlzunregister(dns_sdlzimplementation_t **sdlzimp) {
+ dns_sdlzimplementation_t *imp;
+ isc_mem_t *mctx;
+
+ /* Write debugging message to log */
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2),
+ "Unregistering SDLZ driver.");
+
+ /*
+ * Performs checks to make sure data is as we expect it to be.
+ */
+ REQUIRE(sdlzimp != NULL && *sdlzimp != NULL);
+
+ imp = *sdlzimp;
+
+ /* Unregister the DLZ driver implementation */
+ dns_dlzunregister(&imp->dlz_imp);
+
+ /* destroy the driver lock, we don't need it anymore */
+ DESTROYLOCK(&imp->driverlock);
+
+ mctx = imp->mctx;
+
+ /*
+ * return the memory back to the available memory pool and
+ * remove it from the memory context.
+ */
+ isc_mem_put(mctx, imp, sizeof(dns_sdlzimplementation_t));
+ isc_mem_detach(&mctx);
+
+ *sdlzimp = NULL;
+}
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: view.c,v 1.132 2005/07/12 01:00:16 marka Exp $ */
+/* $Id: view.c,v 1.133 2005/09/05 00:11:02 marka Exp $ */
/*! \file */
#include <dns/adb.h>
#include <dns/cache.h>
#include <dns/db.h>
+#include <dns/dlz.h>
#include <dns/events.h>
#include <dns/forward.h>
#include <dns/keytable.h>
view->acache = NULL;
view->cache = NULL;
view->cachedb = NULL;
+ view->dlzdatabase = NULL;
view->hints = NULL;
view->resolver = NULL;
view->adb = NULL;
isc_task_detach(&view->task);
if (view->hints != NULL)
dns_db_detach(&view->hints);
+ if (view->dlzdatabase != NULL)
+ dns_dlzdestroy(&view->dlzdatabase);
if (view->cachedb != NULL)
dns_db_detach(&view->cachedb);
if (view->cache != NULL)
dns_dispatchmgr_getblackhole
dns_dispatchmgr_setblackhole
dns_dispatchmgr_setblackportlist
+dns_dlzallowzonexfr
+dns_dlzcreate
+dns_dlzdestroy
+dns_dlzfindzone
+dns_dlzregister
+dns_dlzstrtoargv
+dns_dlzunregister
dns_dnssec_findzonekeys
dns_dnssec_findzonekeys2
dns_dnssec_keyfromrdata
dns_sdb_putsoa
dns_sdb_register
dns_sdb_unregister
+dns_sdlz_putnamedrr
+dns_sdlz_putrr
+dns_sdlz_putsoa
+dns_sdlzregister
+dns_sdlzunregister
dns_secalg_fromtext
dns_secalg_totext
dns_secproto_fromtext
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: dir.c,v 1.22 2005/04/29 00:23:49 marka Exp $ */
+/* $Id: dir.c,v 1.23 2005/09/05 00:11:04 marka Exp $ */
/*! \file
* \author Principal Authors: DCL */
*/
isc_result_t
isc_dir_open(isc_dir_t *dir, const char *dirname) {
+ char *p;
isc_result_t result = ISC_R_SUCCESS;
REQUIRE(VALID_DIR(dir));
REQUIRE(dirname != NULL);
+ /*
+ * Copy directory name. Need to have enough space for the name,
+ * a possible path separator, the wildcard, and the final NUL.
+ */
+ if (strlen(dirname) + 3 > sizeof(dir->dirname))
+ /* XXXDCL ? */
+ return (ISC_R_NOSPACE);
+ strcpy(dir->dirname, dirname);
+
+ /*
+ * Append path separator, if needed, and "*".
+ */
+ p = dir->dirname + strlen(dir->dirname);
+ if (dir->dirname < p && *(p - 1) != '/')
+ *p++ = '/';
+ *p++ = '*';
+ *p++ = '\0';
+
/*
* Open stream.
*/
# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
# PERFORMANCE OF THIS SOFTWARE.
-# $Id: Makefile.in,v 1.15 2005/01/12 01:56:12 marka Exp $
+# $Id: Makefile.in,v 1.16 2005/09/05 00:11:04 marka Exp $
srcdir = @srcdir@
VPATH = @srcdir@
CINCLUDES = -I. ${DNS_INCLUDES} ${ISC_INCLUDES} ${ISCCFG_INCLUDES}
-CDEFINES =
+CDEFINES = @USE_DLZ@
CWARNINGS =
ISCLIBS = ../../lib/isc/libisc.@A@
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: namedconf.c,v 1.56 2005/08/24 23:54:04 marka Exp $ */
+/* $Id: namedconf.c,v 1.57 2005/09/05 00:11:05 marka Exp $ */
/*! \file */
static cfg_type_t cfg_type_viewopts;
static cfg_type_t cfg_type_zone;
static cfg_type_t cfg_type_zoneopts;
+static cfg_type_t cfg_type_dynamically_loadable_zones;
+static cfg_type_t cfg_type_dynamically_loadable_zones_opts;
+
+/*
+ * Clauses that can be found in a 'dynamically loadable zones' statement
+ */
+static cfg_clausedef_t
+dynamically_loadable_zones_clauses[] = {
+ { "database", &cfg_type_astring, 0 },
+ { NULL, NULL, 0 }
+};
+
+/*
+ * A dynamically loadable zones statement.
+ */
+static cfg_tuplefielddef_t dynamically_loadable_zones_fields[] = {
+ { "name", &cfg_type_astring, 0 },
+ { "options", &cfg_type_dynamically_loadable_zones_opts, 0 },
+ { NULL, NULL, 0 }
+};
+
+static cfg_type_t cfg_type_dynamically_loadable_zones = {
+ "dlz", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple,
+ &cfg_rep_tuple,
+ dynamically_loadable_zones_fields
+ };
+
/*% tkey-dhkey */
namedconf_or_view_clauses[] = {
{ "key", &cfg_type_key, CFG_CLAUSEFLAG_MULTI },
{ "zone", &cfg_type_zone, CFG_CLAUSEFLAG_MULTI },
+ /* only 1 DLZ per view allowed */
+ { "dlz", &cfg_type_dynamically_loadable_zones, 0 },
{ "server", &cfg_type_server, CFG_CLAUSEFLAG_MULTI },
{ "trusted-keys", &cfg_type_trustedkeys, CFG_CLAUSEFLAG_MULTI },
{ NULL, NULL, 0 }
namedconf_or_view_clauses,
view_clauses,
zone_clauses,
+ dynamically_loadable_zones_clauses,
NULL
};
static cfg_type_t cfg_type_viewopts = {
NULL
};
static cfg_type_t cfg_type_zoneopts = {
- "zoneopts", cfg_parse_map, cfg_print_map, cfg_doc_map, &cfg_rep_map, zone_clausesets };
-
+ "zoneopts", cfg_parse_map, cfg_print_map,
+ cfg_doc_map, &cfg_rep_map, zone_clausesets };
+
+/*% The "dynamically loadable zones" statement syntax. */
+
+static cfg_clausedef_t *
+dynamically_loadable_zones_clausesets[] = {
+ dynamically_loadable_zones_clauses,
+ NULL
+};
+static cfg_type_t cfg_type_dynamically_loadable_zones_opts = {
+ "dynamically_loadable_zones_opts", cfg_parse_map,
+ cfg_print_map, cfg_doc_map, &cfg_rep_map,
+ dynamically_loadable_zones_clausesets
+};
+
/*%
* Clauses that can be found within the 'key' statement.
*/
NULL
};
static cfg_type_t cfg_type_key = {
- "key", cfg_parse_named_map, cfg_print_map, cfg_doc_map, &cfg_rep_map, key_clausesets };
+ "key", cfg_parse_named_map, cfg_print_map,
+ cfg_doc_map, &cfg_rep_map, key_clausesets
+};
/*%
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: parser.c,v 1.118 2005/08/23 02:36:10 marka Exp $ */
+/* $Id: parser.c,v 1.119 2005/09/05 00:11:05 marka Exp $ */
/*! \file */
}
}
-
isc_boolean_t
cfg_obj_islist(cfg_obj_t *obj) {
REQUIRE(obj != NULL);