summaryrefslogtreecommitdiffstats
path: root/src/modules/rlm_ldap/clients.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/modules/rlm_ldap/clients.c263
1 files changed, 263 insertions, 0 deletions
diff --git a/src/modules/rlm_ldap/clients.c b/src/modules/rlm_ldap/clients.c
new file mode 100644
index 0000000..8654475
--- /dev/null
+++ b/src/modules/rlm_ldap/clients.c
@@ -0,0 +1,263 @@
+/*
+ * 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.
+ */
+#include <freeradius-devel/rad_assert.h>
+#include <ctype.h>
+
+#include "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_find_next(cs, NULL);
+ ci != NULL;
+ ci = cf_item_find_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 ldap_client_data {
+ ldap_handle_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 = rlm_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;
+ ldap_rcode_t status;
+ ldap_handle_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;
+
+ LDAP_DBG("Loading dynamic clients");
+
+ rad_assert(inst->clientobj_base_dn);
+
+ count = cf_pair_count(map);
+ count++;
+
+ /*
+ * Create an array of LDAP attributes to feed to rlm_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 = rlm_ldap_bind(inst, NULL, &conn, conn->inst->admin_identity, conn->inst->admin_password,
+ &(conn->inst->admin_sasl), true);
+ if (status != LDAP_PROC_SUCCESS) {
+ ret = -1;
+ goto finish;
+ }
+
+ rad_assert(conn);
+
+ conn->rebound = false;
+ }
+
+ status = rlm_ldap_search(&result, inst, 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:
+ LDAP_INFO("No clients were found in the directory");
+ ret = 0;
+ goto finish;
+
+ default:
+ ret = -1;
+ goto finish;
+ }
+
+ rad_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);
+ LDAP_ERR("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);
+ LDAP_ERR("Retrieving object DN from entry failed: %s", ldap_err2string(ldap_errno));
+
+ goto finish;
+ }
+ rlm_ldap_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 = rlm_ldap_berval_to_string(NULL, values[0]);
+ ldap_value_free_len(values);
+ }
+
+ /*
+ * Iterate over mapping sections
+ */
+ client = tmpl ? cf_section_dup(NULL, tmpl, "client", id, true) :
+ cf_section_alloc(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, false, false);
+ 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)) {
+ LDAP_ERR("Failed to add client \"%s\", possible duplicate?", dn);
+ ret = -1;
+ client_free(c);
+ goto finish;
+ }
+
+ LDAP_DBG("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, conn);
+
+ return ret;
+}
+