diff options
author | Martin Nagy <mnagy@redhat.com> | 2009-01-14 16:41:12 +0100 |
---|---|---|
committer | Martin Nagy <mnagy@redhat.com> | 2009-01-14 16:41:12 +0100 |
commit | b5a1cfb1cded6a31719da75525aa6ffb7d0915f3 (patch) | |
tree | ce37ffd4c18a918bd1977c89ff0bde8a36881b0f | |
parent | 4a78983d04dc77729b75d1620c41f1d2d140e8cc (diff) | |
download | ldap_driver_testing-b5a1cfb1cded6a31719da75525aa6ffb7d0915f3.tar.gz ldap_driver_testing-b5a1cfb1cded6a31719da75525aa6ffb7d0915f3.tar.xz ldap_driver_testing-b5a1cfb1cded6a31719da75525aa6ffb7d0915f3.zip |
Add LDAP helper routines.
-rw-r--r-- | Makefile | 2 | ||||
-rw-r--r-- | ldap_driver.c | 23 | ||||
-rw-r--r-- | ldap_helper.c | 419 | ||||
-rw-r--r-- | ldap_helper.h | 30 |
4 files changed, 469 insertions, 5 deletions
@@ -5,7 +5,7 @@ LIBMINOR = 0 LIBNAME = libdnsldap.so.$(LIBMAJOR).$(LIBMINOR).0 LIBSONAME = libdnsldap.so.$(LIBMAJOR) -OBJS = ldap_driver.o semaphore.o log.o settings.o str.o +OBJS = ldap_driver.o semaphore.o ldap_helper.o log.o settings.o str.o CFLAGS := -Wall -Wextra -pedantic -std=c99 -g -fPIC $(CFLAGS) diff --git a/ldap_driver.c b/ldap_driver.c index 1bda8b6..7d3c4fe 100644 --- a/ldap_driver.c +++ b/ldap_driver.c @@ -25,6 +25,7 @@ #include <dns/db.h> #include <dns/result.h> +#include "ldap_helper.h" #include "log.h" #include "util.h" @@ -37,6 +38,10 @@ LDAPDBNODE_MAGIC) typedef struct { + ldap_db_t *ldap_db; +} ldapdb_data_t; + +typedef struct { dns_db_t common; isc_refcount_t refs; isc_mutex_t lock; /* convert to isc_rwlock_t ? */ @@ -57,6 +62,7 @@ typedef struct { static int dummy; static void *ldapdb_version = &dummy; +static ldapdb_data_t driver_data; /* ldapdbnode_t functions */ static isc_result_t @@ -640,15 +646,16 @@ dynamic_driver_init(isc_mem_t *mctx, const char *name, const char * const *argv, { isc_result_t result; - UNUSED(mctx); + REQUIRE(argv != NULL); UNUSED(view); log_debug(2, "Registering dynamic ldap driver for %s.", name); /* Test argv. */ - while (*argv != NULL) { - log_debug(2, "Arg: %s", *argv); - argv++; + int i = 0; + while (argv[i] != NULL) { + log_debug(2, "Arg: %s", argv[i]); + i++; } result = dns_db_register(ldapdb_impname, &ldapdb_create, NULL, mctx, @@ -659,6 +666,10 @@ dynamic_driver_init(isc_mem_t *mctx, const char *name, const char * const *argv, if (result != ISC_R_SUCCESS) return result; + CHECK(new_ldap_db(mctx, &driver_data.ldap_db, argv)); + + get_zone_list(driver_data.ldap_db); + /* * XXX now fetch all zones and initialize ldap zone manager * (periodically check for new zones) @@ -682,10 +693,14 @@ dynamic_driver_init(isc_mem_t *mctx, const char *name, const char * const *argv, */ return ISC_R_SUCCESS; + +cleanup: + return result; } void dynamic_driver_destroy(void) { dns_db_unregister(&ldapdb_imp); + destroy_ldap_db(&driver_data.ldap_db); } diff --git a/ldap_helper.c b/ldap_helper.c new file mode 100644 index 0000000..c766348 --- /dev/null +++ b/ldap_helper.c @@ -0,0 +1,419 @@ +/* Authors: Martin Nagy <mnagy@redhat.com> + * + * Copyright (C) 2008 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/result.h> + +#include <isc/mem.h> +#include <isc/mutex.h> +#include <isc/util.h> + +#define LDAP_DEPRECATED 1 +#include <ldap.h> +#include <stddef.h> +#include <string.h> +#include <strings.h> + +#include "ldap_helper.h" +#include "log.h" +#include "semaphore.h" +#include "settings.h" +#include "str.h" +#include "util.h" + + +/* + * LDAP related typedefs and structs. + */ + +typedef struct ldap_auth_pair ldap_auth_pair_t; +typedef struct settings settings_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; + /* List of LDAP connections. */ + semaphore_t conn_semaphore; + LIST(ldap_instance_t) conn_list; + /* Settings. */ + ld_string_t *host; + ld_string_t *base; + unsigned int connections; + ldap_auth_t auth_method; +}; + +struct ldap_instance { + ldap_db_t *database; + isc_mutex_t lock; + LINK(ldap_instance_t) link; + LDAP *ldap_handle; + LDAPMessage *result; + ld_string_t *query_string; + ld_string_t *base; +}; + +/* + * Constants. + */ + +/* Supported authentication types. */ +const ldap_auth_pair_t supported_ldap_auth[] = { + { AUTH_NONE, "none" }, +#if 0 + { AUTH_SIMPLE, "simple" }, + { AUTH_SASL, "sasl" }, +#endif + { AUTH_INVALID, NULL }, +}; + +/* + * Forward declarations. + */ + +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 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, int scope, + char **attrs, int attrsonly, const char *filter, ...); + + +isc_result_t +new_ldap_db(isc_mem_t *mctx, 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; + setting_t ldap_settings[] = { + { "host", no_default_string, NULL }, + { "connections", default_uint(1), NULL }, + { "base", no_default_string, NULL }, + end_of_settings + }; + + REQUIRE(mctx != 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, ldap_db_t); + memset(ldap_db, 0, sizeof(ldap_db_t)); + + isc_mem_attach(mctx, &ldap_db->mctx); + + INIT_LIST(ldap_db->conn_list); + ldap_db->auth_method = AUTH_NONE; /* todo: should be in settings */ + + CHECK(str_new(ldap_db->mctx, &ldap_db->host)); + CHECK(str_new(ldap_db->mctx, &ldap_db->base)); + + ldap_settings[0].target = ldap_db->host; + ldap_settings[1].target = &ldap_db->connections; + ldap_settings[2].target = ldap_db->base; + + CHECK(set_settings(ldap_settings, argv)); + if (ldap_db->connections < 1) { + log_error("at least one connection is required"); + 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); + } + + *ldap_dbp = ldap_db; + + return ISC_R_SUCCESS; + +cleanup: + destroy_ldap_db(&ldap_db); + + 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); + + semaphore_destroy(&ldap_db->conn_semaphore); + 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_instance_t); + memset(ldap_inst, 0, sizeof(ldap_instance_t)); + + 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)); + + *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->ldap_handle != NULL) + ldap_unbind_ext_s(ldap_inst->ldap_handle, NULL, NULL); + + str_destroy(&ldap_inst->query_string); + str_destroy(&ldap_inst->base); + + isc_mem_put(ldap_inst->database->mctx, *ldap_instp, sizeof(ldap_instance_t)); + *ldap_instp = NULL; +} + +void +get_zone_list(ldap_db_t *ldap_db) +{ + ldap_instance_t *ldap_inst; + int i; + char *a; + LDAPMessage *e; + BerElement *ber; + char **vals; + char *attrs[] = { + "idnsName", "idnsSOAmName", "idnsSOArName", "idnsSOAserial", + "idnsSOArefresh", "idnsSOAretry", "idnsSOAexpire", + "idnsSOAminimum", NULL + }; + + ldap_inst = get_connection(ldap_db); + + ldap_query(ldap_inst, LDAP_SCOPE_SUBTREE, attrs, 0, + "(objectClass=idnsZone)"); + + log_error("list of ldap values:"); + for (e = ldap_first_entry(ldap_inst->ldap_handle, ldap_inst->result); + e != NULL; + e = ldap_next_entry(ldap_inst->ldap_handle, e)) { + for (a = ldap_first_attribute(ldap_inst->ldap_handle, e, &ber); + a != NULL; + a = ldap_next_attribute(ldap_inst->ldap_handle, e, ber)) { + vals = ldap_get_values(ldap_inst->ldap_handle, e, a); + if (vals == NULL) + continue; + for (i = 0; vals[i] != NULL; i++) { + log_error("attribute %s: %s", a, vals[i]); + } + ldap_value_free(vals); + } + ber_free(ber, 0); + } + log_error("end of ldap values"); + + put_connection(ldap_inst); +} + +static ldap_instance_t * +get_connection(ldap_db_t *ldap_db) +{ + ldap_instance_t *ldap_inst; + + 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); + + /* 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->result != NULL) { + ldap_msgfree(ldap_inst->result); + ldap_inst->result = NULL; + } + + UNLOCK(&ldap_inst->lock); + semaphore_signal(&ldap_inst->database->conn_semaphore); +} + + +static isc_result_t +ldap_query(ldap_instance_t *ldap_inst, int scope, char **attrs, + int attrsonly, const char *filter, ...) +{ + va_list ap; + int ret; + + va_start(ap, filter); + str_vsprintf(ldap_inst->query_string, filter, ap); + va_end(ap); + + log_error("Querying '%s' with '%s'", str_buf(ldap_inst->base), + str_buf(ldap_inst->query_string)); + + ret = ldap_search_ext_s(ldap_inst->ldap_handle, str_buf(ldap_inst->base), + scope, str_buf(ldap_inst->query_string), attrs, + attrsonly, NULL, NULL, NULL, LDAP_NO_LIMIT, + &ldap_inst->result); + + log_error("Result: %d", ldap_count_entries(ldap_inst->ldap_handle, + ldap_inst->result)); + + return ISC_R_SUCCESS; +} + +/* + * Static methods local to this unit ABRAKA + */ +static isc_result_t +ldap_connect(ldap_instance_t *ldap_inst) +{ + LDAP *ld; + int ret; + ldap_db_t *ldap_db; + + REQUIRE(ldap_inst != NULL); + + ldap_db = ldap_inst->database; + + /* XXX: port should be overridable */ + ret = ldap_initialize(&ld, str_buf(ldap_db->host)); + if (ret != LDAP_SUCCESS) { + log_error("LDAP initialization failed: %s", ldap_err2string(ret)); + goto cleanup; + } + + /* + ret = ldap_set_option(ld, LDAP_OPT_TIMELIMIT, (void *)&ldap_db->timeout); + if (ret != LDAP_OPT_SUCCESS) { + log_error("Failed to set timeout: %s", ldap_err2string(ret)); + goto cleanup; + } + */ + + log_debug(2, "Trying to make an 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: + fatal_error("Simple auth not supported yet."); + break; + case AUTH_SASL: + fatal_error("SASL auth not supported yet."); + break; + default: + fatal_error("Bug in ldap_connect(): unsupported authentication mechanism"); + return ISC_R_UNEXPECTED; + } + + if (ret != LDAP_SUCCESS) { + log_error("Bind to LDAP server failed: %s", ldap_err2string(ret)); + goto cleanup; + } + + ldap_inst->ldap_handle = ld; + + return ISC_R_SUCCESS; + +cleanup: + + if (ld != NULL) + ldap_unbind_ext_s(ld, NULL, NULL); + + return ISC_R_FAILURE; +} diff --git a/ldap_helper.h b/ldap_helper.h new file mode 100644 index 0000000..d7239f6 --- /dev/null +++ b/ldap_helper.h @@ -0,0 +1,30 @@ +/* Authors: Martin Nagy <mnagy@redhat.com> + * + * Copyright (C) 2008 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_LDAP_HELPER_H_ + +typedef struct ldap_db ldap_db_t; +typedef struct ldap_instance ldap_instance_t; + +isc_result_t new_ldap_db(isc_mem_t *mctx, ldap_db_t **ldap_dbp, + const char * const *argv); +void destroy_ldap_db(ldap_db_t **ldap_db); +void get_zone_list(ldap_db_t *ldap_db); + +#endif /* !_LD_LDAP_HELPER_H_ */ |