diff options
author | Martin Nagy <mnagy@redhat.com> | 2009-03-30 13:01:56 +0200 |
---|---|---|
committer | Martin Nagy <mnagy@redhat.com> | 2009-03-30 13:08:32 +0200 |
commit | a148a9f5f2659c60a534f82d0ec8736f90afa223 (patch) | |
tree | 2244198110d012ec0afa16a1a3eee64ee4057061 /src/ldap_driver.c | |
parent | dd3b35c40b5709f8ea3ded23d4bb5fb4a9320352 (diff) | |
download | ldap_driver-a148a9f5f2659c60a534f82d0ec8736f90afa223.tar.gz ldap_driver-a148a9f5f2659c60a534f82d0ec8736f90afa223.tar.xz ldap_driver-a148a9f5f2659c60a534f82d0ec8736f90afa223.zip |
Prepare the tree for conversion to autoconf.
All source files are now moved to src/ and the old Makefile is removed.
Diffstat (limited to 'src/ldap_driver.c')
-rw-r--r-- | src/ldap_driver.c | 1076 |
1 files changed, 1076 insertions, 0 deletions
diff --git a/src/ldap_driver.c b/src/ldap_driver.c new file mode 100644 index 0000000..8003c85 --- /dev/null +++ b/src/ldap_driver.c @@ -0,0 +1,1076 @@ +/* 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 <isc/buffer.h> +#include <isc/mem.h> +#include <isc/refcount.h> +#include <isc/util.h> + +#include <dns/db.h> +#include <dns/rdata.h> +#include <dns/rdataclass.h> +#include <dns/rdatalist.h> +#include <dns/rdataset.h> +#include <dns/rdatatype.h> +#include <dns/result.h> +#include <dns/types.h> + +#include <string.h> /* For memcpy */ + +#include "cache.h" +#include "ldap_helper.h" +#include "log.h" +#include "rdlist.h" +#include "util.h" +#include "zone_manager.h" + +#define LDAPDB_MAGIC ISC_MAGIC('L', 'D', 'P', 'D') +#define VALID_LDAPDB(ldapdb) \ + ((ldapdb) != NULL && (ldapdb)->common.impmagic == LDAPDB_MAGIC) + +#define LDAPDBNODE_MAGIC ISC_MAGIC('L', 'D', 'P', 'N') +#define VALID_LDAPDBNODE(ldapdbnode) ISC_MAGIC_VALID(ldapdbnode, \ + LDAPDBNODE_MAGIC) + +static dns_rdatasetmethods_t rdataset_methods; + +typedef struct { + dns_db_t common; + isc_refcount_t refs; + isc_mutex_t lock; /* convert to isc_rwlock_t ? */ + ldap_db_t *ldap_db; + ldap_cache_t *ldap_cache; +} ldapdb_t; + +typedef struct { + unsigned int magic; + isc_refcount_t refs; + dns_name_t owner; + ldapdb_rdatalist_t rdatalist; +} ldapdbnode_t; + +static int dummy; +static void *ldapdb_version = &dummy; + +static void free_ldapdb(ldapdb_t *ldapdb); +static void detachnode(dns_db_t *db, dns_dbnode_t **targetp); +static unsigned int rdatalist_length(const dns_rdatalist_t *rdlist); + +/* ldapdbnode_t functions */ +static isc_result_t +ldapdbnode_create(isc_mem_t *mctx, dns_name_t *owner, ldapdbnode_t **nodep) +{ + ldapdbnode_t *node = NULL; + isc_result_t result; + + REQUIRE(nodep != NULL && *nodep == NULL); + + CHECKED_MEM_GET_PTR(mctx, node); + CHECK(isc_refcount_init(&node->refs, 1)); + + dns_name_init(&node->owner, NULL); + CHECK(dns_name_dup(owner, mctx, &node->owner)); + + node->magic = LDAPDBNODE_MAGIC; + + ISC_LIST_INIT(node->rdatalist); + + *nodep = node; + + return ISC_R_SUCCESS; + +cleanup: + SAFE_MEM_PUT_PTR(mctx, node); + + return result; +} + +/* + * Clone rdlist and convert it into rdataset. + */ +static isc_result_t +clone_rdatalist_to_rdataset(isc_mem_t *mctx, dns_rdatalist_t *rdlist, + dns_rdataset_t *rdataset) +{ + isc_result_t result; + dns_rdatalist_t *new_rdlist = NULL; + + REQUIRE(mctx != NULL); + + CHECK(rdatalist_clone(mctx, rdlist, &new_rdlist)); + + CHECK(dns_rdatalist_tordataset(new_rdlist, rdataset)); + rdataset->methods = &rdataset_methods; + isc_mem_attach(mctx, (isc_mem_t **)&rdataset->private5); + + return result; + +cleanup: + if (new_rdlist != NULL) { + free_rdatalist(mctx, rdlist); + isc_mem_put(mctx, new_rdlist, sizeof(*new_rdlist)); + } + + return result; +} + +/* + * Our own function for disassociating rdatasets. We will also free the + * rdatalist that we put inside from clone_rdatalist_to_rdataset. + */ +void +ldapdb_rdataset_disassociate(dns_rdataset_t *rdataset) +{ + dns_rdatalist_t *rdlist; + isc_mem_t *mctx; + + REQUIRE(rdataset != NULL); + + rdlist = rdataset->private1; + mctx = rdataset->private5; + if (rdlist == NULL) + return; + rdataset->private1 = NULL; + rdataset->private5 = NULL; + + free_rdatalist(mctx, rdlist); + SAFE_MEM_PUT_PTR(mctx, rdlist); + + isc_mem_detach(&mctx); +} + +/* + * Functions. + * + * Most of them don't need db parameter but we are checking if it is valid. + * Invalid db parameter indicates bug in code. + */ + +static void +attach(dns_db_t *source, dns_db_t **targetp) +{ + ldapdb_t *ldapdb = (ldapdb_t *)source; + + REQUIRE(VALID_LDAPDB(ldapdb)); + + isc_refcount_increment(&ldapdb->refs, NULL); + *targetp = source; +} + +static void +detach(dns_db_t **dbp) +{ + ldapdb_t *ldapdb = (ldapdb_t *)(*dbp); + unsigned int refs; + + REQUIRE(VALID_LDAPDB(ldapdb)); + + isc_refcount_decrement(&ldapdb->refs, &refs); + + if (refs == 0) + free_ldapdb(ldapdb); + + *dbp = NULL; +} + +static void +free_ldapdb(ldapdb_t *ldapdb) +{ + DESTROYLOCK(&ldapdb->lock); + dns_name_free(&ldapdb->common.origin, ldapdb->common.mctx); + isc_mem_putanddetach(&ldapdb->common.mctx, ldapdb, sizeof(*ldapdb)); +} + +static isc_result_t +beginload(dns_db_t *db, dns_addrdatasetfunc_t *addp, dns_dbload_t **dbloadp) +{ + + UNUSED(db); + UNUSED(addp); + UNUSED(dbloadp); + + fatal_error("ldapdb: method beginload() should never be called"); + + /* Not reached */ + return ISC_R_SUCCESS; +} + +static isc_result_t +endload(dns_db_t *db, dns_dbload_t **dbloadp) +{ + + UNUSED(db); + UNUSED(dbloadp); + + fatal_error("ldapdb: method endload() should never be called"); + + /* Not reached */ + return ISC_R_SUCCESS; +} + +static isc_result_t +dump(dns_db_t *db, dns_dbversion_t *version, const char *filename, + dns_masterformat_t masterformat) +{ + + UNUSED(db); + UNUSED(version); + UNUSED(filename); + UNUSED(masterformat); + + fatal_error("ldapdb: method dump() should never be called"); + + /* Not reached */ + return ISC_R_SUCCESS; +} + +static void +currentversion(dns_db_t *db, dns_dbversion_t **versionp) +{ + ldapdb_t *ldapdb = (ldapdb_t *)db; + + REQUIRE(VALID_LDAPDB(ldapdb)); + REQUIRE(versionp != NULL && *versionp == NULL); + + *versionp = ldapdb_version; +} + +static isc_result_t +newversion(dns_db_t *db, dns_dbversion_t **versionp) +{ + ldapdb_t *ldapdb = (ldapdb_t *)db; + + REQUIRE(VALID_LDAPDB(ldapdb)); + REQUIRE(versionp != NULL && *versionp == NULL); + + *versionp = ldapdb_version; + return ISC_R_SUCCESS; +} + +static void +attachversion(dns_db_t *db, dns_dbversion_t *source, + dns_dbversion_t **targetp) +{ + ldapdb_t *ldapdb = (ldapdb_t *)db; + + REQUIRE(VALID_LDAPDB(ldapdb)); + REQUIRE(source == ldapdb_version); + REQUIRE(targetp != NULL && *targetp == NULL); + + *targetp = ldapdb_version; +} + +static void +closeversion(dns_db_t *db, dns_dbversion_t **versionp, isc_boolean_t commit) +{ + ldapdb_t *ldapdb = (ldapdb_t *)db; + + UNUSED(commit); + + REQUIRE(VALID_LDAPDB(ldapdb)); + REQUIRE(versionp != NULL && *versionp == ldapdb_version); + + *versionp = NULL; +} + +static isc_result_t +findnode(dns_db_t *db, dns_name_t *name, isc_boolean_t create, + dns_dbnode_t **nodep) +{ + ldapdb_t *ldapdb = (ldapdb_t *) db; + isc_result_t result; + ldapdb_rdatalist_t rdatalist; + ldapdbnode_t *node = NULL; + + REQUIRE(VALID_LDAPDB(ldapdb)); + + result = cached_ldap_rdatalist_get(ldapdb->common.mctx, + ldapdb->ldap_cache, ldapdb->ldap_db, + name, &rdatalist); + + if (result == ISC_R_NOMEMORY) + return ISC_R_NOMEMORY; + + if (create == ISC_FALSE) { + /* No partial matches are allowed in this function */ + if (result == DNS_R_PARTIALMATCH) { + result = ISC_R_NOTFOUND; + goto cleanup; + } else if (result != ISC_R_SUCCESS) { + return result; + } + } + + CHECK(ldapdbnode_create(ldapdb->common.mctx, name, &node)); + + memcpy(&node->rdatalist, &rdatalist, sizeof(rdatalist)); + + *nodep = node; + + return ISC_R_SUCCESS; + +cleanup: + ldapdb_rdatalist_destroy(ldapdb->common.mctx, &rdatalist); + + return result; +} + +/* XXX add support for DNAME redirection */ +static isc_result_t +find(dns_db_t *db, dns_name_t *name, dns_dbversion_t *version, + dns_rdatatype_t type, unsigned int options, isc_stdtime_t now, + dns_dbnode_t **nodep, dns_name_t *foundname, dns_rdataset_t *rdataset, + dns_rdataset_t *sigrdataset) +{ + ldapdb_t *ldapdb = (ldapdb_t *) db; + isc_result_t result; + ldapdbnode_t *node = NULL; + dns_rdatalist_t *rdlist = NULL; + isc_boolean_t is_cname = ISC_FALSE; + ldapdb_rdatalist_t rdatalist; + + UNUSED(now); + UNUSED(options); + UNUSED(sigrdataset); + + REQUIRE(VALID_LDAPDB(ldapdb)); + REQUIRE(!(node != NULL && type == dns_rdatatype_any)); + //REQUIRE(!(node == NULL && rdataset != NULL)); + + if (version != NULL) { + REQUIRE(version == ldapdb_version); + } + + result = cached_ldap_rdatalist_get(ldapdb->common.mctx, + ldapdb->ldap_cache, ldapdb->ldap_db, + name, &rdatalist); + INSIST(result != DNS_R_PARTIALMATCH); /* XXX Not yet implemented */ + + if (result != ISC_R_SUCCESS && result != DNS_R_PARTIALMATCH) + return (result == ISC_R_NOTFOUND) ? DNS_R_NXDOMAIN : result; + + result = ldapdb_rdatalist_findrdatatype(&rdatalist, type, &rdlist); + if (result != ISC_R_SUCCESS) { + /* No exact rdtype match. Check CNAME */ + + rdlist = HEAD(rdatalist); + while (rdlist != NULL && rdlist->type != dns_rdatatype_cname) + rdlist = NEXT(rdlist, link); + + /* CNAME was found */ + if (rdlist != NULL) { + result = ISC_R_SUCCESS; + is_cname = ISC_TRUE; + } + } + + if (result != ISC_R_SUCCESS) { + result = DNS_R_NXRRSET; + goto cleanup; + } + + /* XXX currently we implemented only exact authoritative matches */ + CHECK(dns_name_copy(name, foundname, NULL)); + + if (rdataset != NULL && type != dns_rdatatype_any) { + /* dns_rdatalist_tordataset returns success only */ + CHECK(clone_rdatalist_to_rdataset(ldapdb->common.mctx, rdlist, + rdataset)); + } + + if (nodep != NULL) { + CHECK(ldapdbnode_create(ldapdb->common.mctx, name, &node)); + memcpy(&node->rdatalist, &rdatalist, sizeof(rdatalist)); + *nodep = node; + } else { + ldapdb_rdatalist_destroy(ldapdb->common.mctx, &rdatalist); + } + + return (is_cname == ISC_TRUE) ? DNS_R_CNAME : ISC_R_SUCCESS; + +cleanup: + ldapdb_rdatalist_destroy(ldapdb->common.mctx, &rdatalist); + return result; +} + +static isc_result_t +findzonecut(dns_db_t *db, dns_name_t *name, unsigned int options, + isc_stdtime_t now, dns_dbnode_t **nodep, dns_name_t *foundname, + dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset) +{ + UNUSED(db); + UNUSED(name); + UNUSED(options); + UNUSED(now); + UNUSED(nodep); + UNUSED(foundname); + UNUSED(rdataset); + UNUSED(sigrdataset); + + return ISC_R_NOTIMPLEMENTED; +} + +static void +attachnode(dns_db_t *db, dns_dbnode_t *source, dns_dbnode_t **targetp) +{ + ldapdbnode_t *node = (ldapdbnode_t *) source; + + REQUIRE(VALID_LDAPDBNODE(node)); + + UNUSED(db); + + isc_refcount_increment(&node->refs, NULL); + *targetp = source; +} + +static void +detachnode(dns_db_t *db, dns_dbnode_t **targetp) +{ + ldapdbnode_t *node = (ldapdbnode_t *)(*targetp); + ldapdb_t *ldapdb = (ldapdb_t *) db; + unsigned int refs; + + /* + * Don't check for db and targetp validity, it's done in + * dns_db_detachnode + */ + + REQUIRE(VALID_LDAPDBNODE(node)); + isc_refcount_decrement(&node->refs, &refs); + if (refs == 0) { + ldapdb_rdatalist_destroy(ldapdb->common.mctx, &node->rdatalist); + dns_name_free(&node->owner, ldapdb->common.mctx); + SAFE_MEM_PUT_PTR(ldapdb->common.mctx, node); + } + + *targetp = NULL; +} + +static isc_result_t +expirenode(dns_db_t *db, dns_dbnode_t *node, isc_stdtime_t now) +{ + UNUSED(db); + UNUSED(node); + UNUSED(now); + + return ISC_R_NOTIMPLEMENTED; +} + +static void +printnode(dns_db_t *db, dns_dbnode_t *node, FILE *out) +{ + UNUSED(db); + UNUSED(node); + UNUSED(out); +} + +static isc_result_t +createiterator(dns_db_t *db, unsigned int options, + dns_dbiterator_t **iteratorp) +{ + UNUSED(db); + UNUSED(options); + UNUSED(iteratorp); + + return ISC_R_NOTIMPLEMENTED; +} + +static isc_result_t +findrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, + dns_rdatatype_t type, dns_rdatatype_t covers, isc_stdtime_t now, + dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset) +{ + ldapdb_t *ldapdb = (ldapdb_t *) db; + ldapdbnode_t *ldapdbnode = (ldapdbnode_t *) node; + dns_rdatalist_t *rdlist = NULL; + isc_result_t result; + + UNUSED(db); + UNUSED(now); + UNUSED(sigrdataset); + + REQUIRE(covers == 0); /* Only meaningful with DNSSEC capable DB*/ + REQUIRE(VALID_LDAPDBNODE(ldapdbnode)); + + if (version != NULL) { + REQUIRE(version == ldapdb_version); + } + + result = ldapdb_rdatalist_findrdatatype(&ldapdbnode->rdatalist, type, + &rdlist); + if (result != ISC_R_SUCCESS) + return result; + + result = clone_rdatalist_to_rdataset(ldapdb->common.mctx, rdlist, + rdataset); + + return result; +} + +static isc_result_t +allrdatasets(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, + isc_stdtime_t now, dns_rdatasetiter_t **iteratorp) +{ + UNUSED(db); + UNUSED(node); + UNUSED(version); + UNUSED(now); + UNUSED(iteratorp); + + return ISC_R_NOTIMPLEMENTED; +} + +/* + * Remove duplicates between rdlists. If rm_from1 == true then remove rdata + * from the first rdatalist. same rdata are removed from rdlist1 or 2 and are + * returned in diff. + */ +static void +rdatalist_removedups(dns_rdatalist_t *rdlist1, dns_rdatalist_t *rdlist2, + isc_boolean_t rm_from1, + dns_rdatalist_t *diff) +{ + dns_rdata_t *rdata1, *rdata2; + + rdata1 = HEAD(rdlist1->rdata); + while (rdata1 != NULL) { + rdata2 = HEAD(rdlist2->rdata); + while (rdata2 != NULL) { + if (dns_rdata_compare(rdata1, rdata2) != 0) { + rdata2 = NEXT(rdata2, link); + continue; + } + /* same rdata has been found */ + if (rm_from1) { + ISC_LIST_UNLINK(rdlist1->rdata, rdata1, link); + APPEND(diff->rdata, rdata1, link); + } else { + ISC_LIST_UNLINK(rdlist2->rdata, rdata2, link); + APPEND(diff->rdata, rdata2, link); + } + break; + } + rdata1 = NEXT(rdata1, link); + } +} + +static isc_result_t +addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, + isc_stdtime_t now, dns_rdataset_t *rdataset, unsigned int options, + dns_rdataset_t *addedrdataset) +{ + ldapdbnode_t *ldapdbnode = (ldapdbnode_t *) node; + ldapdb_t *ldapdb = (ldapdb_t *) db; + dns_rdatalist_t *rdlist = NULL, *new_rdlist = NULL; + dns_rdatalist_t *found_rdlist = NULL; + dns_rdatalist_t diff; + isc_result_t result; + isc_boolean_t rdatalist_exists = ISC_FALSE; + + UNUSED(now); + UNUSED(db); + UNUSED(addedrdataset); + + REQUIRE(VALID_LDAPDBNODE(ldapdbnode)); + /* version == NULL is valid only for cache databases */ + REQUIRE(version == ldapdb_version); + REQUIRE((options & DNS_DBADD_FORCE) == 0); + + dns_rdatalist_init(&diff); + + result = dns_rdatalist_fromrdataset(rdataset, &rdlist); + INSIST(result == ISC_R_SUCCESS); + INSIST(rdlist->rdclass == dns_rdataclass_in); + + CHECK(rdatalist_clone(ldapdb->common.mctx, rdlist, &new_rdlist)); + + result = ldapdb_rdatalist_findrdatatype(&ldapdbnode->rdatalist, + rdlist->type, &found_rdlist); + if (result == ISC_R_SUCCESS) { + rdatalist_exists = ISC_TRUE; + + if (rdlist->ttl != found_rdlist->ttl) { + /* + * TODO: support it. When supported handle + * DNS_DBADD_EXACTTTL option well. + */ + log_error("Multiple TTLs for one name are not " + "supported"); + result = ISC_R_NOTIMPLEMENTED; + goto cleanup; + } + + if ((options & DNS_DBADD_MERGE) != 0 || + (options & DNS_DBADD_EXACT) != 0) { + rdatalist_removedups(found_rdlist, new_rdlist, + ISC_FALSE, &diff); + + if ((options & DNS_DBADD_MERGE) != 0) + free_rdatalist(ldapdb->common.mctx, &diff); + else if (rdatalist_length(&diff) != 0) { + free_rdatalist(ldapdb->common.mctx, &diff); + result = DNS_R_NOTEXACT; + goto cleanup; + } + } else { + /* Replace existing rdataset */ + free_rdatalist(ldapdb->common.mctx, found_rdlist); + } + } + + CHECK(write_to_ldap(&ldapdbnode->owner, ldapdb->ldap_db, new_rdlist)); + CHECK(discard_from_cache(ldapdb->ldap_cache, &ldapdbnode->owner)); + + if (addedrdataset != NULL) { + result = dns_rdatalist_tordataset(new_rdlist, addedrdataset); + /* Use strong condition here, returns only SUCCESS */ + INSIST(result == ISC_R_SUCCESS); + } + + if (rdatalist_exists) { + ISC_LIST_APPENDLIST(found_rdlist->rdata, new_rdlist->rdata, + link); + SAFE_MEM_PUT_PTR(ldapdb->common.mctx, new_rdlist); + } else + APPEND(ldapdbnode->rdatalist, new_rdlist, link); + + + return ISC_R_SUCCESS; + +cleanup: + if (new_rdlist != NULL) { + free_rdatalist(ldapdb->common.mctx, new_rdlist); + SAFE_MEM_PUT_PTR(ldapdb->common.mctx, new_rdlist); + } + + return result; +} + +static unsigned int +rdatalist_length(const dns_rdatalist_t *rdlist) +{ + dns_rdata_t *ptr = HEAD(rdlist->rdata); + unsigned int length = 0; + + while (ptr != NULL) { + length++; + ptr = NEXT(ptr, link); + } + + return length; +} + +static isc_result_t +subtractrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, + dns_rdataset_t *rdataset, unsigned int options, + dns_rdataset_t *newrdataset) +{ + ldapdb_t *ldapdb = (ldapdb_t *) db; + ldapdbnode_t *ldapdbnode = (ldapdbnode_t *) node; + dns_rdatalist_t *found_rdlist = NULL; + dns_rdatalist_t *rdlist; + dns_rdatalist_t diff; + isc_result_t result; + + REQUIRE(version == ldapdb_version); + + result = dns_rdatalist_fromrdataset(rdataset, &rdlist); + /* Use strong condition here, no other value is returned */ + INSIST(result == ISC_R_SUCCESS); + + /* Do we want to use memcpy here? */ + dns_rdatalist_init(&diff); + diff.rdclass = rdlist->rdclass; + diff.type = rdlist->type; + diff.covers = rdlist->covers; + diff.ttl = rdlist->ttl; + + result = ldapdb_rdatalist_findrdatatype(&ldapdbnode->rdatalist, + rdlist->type, &found_rdlist); + + if (result == ISC_R_NOTFOUND) + return DNS_R_NXRRSET; + + /* We found correct type, remove maching rdata */ + rdatalist_removedups(rdlist, found_rdlist, ISC_FALSE, &diff); + + if ((options & DNS_DBSUB_EXACT) != 0 && + rdatalist_length(&diff) != rdatalist_length(rdlist)) { + /* Not exact match, rollback */ + result = DNS_R_NOTEXACT; + goto cleanup; + } + + if (rdatalist_length(&diff) == 0) { + result = DNS_R_UNCHANGED; + goto cleanup; + } + + CHECK(remove_from_ldap(&ldapdbnode->owner, ldapdb->ldap_db, &diff)); + + if (newrdataset != NULL) { + result = dns_rdatalist_tordataset(found_rdlist, newrdataset); + /* Use strong condition here, no other value is returned */ + INSIST(result == ISC_R_SUCCESS); + } + + free_rdatalist(ldapdb->common.mctx, &diff); + + return ISC_R_SUCCESS; + +cleanup: + /* Roll back changes */ + ISC_LIST_APPENDLIST(found_rdlist->rdata, diff.rdata, link); + + return result; +} + +static isc_result_t +deleterdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, + dns_rdatatype_t type, dns_rdatatype_t covers) +{ + UNUSED(db); + UNUSED(node); + UNUSED(version); + UNUSED(type); + UNUSED(covers); + + REQUIRE("deleterdataset" == NULL); + + return ISC_R_NOTIMPLEMENTED; +} + +static isc_boolean_t +issecure(dns_db_t *db) +{ + UNUSED(db); + + return ISC_FALSE; +} + +static unsigned int +nodecount(dns_db_t *db) +{ + UNUSED(db); + + return ISC_R_NOTIMPLEMENTED; +} + +static isc_boolean_t +ispersistent(dns_db_t *db) +{ + UNUSED(db); + + return ISC_R_NOTIMPLEMENTED; +} + +static void +overmem(dns_db_t *db, isc_boolean_t overmem) +{ + UNUSED(db); + UNUSED(overmem); +} + +static void +settask(dns_db_t *db, isc_task_t *task) +{ + UNUSED(db); + UNUSED(task); +} + +static isc_result_t +getoriginnode(dns_db_t *db, dns_dbnode_t **nodep) +{ + ldapdb_t *ldapdb = (ldapdb_t *) db; + + return findnode(db, &ldapdb->common.origin, ISC_FALSE, nodep); +} + +static void +transfernode(dns_db_t *db, dns_dbnode_t **sourcep, dns_dbnode_t **targetp) +{ + UNUSED(db); + UNUSED(sourcep); + UNUSED(targetp); +} + +static isc_result_t +getnsec3parameters(dns_db_t *db, dns_dbversion_t *version, dns_hash_t *hash, + isc_uint8_t *flags, isc_uint16_t *iterations, + unsigned char *salt, size_t *salt_len) +{ + UNUSED(db); + UNUSED(version); + UNUSED(hash); + UNUSED(flags); + UNUSED(iterations); + UNUSED(salt); + UNUSED(salt_len); + + return ISC_R_NOTIMPLEMENTED; +} + +static isc_result_t +findnsec3node(dns_db_t *db, dns_name_t *name, isc_boolean_t create, + dns_dbnode_t **nodep) +{ + UNUSED(db); + UNUSED(name); + UNUSED(create); + UNUSED(nodep); + + return ISC_R_NOTIMPLEMENTED; +} + +static isc_result_t +setsigningtime(dns_db_t *db, dns_rdataset_t *rdataset, isc_stdtime_t resign) +{ + UNUSED(db); + UNUSED(rdataset); + UNUSED(resign); + + return ISC_R_NOTIMPLEMENTED; +} + +static isc_result_t +getsigningtime(dns_db_t *db, dns_rdataset_t *rdataset, dns_name_t *name) +{ + UNUSED(db); + UNUSED(rdataset); + UNUSED(name); + + return ISC_R_NOTIMPLEMENTED; +} + +static void +resigned(dns_db_t *db, dns_rdataset_t *rdataset, dns_dbversion_t *version) +{ + UNUSED(db); + UNUSED(rdataset); + UNUSED(version); +} + +static isc_boolean_t +isdnssec(dns_db_t *db) +{ + UNUSED(db); + + return ISC_R_NOTIMPLEMENTED; +} + +static dns_stats_t * +getrrsetstats(dns_db_t *db) +{ + UNUSED(db); + + return NULL; +} + +static dns_dbmethods_t ldapdb_methods = { + attach, + detach, + beginload, + endload, + dump, + currentversion, + newversion, + attachversion, + closeversion, + findnode, + find, + findzonecut, + attachnode, + detachnode, + expirenode, + printnode, + createiterator, + findrdataset, + allrdatasets, + addrdataset, + subtractrdataset, + deleterdataset, + issecure, + nodecount, + ispersistent, + overmem, + settask, + getoriginnode, + transfernode, + getnsec3parameters, + findnsec3node, + setsigningtime, + getsigningtime, + resigned, + isdnssec, + getrrsetstats +}; + +static isc_result_t +ldapdb_create(isc_mem_t *mctx, dns_name_t *name, dns_dbtype_t type, + dns_rdataclass_t rdclass, unsigned int argc, char *argv[], + void *driverarg, dns_db_t **dbp) +{ + ldapdb_t *ldapdb = NULL; + isc_result_t result; + int lock_is_initialized = 0; + + UNUSED(driverarg); /* Currently we don't need any data */ + + /* Database instance name. */ + REQUIRE(argc > 0); + + REQUIRE(type == dns_dbtype_zone); + REQUIRE(rdclass == dns_rdataclass_in); + REQUIRE(dbp != NULL && *dbp == NULL); + + CHECKED_MEM_GET_PTR(mctx, ldapdb); + ZERO_PTR(ldapdb); + + isc_mem_attach(mctx, &ldapdb->common.mctx); + + dns_name_init(&ldapdb->common.origin, NULL); + isc_ondestroy_init(&ldapdb->common.ondest); + + CHECK(isc_mutex_init(&ldapdb->lock)); + lock_is_initialized = 1; + + ldapdb->common.magic = DNS_DB_MAGIC; + ldapdb->common.impmagic = LDAPDB_MAGIC; + + ldapdb->common.methods = &ldapdb_methods; + ldapdb->common.attributes = 0; + ldapdb->common.rdclass = rdclass; + + CHECK(dns_name_dupwithoffsets(name, mctx, &ldapdb->common.origin)); + + CHECK(isc_refcount_init(&ldapdb->refs, 1)); + CHECK(manager_get_ldap_db_and_cache(argv[0], &ldapdb->ldap_db, + &ldapdb->ldap_cache)); + + *dbp = (dns_db_t *)ldapdb; + + return ISC_R_SUCCESS; + +cleanup: + if (ldapdb != NULL) { + if (lock_is_initialized) + DESTROYLOCK(&ldapdb->lock); + if (dns_name_dynamic(&ldapdb->common.origin)) + dns_name_free(&ldapdb->common.origin, mctx); + + isc_mem_putanddetach(&ldapdb->common.mctx, ldapdb, + sizeof(*ldapdb)); + } + + return result; +} + +static dns_dbimplementation_t *ldapdb_imp; +const char *ldapdb_impname = "dynamic-ldap"; + + +isc_result_t +dynamic_driver_init(isc_mem_t *mctx, const char *name, const char * const *argv, + dns_view_t *view, dns_zonemgr_t *zmgr) +{ + isc_result_t result; + ldap_db_t *ldap_db = NULL; + ldap_cache_t *ldap_cache = NULL; + + REQUIRE(mctx != NULL); + REQUIRE(name != NULL); + REQUIRE(argv != NULL); + REQUIRE(view != NULL); + + log_debug(2, "Registering dynamic ldap driver for %s.", name); + + /* Test argv. */ + int i = 0; + while (argv[i] != NULL) { + log_debug(2, "Arg: %s", argv[i]); + i++; + } + + /* + * We need to discover what rdataset methods does + * dns_rdatalist_tordataset use. We then make a copy for ourselves + * with the exception that we modify the disassociate method to free + * the rdlist we allocate for it in clone_rdatalist_to_rdataset(). + */ + if (rdataset_methods.disassociate == NULL) { + dns_rdataset_t rdset; + dns_rdatalist_t rdatalist; + + dns_rdataset_init(&rdset); + dns_rdatalist_tordataset(&rdatalist, &rdset); + memcpy(&rdataset_methods, rdset.methods, + sizeof(dns_rdatasetmethods_t)); + rdataset_methods.disassociate = ldapdb_rdataset_disassociate; + } + + /* Register new DNS DB implementation. */ + result = dns_db_register(ldapdb_impname, &ldapdb_create, NULL, mctx, + &ldapdb_imp); + if (result != ISC_R_SUCCESS && result != ISC_R_EXISTS) + return result; + + CHECK(new_ldap_db(mctx, view, &ldap_db, argv)); + CHECK(new_ldap_cache(mctx, &ldap_cache, argv)); + CHECK(manager_add_db_instance(mctx, name, ldap_db, ldap_cache, zmgr)); + + /* + * XXX now fetch all zones and initialize ldap zone manager + * (periodically check for new zones) + * - manager has to share server zonemgr (ns_g_server->zonemgr) + * + * XXX manager has to this this for each zone: + * - dns_zone_create + * - dns_zone_setorigin + * - dns_zone_setview + * - dns_zone_setacache (probably not needed) + * - dns_zone_setclass + * - dns_zone_settype + * - dns_zone_setdbtype (note: pass all connection arguments etc here - + * will be used by ldapdb_create) + * - continue as in bin/server.c - ns_zone_configure() + * - dns_zonemgr_managezone + * + * zone has to be bind-ed to specified view: + * - dns_view_findzone (check if zone already exists) + * - dns_view_addzone + */ + + return ISC_R_SUCCESS; + +cleanup: + if (ldap_db != NULL) + destroy_ldap_db(&ldap_db); + if (ldap_cache != NULL) + destroy_ldap_cache(&ldap_cache); + + return result; +} + +void +dynamic_driver_destroy(void) +{ + dns_db_unregister(&ldapdb_imp); + destroy_manager(); +} |