#include <freeradius-devel/server/base.h>
#include <freeradius-devel/ldap/base.h>
+#include <freeradius-devel/unlang/function.h>
LDAP *ldap_global_handle; //!< Hack for OpenLDAP libldap global initialisation.
size_t fr_ldap_connection_states_len = NUM_ELEMENTS(fr_ldap_connection_states);
fr_table_num_sorted_t const fr_ldap_supported_extensions[] = {
- { L("bindname"), LDAP_DEREF_NEVER },
- { L("x-bindpw"), LDAP_DEREF_SEARCHING }
+ { L("bindname"), LDAP_EXT_BINDNAME },
+ { L("x-bindpw"), LDAP_EXT_BINDPW }
};
size_t fr_ldap_supported_extensions_len = NUM_ELEMENTS(fr_ldap_supported_extensions);
};
size_t fr_ldap_dereference_len = NUM_ELEMENTS(fr_ldap_dereference);
+typedef struct {
+ fr_ldap_query_t *query;
+ LDAPMessage **result;
+} sync_ldap_query_t;
+
/** Prints information to the debug log on the current timeout settings
*
* There are so many different timers in LDAP it's often hard to debug
return LDAP_PROC_SUCCESS;
}
+/** Submit an LDAP query to be handled by a trunk conneciton
+ *
+ */
+static unlang_action_t ldap_trunk_query_start(UNUSED rlm_rcode_t *p_result, UNUSED int *priority, request_t *request, void *uctx)
+{
+ fr_ldap_query_t *query = talloc_get_type_abort(uctx, fr_ldap_query_t);
+
+ fr_trunk_request_enqueue(&query->treq, query->ttrunk->trunk, request, query, NULL);
+
+ return UNLANG_ACTION_YIELD;
+}
+
+/** Handle the return code from parsed LDAP results to set the module rcode
+ *
+ */
+static unlang_action_t ldap_trunk_query_results(rlm_rcode_t *p_result, UNUSED int *priority, UNUSED request_t *request, void *uctx)
+{
+ fr_ldap_query_t *query = talloc_get_type_abort(uctx, fr_ldap_query_t);
+
+ switch (query->ret) {
+ case LDAP_RESULT_PENDING:
+ /* The query we want hasn't returned yet */
+ return UNLANG_ACTION_YIELD;
+
+ case LDAP_RESULT_SUCCESS:
+ RETURN_MODULE_OK;
+
+ case LDAP_RESULT_BAD_DN:
+ case LDAP_RESULT_NO_RESULT:
+ RETURN_MODULE_NOTFOUND;
+
+ default:
+ RETURN_MODULE_FAIL;
+ }
+}
+
+/** Signal an LDAP query running on a trunk connection to cancel
+ *
+ */
+static void ldap_trunk_query_cancel(UNUSED request_t *request, fr_state_signal_t action, void *uctx)
+{
+ fr_ldap_query_t *query = talloc_get_type_abort(uctx, fr_ldap_query_t);
+
+ if (action != FR_SIGNAL_CANCEL) return;
+
+ fr_trunk_request_signal_cancel(query->treq);
+
+}
+
+#define SET_LDAP_CTRLS(_dest, _src) \
+do { \
+ if (!_src) break; \
+ int i; \
+ for (i = 0; i < LDAP_MAX_CONTROLS; i++) { \
+ if (!(_src[i])) break; \
+ _dest[i].control = _src[i]; \
+ } \
+} while (0)
+
+/** Run an async search LDAP query on a trunk connection
+ *
+ * @param[in] ctx to allocate the query in.
+ * @param[out] query that has been allocated.
+ * @param[in] request this query relates to.
+ * @param[in] ttrunk to submit the query to.
+ * @param[in] base_dn for the search.
+ * @param[in] scope of the search.
+ * @param[in] filter for the search.
+ * @param[in] attrs to be returned.
+ * @param[in] serverctrls specific to this query.
+ * @param[in] clientctrls specific to this query.
+ */
+int fr_ldap_trunk_search(TALLOC_CTX *ctx, fr_ldap_query_t **query, request_t *request, fr_ldap_thread_trunk_t *ttrunk, char const *base_dn,
+ int scope, char const *filter, char const * const *attrs, LDAPControl **serverctrls, LDAPControl **clientctrls )
+{
+ *query = fr_ldap_query_alloc(ctx);
+
+ (*query)->type = LDAP_REQUEST_SEARCH;
+ (*query)->request = request;
+ (*query)->ttrunk = ttrunk;
+ (*query)->dn = base_dn;
+ (*query)->search.scope = scope;
+ (*query)->search.filter = filter;
+ memcpy(&(*query)->search.attrs, &attrs, sizeof((*query)->search.attrs));
+ SET_LDAP_CTRLS((*query)->serverctrls, serverctrls);
+ SET_LDAP_CTRLS((*query)->clientctrls, clientctrls);
+
+ return unlang_function_push(request, ldap_trunk_query_start, ldap_trunk_query_results, ldap_trunk_query_cancel, UNLANG_TOP_FRAME, *query);
+}
+
+/** Run an async modification LDAP query on a trunk connection
+ *
+ * @param[in] ctx to allocate the query in.
+ * @param[out] query that has been allocated.
+ * @param[in] request this query relates to.
+ * @param[in] ttrunk to submit the query to.
+ * @param[in] dn of the object being modified.
+ * @param[in] mods to be performed.
+ * @param[in] serverctrls specific to this query.
+ * @param[in] clientctrls specific to this query.
+ */
+int fr_ldap_trunk_modify(TALLOC_CTX *ctx, fr_ldap_query_t **query, request_t *request, fr_ldap_thread_trunk_t *ttrunk,
+ char const *dn, LDAPMod *mods[], LDAPControl **serverctrls, LDAPControl **clientctrls)
+{
+ *query = fr_ldap_query_alloc(ctx);
+
+ (*query)->type = LDAP_REQUEST_MODIFY;
+ (*query)->request = request;
+ (*query)->ttrunk = ttrunk;
+ (*query)->dn = dn;
+ (*query)->mods = mods;
+ SET_LDAP_CTRLS((*query)->serverctrls, serverctrls);
+ SET_LDAP_CTRLS((*query)->clientctrls, clientctrls);
+
+ return unlang_function_push(request, ldap_trunk_query_start, ldap_trunk_query_results, ldap_trunk_query_cancel, UNLANG_TOP_FRAME, *query);
+}
+
/** Modify something in the LDAP directory
*
* Binds as the administrative user and attempts to modify an LDAP object.
fr_ldap_query_t *fr_ldap_query_alloc(TALLOC_CTX *ctx);
+int fr_ldap_trunk_search(TALLOC_CTX *ctx, fr_ldap_query_t **query, request_t *request, fr_ldap_thread_trunk_t *ttrunk,
+ char const *base_dn, int scope, char const *filter, char const * const *attrs,
+ LDAPControl **serverctrls, LDAPControl **clientctrls);
+
+int fr_ldap_trunk_modify(TALLOC_CTX *ctx, fr_ldap_query_t **query, request_t *request, fr_ldap_thread_trunk_t *ttrunk,
+ char const *dn, LDAPMod *mods[], LDAPControl **serverctrls, LDAPControl **clientctrls);
+
/*
* ldap.c - Wrappers arounds OpenLDAP functions.
*/
state = fr_ldap_state_next(c);
if (state == FR_LDAP_STATE_ERROR) goto error;
+ /*
+ * Initialise tree for outstanding queries handled by this connection
+ */
+ MEM(c->queries = fr_rb_inline_talloc_alloc(c, fr_ldap_query_t, node, fr_ldap_query_cmp, NULL));
+
*h = c; /* Set the handle */
return FR_CONNECTION_STATE_CONNECTING;
fr_rb_remove(ldap_conn->queries, query);
fr_trunk_request_signal_cancel_complete(treq);
+
+ /*
+ * Ensure any query resouces are cleared straight away
+ */
+ talloc_free(query);
}
}
+++ /dev/null
-/*
- * This program is 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; either version 2 of the License, or (at
- * your option) any later version.
- *
- * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
- */
-
-/**
- * $Id$
- * @file clients.c
- * @brief LDAP module dynamic clients.
- *
- * @author Arran Cudbard-Bell (a.cudbardb@freeradius.org)
- * @copyright 2013,2015 Arran Cudbard-Bell (a.cudbardb@freeradius.org)
- * @copyright 2013-2015 The FreeRADIUS Server Project.
- */
-RCSID("$Id$")
-
-USES_APPLE_DEPRECATED_API
-
-#include <freeradius-devel/util/debug.h>
-#include <ctype.h>
-
-#define LOG_PREFIX "rlm_ldap (%s) - "
-#define LOG_PREFIX_ARGS inst->name
-
-#include "rlm_ldap.h"
-
-/** Iterate over pairs in mapping section recording their values in an array
- *
- * This array is the list of attributes we retrieve from LDAP, and is NULL
- * terminated.
- *
- * If we hit a CONF_SECTION we recurse and process its CONF_PAIRS too.
- *
- * @param[out] values array of char pointers.
- * @param[in,out] idx records current array offset.
- * @param[in] cs to iterate over.
- * @return
- * - 0 on success.
- * - -1 on failure.
- */
-static int rlm_ldap_client_get_attrs(char const **values, int *idx, CONF_SECTION const *cs)
-{
- CONF_ITEM const *ci;
-
- for (ci = cf_item_next(cs, NULL);
- ci != NULL;
- ci = cf_item_next(cs, ci)) {
- char const *value;
-
- if (cf_item_is_section(ci)) {
- if (rlm_ldap_client_get_attrs(values, idx, cf_item_to_section(ci)) < 0) return -1;
- continue;
- }
-
- value = cf_pair_value(cf_item_to_pair(ci));
- if (!value) return -1;
-
- values[(*idx)++] = value;
- }
-
- values[*idx] = NULL;
-
- return 0;
-}
-
-typedef struct {
- fr_ldap_connection_t *conn;
- LDAPMessage *entry;
-} ldap_client_data_t;
-
-static int _get_client_value(char **out, CONF_PAIR const *cp, void *data)
-{
- struct berval **values;
- ldap_client_data_t *this = data;
-
- values = ldap_get_values_len(this->conn->handle, this->entry, cf_pair_value(cp));
- if (!values) {
- *out = NULL;
- return 0;
- }
-
- *out = fr_ldap_berval_to_string(NULL, values[0]);
- ldap_value_free_len(values);
-
- if (!*out) return -1;
- return 0;
-}
-
-/** Load clients from LDAP on server start
- *
- * @param[in] inst rlm_ldap configuration.
- * @param[in] tmpl to use as the base for the new client.
- * @param[in] map to load client attribute/LDAP attribute mappings from.
- * @return
- * - 0 on success.
- * - -1 on failure.
- */
-int rlm_ldap_client_load(rlm_ldap_t const *inst, CONF_SECTION *tmpl, CONF_SECTION *map)
-{
- int ret = 0;
- fr_ldap_rcode_t status;
- fr_ldap_connection_t *conn = NULL;
-
- char const **attrs = NULL;
-
- CONF_PAIR *cp;
- int count = 0, idx = 0;
-
- LDAPMessage *result = NULL;
- LDAPMessage *entry;
- char *dn = NULL;
-
- RADCLIENT *c;
-
- DEBUG("Loading dynamic clients");
-
- fr_assert(inst->clientobj_base_dn);
-
- count = cf_pair_count(map);
- count++;
-
- /*
- * Create an array of LDAP attributes to feed to fr_ldap_search.
- */
- attrs = talloc_array(inst, char const *, count);
- if (rlm_ldap_client_get_attrs(attrs, &idx, map) < 0) {
- talloc_free(attrs);
- return -1;
- }
-
- conn = mod_conn_get(inst, NULL);
- if (!conn) {
- talloc_free(attrs);
- return -1;
- }
-
- /*
- * Perform all searches as the admin user.
- */
- if (conn->rebound) {
- status = fr_ldap_bind(NULL, &conn,
- conn->config->admin_identity, conn->config->admin_password,
- &(conn->config->admin_sasl),
- NULL,
- NULL, NULL);
- if (status != LDAP_PROC_SUCCESS) {
- ret = -1;
- goto finish;
- }
-
- fr_assert(conn);
-
- conn->rebound = false;
- }
-
- status = fr_ldap_search(&result, NULL, &conn, inst->clientobj_base_dn, inst->clientobj_scope,
- inst->clientobj_filter, attrs, NULL, NULL);
- switch (status) {
- case LDAP_PROC_SUCCESS:
- break;
-
- case LDAP_PROC_NO_RESULT:
- INFO("No clients were found in the directory");
- ret = 0;
- goto finish;
-
- default:
- ret = -1;
- goto finish;
- }
-
- fr_assert(conn);
- entry = ldap_first_entry(conn->handle, result);
- if (!entry) {
- int ldap_errno;
-
- ldap_get_option(conn->handle, LDAP_OPT_RESULT_CODE, &ldap_errno);
- ERROR("Failed retrieving entry: %s", ldap_err2string(ldap_errno));
-
- ret = -1;
- goto finish;
- }
-
- do {
- ldap_client_data_t data;
-
- CONF_SECTION *client;
- char *id;
-
- struct berval **values;
-
- id = dn = ldap_get_dn(conn->handle, entry);
- if (!dn) {
- int ldap_errno;
-
- ldap_get_option(conn->handle, LDAP_OPT_RESULT_CODE, &ldap_errno);
- ERROR("Retrieving object DN from entry failed: %s", ldap_err2string(ldap_errno));
-
- goto finish;
- }
- fr_ldap_util_normalise_dn(dn, dn);
-
- cp = cf_pair_find(map, "identifier");
- if (cp) {
- values = ldap_get_values_len(conn->handle, entry, cf_pair_value(cp));
- if (values) id = fr_ldap_berval_to_string(NULL, values[0]);
- ldap_value_free_len(values);
- }
-
- /*
- * Iterate over mapping sections
- */
- client = tmpl ? cf_section_dup(NULL, NULL, tmpl, "client", id, true) :
- cf_section_alloc(NULL, NULL, "client", id);
-
- data.conn = conn;
- data.entry = entry;
-
- if (client_map_section(client, map, _get_client_value, &data) < 0) {
- talloc_free(client);
- ret = -1;
- goto finish;
- }
-
- /*
- *@todo these should be parented from something
- */
- c = client_afrom_cs(NULL, client, NULL);
- if (!c) {
- talloc_free(client);
- ret = -1;
- goto finish;
- }
-
- /*
- * Client parents the CONF_SECTION which defined it
- */
- talloc_steal(c, client);
-
- if (!client_add(NULL, c)) {
- ERROR("Failed to add client \"%s\", possible duplicate?", dn);
- ret = -1;
- client_free(c);
- goto finish;
- }
-
- DEBUG("Client \"%s\" added", dn);
-
- ldap_memfree(dn);
- dn = NULL;
- } while ((entry = ldap_next_entry(conn->handle, entry)));
-
-finish:
- talloc_free(attrs);
- if (dn) ldap_memfree(dn);
- if (result) ldap_msgfree(result);
-
- mod_conn_release(inst, NULL, conn);
-
- return ret;
-}
-