mirror of
https://gitlab.isc.org/isc-projects/bind9.git
synced 2025-04-18 09:44:09 +03:00
1235 lines
32 KiB
C
1235 lines
32 KiB
C
/*
|
|
* 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, 2016 Internet Systems Consortium, Inc. ("ISC")
|
|
*
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
*/
|
|
|
|
#ifdef DLZ_LDAP
|
|
#include <stdbool.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.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 <dns/log.h>
|
|
#include <dns/result.h>
|
|
#include <dns/sdlz.h>
|
|
|
|
#include <dlz/dlz_ldap_driver.h>
|
|
#include <dlz/sdlz_helper.h>
|
|
#include <named/globals.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 everything needed by this "instance" of the LDAP
|
|
* driver remember, the driver code is only loaded once, but may have
|
|
* many separate instances.
|
|
*/
|
|
|
|
typedef struct {
|
|
db_list_t *db; /*%< handle to a list of DB */
|
|
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,
|
|
dns_clientinfomethods_t *methods,
|
|
dns_clientinfo_t *clientinfo);
|
|
|
|
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);
|
|
}
|
|
|
|
/*%
|
|
* 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(named_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);
|
|
}
|
|
|
|
static isc_result_t
|
|
ldap_process_results(LDAP *dbc, LDAPMessage *msg, char **attrs, void *ptr,
|
|
bool 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(named_g_mctx, len + 1);
|
|
|
|
/*
|
|
* 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 attribute 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 positive number");
|
|
goto cleanup;
|
|
}
|
|
break;
|
|
case 1:
|
|
j++;
|
|
type = isc_mem_strdup(named_g_mctx, vals[0]);
|
|
break;
|
|
case 2:
|
|
j++;
|
|
if (allnodes) {
|
|
host = isc_mem_strdup(named_g_mctx,
|
|
vals[0]);
|
|
} else {
|
|
strcpy(data, vals[0]);
|
|
}
|
|
break;
|
|
case 3:
|
|
j++;
|
|
if (allnodes) {
|
|
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 attribute 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 && host != NULL) {
|
|
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);
|
|
}
|
|
if (result != ISC_R_SUCCESS) {
|
|
isc_log_write(dns_lctx,
|
|
DNS_LOGCATEGORY_DATABASE,
|
|
DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
|
|
"dlz-ldap: putnamedrr failed "
|
|
"for \"%s %s %u %s\", %s",
|
|
host, type, ttl, data,
|
|
isc_result_totext(result));
|
|
}
|
|
} 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,
|
|
"dlz-ldap: putrr failed "
|
|
"for \"%s %u %s\", %s",
|
|
type, ttl, data,
|
|
isc_result_totext(result));
|
|
}
|
|
}
|
|
|
|
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(named_g_mctx, type);
|
|
isc_mem_free(named_g_mctx, data);
|
|
if (host != NULL) {
|
|
isc_mem_free(named_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(named_g_mctx, host);
|
|
}
|
|
if (type != NULL) {
|
|
isc_mem_free(named_g_mctx, type);
|
|
}
|
|
if (data != NULL) {
|
|
isc_mem_free(named_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 */
|
|
/* find an available DBI from the list */
|
|
dbi = ldap_find_avail_conn(
|
|
(db_list_t *)((ldap_instance_t *)dbdata)->db);
|
|
|
|
/* 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(named_g_mctx, zone);
|
|
} else {
|
|
dbi->zone = NULL;
|
|
}
|
|
if (record != NULL) {
|
|
dbi->record = isc_mem_strdup(named_g_mctx, record);
|
|
} else {
|
|
dbi->record = NULL;
|
|
}
|
|
if (client != NULL) {
|
|
dbi->client = isc_mem_strdup(named_g_mctx, client);
|
|
} 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(named_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(named_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(named_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(named_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(named_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 synchronously */
|
|
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, true);
|
|
break;
|
|
case AUTHORITY:
|
|
case LOOKUP:
|
|
result = ldap_process_results((LDAP *)dbi->dbconn, ldap_msg,
|
|
ldap_url->lud_attrs, ptr, 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(named_g_mctx, dbi->zone);
|
|
}
|
|
if (dbi->record != NULL) {
|
|
isc_mem_free(named_g_mctx, dbi->record);
|
|
}
|
|
if (dbi->client != NULL) {
|
|
isc_mem_free(named_g_mctx, dbi->client);
|
|
}
|
|
|
|
/* release the lock so another thread can use this dbi */
|
|
isc_mutex_unlock(&dbi->instance_lock);
|
|
|
|
/* release query string */
|
|
if (querystring != NULL) {
|
|
isc_mem_free(named_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, NULL, NULL);
|
|
if (result != ISC_R_SUCCESS) {
|
|
return (result);
|
|
}
|
|
|
|
/* get all the zone data */
|
|
result = ldap_get_results(name, NULL, client, ALLOWXFR, dbdata, NULL);
|
|
return (result);
|
|
}
|
|
|
|
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,
|
|
dns_clientinfomethods_t *methods,
|
|
dns_clientinfo_t *clientinfo) {
|
|
UNUSED(driverarg);
|
|
UNUSED(methods);
|
|
UNUSED(clientinfo);
|
|
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,
|
|
dns_clientinfomethods_t *methods,
|
|
dns_clientinfo_t *clientinfo) {
|
|
isc_result_t result;
|
|
|
|
UNUSED(driverarg);
|
|
UNUSED(methods);
|
|
UNUSED(clientinfo);
|
|
|
|
if (strcmp(name, "*") == 0) {
|
|
result = ldap_get_results(zone, "~", NULL, LOOKUP, dbdata,
|
|
lookup);
|
|
} else {
|
|
result = ldap_get_results(zone, name, NULL, LOOKUP, dbdata,
|
|
lookup);
|
|
}
|
|
return (result);
|
|
}
|
|
|
|
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;
|
|
int dbcount;
|
|
char *endp;
|
|
/* db_list_t *dblist = NULL; */
|
|
int i;
|
|
|
|
UNUSED(dlzname);
|
|
UNUSED(driverarg);
|
|
|
|
/* 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");
|
|
|
|
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);
|
|
}
|
|
|
|
/* 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);
|
|
}
|
|
|
|
/* 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(named_g_mctx, sizeof(ldap_instance_t));
|
|
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(named_g_mctx, argv[6]);
|
|
ldap_inst->user = isc_mem_strdup(named_g_mctx, argv[4]);
|
|
ldap_inst->cred = isc_mem_strdup(named_g_mctx, argv[5]);
|
|
|
|
/* allocate memory for database connection list */
|
|
ldap_inst->db = isc_mem_get(named_g_mctx, sizeof(db_list_t));
|
|
|
|
/* 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++) {
|
|
/* how many queries were passed in from config file? */
|
|
switch (argc) {
|
|
case 9:
|
|
result = build_sqldbinstance(named_g_mctx, NULL, NULL,
|
|
NULL, argv[7], argv[8],
|
|
NULL, &dbi);
|
|
break;
|
|
case 10:
|
|
result = build_sqldbinstance(named_g_mctx, NULL, NULL,
|
|
argv[9], argv[7], argv[8],
|
|
NULL, &dbi);
|
|
break;
|
|
case 11:
|
|
result = build_sqldbinstance(named_g_mctx, argv[10],
|
|
NULL, argv[9], argv[7],
|
|
argv[8], NULL, &dbi);
|
|
break;
|
|
case 12:
|
|
result = build_sqldbinstance(named_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;
|
|
}
|
|
|
|
ISC_LINK_INIT(dbi, link);
|
|
ISC_LIST_APPEND(*(ldap_inst->db), dbi, link);
|
|
|
|
/* 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:
|
|
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);
|
|
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:
|
|
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);
|
|
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) */
|
|
|
|
/* set DBI = null for next loop through. */
|
|
dbi = NULL;
|
|
} /* end for loop */
|
|
|
|
/* 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) {
|
|
/* cleanup the list of DBI's */
|
|
ldap_destroy_dblist(
|
|
(db_list_t *)((ldap_instance_t *)dbdata)->db);
|
|
|
|
if (((ldap_instance_t *)dbdata)->hosts != NULL) {
|
|
isc_mem_free(named_g_mctx,
|
|
((ldap_instance_t *)dbdata)->hosts);
|
|
}
|
|
|
|
if (((ldap_instance_t *)dbdata)->user != NULL) {
|
|
isc_mem_free(named_g_mctx,
|
|
((ldap_instance_t *)dbdata)->user);
|
|
}
|
|
|
|
if (((ldap_instance_t *)dbdata)->cred != NULL) {
|
|
isc_mem_free(named_g_mctx,
|
|
((ldap_instance_t *)dbdata)->cred);
|
|
}
|
|
|
|
isc_mem_put(named_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,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
};
|
|
|
|
/*%
|
|
* 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,
|
|
named_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 /* ifdef DLZ_LDAP */
|