diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/Makefile.am | 6 | ||||
-rw-r--r-- | src/zone_register.c | 273 | ||||
-rw-r--r-- | src/zone_register.h | 41 |
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_ */ |