dlz_ldap_driver.c revision 03e200df5dc283f24a6a349f0b31d3eab26da893
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister/*
dda4bfe6499d09ea8123447579e56069d8176fcbBob Halley * Copyright (C) 2002 Stichting NLnet, Netherlands, stichting@nlnet.nl.
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister *
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister * Permission to use, copy, modify, and distribute this software for any
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister * purpose with or without fee is hereby granted, provided that the
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister * above copyright notice and this permission notice appear in all
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister * copies.
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister *
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister * THE SOFTWARE IS PROVIDED "AS IS" AND STICHTING NLNET
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister * STICHTING NLNET BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister * USE OR PERFORMANCE OF THIS SOFTWARE.
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister *
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister * The development of Dynamically Loadable Zones (DLZ) for Bind 9 was
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister * conceived and contributed by Rob Butler.
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister *
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister * Permission to use, copy, modify, and distribute this software for any
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister * purpose with or without fee is hereby granted, provided that the
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister * above copyright notice and this permission notice appear in all
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister * copies.
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister *
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister * THE SOFTWARE IS PROVIDED "AS IS" AND ROB BUTLER
364a82f7c25b62967678027043425201a5e5171aBob Halley * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
b3e77535185043f089b346166440402d092030c3David Lawrence * ROB BUTLER BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
b3e77535185043f089b346166440402d092030c3David Lawrence * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister * USE OR PERFORMANCE OF THIS SOFTWARE.
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister */
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister/*
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister * Copyright (C) 1999-2001 Internet Software Consortium.
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister *
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister * Permission to use, copy, modify, and distribute this software for any
72166c5cf59db011cce11e98abe377f5aa6f7052Andreas Gustafsson * purpose with or without fee is hereby granted, provided that the above
5475a2d296215b7a93bd89804dc33c36a6de7cb5James Brister * copyright notice and this permission notice appear in all copies.
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister *
b3e77535185043f089b346166440402d092030c3David Lawrence * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
b3e77535185043f089b346166440402d092030c3David Lawrence * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
b3e77535185043f089b346166440402d092030c3David Lawrence * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
b3e77535185043f089b346166440402d092030c3David Lawrence * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
b3e77535185043f089b346166440402d092030c3David Lawrence * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
b3e77535185043f089b346166440402d092030c3David Lawrence * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister */
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister#ifdef DLZ_LDAP
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister#include <config.h>
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister#include <stdio.h>
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister#include <string.h>
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister#include <stdlib.h>
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister#include <dns/log.h>
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister#include <dns/sdlz.h>
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister#include <dns/result.h>
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister#include <isc/mem.h>
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister#include <isc/platform.h>
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister#include <isc/print.h>
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister#include <isc/result.h>
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister#include <isc/string.h>
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister#include <isc/util.h>
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister#include <named/globals.h>
b3e77535185043f089b346166440402d092030c3David Lawrence
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister#include <dlz/sdlz_helper.h>
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister#include <dlz/dlz_ldap_driver.h>
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister/*
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister * Need older API functions from ldap.h.
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister */
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister#define LDAP_DEPRECATED 1
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister#include <ldap.h>
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister#define SIMPLE "simple"
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister#define KRB41 "krb41"
b3e77535185043f089b346166440402d092030c3David Lawrence#define KRB42 "krb42"
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister#define V2 "v2"
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister#define V3 "v3"
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister
2cde028c51055c9fd4837337116cd4fdfe8ff623James Bristerstatic dns_sdlzimplementation_t *dlz_ldap = NULL;
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister#define dbc_search_limit 30
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister#define ALLNODES 1
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister#define ALLOWXFR 2
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister#define AUTHORITY 3
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister#define FINDZONE 4
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister#define LOOKUP 5
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister/*%
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister * Structure to hold everthing needed by this "instance" of the LDAP
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister * driver remember, the driver code is only loaded once, but may have
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister * many separate instances.
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister */
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister
2cde028c51055c9fd4837337116cd4fdfe8ff623James Bristertypedef struct {
b3e77535185043f089b346166440402d092030c3David Lawrence
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister#ifdef ISC_PLATFORM_USETHREADS
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister db_list_t *db; /*%< handle to a list of DB */
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister#else
b3e77535185043f089b346166440402d092030c3David Lawrence dbinstance_t *db; /*%< handle to db */
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister#endif
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister int method; /*%< security authentication method */
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister char *user; /*%< who is authenticating */
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister char *cred; /*%< password for simple authentication method */
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister int protocol; /*%< LDAP communication protocol version */
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister char *hosts; /*%< LDAP server hosts */
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister} ldap_instance_t;
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister/* forward references */
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister
2cde028c51055c9fd4837337116cd4fdfe8ff623James Bristerstatic isc_result_t
2cde028c51055c9fd4837337116cd4fdfe8ff623James Bristerdlz_ldap_findzone(void *driverarg, void *dbdata, const char *name);
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister
2cde028c51055c9fd4837337116cd4fdfe8ff623James Bristerstatic void
2cde028c51055c9fd4837337116cd4fdfe8ff623James Bristerdlz_ldap_destroy(void *driverarg, void *dbdata);
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister/*
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister * Private methods
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister */
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister/*% checks that the LDAP URL parameters make sense */
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister
2cde028c51055c9fd4837337116cd4fdfe8ff623James Bristerstatic isc_result_t
2cde028c51055c9fd4837337116cd4fdfe8ff623James Bristerdlz_ldap_checkURL(char *URL, int attrCnt, const char *msg) {
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister isc_result_t result = ISC_R_SUCCESS;
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister int ldap_result;
b3e77535185043f089b346166440402d092030c3David Lawrence LDAPURLDesc *ldap_url = NULL;
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister if (!ldap_is_ldap_url(URL)) {
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister "%s query is not a valid LDAP URL", msg);
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister result = ISC_R_FAILURE;
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister goto cleanup;
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister }
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister ldap_result = ldap_url_parse(URL, &ldap_url);
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister if (ldap_result != LDAP_SUCCESS || ldap_url == NULL) {
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister "parsing %s query failed", msg);
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister result = ISC_R_FAILURE;
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister goto cleanup;
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister }
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister if (ldap_count_values(ldap_url->lud_attrs) < attrCnt) {
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister "%s query must specify at least "
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister "%d attributes to return",
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister msg, attrCnt);
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister result = ISC_R_FAILURE;
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister goto cleanup;
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister }
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister if (ldap_url->lud_host != NULL) {
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister "%s query must not specify a host", msg);
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister result = ISC_R_FAILURE;
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister goto cleanup;
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister }
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister if (ldap_url->lud_port != 389) {
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
b3e77535185043f089b346166440402d092030c3David Lawrence "%s query must not specify a port", msg);
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister result = ISC_R_FAILURE;
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister goto cleanup;
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister }
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister if (ldap_url->lud_dn == NULL || strlen (ldap_url->lud_dn) < 1) {
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister "%s query must specify a search base", msg);
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister result = ISC_R_FAILURE;
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister goto cleanup;
b3e77535185043f089b346166440402d092030c3David Lawrence }
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister if (ldap_url->lud_exts != NULL || ldap_url->lud_crit_exts != 0) {
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister "%s uses extensions. "
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister "The driver does not support LDAP extensions.",
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister msg);
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister result = ISC_R_FAILURE;
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister goto cleanup;
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister }
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister cleanup:
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister if (ldap_url != NULL)
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister ldap_free_urldesc(ldap_url);
5475a2d296215b7a93bd89804dc33c36a6de7cb5James Brister
5475a2d296215b7a93bd89804dc33c36a6de7cb5James Brister return result;
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister}
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister/*% Connects / reconnects to LDAP server */
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister
2cde028c51055c9fd4837337116cd4fdfe8ff623James Bristerstatic isc_result_t
2cde028c51055c9fd4837337116cd4fdfe8ff623James Bristerdlz_ldap_connect(ldap_instance_t *dbi, dbinstance_t *dbc) {
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister isc_result_t result;
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister int ldap_result;
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister /* if we have a connection, get ride of it. */
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister if (dbc->dbconn != NULL) {
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister ldap_unbind_s((LDAP *) dbc->dbconn);
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister dbc->dbconn = NULL;
b3e77535185043f089b346166440402d092030c3David Lawrence }
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister /* now connect / reconnect. */
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister /* initialize. */
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister dbc->dbconn = ldap_init(dbi->hosts, LDAP_PORT);
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister if (dbc->dbconn == NULL)
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister return ISC_R_NOMEMORY;
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister /* set protocol version. */
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister ldap_result = ldap_set_option((LDAP *) dbc->dbconn,
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister LDAP_OPT_PROTOCOL_VERSION,
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister &(dbi->protocol));
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister if (ldap_result != LDAP_SUCCESS) {
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister result = ISC_R_NOPERM;
b3e77535185043f089b346166440402d092030c3David Lawrence goto cleanup;
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister }
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister /* "bind" to server. i.e. send username / pass */
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister ldap_result = ldap_bind_s((LDAP *) dbc->dbconn, dbi->user,
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister dbi->cred, dbi->method);
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister if (ldap_result != LDAP_SUCCESS) {
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister result = ISC_R_FAILURE;
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister goto cleanup;
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister }
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister return ISC_R_SUCCESS;
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister cleanup:
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister /* cleanup if failure. */
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister if (dbc->dbconn != NULL) {
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister ldap_unbind_s((LDAP *) dbc->dbconn);
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister dbc->dbconn = NULL;
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister }
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister return result;
b3e77535185043f089b346166440402d092030c3David Lawrence}
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister#ifdef ISC_PLATFORM_USETHREADS
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister/*%
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister * Properly cleans up a list of database instances.
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister * This function is only used when the driver is compiled for
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister * multithreaded operation.
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister */
2cde028c51055c9fd4837337116cd4fdfe8ff623James Bristerstatic void
2cde028c51055c9fd4837337116cd4fdfe8ff623James Bristerldap_destroy_dblist(db_list_t *dblist)
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister{
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister dbinstance_t *ndbi = NULL;
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister dbinstance_t *dbi = NULL;
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister /* get the first DBI in the list */
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister ndbi = ISC_LIST_HEAD(*dblist);
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister /* loop through the list */
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister while (ndbi != NULL) {
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister dbi = ndbi;
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister /* get the next DBI in the list */
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister ndbi = ISC_LIST_NEXT(dbi, link);
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister /* release DB connection */
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister if (dbi->dbconn != NULL)
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister ldap_unbind_s((LDAP *) dbi->dbconn);
b3e77535185043f089b346166440402d092030c3David Lawrence /* release all memory that comprised a DBI */
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister destroy_sqldbinstance(dbi);
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister }
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister /* release memory for the list structure */
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister isc_mem_put(ns_g_mctx, dblist, sizeof(db_list_t));
b3e77535185043f089b346166440402d092030c3David Lawrence}
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister/*%
b3e77535185043f089b346166440402d092030c3David Lawrence * Loops through the list of DB instances, attempting to lock
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister * on the mutex. If successful, the DBI is reserved for use
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister * and the thread can perform queries against the database.
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister * If the lock fails, the next one in the list is tried.
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister * looping continues until a lock is obtained, or until
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister * the list has been searched dbc_search_limit times.
b3e77535185043f089b346166440402d092030c3David Lawrence * This function is only used when the driver is compiled for
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister * multithreaded operation.
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister */
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister
b3e77535185043f089b346166440402d092030c3David Lawrencestatic dbinstance_t *
2cde028c51055c9fd4837337116cd4fdfe8ff623James Bristerldap_find_avail_conn(db_list_t *dblist)
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister{
b3e77535185043f089b346166440402d092030c3David Lawrence dbinstance_t *dbi = NULL;
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister dbinstance_t *head;
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister int count = 0;
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister /* get top of list */
5475a2d296215b7a93bd89804dc33c36a6de7cb5James Brister head = dbi = ISC_LIST_HEAD(*dblist);
b3e77535185043f089b346166440402d092030c3David Lawrence
5475a2d296215b7a93bd89804dc33c36a6de7cb5James Brister /* loop through list */
5475a2d296215b7a93bd89804dc33c36a6de7cb5James Brister while (count < dbc_search_limit) {
5475a2d296215b7a93bd89804dc33c36a6de7cb5James Brister /* try to lock on the mutex */
5475a2d296215b7a93bd89804dc33c36a6de7cb5James Brister if (isc_mutex_trylock(&dbi->instance_lock) == ISC_R_SUCCESS)
b3e77535185043f089b346166440402d092030c3David Lawrence return dbi; /* success, return the DBI for use. */
5475a2d296215b7a93bd89804dc33c36a6de7cb5James Brister
5475a2d296215b7a93bd89804dc33c36a6de7cb5James Brister /* not successful, keep trying */
b3e77535185043f089b346166440402d092030c3David Lawrence dbi = ISC_LIST_NEXT(dbi, link);
5475a2d296215b7a93bd89804dc33c36a6de7cb5James Brister
5475a2d296215b7a93bd89804dc33c36a6de7cb5James Brister /* check to see if we have gone to the top of the list. */
5475a2d296215b7a93bd89804dc33c36a6de7cb5James Brister if (dbi == NULL) {
5475a2d296215b7a93bd89804dc33c36a6de7cb5James Brister count++;
5475a2d296215b7a93bd89804dc33c36a6de7cb5James Brister dbi = head;
b3e77535185043f089b346166440402d092030c3David Lawrence }
5475a2d296215b7a93bd89804dc33c36a6de7cb5James Brister }
5475a2d296215b7a93bd89804dc33c36a6de7cb5James Brister isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
5475a2d296215b7a93bd89804dc33c36a6de7cb5James Brister DNS_LOGMODULE_DLZ, ISC_LOG_INFO,
b3e77535185043f089b346166440402d092030c3David Lawrence "LDAP driver unable to find available connection "
5475a2d296215b7a93bd89804dc33c36a6de7cb5James Brister "after searching %d times",
5475a2d296215b7a93bd89804dc33c36a6de7cb5James Brister count);
5475a2d296215b7a93bd89804dc33c36a6de7cb5James Brister return NULL;
5475a2d296215b7a93bd89804dc33c36a6de7cb5James Brister}
5475a2d296215b7a93bd89804dc33c36a6de7cb5James Brister
5475a2d296215b7a93bd89804dc33c36a6de7cb5James Brister#endif /* ISC_PLATFORM_USETHREADS */
5475a2d296215b7a93bd89804dc33c36a6de7cb5James Brister
5475a2d296215b7a93bd89804dc33c36a6de7cb5James Bristerstatic isc_result_t
b3e77535185043f089b346166440402d092030c3David Lawrenceldap_process_results(LDAP *dbc, LDAPMessage *msg, char ** attrs,
5475a2d296215b7a93bd89804dc33c36a6de7cb5James Brister void *ptr, isc_boolean_t allnodes)
5475a2d296215b7a93bd89804dc33c36a6de7cb5James Brister{
5475a2d296215b7a93bd89804dc33c36a6de7cb5James Brister isc_result_t result = ISC_R_SUCCESS;
5475a2d296215b7a93bd89804dc33c36a6de7cb5James Brister int i = 0;
b3e77535185043f089b346166440402d092030c3David Lawrence int j;
5475a2d296215b7a93bd89804dc33c36a6de7cb5James Brister int len;
5475a2d296215b7a93bd89804dc33c36a6de7cb5James Brister char *attribute = NULL;
b3e77535185043f089b346166440402d092030c3David Lawrence LDAPMessage *entry;
5475a2d296215b7a93bd89804dc33c36a6de7cb5James Brister char *endp = NULL;
5475a2d296215b7a93bd89804dc33c36a6de7cb5James Brister char *host = NULL;
5475a2d296215b7a93bd89804dc33c36a6de7cb5James Brister char *type = NULL;
5475a2d296215b7a93bd89804dc33c36a6de7cb5James Brister char *data = NULL;
5475a2d296215b7a93bd89804dc33c36a6de7cb5James Brister char **vals = NULL;
b3e77535185043f089b346166440402d092030c3David Lawrence int ttl;
5475a2d296215b7a93bd89804dc33c36a6de7cb5James Brister
5475a2d296215b7a93bd89804dc33c36a6de7cb5James Brister /* make sure there are at least some attributes to process. */
5475a2d296215b7a93bd89804dc33c36a6de7cb5James Brister REQUIRE(attrs != NULL || attrs[0] != NULL);
b3e77535185043f089b346166440402d092030c3David Lawrence
5475a2d296215b7a93bd89804dc33c36a6de7cb5James Brister /* get the first entry to process */
5475a2d296215b7a93bd89804dc33c36a6de7cb5James Brister entry = ldap_first_entry(dbc, msg);
b3e77535185043f089b346166440402d092030c3David Lawrence if (entry == NULL) {
5475a2d296215b7a93bd89804dc33c36a6de7cb5James Brister isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
5475a2d296215b7a93bd89804dc33c36a6de7cb5James Brister DNS_LOGMODULE_DLZ, ISC_LOG_INFO,
5475a2d296215b7a93bd89804dc33c36a6de7cb5James Brister "LDAP no entries to process.");
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister return ISC_R_FAILURE;
b3e77535185043f089b346166440402d092030c3David Lawrence }
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister /* loop through all entries returned */
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister while (entry != NULL) {
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister
b3e77535185043f089b346166440402d092030c3David Lawrence /* reset for this loop */
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister ttl = 0;
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister len = 0;
b3e77535185043f089b346166440402d092030c3David Lawrence i = 0;
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister attribute = attrs[i];
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister /* determine how much space we need for data string */
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister for (j=0; attrs[j] != NULL; j++) {
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister /* get the list of values for this attribute. */
b3e77535185043f089b346166440402d092030c3David Lawrence vals = ldap_get_values(dbc, entry, attrs[j]);
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister /* skip empty attributes. */
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister if (vals == NULL || ldap_count_values(vals) < 1)
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister continue;
b3e77535185043f089b346166440402d092030c3David Lawrence /*
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister * we only use the first value. this driver
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister * does not support multi-valued attributes.
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister */
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister len = len + strlen(vals[0]) + 1;
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister /* free vals for next loop */
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister ldap_value_free(vals);
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister } /* end for (j=0; attrs[j] != NULL, j++) loop */
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister
b3e77535185043f089b346166440402d092030c3David Lawrence /* allocate memory for data string */
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister data = isc_mem_allocate(ns_g_mctx, len + 1);
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister if (data == NULL) {
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
b3e77535185043f089b346166440402d092030c3David Lawrence "LDAP driver unable to allocate memory "
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister "while processing results");
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister result = ISC_R_FAILURE;
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister goto cleanup;
b3e77535185043f089b346166440402d092030c3David Lawrence }
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister /*
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister * Make sure data is null termed at the beginning so
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister * we can check if any data was stored to it later.
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister */
b3e77535185043f089b346166440402d092030c3David Lawrence data[0] = '\0';
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister /* reset j to re-use below */
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister j = 0;
b3e77535185043f089b346166440402d092030c3David Lawrence
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister /* loop through the attributes in the order specified. */
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister while (attribute != NULL) {
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister /* get the list of values for this attribute. */
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister vals = ldap_get_values(dbc, entry, attribute);
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister /* skip empty attributes. */
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister if (vals == NULL || vals[0] == NULL) {
b3e77535185043f089b346166440402d092030c3David Lawrence /* increment attibute pointer */
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister attribute = attrs[++i];
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister /* start loop over */
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister continue;
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister }
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister /*
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister * j initially = 0. Increment j each time we
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister * set a field that way next loop will set
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister * next field.
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister */
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister switch(j) {
b3e77535185043f089b346166440402d092030c3David Lawrence case 0:
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister j++;
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister /*
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister * convert text to int, make sure it
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister * worked right
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister */
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister ttl = strtol(vals[0], &endp, 10);
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister if (*endp != '\0' || ttl < 0) {
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister isc_log_write(dns_lctx,
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister DNS_LOGCATEGORY_DATABASE,
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister DNS_LOGMODULE_DLZ,
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister ISC_LOG_ERROR,
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister "LDAP driver ttl must "
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister "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