summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMartin Nagy <mnagy@redhat.com>2009-07-31 11:42:29 +0200
committerMartin Nagy <mnagy@redhat.com>2009-08-04 16:50:53 +0200
commit573182aa22cda2c0c7d25b99f79e967d53813d28 (patch)
tree511f2fb4bb3b249d3b153a210675c69ae38c6b9d
parent785f7db919cc65e5d62800ef77d1d1d39f1c9088 (diff)
downloadldap_driver-573182aa22cda2c0c7d25b99f79e967d53813d28.tar.gz
ldap_driver-573182aa22cda2c0c7d25b99f79e967d53813d28.tar.xz
ldap_driver-573182aa22cda2c0c7d25b99f79e967d53813d28.zip
Add a new structure: zone register
Zone register is used for storing pointers to zones and their corresponding LDAP distinguished names. These can then be accessed by dns name of the zone. The data is needed for conversion of a dns name to DN and to get a pointer of a zone when we need to make changes to it. We could use dns_view_findzone() for this, but that way we would not have any assurance that the found zone is really managed by us.
-rw-r--r--src/Makefile.am6
-rw-r--r--src/zone_register.c273
-rw-r--r--src/zone_register.h41
3 files changed, 318 insertions, 2 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 352a0fe..b776cf0 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -14,7 +14,8 @@ HDRS = \
settings.h \
str.h \
util.h \
- zone_manager.h
+ zone_manager.h \
+ zone_register.h
ldap_la_SOURCES = \
$(HDRS) \
@@ -29,7 +30,8 @@ ldap_la_SOURCES = \
semaphore.c \
settings.c \
str.c \
- zone_manager.c
+ zone_manager.c \
+ zone_register.c
ldap_la_CFLAGS = -Wall -Wextra -std=c99 -O2
diff --git a/src/zone_register.c b/src/zone_register.c
new file mode 100644
index 0000000..58ae98f
--- /dev/null
+++ b/src/zone_register.c
@@ -0,0 +1,273 @@
+/* Authors: Martin Nagy <mnagy@redhat.com>
+ *
+ * Copyright (C) 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/mem.h>
+#include <isc/rwlock.h>
+#include <isc/util.h>
+
+#include <dns/rbt.h>
+#include <dns/result.h>
+#include <dns/zone.h>
+
+#include <string.h>
+
+#include "log.h"
+#include "util.h"
+#include "zone_register.h"
+
+/*
+ * The zone register is a red-black tree that maps a dns name of a zone to the
+ * zone's pointer and it's LDAP DN. Synchronization is done by the zr_*
+ * functions. The data stored in this structure is needed for conversion of
+ * a dns name to DN and to get a pointer of a zone when we need to make changes
+ * to it. We could use dns_view_findzone() for this, but that way we would not
+ * have any assurance that the found zone is really managed by us.
+ */
+
+struct zone_register {
+ isc_mem_t *mctx;
+ isc_rwlock_t rwlock;
+ dns_rbt_t *rbt;
+};
+
+typedef struct {
+ dns_zone_t *zone;
+ char *dn;
+} zone_info_t;
+
+/* Callback for dns_rbt_create(). */
+static void delete_zone_info(void *arg1, void *arg2);
+
+/*
+ * Create a new zone register.
+ */
+isc_result_t
+zr_create(isc_mem_t *mctx, zone_register_t **zrp)
+{
+ isc_result_t result;
+ zone_register_t *zr = NULL;
+
+ REQUIRE(mctx != NULL);
+ REQUIRE(zrp != NULL && *zrp == NULL);
+
+ CHECKED_MEM_GET_PTR(mctx, zr);
+ ZERO_PTR(zr);
+ isc_mem_attach(mctx, &zr->mctx);
+ CHECK(dns_rbt_create(mctx, delete_zone_info, mctx, &zr->rbt));
+ CHECK(isc_rwlock_init(&zr->rwlock, 0, 0));
+
+ *zrp = zr;
+ return ISC_R_SUCCESS;
+
+cleanup:
+ if (zr != NULL) {
+ if (zr->rbt != NULL)
+ dns_rbt_destroy(&zr->rbt);
+ MEM_PUT_AND_DETACH(zr);
+ }
+
+ return result;
+}
+
+/*
+ * Destroy a zone register.
+ */
+void
+zr_destroy(zone_register_t **zrp)
+{
+ zone_register_t *zr;
+
+ if (zrp == NULL || *zrp == NULL)
+ return;
+
+ zr = *zrp;
+
+ RWLOCK(&zr->rwlock, isc_rwlocktype_write);
+ dns_rbt_destroy(&zr->rbt);
+ RWUNLOCK(&zr->rwlock, isc_rwlocktype_write);
+ isc_rwlock_destroy(&zr->rwlock);
+ MEM_PUT_AND_DETACH(zr);
+
+ *zrp = NULL;
+}
+
+/*
+ * Create a new zone info structure.
+ */
+static isc_result_t
+create_zone_info(isc_mem_t *mctx, dns_zone_t *zone, const char *dn,
+ zone_info_t **zinfop)
+{
+ isc_result_t result;
+ zone_info_t *zinfo;
+
+ REQUIRE(mctx != NULL);
+ REQUIRE(zone != NULL);
+ REQUIRE(dn != NULL);
+ REQUIRE(zinfop != NULL && *zinfop == NULL);
+
+ CHECKED_MEM_GET_PTR(mctx, zinfo);
+ CHECKED_MEM_STRDUP(mctx, dn, zinfo->dn);
+ zinfo->zone = NULL;
+ dns_zone_attach(zone, &zinfo->zone);
+
+ *zinfop = zinfo;
+ return ISC_R_SUCCESS;
+
+cleanup:
+ delete_zone_info(zinfo, mctx);
+ return result;
+}
+
+/*
+ * Delete a zone info structure. The two arguments are of type void * so the
+ * function can be used as a node deleter for the red-black tree.
+ */
+static void
+delete_zone_info(void *arg1, void *arg2)
+{
+ zone_info_t *zinfo = arg1;
+ isc_mem_t *mctx = arg2;
+
+ REQUIRE(mctx != NULL);
+
+ if (zinfo == NULL)
+ return;
+
+ isc_mem_free(mctx, zinfo->dn);
+ dns_zone_detach(&zinfo->zone);
+ isc_mem_put(mctx, zinfo, sizeof(*zinfo));
+}
+
+/*
+ * Add 'zone' to the zone register 'zr' with LDAP DN 'dn'. Origin of the zone
+ * must be absolute and the zone cannot already be in the zone register.
+ */
+isc_result_t
+zr_add_zone(zone_register_t *zr, dns_zone_t *zone, const char *dn)
+{
+ isc_result_t result;
+ dns_name_t *name;
+ zone_info_t *new_zinfo = NULL;
+ void *dummy = NULL;
+
+ REQUIRE(zr != NULL);
+ REQUIRE(zone != NULL);
+ REQUIRE(dn != NULL);
+
+ name = dns_zone_getorigin(zone);
+ if (!dns_name_isabsolute(name)) {
+ log_bug("zone with bad origin");
+ return ISC_R_FAILURE;
+ }
+
+ RWLOCK(&zr->rwlock, isc_rwlocktype_write);
+
+ /* First make sure the node doesn't exist. */
+ result = dns_rbt_findname(zr->rbt, name, 0, NULL, &dummy);
+ if (result != ISC_R_NOTFOUND) {
+ if (result == ISC_R_SUCCESS)
+ result = ISC_R_EXISTS;
+ log_error_r("failed to add zone to the zone register");
+ goto cleanup;
+ }
+
+ CHECK(create_zone_info(zr->mctx, zone, dn, &new_zinfo));
+ CHECK(dns_rbt_addname(zr->rbt, name, new_zinfo));
+
+cleanup:
+ RWUNLOCK(&zr->rwlock, isc_rwlocktype_write);
+
+ if (result != ISC_R_SUCCESS) {
+ if (new_zinfo != NULL)
+ delete_zone_info(new_zinfo, zr->mctx);
+ }
+
+ return result;
+}
+
+/*
+ * Find the closest match to zone with origin 'name' in the zone register 'zr'.
+ * The 'matched_name' will be set to the name that was matched while finding
+ * 'name' in the red-black tree. The 'dn' will be set to the LDAP DN that
+ * corresponds to the registered zone.
+ *
+ * The function returns ISC_R_SUCCESS in case of exact or partial match.
+ */
+isc_result_t
+zr_get_zone_dn(zone_register_t *zr, dns_name_t *name, const char **dn,
+ dns_name_t *matched_name)
+{
+ isc_result_t result;
+ void *zinfo = NULL;
+
+ REQUIRE(zr != NULL);
+ REQUIRE(name != NULL);
+ REQUIRE(dn != NULL && *dn == NULL);
+ REQUIRE(matched_name != NULL);
+
+ if (!dns_name_isabsolute(name)) {
+ log_bug("trying to find zone with a relative name");
+ return ISC_R_FAILURE;
+ }
+
+ RWLOCK(&zr->rwlock, isc_rwlocktype_read);
+
+ result = dns_rbt_findname(zr->rbt, name, 0, matched_name, &zinfo);
+ if (result == DNS_R_PARTIALMATCH)
+ result = ISC_R_SUCCESS;
+ if (result == ISC_R_SUCCESS)
+ *dn = ((zone_info_t *)zinfo)->dn;
+
+ RWUNLOCK(&zr->rwlock, isc_rwlocktype_read);
+
+ return result;
+}
+
+/*
+ * Find a zone with origin 'name' within in the zone register 'zr'. If an
+ * exact match is found, the pointer to the zone is returned through 'zonep'.
+ * Note that the function will attach the zone pointer and therefore the
+ * caller has to detach it after use.
+ */
+isc_result_t
+zr_get_zone_ptr(zone_register_t *zr, dns_name_t *name, dns_zone_t **zonep)
+{
+ isc_result_t result;
+ void *zinfo = NULL;
+
+ REQUIRE(zr != NULL);
+ REQUIRE(name != NULL);
+ REQUIRE(zonep != NULL && *zonep == NULL);
+
+ if (!dns_name_isabsolute(name)) {
+ log_bug("trying to find zone with a relative name");
+ return ISC_R_FAILURE;
+ }
+
+ RWLOCK(&zr->rwlock, isc_rwlocktype_read);
+
+ result = dns_rbt_findname(zr->rbt, name, 0, NULL, &zinfo);
+ if (result == ISC_R_SUCCESS)
+ dns_zone_attach(((zone_info_t *)zinfo)->zone, zonep);
+
+ RWUNLOCK(&zr->rwlock, isc_rwlocktype_read);
+
+ return result;
+}
diff --git a/src/zone_register.h b/src/zone_register.h
new file mode 100644
index 0000000..d6b06a4
--- /dev/null
+++ b/src/zone_register.h
@@ -0,0 +1,41 @@
+/* Authors: Martin Nagy <mnagy@redhat.com>
+ *
+ * Copyright (C) 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
+ */
+
+#ifndef _LD_ZONE_REGISTER_H_
+#define _LD_ZONE_REGISTER_H_
+
+typedef struct zone_register zone_register_t;
+
+isc_result_t
+zr_create(isc_mem_t *mctx, zone_register_t **zrp);
+
+void
+zr_destroy(zone_register_t **zrp);
+
+isc_result_t
+zr_add_zone(zone_register_t *zr, dns_zone_t *zone, const char *dn);
+
+isc_result_t
+zr_get_zone_dn(zone_register_t *zr, dns_name_t *name, const char **dn,
+ dns_name_t *matched_name);
+
+isc_result_t
+zr_get_zone_ptr(zone_register_t *zr, dns_name_t *name, dns_zone_t **zonep);
+
+#endif /* !_LD_ZONE_REGISTER_H_ */