+++ /dev/null
-/*
- * mapping.c LDAP attribute to RADIUS attribute mappings
- *
- * 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; 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
- *
- * Copyright 1999,2000,2001,2002,2003,2004,2005,2006,2007,2008,
- * 2009,2010,2011,1012 The FreeRADIUS Server Project.
- *
- * Copyright 2012 Alan DeKok <aland@freeradius.org>
- */
-
-#include <freeradius-devel/ident.h>
-RCSID("$Id$")
-
-#include <freeradius-devel/radiusd.h>
-#include <freeradius-devel/modules.h>
-#include <freeradius-devel/rad_assert.h>
-
-#include "mapping.h"
-
-#define GENERIC_ATTRIBUTE_ID "$GENERIC$"
-#define MAX_ARGV 5
-
-void rlm_ldap_map_free(TLDAP_RADIUS **map)
-{
- TLDAP_RADIUS *t, *next;
-
- if (!map || !*map) return;
-
- for (t = *map; t != NULL; t = next) {
- next = t->next;
- free(t);
- }
-
- *map = NULL;
-}
-
-int rlm_ldap_map_read(const char *xlat_name,
- const char *filename,
- TLDAP_RADIUS **check_map,
- TLDAP_RADIUS **reply_map,
- int offset,
- char *attrs[MAX_ATTRMAP])
-{
- FILE *fp;
- int total;
- int lineno, argc;
- FR_TOKEN operator;
- TLDAP_RADIUS *pair;
- char *argv[MAX_ARGV];
- char *p, buffer[1024];
-
- fp = fopen(filename, "r");
- if (!fp) {
- radlog(L_ERR, "%s: Failed opening %s: %s",
- xlat_name, filename, strerror(errno));
- return -1;
- }
-
- lineno = 0;
- total = offset;
-
- while (fgets(buffer, sizeof(buffer), fp) != NULL) {
- size_t ldap_size, radius_size;
-
- lineno++;
-
- p = strchr(buffer, '#');
- if (p) *p = 0;
-
- argc = str2argv(buffer, argv, MAX_ARGV);
- if (argc == 0) continue;
-
- if ((argc < 3) || (argc > 4)) {
- radlog(L_ERR, "%s: Invalid format in file %s line %d",
- xlat_name, filename, lineno);
- error:
- fclose(fp);
- rlm_ldap_map_free(check_map);
- rlm_ldap_map_free(reply_map);
- return -1;
- }
-
- if (argc == 3) {
- operator = T_OP_INVALID; /* use defaults */
- } else {
- operator = fr_str2int(fr_tokens, argv[3], T_OP_INVALID);
- if ((operator < T_OP_ADD) || (operator > T_OP_CMP_EQ)) {
- radlog(L_ERR, "%s: Invalid operator '%s' in file %s line %d",
- xlat_name, argv[3],
- filename, lineno);
- goto error;
- }
- }
-
- /*
- * Sanity check checkItem or replyItem
- */
- if ((strcasecmp(argv[0], "checkItem") != 0) &&
- (strcasecmp(argv[0], "replyItem") != 0)) {
- radlog(L_ERR, "%s: Entry does not have \"checkItem\" or \"replyItem\" in column 0 of file %s line %d",
- xlat_name, filename, lineno);
- goto error;
- }
-
- /*
- * Sanity check RADIUS attribute.
- * Allow generic name, too.
- */
- if ((strcmp(argv[1], GENERIC_ATTRIBUTE_ID) != 0) &&
- !dict_attrbyname(argv[1])) {
- radlog(L_ERR, "%s: Unknown RADIUS attribute \"%s\" in file %s line %d",
- xlat_name, argv[1], filename, lineno);
- goto error;
- }
-
- /* create new TLDAP_RADIUS list node */
- radius_size = strlen(argv[1]);
- ldap_size = strlen(argv[2]);
-
- /*
- * Doing tons of strcmp() at run-time is bad.
- * Instead, just set the radius field to be ""
- */
- if (strcmp(argv[1], GENERIC_ATTRIBUTE_ID) == 0) {
- argv[1] += radius_size;
- radius_size = 0;
- }
-
- pair = rad_malloc(sizeof(*pair) + radius_size + ldap_size + 2);
- pair->ldap_attr = ((char *) pair) + sizeof(*pair);
- pair->radius_attr = pair->ldap_attr + ldap_size + 1;
-
- memcpy(pair->radius_attr, argv[1], radius_size + 1);
- memcpy(pair->ldap_attr, argv[2], ldap_size + 1);
- pair->operator = operator;
-
- /*
- * Place it in the correct list.
- */
- if (*argv[0] == 'c') {
- pair->next = *check_map;
- *check_map = pair;
- } else {
- pair->next = *reply_map;
- *reply_map = pair;
- }
-
- attrs[total++] = pair->ldap_attr;
-
- if (total >= MAX_ATTRMAP) {
- radlog(L_ERR, "%s: ERROR Too many entries (%d) in %s",
- xlat_name, total, filename);
- goto error;
- }
-
- DEBUG(" %s: %s --> %s",
- xlat_name, pair->ldap_attr,
- *pair->radius_attr ? pair->radius_attr : GENERIC_ATTRIBUTE_ID);
- }
-
- fclose(fp);
-
- attrs[total] = NULL;
- return 0; /* success */
-}
-
-static VALUE_PAIR *ldap2vp(const char *xlat_name, TLDAP_RADIUS *pair,
- const char *value, int is_check)
-{
- int do_xlat;
- const char *p;
- VALUE_PAIR *vp;
- FR_TOKEN token, operator;
- char buffer[1024];
-
- p = value;
-
- if (!*pair->radius_attr) {
- FR_TOKEN eol;
-
- vp = pairread(&p, &eol);
- goto done; /* I hate indentation */
- }
-
- /*
- * This is a one-to-one-mapped attribute
- */
- operator = gettoken(&p, buffer, sizeof(buffer));
- if (operator < T_EQSTART || operator > T_EQEND) {
- if (pair->operator != T_OP_INVALID) {
- operator = pair->operator;
- } else if (is_check) {
- operator = T_OP_CMP_EQ;
- } else {
- operator = T_OP_EQ;
- }
- } else { /* skip the operator */
- value = p;
- }
-
- if (!*value) {
- empty_string:
- DEBUG(" [%s] FAILED parsing %s -> empty string",
- xlat_name, pair->ldap_attr);
- return NULL;
- }
-
- p = value;
- token = gettoken(&p, buffer, sizeof(buffer));
- switch (token) {
- case T_BARE_WORD:
- case T_SINGLE_QUOTED_STRING:
- case T_DOUBLE_QUOTED_STRING:
- do_xlat = FALSE;
- break;
-
- /* the value will be xlat'ed later */
- case T_BACK_QUOTED_STRING:
- do_xlat = TRUE;
- break;
-
- case T_OP_INVALID:
- default:
- DEBUG(" [%s] FAILED Parsing %s -> %s",
- xlat_name, pair->ldap_attr, value);
- return NULL;
-
- }
-
- if (!*buffer) goto empty_string;
-
- /*
- * Create the pair.
- */
- if (do_xlat) {
- vp = pairmake_xlat(pair->radius_attr, buffer, operator);
- } else {
- vp = pairmake(pair->radius_attr, buffer, operator);
- }
-
-done:
- if (!vp) {
- DEBUG(" [%s] FAILED parsing %s -> %s",
- xlat_name, pair->ldap_attr, value);
- return NULL;
- }
-
- if (fr_debug_flag) {
- vp_prints(buffer, sizeof(buffer), vp);
- DEBUG(" [%s] %s -> %s",
- xlat_name, pair->ldap_attr, buffer);
- }
-
- return vp;
-}
-
-/*****************************************************************************
- * Get RADIUS attributes from LDAP object
- * ( according to draft-adoba-radius-05.txt
- * <http://www.ietf.org/internet-drafts/draft-adoba-radius-05.txt> )
- *
- *****************************************************************************/
-VALUE_PAIR *rlm_ldap_pairget(const char *xlat_name,
- LDAP *ld, LDAPMessage *entry,
- TLDAP_RADIUS *map,
- VALUE_PAIR **vps, int is_check)
-{
- char **vals;
- int count;
- int i;
- TLDAP_RADIUS *pair;
- VALUE_PAIR *head, **tail;
-
- head = NULL;
- tail = &head;
-
- /*
- * check if there is a mapping from this LDAP attribute
- * to a RADIUS attribute
- */
- for (pair = map; pair != NULL; pair = pair->next) {
- /*
- * No mapping found, skip it.
- */
- vals = ldap_get_values(ld, entry, pair->ldap_attr);
- if (!vals) continue;
-
- /*
- * Find out how many values there are for the
- * attribute and extract all of them.
- */
- count = ldap_count_values(vals);
-
- /*
- * FIXME: The old code DELETES all references
- * to pair->radius_attr from the vps list.
- * Why?
- */
-
- for (i = 0; i < count; i++) {
- VALUE_PAIR *vp;
-
- vp = ldap2vp(xlat_name, pair, vals[i], is_check);
- if (!vp) continue;
-
- /*
- * FIXME: if i==0, delete from vps?
- */
-
- *tail = vp;
- tail = &vp->next;
- }
-
- ldap_value_free(vals);
- }
-
- return head;
-}
#include <stdarg.h>
#include <ctype.h>
-#include "mapping.h"
+#include <lber.h>
+#include <ldap.h>
+#define MAX_ATTRMAP 128
+#define MAX_ATTR_STR_LEN 256
#define MAX_FILTER_STR_LEN 1024
typedef struct {
- CONF_SECTION *cs;
+ CONF_SECTION *cs;
fr_connection_pool_t *pool;
- char *server;
- int port;
+
+ char *server;
+ int port;
- char *login;
- char *password;
+ char *login;
+ char *password;
- char *filter;
- char *basedn;
+ char *filter;
+ char *basedn;
int chase_referrals;
int rebind;
- int ldap_debug; /* Debug flag for LDAP SDK */
+ int ldap_debug; /* Debug flag for LDAP SDK */
+
const char *xlat_name; /* name used to xlat */
- const char *map_file;
int expect_password;
- TLDAP_RADIUS *check_map;
- TLDAP_RADIUS *reply_map;
- char **attrs;
+
+ /*
+ * RADIUS attribute to LDAP attribute maps
+ */
+ VALUE_PAIR_MAP *user_map; /* Applied to user object, and profiles */
int do_xlat;
/*
* Access related configuration
*/
- char *access_attr;
+ char *access_attr;
int positive_access_attr;
/*
* Profiles
*/
- char *base_filter;
- char *default_profile;
- char *profile_attr;
+ char *base_filter;
+ char *default_profile;
+ char *profile_attr;
/*
* Group checking.
* TLS items. We should really normalize these with the
* TLS code in 3.0.
*/
- int tls_mode;
+ int tls_mode;
int start_tls;
char *tls_cacertfile;
char *tls_cacertdir;
/*
* Options
*/
- int timelimit;
+ int timelimit;
int net_timeout;
int timeout;
int is_url;
{"filter", PW_TYPE_STRING_PTR,
offsetof(ldap_instance,filter), NULL, "(uid=%u)"},
- /* file with mapping between LDAP and RADIUS attributes */
- {"dictionary_mapping", PW_TYPE_FILENAME,
- offsetof(ldap_instance, map_file), NULL, NULL},
-
/* turn off the annoying warning if we don't expect a password */
{"expect_password", PW_TYPE_BOOLEAN,
offsetof(ldap_instance,expect_password), NULL, "yes"},
};
typedef struct ldap_conn {
- LDAP *ld;
+ LDAP *handle;
int rebound;
int referred;
ldap_instance *inst;
} LDAP_CONN;
+typedef struct xlat_attrs {
+ const VALUE_PAIR_MAP *maps;
+ const char *attrs[MAX_ATTRMAP];
+} xlat_attrs_t;
+
+typedef struct rlm_ldap_result {
+ char **values;
+ int count;
+} rlm_ldap_result_t;
+
#if LDAP_SET_REBIND_PROC_ARGS == 3
/*
* Rebind && chase referral stuff
*/
-static int ldap_rebind(LDAP *ld, LDAP_CONST char *url,
+static int ldap_rebind(LDAP *handle, LDAP_CONST char *url,
UNUSED ber_tag_t request, UNUSED ber_int_t msgid,
void *ctx )
{
conn->referred = TRUE;
conn->rebound = TRUE; /* not really, but oh well... */
- rad_assert(ld == conn->ld);
+ rad_assert(handle == conn->handle);
DEBUG(" [%s] rebind to URL %s", conn->inst->xlat_name, url);
- return ldap_bind_s(ld, conn->inst->login, conn->inst->password,
+ return ldap_bind_s(handle, conn->inst->login, conn->inst->password,
LDAP_AUTH_SIMPLE);
}
#endif
struct timeval tv;
redo:
- ldap_errno = ldap_bind(conn->ld, user, password, LDAP_AUTH_SIMPLE);
+ ldap_errno = ldap_bind(conn->handle, user, password, LDAP_AUTH_SIMPLE);
if (ldap_errno < 0) {
get_error:
- ldap_get_option(conn->ld, LDAP_OPT_ERROR_NUMBER, &ldap_errno);
+ ldap_get_option(conn->handle, LDAP_OPT_ERROR_NUMBER,
+ &ldap_errno);
error_string = ldap_err2string(ldap_errno);
if (do_rebind && !reconnect) {
tv.tv_sec = inst->timeout;
tv.tv_usec = 0;
- rcode = ldap_result(conn->ld, ldap_errno, 1, &tv, &result);
+ rcode = ldap_result(conn->handle, ldap_errno, 1, &tv, &result);
if (rcode < 0) goto get_error;
if (rcode == 0) {
goto print_error;
}
- ldap_errno = ldap_result2error(conn->ld, result, 1);
+ ldap_errno = ldap_result2error(conn->handle, result, 1);
switch (ldap_errno) {
case LDAP_SUCCESS:
break;
int ldap_errno, ldap_version;
struct timeval tv;
ldap_instance *inst = ctx;
- LDAP *ld = NULL;
+ LDAP *handle = NULL;
LDAP_CONN *conn = NULL;
const char *error;
if (inst->is_url) {
DEBUG(" [%s] Connect to %s", inst->xlat_name, inst->server);
- ldap_errno = ldap_initialize(&ld, inst->server);
+ ldap_errno = ldap_initialize(&handle, inst->server);
if (ldap_errno != LDAP_SUCCESS) {
radlog(L_ERR, " [%s] ldap_initialize() failed: %s",
DEBUG(" [%s] Connect to %s:%d", inst->xlat_name,
inst->server, inst->port);
- ld = ldap_init(inst->server, inst->port);
- if (!ld) {
+ handle = ldap_init(inst->server, inst->port);
+ if (!handle) {
radlog(L_ERR, " [%s] ldap_init() failed", inst->xlat_name);
conn_fail:
- if (ld) ldap_unbind_s(ld);
+ if (handle) ldap_unbind_s(handle);
return NULL;
}
}
* Set a bunch of LDAP options, using common code.
*/
-#define do_ldap_option(_option, _name, _value) if (ldap_set_option(ld, _option, _value) != LDAP_OPT_SUCCESS) { \
- ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &ldap_errno); \
+#define do_ldap_option(_option, _name, _value) if (ldap_set_option(handle, _option, _value) != LDAP_OPT_SUCCESS) { \
+ ldap_get_option(handle, LDAP_OPT_ERROR_NUMBER, &ldap_errno); \
radlog(L_ERR, " [%s] Could not set %s: %s", inst->xlat_name, _name, ldap_err2string(ldap_errno)); \
}
#if LDAP_SET_REBIND_PROC_ARGS == 3
if (inst->rebind == 1) {
- ldap_set_rebind_proc(ld, ldap_rebind, inst);
+ ldap_set_rebind_proc(handle, ldap_rebind, inst);
}
#endif
} else {
#ifdef HAVE_LDAP_INT_TLS_CONFIG
if (ldap_int_tls_config(NULL, LDAP_OPT_X_TLS_REQUIRE_CERT,
(inst->tls_require_cert)) != LDAP_OPT_SUCCESS) {
- ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &ldap_errno);
+ ldap_get_option(handle, LDAP_OPT_ERROR_NUMBER, &ldap_errno);
radlog(L_ERR, " [%s] could not set ",
"LDAP_OPT_X_TLS_REQUIRE_CERT option to %s: %s",
inst->xlat_name,
* And finally start the TLS code.
*/
if (inst->start_tls && (inst->port != 636)) {
- ldap_errno = ldap_start_tls_s(ld, NULL, NULL);
+ ldap_errno = ldap_start_tls_s(handle, NULL, NULL);
if (ldap_errno != LDAP_SUCCESS) {
- ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER,
+ ldap_get_option(handle, LDAP_OPT_ERROR_NUMBER,
&ldap_errno);
radlog(L_ERR, " [%s] could not start TLS: %s",
inst->xlat_name,
conn = rad_malloc(sizeof(*conn));
conn->inst = inst;
- conn->ld = ld;
+ conn->handle = handle;
conn->rebound = FALSE;
conn->referred = FALSE;
{
LDAP_CONN *conn = connection;
- ldap_unbind_s(conn->ld);
+ ldap_unbind_s(conn->handle);
free(conn);
return 0;
*
*************************************************************************/
static int perform_search(ldap_instance *inst, LDAP_CONN **pconn,
- char *search_basedn, int scope, char *filter,
- char **attrs, LDAPMessage **presult)
+ const char *search_basedn, int scope,
+ const char *filter, const char *attrs[],
+ LDAPMessage **presult)
{
int ldap_errno;
int reconnect = FALSE;
LDAP_CONN *conn = *pconn;
struct timeval tv;
+ /*
+ * OpenLDAP library doesn't declare attrs array as const, but
+ * it really should be *sigh*.
+ */
+ char **search_attrs;
+ memcpy(&search_attrs, &attrs, sizeof(attrs));
+
*presult = NULL;
/*
search_basedn ? search_basedn : "(null)" , filter);
retry:
- ldap_errno = ldap_search_st(conn->ld, search_basedn, scope, filter,
- attrs, 0, &tv, presult);
+ ldap_errno = ldap_search_ext_s(conn->handle, search_basedn, scope,
+ filter, search_attrs, 0, NULL, NULL,
+ &tv, 0, presult);
switch (ldap_errno) {
case LDAP_SUCCESS:
case LDAP_NO_SUCH_OBJECT:
* Reconnect. There's an issue with the socket
* or LDAP server.
*/
- ldap_get_option(conn->ld, LDAP_OPT_ERROR_NUMBER, &ldap_errno);
- radlog(L_ERR, " [%s] ldap_search() failed: %s", inst->xlat_name,
- ldap_err2string(ldap_errno));
+ ldap_get_option(conn->handle, LDAP_OPT_ERROR_NUMBER,
+ &ldap_errno);
+ radlog(L_ERR, " [%s] ldap_search() failed: %s",
+ inst->xlat_name, ldap_err2string(ldap_errno));
goto do_reconnect;
default:
- ldap_get_option(conn->ld, LDAP_OPT_ERROR_NUMBER, &ldap_errno);
- radlog(L_ERR, " [%s] ldap_search() failed: %s", inst->xlat_name,
- ldap_err2string(ldap_errno));
+ ldap_get_option(conn->handle, LDAP_OPT_ERROR_NUMBER,
+ &ldap_errno);
+ radlog(L_ERR, " [%s] ldap_search() failed: %s",
+ inst->xlat_name, ldap_err2string(ldap_errno));
ldap_msgfree(*presult);
return -1;
}
- ldap_errno = ldap_count_entries(conn->ld, *presult);
+ ldap_errno = ldap_count_entries(conn->handle, *presult);
if (ldap_errno == 0) {
ldap_msgfree(*presult);
DEBUG(" [%s] object not found", inst->xlat_name);
if (ldap_errno != 1) {
ldap_msgfree(*presult);
- DEBUG(" [%s] got ambiguous search result (%d results)", inst->xlat_name, ldap_errno);
+ DEBUG(" [%s] got ambiguous search result (%d results)",
+ inst->xlat_name, ldap_errno);
return -2;
}
ldap_instance *inst = instance;
LDAPURLDesc *ldap_url;
LDAPMessage *result = NULL;
- LDAPMessage *msg = NULL;
+ LDAPMessage *entry = NULL;
char **vals;
LDAP_CONN *conn;
const char *url;
+ const char **attrs;
char buffer[MAX_FILTER_STR_LEN];
if (strchr(fmt, '%') != NULL) {
conn = ldap_get_socket(inst);
if (!conn) goto free_urldesc;
+ memcpy(&attrs, &ldap_url->lud_attrs, sizeof(attrs));
+
rcode = perform_search(inst, &conn, ldap_url->lud_dn, ldap_url->lud_scope,
- ldap_url->lud_filter, ldap_url->lud_attrs, &result);
+ ldap_url->lud_filter, attrs, &result);
if (rcode < 0) {
if (rcode == -2) {
DEBUG(" [%s] Search returned not found", inst->xlat_name);
goto free_socket;
}
- msg = ldap_first_entry(conn->ld, result);
- if (!msg) {
+ entry = ldap_first_entry(conn->handle, result);
+ if (!entry) {
DEBUG(" [%s] ldap_first_entry() failed", inst->xlat_name);
goto free_result;
}
- vals = ldap_get_values(conn->ld, msg, ldap_url->lud_attrs[0]);
+ vals = ldap_get_values(conn->handle, entry, ldap_url->lud_attrs[0]);
if (!vals) {
DEBUG(" [%s] ldap_get_values failed", inst->xlat_name);
goto free_result;
{
int rcode;
VALUE_PAIR *vp;
- ldap_instance *inst = (*pconn)->inst;
- LDAPMessage *result, *msg;
+ ldap_instance *inst = (*pconn)->inst;
+ LDAPMessage *result, *entry;
static char firstattr[] = "uid";
- char *user_dn, *attrs[] = {firstattr, NULL};
+ char *user_dn;
+ const char *attrs[] = {firstattr, NULL};
char filter[MAX_FILTER_STR_LEN];
char basedn[MAX_FILTER_STR_LEN];
return NULL;
}
- if ((msg = ldap_first_entry((*pconn)->ld, result)) == NULL) {
+ if ((entry = ldap_first_entry((*pconn)->handle, result)) == NULL) {
ldap_msgfree(result);
return NULL;
}
- if ((user_dn = ldap_get_dn((*pconn)->ld, msg)) == NULL) {
+ if ((user_dn = ldap_get_dn((*pconn)->handle, entry)) == NULL) {
ldap_msgfree(result);
return NULL;
}
ldap_instance *inst = instance;
int i, rcode, found;
LDAPMessage *result = NULL;
- LDAPMessage *msg = NULL;
+ LDAPMessage *entry = NULL;
static char firstattr[] = "dn";
- char *attrs[] = {firstattr,NULL};
+ const char *attrs[] = {firstattr, NULL};
char **vals;
- char *group_attrs[] = {inst->groupmemb_attr,NULL};
+ const char *group_attrs[] = {inst->groupmemb_attr, NULL};
LDAP_CONN *conn;
char *user_dn;
int module_rcode;
- char gr_filter[MAX_FILTER_STR_LEN];
- char filter[MAX_FILTER_STR_LEN];
- char basedn[MAX_FILTER_STR_LEN];
+ char gr_filter[MAX_FILTER_STR_LEN];
+ char filter[MAX_FILTER_STR_LEN];
+ char basedn[MAX_FILTER_STR_LEN];
if (check->length == 0) {
RDEBUG("Cannot do comparison: group name is empty");
return 1;
}
- msg = ldap_first_entry(conn->ld, result);
- if (!msg) {
+ entry = ldap_first_entry(conn->handle, result);
+ if (!entry) {
RDEBUG("First entry failed for group attrs");
ldap_release_socket(inst, conn);
ldap_msgfree(result);
return 1;
}
- vals = ldap_get_values(conn->ld, msg, inst->groupmemb_attr);
+ vals = ldap_get_values(conn->handle, entry, inst->groupmemb_attr);
if (!vals) {
RDEBUG("Get values failed for group attrs");
ldap_release_socket(inst, conn);
return 0;
}
+/*
+ * Verify that the ldap update section makes sense, and add attribute names
+ * to array of attributes for efficient querying later.
+ */
+static VALUE_PAIR_MAP *build_attrmap(CONF_SECTION *cs)
+{
+ const char *cs_list, *p;
+
+ request_refs_t request_def = REQUEST_CURRENT;
+ pair_lists_t list_def = PAIR_LIST_REQUEST;
+
+ CONF_ITEM *ci = cf_sectiontoitem(cs);
+ CONF_PAIR *cp;
+
+ unsigned int total = 0;
+ VALUE_PAIR_MAP **tail, *map, *head;
+ head = NULL;
+ tail = &head;
+
+ if (!cs) return NULL;
+
+ cs_list = p = cf_section_name2(cs);
+ if (cs_list) {
+ request_def = radius_request_name(&p, REQUEST_UNKNOWN);
+ if (request_def == REQUEST_UNKNOWN) {
+ cf_log_err(ci, "rlm_ldap: Default request specified "
+ "in mapping section is invalid");
+ return NULL;
+ }
+
+ list_def = fr_str2int(pair_lists, p, PAIR_LIST_UNKNOWN);
+ if (list_def == PAIR_LIST_UNKNOWN) {
+ cf_log_err(ci, "rlm_ldap: Default list specified "
+ "in mapping section is invalid");
+ return NULL;
+ }
+ }
+
+ for (ci = cf_item_find_next(cs, NULL);
+ ci != NULL;
+ ci = cf_item_find_next(cs, ci)) {
+ if (total++ == MAX_ATTRMAP) {
+ cf_log_err(ci, "rlm_ldap: Attribute map size exceeded");
+ goto error;
+ }
+
+ if (!cf_item_is_pair(ci)) {
+ cf_log_err(ci, "rlm_ldap: Entry is not in \"attribute ="
+ " ldap-attribute\" format");
+ goto error;
+ }
+
+ cp = cf_itemtopair(ci);
+ map = radius_cp2map(cp, REQUEST_CURRENT, list_def);
+ if (!map) {
+ goto error;
+ }
+
+ *tail = map;
+ tail = &(map->next);
+ }
+
+ return head;
+
+ error:
+ radius_mapfree(&head);
+ return NULL;
+}
/*****************************************************************************
*
ldap_instance *inst = instance;
fr_connection_pool_delete(inst->pool);
-
- if (inst->map_file) {
- rlm_ldap_map_free(&inst->check_map);
- rlm_ldap_map_free(&inst->reply_map);
- free(inst->attrs);
+
+ if (inst->user_map) {
+ radius_mapfree(&inst->user_map);
}
free(inst);
static int ldap_instantiate(CONF_SECTION * conf, void **instance)
{
ldap_instance *inst;
+ CONF_SECTION *cs;
inst = rad_malloc(sizeof *inst);
if (!inst) {
inst->is_url = 1;
inst->port = 0;
#else
- radlog(L_ERR, "rlm_ldap: 'server' directive is in URL form but ldap_initialize() is not available.");
+ radlog(L_ERR, "rlm_ldap: 'server' directive is in URL form but "
+ "ldap_initialize() is not available.");
ldap_detach(inst);
return -1;
#endif
* variable for the username, password, etc.
*/
if (inst->rebind == 1) {
- radlog(L_ERR, "%s: Cannot use 'rebind' directive as this version of libldap does not support the API that we need.", inst->xlat-name);
+ radlog(L_ERR, "%s: Cannot use 'rebind' directive as this "
+ "version of libldap does not support the API that "
+ "we need.", inst->xlat-name);
ldap_detach(inst);
return -1;
}
#endif
- if (inst->map_file) {
- int offset = 0;
-
- inst->attrs = rad_malloc(sizeof(inst->attrs[0]) * MAX_ATTRMAP);
- inst->attrs[0] = NULL;
-
- if (inst->profile_attr) inst->attrs[offset++] = inst->profile_attr;
- if (inst->access_attr) inst->attrs[offset++] = inst->access_attr;
-
- if (rlm_ldap_map_read(inst->xlat_name, inst->map_file,
- &inst->check_map, &inst->reply_map,
- offset,
- inst->attrs) < 0) {
- ldap_detach(inst);
- return -1;
- }
-
- if (!inst->check_map || !inst->reply_map) {
- radlog(L_ERR, "%s: Empty file: %s",
- inst->xlat_name, inst->map_file);
- ldap_detach(inst);
- return -1;
- }
-
- } else {
- if (inst->default_profile || inst->profile_attr) {
- radlog(L_ERR, "%s: You MUST specify \"dictionary_mapping\" to use the profile attributes", inst->xlat_name);
+ /*
+ * Build the attribute map
+ */
+ cs = cf_section_sub_find(conf, "update");
+ if (cs) {
+ inst->user_map = build_attrmap(cs);
+ if (!inst->user_map) {
ldap_detach(inst);
return -1;
}
}
-static int check_access(ldap_instance *inst, LDAP_CONN *conn, LDAPMessage *msg)
+static int check_access(ldap_instance *inst, LDAP_CONN *conn, LDAPMessage *entry)
{
int rcode = -1;
char **vals = NULL;
- vals = ldap_get_values(conn->ld, msg, inst->access_attr);
+ vals = ldap_get_values(conn->handle, entry, inst->access_attr);
if (vals) {
if (inst->positive_access_attr) {
if (strncmp(vals[0], "FALSE", 5) == 0) {
}
-static void apply_profile(ldap_instance *inst, LDAP_CONN **pconn,
- REQUEST *request, char *profile)
+static VALUE_PAIR *ldap_getvalue(REQUEST *request, VALUE_PAIR_TMPL *dst,
+ void *ctx)
{
- int rcode;
- LDAPMessage *result, *msg;
- VALUE_PAIR *check_tmp, *reply_tmp;
- char filter[MAX_FILTER_STR_LEN];
+ rlm_ldap_result_t *self = ctx;
+ VALUE_PAIR *head, **tail, *vp;
+ int i;
+
+ request = request;
+
+ head = NULL;
+ tail = &head;
+
+ /*
+ * Iterate over all the retrieved values,
+ * don't try and be clever about changing operators
+ * just use whatever was set in the attribute map.
+ */
+ for (i = 0; i < self->count; i++) {
+ vp = pairalloc(dst->da);
+ rad_assert(vp);
- if (!profile || !*profile) return;
+ pairparsevalue(vp, self->values[i]);
+
+ *tail = vp;
+ tail = &(vp->next);
+ }
+
+ return head;
+}
- strlcpy(filter,inst->base_filter,sizeof(filter));
- rcode = perform_search(inst, pconn, profile, LDAP_SCOPE_BASE, filter,
- inst->attrs, &result);
- if (rcode < 0) {
- RDEBUG("FAILED Searching profile %s", profile);
- return;
+static void xlat_attrsfree(const xlat_attrs_t *expanded)
+{
+ const VALUE_PAIR_MAP *map;
+ unsigned int total = 0;
+
+ char *name;
+
+ for (map = expanded->maps; map != NULL; map = map->next)
+ {
+ memcpy(&name, &(expanded->attrs[total++]), sizeof(name));
+
+ if (!name) return;
+
+ if (map->src.do_xlat) {
+ free(name);
+ }
}
+}
- msg = ldap_first_entry((*pconn)->ld, result);
- if (!msg) goto free_result;
- check_tmp = rlm_ldap_pairget(inst->xlat_name, (*pconn)->ld, msg,
- inst->check_map, &request->config_items, 1);
- if (check_tmp) {
- pairfree(&check_tmp);
- }
+static int xlat_attrs(REQUEST *request, const VALUE_PAIR_MAP *maps,
+ xlat_attrs_t *expanded)
+{
+ const VALUE_PAIR_MAP *map;
+ unsigned int total = 0;
+
+ size_t len;
+ char *buffer;
- reply_tmp = rlm_ldap_pairget(inst->xlat_name, (*pconn)->ld, msg,
- inst->reply_map, &request->packet->vps, 0);
- if (reply_tmp) {
- pairfree(&reply_tmp);
+ for (map = maps; map != NULL; map = map->next)
+ {
+ if (map->src.do_xlat) {
+ buffer = rad_malloc(MAX_ATTR_STR_LEN);
+ len = radius_xlat(buffer, MAX_ATTR_STR_LEN,
+ map->src.name, request, NULL, NULL);
+
+ if (!len) {
+ DEBUG2("WARNING: Expansion of LDAP attribute "
+ "\"%s\" failed", map->src.name);
+
+ expanded->attrs[total] = NULL;
+
+ xlat_attrsfree(expanded);
+
+ return -1;
+ }
+
+ expanded->attrs[total++] = buffer;
+ } else {
+ expanded->attrs[total++] = map->src.name;
+ }
}
-
-free_result:
- ldap_msgfree(result);
+
+ expanded->attrs[total] = NULL;
+ expanded->maps = maps;
+
+ return 0;
}
-static void do_one_map(ldap_instance *inst, LDAP *ld, REQUEST *request,
- LDAPMessage *msg, TLDAP_RADIUS *map, VALUE_PAIR **vps,
- int is_check)
+/** Convert attribute map into valuepairs
+ *
+ * Use the attribute map built earlier to convert LDAP values into valuepairs
+ * and insert them into whichever list they need to go into.
+ *
+ * This is *NOT* atomic, but there's no condition in which we should error
+ * out...
+ */
+static void do_attrmap(UNUSED ldap_instance *inst, REQUEST *request,
+ LDAP *handle, const xlat_attrs_t *expanded,
+ LDAPMessage *entry)
{
- VALUE_PAIR *vp;
+ const VALUE_PAIR_MAP *map;
+ unsigned int total = 0;
+
+ rlm_ldap_result_t result;
- vp = rlm_ldap_pairget(inst->xlat_name, ld, msg, map, vps, is_check);
- if (vp) {
- if (inst->do_xlat) {
- pairxlatmove(request, vps, &vp);
- pairfree(&vp);
+ REQUEST *update_request;
+ const char *name;
- } else {
- pairadd(vps, vp);
+ for (map = expanded->maps; map != NULL; map = map->next)
+ {
+ update_request = request;
+
+ name = expanded->attrs[total++];
+
+ result.values = ldap_get_values(handle, entry, name);
+ if (!result.values) {
+ DEBUG2("WARNING: Attribute \"%s\" not found in LDAP "
+ "object", name);
+
+ goto next;
}
+
+ /*
+ * Find out how many values there are for the
+ * attribute and extract all of them.
+ */
+ result.count = ldap_count_values(result.values);
+
+ /*
+ * If something bad happened, just skip, this is probably
+ * a case of the dst being incorrect for the current
+ * request context
+ */
+ if (radius_map2request(request, map, name, ldap_getvalue,
+ &result) < 0) {
+ goto next;
+ }
+
+ next:
+
+ ldap_value_free(result.values);
}
-
}
-static void do_check_reply(ldap_instance *inst, LDAP *ld, REQUEST *request,
- LDAPMessage *msg)
-{
- do_one_map(inst, ld, request, msg, inst->check_map, &request->config_items, 1);
- do_one_map(inst, ld, request, msg, inst->reply_map, &request->reply->vps, 0);
+static void do_check_reply(ldap_instance *inst, REQUEST *request)
+{
/*
* More warning messages for people who can't be bothered
* to read the documentation.
}
}
+
+static void apply_profile(ldap_instance *inst, REQUEST *request,
+ LDAP_CONN **pconn, const char *profile,
+ const xlat_attrs_t *expanded)
+{
+ int rcode;
+ LDAPMessage *result, *entry;
+ char filter[MAX_FILTER_STR_LEN];
+
+ if (!profile || !*profile) return;
+
+ strlcpy(filter, inst->base_filter, sizeof(filter));
+
+ rcode = perform_search(inst, pconn, profile, LDAP_SCOPE_BASE,
+ filter, expanded->attrs, &result);
+
+ if (rcode < 0) {
+ RDEBUG("FAILED Searching profile %s", profile);
+ goto free_result;
+ }
+
+ entry = ldap_first_entry((*pconn)->handle, result);
+ if (!entry) goto free_result;
+
+ do_attrmap(inst, request, (*pconn)->handle, expanded, entry);
+
+free_result:
+ ldap_msgfree(result);
+}
+
+
/******************************************************************************
*
* Function: ldap_authorize
char **vals;
VALUE_PAIR *vp;
LDAP_CONN *conn;
- LDAPMessage *result, *msg;
+ LDAPMessage *result, *entry;
char filter[MAX_FILTER_STR_LEN];
char basedn[MAX_FILTER_STR_LEN];
-
+ xlat_attrs_t expanded; /* faster that mallocing every time */
+
if (!request->username) {
RDEBUG2("attribute \"User-Name\" is required for authorization.\n");
return RLM_MODULE_NOOP;
conn = ldap_get_socket(inst);
if (!conn) return RLM_MODULE_FAIL;
-
+
+ if (xlat_attrs(request, inst->user_map, &expanded) < 0) {
+ return RLM_MODULE_FAIL;
+ }
+
rcode = perform_search(inst, &conn, basedn, LDAP_SCOPE_SUBTREE, filter,
- inst->attrs, &result);
+ expanded.attrs, &result);
+
if (rcode < 0) {
if (rcode == -2) {
module_failure_msg(&request->packet->vps,
goto free_socket;
}
- msg = ldap_first_entry(conn->ld, result);
- if (!msg) {
+ entry = ldap_first_entry(conn->handle, result);
+ if (!entry) {
RDEBUG2("ldap_first_entry() failed");
goto free_result;
}
- user_dn = ldap_get_dn(conn->ld, msg);
+ user_dn = ldap_get_dn(conn->handle, entry);
if (!user_dn) {
RDEBUG2("ldap_get_dn() failed");
goto free_result;
* Check for access.
*/
if (inst->access_attr) {
- if (check_access(inst, conn, msg) < 0) {
+ if (check_access(inst, conn, entry) < 0) {
module_rcode = RLM_MODULE_USERLOCK;
goto free_result;
}
if (vp) profile = vp->vp_strvalue;
- apply_profile(inst, &conn, request, profile);
+ apply_profile(inst, request, &conn, profile, &expanded);
}
/*
* Apply a SET of user profiles.
*/
if (inst->profile_attr &&
- (vals = ldap_get_values(conn->ld, msg, inst->profile_attr)) != NULL) {
+ (vals = ldap_get_values(conn->handle, entry, inst->profile_attr)) != NULL) {
int i;
for (i = 0; (vals[i] != NULL) && (*vals[i] != '\0'); i++) {
- apply_profile(inst, &conn, request, vals[i]);
+ apply_profile(inst, request, &conn, vals[i], &expanded);
}
ldap_value_free(vals);
}
- if (inst->map_file) {
- do_check_reply(inst, conn->ld, request, msg);
+ if (inst->user_map) {
+ do_attrmap(inst, request, conn->handle, &expanded, entry);
+ do_check_reply(inst, request);
}
free_result:
+ xlat_attrsfree(&expanded);
ldap_msgfree(result);
free_socket:
ldap_release_socket(inst, conn);