diff options
Diffstat (limited to 'ldap_helper.c')
-rw-r--r-- | ldap_helper.c | 1707 |
1 files changed, 0 insertions, 1707 deletions
diff --git a/ldap_helper.c b/ldap_helper.c deleted file mode 100644 index 427191a..0000000 --- a/ldap_helper.c +++ /dev/null @@ -1,1707 +0,0 @@ -/* Authors: Martin Nagy <mnagy@redhat.com> - * Adam Tkac <atkac@redhat.com> - * - * Copyright (C) 2008, 2009 Red Hat - * see file 'COPYING' for use and warranty information - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; version 2 only - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include <dns/rbt.h> -#include <dns/rdata.h> -#include <dns/rdataclass.h> -#include <dns/rdatalist.h> -#include <dns/rdatatype.h> -#include <dns/result.h> -#include <dns/ttl.h> -#include <dns/view.h> -#include <dns/zone.h> - -#include <isc/buffer.h> -#include <isc/lex.h> -#include <isc/mem.h> -#include <isc/mutex.h> -#include <isc/region.h> -#include <isc/rwlock.h> -#include <isc/util.h> - -#define LDAP_DEPRECATED 1 -#include <ldap.h> -#include <sasl/sasl.h> -#include <stddef.h> -#include <string.h> -#include <strings.h> - -#include "ldap_convert.h" -#include "ldap_helper.h" -#include "log.h" -#include "semaphore.h" -#include "settings.h" -#include "str.h" -#include "util.h" - - -/* Max type length definitions, from lib/dns/master.c */ -#define MINTSIZ (65535 - 12 - 1 - 2 - 2 - 4 - 2) -#define TOKENSIZ (8*1024) - -#define LDAP_OPT_CHECK(r, ...) \ - do { \ - if ((r) != LDAP_OPT_SUCCESS) { \ - log_error(__VA_ARGS__); \ - goto cleanup; \ - } \ - } while (0) - -/* - * LDAP related typedefs and structs. - */ - -typedef struct ldap_auth_pair ldap_auth_pair_t; -typedef struct settings settings_t; -typedef struct ldap_value ldap_value_t; -typedef struct ldap_attribute ldap_attribute_t; -typedef struct ldap_entry ldap_entry_t; -typedef LIST(ldap_value_t) ldap_value_list_t; -typedef LIST(ldap_attribute_t) ldap_attribute_list_t; -typedef LIST(ldap_entry_t) ldap_entry_list_t; - -/* Authentication method. */ -typedef enum ldap_auth { - AUTH_INVALID = 0, - AUTH_NONE, - AUTH_SIMPLE, - AUTH_SASL, -} ldap_auth_t; - -struct ldap_auth_pair { - enum ldap_auth value; /* Value actually passed to ldap_bind(). */ - char *name; /* String representation used in configuration file */ -}; - -/* These are typedefed in ldap_helper.h */ -struct ldap_db { - isc_mem_t *mctx; - dns_view_t *view; - - /* List of LDAP connections. */ - semaphore_t conn_semaphore; - LIST(ldap_instance_t) conn_list; - - /* Our own list of zones. */ - isc_rwlock_t zone_rwlock; - dns_rbt_t *zone_names; - - /* Settings. */ - ld_string_t *host; - ld_string_t *base; - unsigned int connections; - ldap_auth_t auth_method; - ld_string_t *bind_dn; - ld_string_t *password; - ld_string_t *sasl_mech; - ld_string_t *sasl_user; - ld_string_t *sasl_realm; -}; - -struct ldap_instance { - ldap_db_t *database; - isc_mutex_t lock; - LINK(ldap_instance_t) link; - ld_string_t *query_string; - ld_string_t *base; - - LDAP *handle; - LDAPMessage *result; - - /* Parsing. */ - isc_lex_t *lex; - isc_buffer_t rdata_target; - unsigned char *rdata_target_mem; - - /* Cache. */ - ldap_entry_list_t ldap_entries; - isc_boolean_t cache_active; - - /* Temporary stuff. */ - LDAPMessage *entry; - BerElement *ber; - char *attribute; - char **values; - char *dn; -}; - -struct ldap_entry { - LDAPMessage *entry; - ldap_attribute_t *last_attr; - ldap_attribute_list_t attributes; - LINK(ldap_entry_t) link; -}; - -struct ldap_attribute { - char *name; - char **ldap_values; - ldap_value_t *last_value; - ldap_value_list_t values; - LINK(ldap_attribute_t) link; -}; - -struct ldap_value { - char *value; - LINK(ldap_value_t) link; -}; - -/* - * Constants. - */ - -extern const char *ldapdb_impname; - -/* Supported authentication types. */ -const ldap_auth_pair_t supported_ldap_auth[] = { - { AUTH_NONE, "none" }, - { AUTH_SIMPLE, "simple" }, - { AUTH_SASL, "sasl" }, - { AUTH_INVALID, NULL }, -}; - -/* - * Forward declarations. - */ - -/* TODO: reorganize this stuff & clean it up. */ -void string_deleter(void *arg1, void *arg2); -static isc_result_t new_ldap_instance(ldap_db_t *ldap_db, - ldap_instance_t **ldap_instp); -static void destroy_ldap_instance(ldap_instance_t **ldap_instp); -static isc_result_t add_or_modify_zone(ldap_db_t *ldap_db, const char *dn, - const char *db_name, dns_zonemgr_t *zmgr); - -static isc_result_t findrdatatype_or_create(isc_mem_t *mctx, - ldapdb_rdatalist_t *rdatalist, ldap_entry_t *entry, - dns_rdatatype_t rdtype, dns_rdatalist_t **rdlistp); -static isc_result_t add_soa_record(isc_mem_t *mctx, ldap_instance_t *ldap_inst, - dns_name_t *name, ldap_entry_t *entry, - ldapdb_rdatalist_t *rdatalist); -static dns_rdataclass_t get_rdataclass(ldap_entry_t *ldap_entry); -static dns_ttl_t get_ttl(ldap_entry_t *ldap_entry); -static isc_result_t get_values(const ldap_entry_t *entry, - const char *attr_name, ldap_value_list_t *values); -static isc_result_t get_soa_record(ldap_entry_t *entry, ld_string_t *target); -static ldap_attribute_t *get_next_attr(ldap_entry_t *entry, - const char **attr_list); -static ldap_value_t *get_next_value(ldap_attribute_t *attr); -static isc_boolean_t array_contains_nocase(const char **haystack, - const char *needle); -static isc_result_t get_next_rdatatype(ldap_entry_t *entry, - ldap_attribute_t **attr, dns_rdatatype_t *rdtype); -static isc_result_t get_next_rdatatext(ldap_attribute_t *attr, - ld_string_t *rdata_text); -static isc_result_t parse_rdata(isc_mem_t *mctx, ldap_instance_t *ldap_inst, - dns_rdataclass_t rdclass, dns_rdatatype_t rdtype, - dns_name_t *origin, const char *rdata_text, - dns_rdata_t **rdatap); - -static isc_result_t cache_query_results(ldap_instance_t *inst); -static isc_result_t fill_ldap_entry(ldap_instance_t *inst, - ldap_entry_t *ldap_entry); -static isc_result_t fill_ldap_attribute(ldap_instance_t *inst, - ldap_attribute_t *ldap_attr); -static void free_query_cache(ldap_instance_t *inst); -static void free_ldap_attributes(isc_mem_t *mctx, ldap_entry_t *entry); -static void free_ldap_values(isc_mem_t *mctx, ldap_attribute_t *attr); - - -static const LDAPMessage *next_entry(ldap_instance_t *inst); -static const char *get_dn(ldap_instance_t *inst); - -static ldap_instance_t * get_connection(ldap_db_t *ldap_db); -static void put_connection(ldap_instance_t *ldap_inst); -static isc_result_t ldap_connect(ldap_instance_t *ldap_inst); -static isc_result_t ldap_query(ldap_instance_t *ldap_inst, const char *base, - int scope, char **attrs, int attrsonly, const char *filter, ...); - -/* Functions for writing to LDAP. */ -static isc_result_t ldap_modify_do(ldap_instance_t *ldap_inst, const char *dn, - LDAPMod **mods); -static isc_result_t ldap_rdatalist_to_ldapmod(isc_mem_t *mctx, - dns_rdatalist_t *rdlist, LDAPMod **changep, int mod_op); -static void free_ldapmod(isc_mem_t *mctx, LDAPMod **changep); -static void free_char_array(isc_mem_t *mctx, char ***valsp); -static isc_result_t modify_ldap_common(dns_name_t *owner, ldap_db_t *ldap_db, - dns_rdatalist_t *rdlist, int mod_op); - -isc_result_t -new_ldap_db(isc_mem_t *mctx, dns_view_t *view, ldap_db_t **ldap_dbp, - const char * const *argv) -{ - unsigned int i; - isc_result_t result; - ldap_db_t *ldap_db; - ldap_instance_t *ldap_inst; - ld_string_t *auth_method_str = NULL; - setting_t ldap_settings[] = { - { "host", no_default_string }, - { "connections", default_uint(1) }, - { "base", no_default_string }, - { "auth_method", default_string("none") }, - { "bind_dn", default_string("") }, - { "password", default_string("") }, - { "sasl_mech", default_string("ANONYMOUS") }, - { "sasl_user", default_string("") }, - { "sasl_realm", default_string("") }, - end_of_settings - }; - - REQUIRE(mctx != NULL); - REQUIRE(view != NULL); - REQUIRE(ldap_dbp != NULL && *ldap_dbp == NULL); - - ldap_db = isc_mem_get(mctx, sizeof(ldap_db_t)); - if (ldap_db == NULL) - return ISC_R_NOMEMORY; - - ZERO_PTR(ldap_db); - - isc_mem_attach(mctx, &ldap_db->mctx); - ldap_db->view = view; - /* commented out for now, cause named to hang */ - //dns_view_attach(view, &ldap_db->view); - - INIT_LIST(ldap_db->conn_list); - - CHECK(isc_rwlock_init(&ldap_db->zone_rwlock, 0, 0)); - CHECK(dns_rbt_create(mctx, string_deleter, mctx, &ldap_db->zone_names)); - - CHECK(str_new(mctx, &auth_method_str)); - CHECK(str_new(mctx, &ldap_db->host)); - CHECK(str_new(mctx, &ldap_db->base)); - CHECK(str_new(mctx, &ldap_db->bind_dn)); - CHECK(str_new(mctx, &ldap_db->password)); - CHECK(str_new(mctx, &ldap_db->sasl_mech)); - CHECK(str_new(mctx, &ldap_db->sasl_user)); - CHECK(str_new(mctx, &ldap_db->sasl_realm)); - - ldap_settings[0].target = ldap_db->host; - ldap_settings[1].target = &ldap_db->connections; - ldap_settings[2].target = ldap_db->base; - ldap_settings[3].target = auth_method_str; - ldap_settings[4].target = ldap_db->bind_dn; - ldap_settings[5].target = ldap_db->password; - ldap_settings[6].target = ldap_db->sasl_mech; - ldap_settings[7].target = ldap_db->sasl_user; - ldap_settings[8].target = ldap_db->sasl_realm; - - CHECK(set_settings(ldap_settings, argv)); - - /* Validate and check settings. */ - str_toupper(ldap_db->sasl_mech); - if (ldap_db->connections < 1) { - log_error("at least one connection is required"); - result = ISC_R_FAILURE; - goto cleanup; - } - /* Select authentication method. */ - ldap_db->auth_method = AUTH_INVALID; - for (i = 0; supported_ldap_auth[i].name != NULL; i++) { - if (!str_casecmp_char(auth_method_str, - supported_ldap_auth[i].name)) { - ldap_db->auth_method = supported_ldap_auth[i].value; - break; - } - } - if (ldap_db->auth_method == AUTH_INVALID) { - log_error("unknown authentication method '%s'", - str_buf(auth_method_str)); - result = ISC_R_FAILURE; - goto cleanup; - } - - CHECK(semaphore_init(&ldap_db->conn_semaphore, ldap_db->connections)); - - for (i = 0; i < ldap_db->connections; i++) { - ldap_inst = NULL; - CHECK(new_ldap_instance(ldap_db, &ldap_inst)); - ldap_connect(ldap_inst); - APPEND(ldap_db->conn_list, ldap_inst, link); - } - -cleanup: - if (result != ISC_R_SUCCESS) - destroy_ldap_db(&ldap_db); - else - *ldap_dbp = ldap_db; - - str_destroy(&auth_method_str); - - return result; -} - -void -destroy_ldap_db(ldap_db_t **ldap_dbp) -{ - ldap_db_t *ldap_db; - ldap_instance_t *elem; - ldap_instance_t *next; - - REQUIRE(ldap_dbp != NULL && *ldap_dbp != NULL); - - ldap_db = *ldap_dbp; - - elem = HEAD(ldap_db->conn_list); - while (elem != NULL) { - next = NEXT(elem, link); - UNLINK(ldap_db->conn_list, elem, link); - destroy_ldap_instance(&elem); - elem = next; - } - - str_destroy(&ldap_db->host); - str_destroy(&ldap_db->base); - str_destroy(&ldap_db->bind_dn); - str_destroy(&ldap_db->password); - str_destroy(&ldap_db->sasl_mech); - str_destroy(&ldap_db->sasl_user); - str_destroy(&ldap_db->sasl_realm); - - semaphore_destroy(&ldap_db->conn_semaphore); - /* commented out for now, causes named to hang */ - //dns_view_detach(&ldap_db->view); - - dns_rbt_destroy(&ldap_db->zone_names); - isc_rwlock_destroy(&ldap_db->zone_rwlock); - - isc_mem_putanddetach(&ldap_db->mctx, ldap_db, sizeof(ldap_db_t)); - - *ldap_dbp = NULL; -} - -static isc_result_t -new_ldap_instance(ldap_db_t *ldap_db, ldap_instance_t **ldap_instp) -{ - isc_result_t result; - ldap_instance_t *ldap_inst; - - REQUIRE(ldap_db != NULL); - REQUIRE(ldap_instp != NULL && *ldap_instp == NULL); - - ldap_inst = isc_mem_get(ldap_db->mctx, sizeof(ldap_instance_t)); - if (ldap_inst == NULL) - return ISC_R_NOMEMORY; - - ZERO_PTR(ldap_inst); - - ldap_inst->database = ldap_db; - INIT_LINK(ldap_inst, link); - result = isc_mutex_init(&ldap_inst->lock); - if (result != ISC_R_SUCCESS) { - isc_mem_put(ldap_db->mctx, ldap_db, sizeof(ldap_instance_t)); - return result; - } - - CHECK(str_new(ldap_db->mctx, &ldap_inst->query_string)); - CHECK(str_new(ldap_db->mctx, &ldap_inst->base)); - - CHECK(isc_lex_create(ldap_db->mctx, TOKENSIZ, &ldap_inst->lex)); - CHECKED_MEM_GET(ldap_db->mctx, ldap_inst->rdata_target_mem, MINTSIZ); - - *ldap_instp = ldap_inst; - - return ISC_R_SUCCESS; - -cleanup: - destroy_ldap_instance(&ldap_inst); - - return result; -} - -static void -destroy_ldap_instance(ldap_instance_t **ldap_instp) -{ - ldap_instance_t *ldap_inst; - - REQUIRE(ldap_instp != NULL && *ldap_instp != NULL); - - ldap_inst = *ldap_instp; - DESTROYLOCK(&ldap_inst->lock); - if (ldap_inst->handle != NULL) - ldap_unbind_ext_s(ldap_inst->handle, NULL, NULL); - - str_destroy(&ldap_inst->query_string); - str_destroy(&ldap_inst->base); - - if (ldap_inst->lex != NULL) - isc_lex_destroy(&ldap_inst->lex); - if (ldap_inst->rdata_target_mem != NULL) { - isc_mem_put(ldap_inst->database->mctx, - ldap_inst->rdata_target_mem, MINTSIZ); - } - - isc_mem_put(ldap_inst->database->mctx, *ldap_instp, sizeof(ldap_instance_t)); - *ldap_instp = NULL; -} - -/* TODO: Delete old zones. */ -isc_result_t -refresh_zones_from_ldap(ldap_db_t *ldap_db, const char *name, - dns_zonemgr_t *zmgr) -{ - isc_result_t result = ISC_R_SUCCESS; - ldap_instance_t *ldap_inst; - char *attrs[] = { - "idnsName", NULL - }; - - REQUIRE(ldap_db != NULL); - REQUIRE(name != NULL); - - log_debug(2, "refreshing list of zones"); - - ldap_inst = get_connection(ldap_db); - - ldap_query(ldap_inst, str_buf(ldap_db->base), LDAP_SCOPE_SUBTREE, - attrs, 0, "(objectClass=idnsZone)"); - - while (next_entry(ldap_inst)) - CHECK(add_or_modify_zone(ldap_db, get_dn(ldap_inst), name, zmgr)); - -cleanup: - put_connection(ldap_inst); - - log_debug(2, "finished refreshing list of zones"); - - return result; -} - -static const char * -get_dn(ldap_instance_t *inst) -{ - if (inst->dn) { - ldap_memfree(inst->dn); - inst->dn = NULL; - } - - if (inst->handle && inst->entry) - inst->dn = ldap_get_dn(inst->handle, inst->entry); - - return inst->dn; - -} - - -void -string_deleter(void *arg1, void *arg2) -{ - char *string = (char *)arg1; - isc_mem_t *mctx = (isc_mem_t *)arg2; - - REQUIRE(string != NULL); - REQUIRE(mctx != NULL); - - isc_mem_free(mctx, string); -} - -isc_result_t -get_zone_dn(ldap_db_t *ldap_db, dns_name_t *name, const char **dn, - dns_name_t *matched_name) -{ - isc_result_t result; - dns_rbt_t *rbt; - void *data = NULL; - - REQUIRE(ldap_db != NULL); - REQUIRE(name != NULL); - REQUIRE(dn != NULL && *dn == NULL); - REQUIRE(matched_name != NULL); - - RWLOCK(&ldap_db->zone_rwlock, isc_rwlocktype_read); - rbt = ldap_db->zone_names; - - result = dns_rbt_findname(rbt, name, 0, matched_name, &data); - if (result == DNS_R_PARTIALMATCH) - result = ISC_R_SUCCESS; - if (result == ISC_R_SUCCESS) { - INSIST(data != NULL); - *dn = data; - } - - RWUNLOCK(&ldap_db->zone_rwlock, isc_rwlocktype_read); - - return result; -} - -static isc_result_t -add_zone_dn(ldap_db_t *ldap_db, dns_name_t *name, const char *dn) -{ - isc_result_t result; - dns_rbt_t *rbt; - void *data = NULL; - char *new_dn = NULL; - - REQUIRE(ldap_db != NULL); - REQUIRE(name != NULL); - REQUIRE(dn != NULL); - - RWLOCK(&ldap_db->zone_rwlock, isc_rwlocktype_write); - rbt = ldap_db->zone_names; - - CHECKED_MEM_STRDUP(ldap_db->mctx, dn, new_dn); - - /* First make sure the node doesn't exist. */ - result = dns_rbt_findname(rbt, name, 0, NULL, &data); - if (result == ISC_R_SUCCESS) - CHECK(dns_rbt_deletename(rbt, name, ISC_FALSE)); - else if (result != ISC_R_NOTFOUND && result != DNS_R_PARTIALMATCH) - goto cleanup; - - /* Now add it. */ - CHECK(dns_rbt_addname(rbt, name, (void *)new_dn)); - - RWUNLOCK(&ldap_db->zone_rwlock, isc_rwlocktype_write); - - return ISC_R_SUCCESS; - -cleanup: - RWUNLOCK(&ldap_db->zone_rwlock, isc_rwlocktype_write); - - if (new_dn) - isc_mem_free(ldap_db->mctx, new_dn); - - return result; -} - -/* FIXME: Better error handling. */ -static isc_result_t -add_or_modify_zone(ldap_db_t *ldap_db, const char *dn, const char *db_name, - dns_zonemgr_t *zmgr) -{ - isc_result_t result; - dns_zone_t *zone; - dns_name_t name; - dns_acl_t *updateacl = NULL; - const char *argv[2]; - - REQUIRE(ldap_db != NULL); - REQUIRE(dn != NULL); - REQUIRE(db_name != NULL); - - argv[0] = ldapdb_impname; - argv[1] = db_name; - - zone = NULL; - dns_name_init(&name, NULL); - - CHECK(dn_to_dnsname(ldap_db->mctx, dn, &name)); - - /* If the zone doesn't exist, create it. */ - result = dns_view_findzone(ldap_db->view, &name, &zone); - if (result == ISC_R_NOTFOUND) { - CHECK(dns_zone_create(&zone, ldap_db->mctx)); - dns_zone_setview(zone, ldap_db->view); - CHECK(dns_zone_setorigin(zone, &name)); - dns_zone_setclass(zone, dns_rdataclass_in); - dns_zone_settype(zone, dns_zone_master); - CHECK(dns_zone_setdbtype(zone, 2, argv)); - - /* XXX Temporary set update ACLs to any */ - CHECK(dns_acl_any(ldap_db->mctx, &updateacl)); - dns_zone_setupdateacl(zone, updateacl); - dns_acl_detach(&updateacl); - - CHECK(dns_zonemgr_managezone(zmgr, zone)); - CHECK(dns_view_addzone(ldap_db->view, zone)); - CHECK(add_zone_dn(ldap_db, &name, dn)); - } else if (result != ISC_R_SUCCESS) { - goto cleanup; - } - - /* - * ACLs: - * dns_zone_setqueryacl() - * dns_zone_setqueryonacl() - * dns_zone_setupdateacl() - * dns_zone_setforwardacl() - * dns_zone_setxfracl() - */ - - /* - * maybe? - * dns_zone_setnotifytype() - * dns_zone_setalsonotify() - */ - -cleanup: - if (dns_name_dynamic(&name)) - dns_name_free(&name, ldap_db->mctx); - if (zone != NULL) - dns_zone_detach(&zone); - - return result; -} - -static isc_result_t -findrdatatype_or_create(isc_mem_t *mctx, ldapdb_rdatalist_t *rdatalist, - ldap_entry_t *entry, dns_rdatatype_t rdtype, - dns_rdatalist_t **rdlistp) -{ - isc_result_t result; - dns_rdatalist_t *rdlist = NULL; - dns_ttl_t ttl; - - REQUIRE(rdatalist != NULL); - REQUIRE(entry != NULL); - REQUIRE(rdlistp != NULL); - - *rdlistp = NULL; - - ttl = get_ttl(entry); - - result = ldapdb_rdatalist_findrdatatype(rdatalist, rdtype, &rdlist); - if (result != ISC_R_SUCCESS) { - CHECKED_MEM_GET_PTR(mctx, rdlist); - - dns_rdatalist_init(rdlist); - rdlist->rdclass = get_rdataclass(entry); - rdlist->type = rdtype; - rdlist->ttl = ttl; - APPEND(*rdatalist, rdlist, link); - result = ISC_R_SUCCESS; - } else { - /* - * No support for different TTLs yet. - */ - if (rdlist->ttl != ttl) - result = ISC_R_FAILURE; - } - - *rdlistp = rdlist; - return ISC_R_SUCCESS; - -cleanup: - SAFE_MEM_PUT_PTR(mctx, rdlist); - - return result; -} - -/* - * ldapdb_rdatalist_t related functions. - */ -isc_result_t -ldapdb_rdatalist_findrdatatype(ldapdb_rdatalist_t *rdatalist, - dns_rdatatype_t rdtype, - dns_rdatalist_t **rdlistp) -{ - dns_rdatalist_t *rdlist; - - REQUIRE(rdatalist != NULL); - REQUIRE(rdlistp != NULL && *rdlistp == NULL); - - rdlist = HEAD(*rdatalist); - while (rdlist != NULL && rdlist->type != rdtype) { - rdlist = NEXT(rdlist, link); - } - - *rdlistp = rdlist; - - return (rdlist == NULL) ? ISC_R_NOTFOUND : ISC_R_SUCCESS; -} - -void -ldapdb_rdatalist_destroy(isc_mem_t *mctx, ldapdb_rdatalist_t *rdatalist) -{ - dns_rdatalist_t *rdlist; - - REQUIRE(rdatalist != NULL); - - while (!EMPTY(*rdatalist)) { - rdlist = HEAD(*rdatalist); - free_rdatalist(mctx, rdlist); - UNLINK(*rdatalist, rdlist, link); - isc_mem_put(mctx, rdlist, sizeof(*rdlist)); - } -} - -void -free_rdatalist(isc_mem_t *mctx, dns_rdatalist_t *rdlist) -{ - dns_rdata_t *rdata; - isc_region_t r; - - REQUIRE(rdlist != NULL); - - while (!EMPTY(rdlist->rdata)) { - rdata = HEAD(rdlist->rdata); - UNLINK(rdlist->rdata, rdata, link); - dns_rdata_toregion(rdata, &r); - isc_mem_put(mctx, r.base, r.length); - isc_mem_put(mctx, rdata, sizeof(*rdata)); - } -} - -isc_result_t -ldapdb_rdatalist_get(isc_mem_t *mctx, ldap_db_t *ldap_db, dns_name_t *name, - ldapdb_rdatalist_t *rdatalist) -{ - isc_result_t result; - ldap_instance_t *ldap_inst; - ldap_entry_t *entry; - ldap_attribute_t *attr; - ld_string_t *string = NULL; - - dns_rdataclass_t rdclass; - dns_ttl_t ttl; - dns_rdatatype_t rdtype; - dns_rdata_t *rdata = NULL; - dns_rdatalist_t *rdlist = NULL; - - REQUIRE(mctx != NULL); - REQUIRE(ldap_db != NULL); - REQUIRE(name != NULL); - REQUIRE(rdatalist != NULL); - - ldap_inst = get_connection(ldap_db); - - INIT_LIST(*rdatalist); - CHECK(str_new(mctx, &string)); - CHECK(dnsname_to_dn(ldap_db, name, string)); - - CHECK(ldap_query(ldap_inst, str_buf(string), LDAP_SCOPE_BASE, NULL, 0, - "(objectClass=idnsRecord)")); - CHECK(cache_query_results(ldap_inst)); - - if (EMPTY(ldap_inst->ldap_entries)) { - result = ISC_R_NOTFOUND; - goto cleanup; - } - - for (entry = HEAD(ldap_inst->ldap_entries); - entry != NULL; - entry = NEXT(entry, link)) { - - result = add_soa_record(mctx, ldap_inst, name, entry, - rdatalist); - if (result != ISC_R_SUCCESS && result != ISC_R_NOTFOUND) - goto cleanup; - - rdclass = get_rdataclass(entry); - ttl = get_ttl(entry); - - for (result = get_next_rdatatype(entry, &attr, &rdtype); - result == ISC_R_SUCCESS; - result = get_next_rdatatype(entry, &attr, &rdtype)) { - - CHECK(findrdatatype_or_create(mctx, rdatalist, entry, - rdtype, &rdlist)); - for (result = get_next_rdatatext(attr, string); - result == ISC_R_SUCCESS; - result = get_next_rdatatext(attr, string)) { - CHECK(parse_rdata(mctx, ldap_inst, rdclass, - rdtype, name, str_buf(string), - &rdata)); - APPEND(rdlist->rdata, rdata, link); - rdata = NULL; - } - rdlist = NULL; - } - } - - result = ISC_R_SUCCESS; - -cleanup: - put_connection(ldap_inst); - str_destroy(&string); - - if (result != ISC_R_SUCCESS) - ldapdb_rdatalist_destroy(mctx, rdatalist); - - return result; -} - -static dns_rdataclass_t -get_rdataclass(ldap_entry_t *ldap_entry) -{ - UNUSED(ldap_entry); - - /* - * Not implemented for now. - * Probably won't ever be. - */ - - return dns_rdataclass_in; -} - -static dns_ttl_t -get_ttl(ldap_entry_t *ldap_entry) -{ - UNUSED(ldap_entry); - - /* - * TODO: Not implemented yet. - */ -#if 0 - isc_textregion_t ttl_text; - - ttl_text.base = "86400"; - ttl_text.length = strlen(ttl_text.base); - result = dns_ttl_fromtext(&ttl_text, &ttl); - if (result != ISC_R_SUCCESS) { - seen_error = ISC_TRUE; - break; - } -#endif - - return 86400; -} - -static isc_result_t -get_soa_record(ldap_entry_t *entry, ld_string_t *target) -{ - isc_result_t result; - ldap_value_list_t values; - - const char *soa_attrs[] = { - "idnsSOAmName", "idnsSOArName", "idnsSOAserial", - "idnsSOArefresh", "idnsSOAretry", "idnsSOAexpire", - "idnsSOAminimum", NULL - }; - - REQUIRE(entry != NULL); - REQUIRE(target != NULL); - - str_clear(target); - for (unsigned i = 0; soa_attrs[i] != NULL; i++) { - CHECK(get_values(entry, soa_attrs[i], &values)); - CHECK(str_cat_char(target, HEAD(values)->value)); - CHECK(str_cat_char(target, " ")); - } - -cleanup: - return result; -} - -static isc_result_t -add_soa_record(isc_mem_t *mctx, ldap_instance_t *ldap_inst, dns_name_t *name, - ldap_entry_t *entry, ldapdb_rdatalist_t *rdatalist) -{ - isc_result_t result; - ld_string_t *string = NULL; - dns_rdataclass_t rdclass; - dns_rdata_t *rdata = NULL; - dns_rdatalist_t *rdlist = NULL; - - CHECK(str_new(mctx, &string)); - - CHECK(get_soa_record(entry, string)); - rdclass = get_rdataclass(entry); - - CHECK(get_soa_record(entry, string)); - CHECK(parse_rdata(mctx, ldap_inst, rdclass, dns_rdatatype_soa, name, - str_buf(string), &rdata)); - - CHECK(findrdatatype_or_create(mctx, rdatalist, entry, dns_rdatatype_soa, - &rdlist)); - - APPEND(rdlist->rdata, rdata, link); - -cleanup: - str_destroy(&string); - if (result != ISC_R_SUCCESS) - SAFE_MEM_PUT_PTR(mctx, rdata); - - return result; -} - -static isc_result_t -get_next_rdatatype(ldap_entry_t *entry, ldap_attribute_t **attrp, - dns_rdatatype_t *rdtype) -{ - isc_result_t result; - ldap_attribute_t *attr; - - result = ISC_R_NOTFOUND; - - for (attr = get_next_attr(entry, NULL); - attr != NULL; - attr = get_next_attr(entry, NULL)) { - result = ldap_record_to_rdatatype(attr->name, rdtype); - if (result == ISC_R_SUCCESS) - break; - } - - if (result == ISC_R_SUCCESS) - *attrp = attr; - else if (result == ISC_R_NOTFOUND) - *attrp = NULL; - - return result; -} - -static isc_result_t -get_next_rdatatext(ldap_attribute_t *attr, ld_string_t *rdata_text) -{ - ldap_value_t *value; - - REQUIRE(attr != NULL); - REQUIRE(rdata_text != NULL); - - str_clear(rdata_text); - - value = get_next_value(attr); - if (value == NULL) - return ISC_R_NOTFOUND; - - str_init_char(rdata_text, value->value); - - return ISC_R_SUCCESS; -} - -static isc_result_t -parse_rdata(isc_mem_t *mctx, ldap_instance_t *ldap_inst, - dns_rdataclass_t rdclass, dns_rdatatype_t rdtype, - dns_name_t *origin, const char *rdata_text, dns_rdata_t **rdatap) -{ - isc_result_t result; - isc_consttextregion_t text; - isc_buffer_t lex_buffer; - isc_region_t rdatamem; - dns_rdata_t *rdata; - - REQUIRE(mctx != NULL); - REQUIRE(ldap_inst != NULL); - REQUIRE(rdata_text != NULL); - REQUIRE(rdatap != NULL); - - rdata = NULL; - rdatamem.base = NULL; - - text.base = rdata_text; - text.length = strlen(text.base); - - isc_buffer_init(&lex_buffer, text.base, text.length); - isc_buffer_add(&lex_buffer, text.length); - isc_buffer_setactive(&lex_buffer, text.length); - - CHECK(isc_lex_openbuffer(ldap_inst->lex, &lex_buffer)); - - isc_buffer_init(&ldap_inst->rdata_target, ldap_inst->rdata_target_mem, - MINTSIZ); - CHECK(dns_rdata_fromtext(NULL, rdclass, rdtype, ldap_inst->lex, origin, - 0, mctx, &ldap_inst->rdata_target, NULL)); - - CHECKED_MEM_GET_PTR(mctx, rdata); - dns_rdata_init(rdata); - - rdatamem.length = isc_buffer_usedlength(&ldap_inst->rdata_target); - CHECKED_MEM_GET(mctx, rdatamem.base, rdatamem.length); - - memcpy(rdatamem.base, isc_buffer_base(&ldap_inst->rdata_target), - rdatamem.length); - dns_rdata_fromregion(rdata, rdclass, rdtype, &rdatamem); - - isc_lex_close(ldap_inst->lex); - - *rdatap = rdata; - return ISC_R_SUCCESS; - -cleanup: - isc_lex_close(ldap_inst->lex); - if (rdata != NULL) - isc_mem_put(mctx, rdata, sizeof(*rdata)); - if (rdatamem.base != NULL) - isc_mem_put(mctx, rdatamem.base, rdatamem.length); - - return result; -} - -static ldap_attribute_t * -get_next_attr(ldap_entry_t *entry, const char **attr_list) -{ - ldap_attribute_t *attr; - - REQUIRE(entry != NULL); - - if (entry->last_attr == NULL) - attr = HEAD(entry->attributes); - else - attr = NEXT(entry->last_attr, link); - - if (attr_list != NULL) { - while (attr != NULL && !array_contains_nocase(attr_list, attr->name)) - attr = NEXT(attr, link); - } - - if (attr != NULL) - entry->last_attr = attr; - - return attr; -} - -static isc_result_t -get_values(const ldap_entry_t *entry, const char *attr_name, - ldap_value_list_t *values) -{ - ldap_attribute_t *attr; - - REQUIRE(entry != NULL); - REQUIRE(attr_name != NULL); - REQUIRE(values != NULL); - - for (attr = HEAD(entry->attributes); - attr != NULL; - attr = NEXT(attr, link)) { - if (!strcasecmp(attr->name, attr_name)) { - *values = attr->values; - return ISC_R_SUCCESS; - } - } - - return ISC_R_NOTFOUND; -} - -static ldap_value_t * -get_next_value(ldap_attribute_t *attr) -{ - ldap_value_t *value; - - REQUIRE(attr != NULL); - - if (attr->last_value == NULL) - value = HEAD(attr->values); - else - value = NEXT(attr->last_value, link); - - if (value != NULL) - attr->last_value = value; - - return value; -} - -static isc_boolean_t -array_contains_nocase(const char **haystack, const char *needle) -{ - for (unsigned int i = 0; haystack[i] != NULL; i++) { - if (strcasecmp(needle, haystack[i]) == 0) - return isc_boolean_true; - } - - return isc_boolean_false; -} - -static ldap_instance_t * -get_connection(ldap_db_t *ldap_db) -{ - ldap_instance_t *ldap_inst; - - REQUIRE(ldap_db != NULL); - - semaphore_wait(&ldap_db->conn_semaphore); - ldap_inst = HEAD(ldap_db->conn_list); - while (ldap_inst != NULL) { - if (isc_mutex_trylock(&ldap_inst->lock) == ISC_R_SUCCESS) - break; - ldap_inst = NEXT(ldap_inst, link); - } - - RUNTIME_CHECK(ldap_inst != NULL); - - INIT_LIST(ldap_inst->ldap_entries); - /* TODO: find a clever way to not really require this */ - str_copy(ldap_inst->base, ldap_db->base); - - return ldap_inst; -} - -static void -put_connection(ldap_instance_t *ldap_inst) -{ - if (ldap_inst == NULL) - return; - - if (ldap_inst->dn) { - ldap_memfree(ldap_inst->dn); - ldap_inst->dn = NULL; - } - if (ldap_inst->values) { - ldap_value_free(ldap_inst->values); - ldap_inst->values = NULL; - } - if (ldap_inst->attribute) { - ldap_memfree(ldap_inst->attribute); - ldap_inst->attribute = NULL; - } - if (ldap_inst->ber) { - ber_free(ldap_inst->ber, 0); - ldap_inst->ber = NULL; - } - if (ldap_inst->result) { - ldap_msgfree(ldap_inst->result); - ldap_inst->result = NULL; - } - - free_query_cache(ldap_inst); - - UNLOCK(&ldap_inst->lock); - semaphore_signal(&ldap_inst->database->conn_semaphore); -} - - -/* FIXME: Handle the case where the LDAP handle is NULL -> try to reconnect. */ -static isc_result_t -ldap_query(ldap_instance_t *ldap_inst, const char *base, int scope, char **attrs, - int attrsonly, const char *filter, ...) -{ - va_list ap; - int ret; - const char *err_string; - - REQUIRE(ldap_inst != NULL); - - va_start(ap, filter); - str_vsprintf(ldap_inst->query_string, filter, ap); - va_end(ap); - - log_debug(2, "querying '%s' with '%s'", base, - str_buf(ldap_inst->query_string)); - - if (ldap_inst->handle == NULL) { - err_string = "not connected"; - goto cleanup; - } - - ret = ldap_search_ext_s(ldap_inst->handle, base, scope, - str_buf(ldap_inst->query_string), attrs, - attrsonly, NULL, NULL, NULL, LDAP_NO_LIMIT, - &ldap_inst->result); - - log_debug(2, "entry count: %d", ldap_count_entries(ldap_inst->handle, - ldap_inst->result)); - - return ISC_R_SUCCESS; - -cleanup: - log_error("error reading from ldap: %s", err_string); - - return ISC_R_FAILURE; -} - -static isc_result_t -cache_query_results(ldap_instance_t *inst) -{ - isc_result_t result; - LDAP *ld; - LDAPMessage *res; - LDAPMessage *entry; - ldap_entry_t *ldap_entry; - - REQUIRE(inst != NULL); - REQUIRE(EMPTY(inst->ldap_entries)); - REQUIRE(inst->result != NULL); - - INIT_LIST(inst->ldap_entries); - - if (inst->cache_active) - free_query_cache(inst); - - ld = inst->handle; - res = inst->result; - - for (entry = ldap_first_entry(ld, res); - entry != NULL; - entry = ldap_next_entry(ld, entry)) { - CHECKED_MEM_GET_PTR(inst->database->mctx, ldap_entry); - ZERO_PTR(ldap_entry); - - ldap_entry->entry = entry; - INIT_LIST(ldap_entry->attributes); - INIT_LINK(ldap_entry, link); - CHECK(fill_ldap_entry(inst, ldap_entry)); - - APPEND(inst->ldap_entries, ldap_entry, link); - } - - return ISC_R_SUCCESS; - -cleanup: - free_query_cache(inst); - - return result; -} - -static isc_result_t -fill_ldap_entry(ldap_instance_t *inst, ldap_entry_t *ldap_entry) -{ - isc_result_t result; - ldap_attribute_t *ldap_attr; - char *attribute; - BerElement *ber; - LDAPMessage *entry; - - REQUIRE(inst != NULL); - REQUIRE(ldap_entry != NULL); - - result = ISC_R_SUCCESS; - entry = ldap_entry->entry; - - for (attribute = ldap_first_attribute(inst->handle, entry, &ber); - attribute != NULL; - attribute = ldap_next_attribute(inst->handle, entry, ber)) { - CHECKED_MEM_GET_PTR(inst->database->mctx, ldap_attr); - ZERO_PTR(ldap_attr); - - ldap_attr->name = attribute; - INIT_LIST(ldap_attr->values); - INIT_LINK(ldap_attr, link); - CHECK(fill_ldap_attribute(inst, ldap_attr)); - - APPEND(ldap_entry->attributes, ldap_attr, link); - } - - if (ber != NULL) - ber_free(ber, 0); - -cleanup: - if (result != ISC_R_SUCCESS) { - free_ldap_attributes(inst->database->mctx, ldap_entry); - } - - return result; -} - -static isc_result_t -fill_ldap_attribute(ldap_instance_t *inst, ldap_attribute_t *ldap_attr) -{ - isc_result_t result; - char **values; - ldap_value_t *ldap_val; - - REQUIRE(inst != NULL); - REQUIRE(ldap_attr != NULL); - - values = ldap_get_values(inst->handle, inst->result, ldap_attr->name); - /* TODO: proper ldap error handling */ - if (values == NULL) - return ISC_R_FAILURE; - - ldap_attr->ldap_values = values; - - for (unsigned int i = 0; values[i] != NULL; i++) { - CHECKED_MEM_GET_PTR(inst->database->mctx, ldap_val); - ldap_val->value = values[i]; - INIT_LINK(ldap_val, link); - - APPEND(ldap_attr->values, ldap_val, link); - } - - return ISC_R_SUCCESS; - -cleanup: - free_ldap_values(inst->database->mctx, ldap_attr); - ldap_value_free(values); - - return result; -} - -static void -free_query_cache(ldap_instance_t *inst) -{ - ldap_entry_t *entry, *next; - - entry = HEAD(inst->ldap_entries); - while (entry != NULL) { - next = NEXT(entry, link); - UNLINK(inst->ldap_entries, entry, link); - free_ldap_attributes(inst->database->mctx, entry); - isc_mem_put(inst->database->mctx, entry, sizeof(*entry)); - entry = next; - } - - inst->cache_active = isc_boolean_false; -} - -static void -free_ldap_attributes(isc_mem_t *mctx, ldap_entry_t *entry) -{ - ldap_attribute_t *attr, *next; - - attr = HEAD(entry->attributes); - while (attr != NULL) { - next = NEXT(attr, link); - UNLINK(entry->attributes, attr, link); - free_ldap_values(mctx, attr); - ldap_value_free(attr->ldap_values); - ldap_memfree(attr->name); - isc_mem_put(mctx, attr, sizeof(*attr)); - attr = next; - } -} - -static void -free_ldap_values(isc_mem_t *mctx, ldap_attribute_t *attr) -{ - ldap_value_t *value, *next; - - value = HEAD(attr->values); - while (value != NULL) { - next = NEXT(value, link); - UNLINK(attr->values, value, link); - isc_mem_put(mctx, value, sizeof(*value)); - value = next; - } -} - -/* FIXME: this function is obsolete, remove. */ -static const LDAPMessage * -next_entry(ldap_instance_t *inst) -{ - if (inst->ber) { - ber_free(inst->ber, 0); - inst->ber = NULL; - } - - if (inst->handle && inst->entry) - inst->entry = ldap_next_entry(inst->handle, inst->entry); - else if (inst->handle && inst->result) - inst->entry = ldap_first_entry(inst->handle, inst->result); - else - inst->entry = NULL; - - return inst->entry; -} - -/* FIXME: Not tested. */ -static int -ldap_sasl_interact(LDAP *ld, unsigned flags, void *defaults, void *sin) -{ - sasl_interact_t *in = (sasl_interact_t *)sin; - ldap_db_t *ldap_db = (ldap_db_t *)defaults; - - REQUIRE(ldap_db != NULL); - UNUSED(flags); - - if (ld == NULL || sin == NULL) - return LDAP_PARAM_ERROR; - - for (in = sin; in != NULL && in->id != SASL_CB_LIST_END; in++) { - switch (in->id) { - case SASL_CB_USER: - log_error("SASL_CB_USER"); - in->result = str_buf(ldap_db->sasl_user); - in->len = str_len(ldap_db->sasl_user); - break; - case SASL_CB_NOECHOPROMPT: - log_error("SASL_CB_NOECHOPROMPT"); - break; - case SASL_CB_ECHOPROMPT: - log_error("SASL_CB_ECHOPROMPT"); - break; - case SASL_CB_GETREALM: - log_error("SASL_CB_GETREALM"); - break; - case SASL_CB_AUTHNAME: - log_error("SASL_CB_AUTHNAME"); - in->result = str_buf(ldap_db->sasl_user); - in->len = str_len(ldap_db->sasl_user); - break; - case SASL_CB_PASS: - log_error("SASL_CB_PASS"); - in->result = str_buf(ldap_db->password); - in->len = str_len(ldap_db->password); - break; - default: - log_error("SASL_UNKNOWN"); - in->result = ""; - in->len = 0; - break; - } - log_error("result: %s", in->result); - } - - return LDAP_SUCCESS; -} - -/* - * Initialize the LDAP handle and bind to the server. Needed authentication - * credentials and settings are available from the ldap_inst->database. - */ -static isc_result_t -ldap_connect(ldap_instance_t *ldap_inst) -{ - LDAP *ld; - int ret; - int version; - const char *bind_dn; - const char *password; - struct berval *servercred = NULL; - ldap_db_t *ldap_db; - - REQUIRE(ldap_inst != NULL); - - ldap_db = ldap_inst->database; - - if (str_len(ldap_db->bind_dn) == 0 || - str_len(ldap_db->password) == 0) { - bind_dn = NULL; - password = NULL; - } else { - bind_dn = str_buf(ldap_db->bind_dn); - password = str_buf(ldap_db->password); - } - - ret = ldap_initialize(&ld, str_buf(ldap_db->host)); - if (ret != LDAP_SUCCESS) { - log_error("LDAP initialization failed: %s", - ldap_err2string(ret)); - goto cleanup; - } - - version = LDAP_VERSION3; - ret = ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, &version); - LDAP_OPT_CHECK(ret, "failed to set LDAP version"); - - /* - ret = ldap_set_option(ld, LDAP_OPT_TIMELIMIT, (void *)&ldap_db->timeout); - LDAP_OPT_CHECK(ret, "failed to set timeout: %s", ldap_err2string(ret)); - */ - - log_debug(2, "trying to establish LDAP connection to %s", - str_buf(ldap_db->host)); - - - switch (ldap_db->auth_method) { - case AUTH_NONE: - ret = ldap_simple_bind_s(ld, NULL, NULL); - break; - case AUTH_SIMPLE: - ret = ldap_simple_bind_s(ld, bind_dn, password); - break; - case AUTH_SASL: - log_error("%s", str_buf(ldap_db->sasl_mech)); - ret = ldap_sasl_interactive_bind_s(ld, NULL, - str_buf(ldap_db->sasl_mech), - NULL, NULL, LDAP_SASL_QUIET, - ldap_sasl_interact, - ldap_db); - ber_bvfree(servercred); - break; - default: - fatal_error("bug in ldap_connect(): unsupported " - "authentication mechanism"); - goto cleanup; - } - - if (ret != LDAP_SUCCESS) { - log_error("bind to LDAP server failed: %s", - ldap_err2string(ret)); - goto cleanup; - } - - ldap_inst->handle = ld; - - return ISC_R_SUCCESS; - -cleanup: - - if (ld != NULL) - ldap_unbind_ext_s(ld, NULL, NULL); - - return ISC_R_FAILURE; -} - -/* FIXME: Handle the case where the LDAP handle is NULL -> try to reconnect. */ -/* FIXME: Handle cases where the entry actually doesn't exist. */ -static isc_result_t -ldap_modify_do(ldap_instance_t *ldap_inst, const char *dn, LDAPMod **mods) -{ - int ret; - - REQUIRE(ldap_inst != NULL); - REQUIRE(dn != NULL); - REQUIRE(mods != NULL); - - log_debug(2, "writing to to '%s'", dn); - - ret = ldap_modify_ext_s(ldap_inst->handle, dn, mods, NULL, NULL); - if (ret != LDAP_SUCCESS) { - log_error("error writing to ldap: %s", ldap_err2string(ret)); - return ISC_R_FAILURE; - } - - return ISC_R_SUCCESS; -} - -static isc_result_t -ldap_rdatalist_to_ldapmod(isc_mem_t *mctx, dns_rdatalist_t *rdlist, - LDAPMod **changep, int mod_op) -{ - isc_result_t result; - LDAPMod *change = NULL; - char **vals = NULL; - const char *attr_name_c; - char *attr_name; - - - REQUIRE(changep != NULL && *changep == NULL); - - CHECKED_MEM_GET_PTR(mctx, change); - ZERO_PTR(change); - - result = rdatatype_to_ldap_attribute(rdlist->type, &attr_name_c); - if (result != ISC_R_SUCCESS) { - result = ISC_R_FAILURE; - goto cleanup; - } - DE_CONST(attr_name_c, attr_name); - CHECK(ldap_rdata_to_char_array(mctx, HEAD(rdlist->rdata), &vals)); - - change->mod_op = mod_op; - change->mod_type = attr_name; - change->mod_values = vals; - - *changep = change; - return ISC_R_SUCCESS; - -cleanup: - free_ldapmod(mctx, &change); - - return result; -} - -static void -free_ldapmod(isc_mem_t *mctx, LDAPMod **changep) -{ - LDAPMod *change; - - REQUIRE(changep != NULL); - - change = *changep; - if (change == NULL) - return; - - free_char_array(mctx, &change->mod_values); - SAFE_MEM_PUT_PTR(mctx, change); - - *changep = NULL; -} - -isc_result_t -ldap_rdata_to_char_array(isc_mem_t *mctx, dns_rdata_t *rdata_head, - char ***valsp) -{ - isc_result_t result; - char **vals; - unsigned int i; - unsigned int rdata_count = 0; - size_t vals_size; - dns_rdata_t *rdata; - - REQUIRE(rdata_head != NULL); - REQUIRE(valsp != NULL && *valsp == NULL); - - for (rdata = rdata_head; rdata != NULL; rdata = NEXT(rdata, link)) - rdata_count++; - - vals_size = (rdata_count + 1) * sizeof(char *); - - CHECKED_MEM_ALLOCATE(mctx, vals, vals_size); - memset(vals, 0, vals_size); - - rdata = rdata_head; - for (i = 0; i < rdata_count && rdata != NULL; i++) { - DECLARE_BUFFER(buffer, MINTSIZ); - isc_region_t region; - - /* Convert rdata to text. */ - INIT_BUFFER(buffer); - CHECK(dns_rdata_totext(rdata, NULL, &buffer)); - isc_buffer_usedregion(&buffer, ®ion); - - /* Now allocate the string with the right size. */ - CHECKED_MEM_ALLOCATE(mctx, vals[i], region.length + 1); - memcpy(vals[i], region.base, region.length); - vals[i][region.length] = '\0'; - - rdata = NEXT(rdata, link); - } - - *valsp = vals; - return ISC_R_SUCCESS; - -cleanup: - free_char_array(mctx, &vals); - return result; -} - -static void -free_char_array(isc_mem_t *mctx, char ***valsp) -{ - char **vals; - unsigned int i; - - REQUIRE(valsp != NULL); - - vals = *valsp; - if (vals == NULL) - return; - - for (i = 0; vals[i] != NULL; i++) - isc_mem_free(mctx, vals[i]); - - isc_mem_free(mctx, vals); - *valsp = NULL; -} - -/* - * TODO: Handle updating of the SOA record, use the settings to determine if - * this is allowed. - */ -static isc_result_t -modify_ldap_common(dns_name_t *owner, ldap_db_t *ldap_db, - dns_rdatalist_t *rdlist, int mod_op) -{ - isc_result_t result; - isc_mem_t *mctx; - ldap_instance_t *ldap_inst; - ld_string_t *owner_dn = NULL; - LDAPMod *change[2]; - - change[0] = change[1] = NULL; - - mctx = ldap_db->mctx; - ldap_inst = get_connection(ldap_db); - - CHECK(str_new(mctx, &owner_dn)); - CHECK(dnsname_to_dn(ldap_db, owner, owner_dn)); - CHECK(ldap_rdatalist_to_ldapmod(mctx, rdlist, &change[0], mod_op)); - CHECK(ldap_modify_do(ldap_inst, str_buf(owner_dn), change)); - -cleanup: - put_connection(ldap_inst); - str_destroy(&owner_dn); - free_ldapmod(mctx, &change[0]); - - return result; -} - -isc_result_t -write_to_ldap(dns_name_t *owner, ldap_db_t *ldap_db, dns_rdatalist_t *rdlist) -{ - return modify_ldap_common(owner, ldap_db, rdlist, LDAP_MOD_ADD); -} - -isc_result_t -remove_from_ldap(dns_name_t *owner, ldap_db_t *ldap_db, - dns_rdatalist_t *rdlist) -{ - return modify_ldap_common(owner, ldap_db, rdlist, LDAP_MOD_DELETE); -} |