diff options
-rw-r--r-- | ldap_convert.c | 78 | ||||
-rw-r--r-- | ldap_convert.h | 5 | ||||
-rw-r--r-- | ldap_helper.c | 118 | ||||
-rw-r--r-- | ldap_helper.h | 4 | ||||
-rw-r--r-- | str.c | 13 | ||||
-rw-r--r-- | util.h | 13 |
6 files changed, 172 insertions, 59 deletions
diff --git a/ldap_convert.c b/ldap_convert.c index 5df83e3..2c02f28 100644 --- a/ldap_convert.c +++ b/ldap_convert.c @@ -19,11 +19,11 @@ #include <isc/buffer.h> #include <isc/mem.h> -#include <isc/result.h> #include <isc/util.h> #include <dns/name.h> #include <dns/rdatatype.h> +#include <dns/result.h> #include <dns/types.h> #define LDAP_DEPRECATED 1 @@ -34,6 +34,7 @@ #include "str.h" #include "ldap_convert.h" +#include "ldap_helper.h" #include "log.h" #include "util.h" @@ -107,13 +108,11 @@ cleanup: } /* - * Convert LDAP dn to DNS name. If root_dn is not NULL then count how much RNDs - * it contains and ignore that much trailing RNDs from dn. + * Convert LDAP dn to DNS name. * * Example: * dn = "idnsName=foo, idnsName=bar, idnsName=example.org, cn=dns," * "dc=example, dc=org" - * root_dn = "cn=dns, dc=example, dc=org" * * The resulting string will be "foo.bar.example.org." */ @@ -203,55 +202,58 @@ explode_rdn(const char *rdn, char ***explodedp, int notypes) return ISC_R_SUCCESS; } -/* - * FIXME: Don't assume that the last RDN consists of the last two labels. - */ isc_result_t -dnsname_to_dn(isc_mem_t *mctx, dns_name_t *name, const char *root_dn, - ld_string_t *target) +dnsname_to_dn(ldap_db_t *ldap_db, dns_name_t *name, ld_string_t *target) { isc_result_t result; - isc_buffer_t target_buffer; - char target_base[DNS_NAME_MAXTEXT + 1]; - ld_string_t *str; - ld_split_t *split; - unsigned int split_count; - REQUIRE(mctx != NULL); + DECLARE_BUFFERED_NAME(zone); + + dns_name_t labels; + + dns_namereln_t reln; + int order; + unsigned int common_labels; + int label_count; + const char *zone_dn = NULL; + + REQUIRE(ldap_db != NULL); REQUIRE(name != NULL); REQUIRE(target != NULL); - str = NULL; - split = NULL; - CHECK(str_new(mctx, &str)); - CHECK(str_new_split(mctx, &split)); - isc_buffer_init(&target_buffer, target_base, sizeof(target_base)); - CHECK(dns_name_totext(name, isc_boolean_true, &target_buffer)); - target_base[isc_buffer_usedlength(&target_buffer)] = '\0'; - CHECK(str_init_char(str, target_base)); - CHECK(str_split(str, '.', split)); - split_count = str_split_count(split); + INIT_BUFFERED_NAME(zone); - for (unsigned int i = 0; i < split_count - 1; i++) { - CHECK(str_cat_char(target, "idnsName=")); - CHECK(str_cat_char(target, str_split_get(split, i))); - if (split_count - i > 2) - CHECK(str_cat_char(target, ", ")); - } + dns_name_init(&labels, NULL); + + /* Find the DN of the zone we belong to. */ + CHECK(get_zone_dn(ldap_db, name, &zone_dn, &zone)); + + reln = dns_name_fullcompare(name, &zone, &order, &common_labels); + INSIST(reln == dns_namereln_subdomain || reln == dns_namereln_equal); + label_count = dns_name_countlabels(name); + label_count -= common_labels; + + str_clear(target); + if (label_count > 0) { + isc_buffer_t buffer; + char target_base[DNS_NAME_MAXTEXT]; + isc_region_t region; + + isc_buffer_init(&buffer, target_base, sizeof(target_base)); - CHECK(str_cat_char(target, ".")); - CHECK(str_cat_char(target, str_split_get(split, split_count - 1))); + dns_name_getlabelsequence(name, 0, label_count, &labels); + CHECK(dns_name_totext(&labels, ISC_TRUE, &buffer)); + isc_buffer_usedregion(&buffer, ®ion); - if (root_dn != NULL) { + CHECK(str_cat_char(target, "idnsName=")); + CHECK(str_cat_char_len(target, (char *)region.base, + region.length)); CHECK(str_cat_char(target, ", ")); - CHECK(str_cat_char(target, root_dn)); } + CHECK(str_cat_char(target, zone_dn)); cleanup: - str_destroy_split(&split); - str_destroy(&str); - return result; } diff --git a/ldap_convert.h b/ldap_convert.h index 4c166b5..d35144a 100644 --- a/ldap_convert.h +++ b/ldap_convert.h @@ -23,6 +23,7 @@ #include <dns/types.h> #include "str.h" +#include "ldap_helper.h" /* * Convert LDAP DN 'dn', to dns_name_t 'target'. 'target' needs to be @@ -32,8 +33,8 @@ isc_result_t dn_to_dnsname(isc_mem_t *mctx, const char *dn, dns_name_t *target); -isc_result_t dnsname_to_dn(isc_mem_t *mctx, dns_name_t *name, - const char *root_dn, ld_string_t *target); +isc_result_t dnsname_to_dn(ldap_db_t *ldap_db, dns_name_t *name, + ld_string_t *target); isc_result_t ldap_record_to_rdatatype(const char *ldap_record, dns_rdatatype_t *rdtype); diff --git a/ldap_helper.c b/ldap_helper.c index e0e66b1..7c0dcb8 100644 --- a/ldap_helper.c +++ b/ldap_helper.c @@ -18,6 +18,7 @@ * 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> @@ -32,6 +33,7 @@ #include <isc/mem.h> #include <isc/mutex.h> #include <isc/region.h> +#include <isc/rwlock.h> #include <isc/util.h> #define LDAP_DEPRECATED 1 @@ -97,6 +99,10 @@ struct ldap_db { 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; @@ -156,7 +162,6 @@ struct ldap_value { LINK(ldap_value_t) link; }; - /* * Constants. */ @@ -176,6 +181,7 @@ const ldap_auth_pair_t supported_ldap_auth[] = { */ /* 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); @@ -275,14 +281,17 @@ new_ldap_db(isc_mem_t *mctx, dns_view_t *view, ldap_db_t **ldap_dbp, INIT_LIST(ldap_db->conn_list); - CHECK(str_new(ldap_db->mctx, &auth_method_str)); - CHECK(str_new(ldap_db->mctx, &ldap_db->host)); - CHECK(str_new(ldap_db->mctx, &ldap_db->base)); - CHECK(str_new(ldap_db->mctx, &ldap_db->bind_dn)); - CHECK(str_new(ldap_db->mctx, &ldap_db->password)); - CHECK(str_new(ldap_db->mctx, &ldap_db->sasl_mech)); - CHECK(str_new(ldap_db->mctx, &ldap_db->sasl_user)); - CHECK(str_new(ldap_db->mctx, &ldap_db->sasl_realm)); + 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; @@ -370,6 +379,9 @@ destroy_ldap_db(ldap_db_t **ldap_dbp) /* 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; @@ -487,6 +499,89 @@ get_dn(ldap_instance_t *inst) } + +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) @@ -526,6 +621,7 @@ add_or_modify_zone(ldap_db_t *ldap_db, const char *dn, const char *db_name, 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; } @@ -678,7 +774,7 @@ ldapdb_rdatalist_get(isc_mem_t *mctx, ldap_db_t *ldap_db, dns_name_t *name, INIT_LIST(*rdatalist); CHECK(str_new(mctx, &string)); - CHECK(dnsname_to_dn(mctx, name, str_buf(ldap_db->base), string)); + CHECK(dnsname_to_dn(ldap_db, name, string)); CHECK(ldap_query(ldap_inst, str_buf(string), LDAP_SCOPE_BASE, NULL, 0, "(objectClass=idnsRecord)")); @@ -1595,7 +1691,7 @@ modify_ldap_common(dns_name_t *owner, ldap_db_t *ldap_db, ldap_inst = get_connection(ldap_db); CHECK(str_new(mctx, &owner_dn)); - CHECK(dnsname_to_dn(mctx, owner, str_buf(ldap_db->base), 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)); diff --git a/ldap_helper.h b/ldap_helper.h index 32edd9c..a0e4aea 100644 --- a/ldap_helper.h +++ b/ldap_helper.h @@ -90,6 +90,10 @@ void destroy_ldap_db(ldap_db_t **ldap_db); isc_result_t refresh_zones_from_ldap(ldap_db_t *ldap_db, const char *name, dns_zonemgr_t *zmgr); +isc_result_t +get_zone_dn(ldap_db_t *ldap_db, dns_name_t *name, const char **dn, + dns_name_t *matched_name); + /* Functions for writing to LDAP. */ isc_result_t ldap_rdata_to_char_array(isc_mem_t *mctx, dns_rdata_t *rdata_head, char ***valsp); @@ -324,20 +324,17 @@ str_cat_char_len(ld_string_t *dest, const char *src, size_t len) isc_result_t result; char *from; size_t dest_size; - size_t src_size; REQUIRE(dest != NULL); - IGNORE_R(src != NULL); + IGNORE_R(src == NULL); + IGNORE_R(len == 0); dest_size = str_len_internal(dest); - src_size = ISC_MAX(strlen(src), len); - IGNORE_R(src_size == 0); - - CHECK(str_alloc(dest, dest_size + src_size)); + CHECK(str_alloc(dest, dest_size + len)); from = dest->data + dest_size; - strncpy(from, src, src_size); - from[src_size - 1] = '\0'; + strncpy(from, src, len); + from[len] = '\0'; return ISC_R_SUCCESS; @@ -62,4 +62,17 @@ isc_mem_putanddetach(&(target_ptr)->mctx, target_ptr, \ sizeof(*(target_ptr))) +#define DECLARE_BUFFERED_NAME(name) \ + dns_name_t name; \ + isc_buffer_t name##__buffer; \ + unsigned char name##__base[DNS_NAME_MAXWIRE] + +#define INIT_BUFFERED_NAME(name) \ + do { \ + isc_buffer_init(&name##__buffer, name##__base, \ + sizeof(name##__base)); \ + dns_name_init(&name, NULL); \ + dns_name_setbuffer(&name, &name##__buffer); \ + } while (0) + #endif /* !_LD_UTIL_H_ */ |