2 * rlm_ldap.c LDAP authorization and authentication module.
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
18 * Copyright 1999,2000,2001,2002,2003,2004,2005,2006,2007,2008,
19 * 2009,2010,2011,1012 The FreeRADIUS Server Project.
21 * Copyright 2012 Alan DeKok <aland@freeradius.org>
24 #include <freeradius-devel/ident.h>
27 #include <freeradius-devel/radiusd.h>
28 #include <freeradius-devel/modules.h>
29 #include <freeradius-devel/rad_assert.h>
37 #define MAX_ATTRMAP 128
38 #define MAX_ATTR_STR_LEN 256
39 #define MAX_FILTER_STR_LEN 1024
43 fr_connection_pool_t *pool;
57 int ldap_debug; /* Debug flag for LDAP SDK */
59 const char *xlat_name; /* name used to xlat */
64 * RADIUS attribute to LDAP attribute maps
66 VALUE_PAIR_MAP *user_map; /* Applied to user object, and profiles */
71 * Access related configuration
74 int positive_access_attr;
80 char *default_profile;
91 * TLS items. We should really normalize these with the
101 char *tls_require_cert;
114 #ifdef LDAP_OPT_X_KEEPALIVE_IDLE
117 #ifdef LDAP_OPT_X_KEEPALIVE_PROBES
118 int keepalive_probes;
120 #ifdef LDAP_OPT_ERROR_NUMBER
121 int keepalive_interval;
126 /* The default setting for TLS Certificate Verification */
127 #define TLS_DEFAULT_VERIFY "allow"
132 static CONF_PARSER tls_config[] = {
133 {"start_tls", PW_TYPE_BOOLEAN,
134 offsetof(ldap_instance,start_tls), NULL, "no"},
135 {"cacertfile", PW_TYPE_FILENAME,
136 offsetof(ldap_instance,tls_cacertfile), NULL, NULL},
137 {"cacertdir", PW_TYPE_FILENAME,
138 offsetof(ldap_instance,tls_cacertdir), NULL, NULL},
139 {"certfile", PW_TYPE_FILENAME,
140 offsetof(ldap_instance,tls_certfile), NULL, NULL},
141 {"keyfile", PW_TYPE_FILENAME,
142 offsetof(ldap_instance,tls_keyfile), NULL, NULL},
143 {"randfile", PW_TYPE_STRING_PTR, /* OK if it changes on HUP */
144 offsetof(ldap_instance,tls_randfile), NULL, NULL},
145 {"require_cert", PW_TYPE_STRING_PTR,
146 offsetof(ldap_instance,tls_require_cert), NULL, TLS_DEFAULT_VERIFY},
147 { NULL, -1, 0, NULL, NULL }
151 static CONF_PARSER attr_config[] = {
155 /* LDAP attribute name that controls remote access */
156 {"access_attr", PW_TYPE_STRING_PTR,
157 offsetof(ldap_instance,access_attr), NULL, NULL},
158 {"positive_access_attr", PW_TYPE_BOOLEAN,
159 offsetof(ldap_instance,positive_access_attr), NULL, "yes"},
161 {"base_filter", PW_TYPE_STRING_PTR,
162 offsetof(ldap_instance,base_filter), NULL, "(objectclass=radiusprofile)"},
163 {"default_profile", PW_TYPE_STRING_PTR,
164 offsetof(ldap_instance,default_profile), NULL, NULL},
165 {"profile_attribute", PW_TYPE_STRING_PTR,
166 offsetof(ldap_instance,profile_attr), NULL, NULL},
168 { NULL, -1, 0, NULL, NULL }
173 * Group configuration
175 static CONF_PARSER group_config[] = {
177 * Group checks. These could probably be done
178 * via dynamic xlat's.
180 {"name_attribute", PW_TYPE_STRING_PTR,
181 offsetof(ldap_instance,groupname_attr), NULL, "cn"},
182 {"membership_filter", PW_TYPE_STRING_PTR,
183 offsetof(ldap_instance,groupmemb_filt), NULL, "(|(&(objectClass=GroupOfNames)(member=%{Ldap-UserDn}))(&(objectClass=GroupOfUniqueNames)(uniquemember=%{Ldap-UserDn})))"},
184 {"membership_attribute", PW_TYPE_STRING_PTR,
185 offsetof(ldap_instance,groupmemb_attr), NULL, NULL},
188 { NULL, -1, 0, NULL, NULL }
192 * Various options that don't belong in the main configuration.
194 * Note that these overlap a bit with the connection pool code!
196 static CONF_PARSER option_config[] = {
198 * Debugging flags to the server
200 {"ldap_debug", PW_TYPE_INTEGER,
201 offsetof(ldap_instance,ldap_debug), NULL, "0x0000"},
203 {"chase_referrals", PW_TYPE_BOOLEAN,
204 offsetof(ldap_instance,chase_referrals), NULL, NULL},
206 {"rebind", PW_TYPE_BOOLEAN,
207 offsetof(ldap_instance,rebind), NULL, NULL},
209 /* timeout on network activity */
210 {"net_timeout", PW_TYPE_INTEGER,
211 offsetof(ldap_instance,net_timeout), NULL, "10"},
213 /* timeout for search results */
214 {"timeout", PW_TYPE_INTEGER,
215 offsetof(ldap_instance,timeout), NULL, "20"},
217 /* allow server unlimited time for search (server-side limit) */
218 {"timelimit", PW_TYPE_INTEGER,
219 offsetof(ldap_instance,timelimit), NULL, "20"},
221 #ifdef LDAP_OPT_X_KEEPALIVE_IDLE
222 {"idle", PW_TYPE_INTEGER, offsetof(ldap_instance,keepalive_idle), NULL, "60"},
224 #ifdef LDAP_OPT_X_KEEPALIVE_PROBES
225 {"probes", PW_TYPE_INTEGER, offsetof(ldap_instance,keepalive_probes), NULL, "3"},
227 #ifdef LDAP_OPT_ERROR_NUMBER
228 {"interval", PW_TYPE_INTEGER, offsetof(ldap_instance,keepalive_interval), NULL, "30"},
230 { NULL, -1, 0, NULL, NULL }
234 static const CONF_PARSER module_config[] = {
235 {"server", PW_TYPE_STRING_PTR,
236 offsetof(ldap_instance,server), NULL, "localhost"},
237 {"port", PW_TYPE_INTEGER,
238 offsetof(ldap_instance,port), NULL, "389"},
240 {"password", PW_TYPE_STRING_PTR,
241 offsetof(ldap_instance,password), NULL, ""},
242 {"identity", PW_TYPE_STRING_PTR,
243 offsetof(ldap_instance,login), NULL, ""},
248 {"basedn", PW_TYPE_STRING_PTR,
249 offsetof(ldap_instance,basedn), NULL, "o=notexist"},
251 {"filter", PW_TYPE_STRING_PTR,
252 offsetof(ldap_instance,filter), NULL, "(uid=%u)"},
254 /* turn off the annoying warning if we don't expect a password */
255 {"expect_password", PW_TYPE_BOOLEAN,
256 offsetof(ldap_instance,expect_password), NULL, "yes"},
259 * Terrible things which should be deleted.
261 {"do_xlat", PW_TYPE_BOOLEAN,
262 offsetof(ldap_instance,do_xlat), NULL, "yes"},
264 { "profiles", PW_TYPE_SUBSECTION, 0, NULL, (const void *) attr_config },
266 { "group", PW_TYPE_SUBSECTION, 0, NULL, (const void *) group_config },
268 { "options", PW_TYPE_SUBSECTION, 0, NULL, (const void *) option_config },
270 { "tls", PW_TYPE_SUBSECTION, 0, NULL, (const void *) tls_config },
272 { "profiles", PW_TYPE_SUBSECTION, 0, NULL, (const void *) attr_config },
274 {NULL, -1, 0, NULL, NULL}
277 typedef struct ldap_conn {
284 typedef struct xlat_attrs {
285 const VALUE_PAIR_MAP *maps;
286 const char *attrs[MAX_ATTRMAP];
289 typedef struct rlm_ldap_result {
295 #if LDAP_SET_REBIND_PROC_ARGS == 3
297 * Rebind && chase referral stuff
299 static int ldap_rebind(LDAP *handle, LDAP_CONST char *url,
300 UNUSED ber_tag_t request, UNUSED ber_int_t msgid,
303 LDAP_CONN *conn = ctx;
305 conn->referred = TRUE;
306 conn->rebound = TRUE; /* not really, but oh well... */
307 rad_assert(handle == conn->handle);
309 DEBUG(" [%s] rebind to URL %s", conn->inst->xlat_name, url);
310 return ldap_bind_s(handle, conn->inst->login, conn->inst->password,
315 static int ldap_bind_wrapper(LDAP_CONN **pconn, const char *user,
316 const char *password,
317 const char **perror_str, int do_rebind)
319 int rcode, ldap_errno;
320 int module_rcode = RLM_MODULE_FAIL;
321 int reconnect = FALSE;
322 const char *error_string;
323 LDAP_CONN *conn = *pconn;
324 ldap_instance *inst = conn->inst;
325 LDAPMessage *result = NULL;
329 ldap_errno = ldap_bind(conn->handle, user, password, LDAP_AUTH_SIMPLE);
330 if (ldap_errno < 0) {
332 ldap_get_option(conn->handle, LDAP_OPT_ERROR_NUMBER,
334 error_string = ldap_err2string(ldap_errno);
336 if (do_rebind && !reconnect) {
337 conn = fr_connection_reconnect(inst->pool, conn);
339 if (!conn) return RLM_MODULE_FAIL;
344 if (perror_str) *perror_str = error_string;
346 #ifdef HAVE_LDAP_INITIALIZE
348 radlog(L_ERR, " [%s] %s bind to %s failed: %s",
349 inst->xlat_name, user,
350 inst->server, error_string);
354 radlog(L_ERR, " [%s] %s bind to %s:%d failed: %s",
355 inst->xlat_name, user,
356 inst->server, inst->port,
360 return module_rcode; /* caller closes the connection */
363 DEBUG3(" [%s] waiting for bind result ...", inst->xlat_name);
365 tv.tv_sec = inst->timeout;
367 rcode = ldap_result(conn->handle, ldap_errno, 1, &tv, &result);
368 if (rcode < 0) goto get_error;
371 error_string = "timeout";
375 ldap_errno = ldap_result2error(conn->handle, result, 1);
376 switch (ldap_errno) {
380 case LDAP_INVALID_CREDENTIALS:
381 case LDAP_CONSTRAINT_VIOLATION:
382 rcode = RLM_MODULE_REJECT;
389 return RLM_MODULE_OK;
392 /*************************************************************************
394 * Function: ldap_conn_create
396 * Purpose: Create and return a new connection
397 * This function is probably too big.
399 *************************************************************************/
400 static void *ldap_conn_create(void *ctx)
403 int ldap_errno, ldap_version;
405 ldap_instance *inst = ctx;
407 LDAP_CONN *conn = NULL;
410 #ifdef HAVE_LDAP_INITIALIZE
412 DEBUG(" [%s] Connect to %s", inst->xlat_name, inst->server);
414 ldap_errno = ldap_initialize(&handle, inst->server);
416 if (ldap_errno != LDAP_SUCCESS) {
417 radlog(L_ERR, " [%s] ldap_initialize() failed: %s",
418 inst->xlat_name, ldap_err2string(ldap_errno));
424 DEBUG(" [%s] Connect to %s:%d", inst->xlat_name,
425 inst->server, inst->port);
427 handle = ldap_init(inst->server, inst->port);
429 radlog(L_ERR, " [%s] ldap_init() failed", inst->xlat_name);
431 if (handle) ldap_unbind_s(handle);
437 * We now have a connection structure, but no actual TCP connection.
439 * Set a bunch of LDAP options, using common code.
442 #define do_ldap_option(_option, _name, _value) if (ldap_set_option(handle, _option, _value) != LDAP_OPT_SUCCESS) { \
443 ldap_get_option(handle, LDAP_OPT_ERROR_NUMBER, &ldap_errno); \
444 radlog(L_ERR, " [%s] Could not set %s: %s", inst->xlat_name, _name, ldap_err2string(ldap_errno)); \
447 if (inst->ldap_debug) {
448 do_ldap_option(LDAP_OPT_DEBUG_LEVEL, "ldap_debug", &(inst->ldap_debug));
452 * Leave "chase_referrals" unset to use the OpenLDAP
455 if (inst->chase_referrals != 2) {
456 if (inst->chase_referrals) {
457 do_ldap_option(LDAP_OPT_REFERRALS, "chase_referrals", LDAP_OPT_ON);
459 #if LDAP_SET_REBIND_PROC_ARGS == 3
460 if (inst->rebind == 1) {
461 ldap_set_rebind_proc(handle, ldap_rebind, inst);
465 do_ldap_option(LDAP_OPT_REFERRALS, "chase_referrals", LDAP_OPT_OFF);
469 tv.tv_sec = inst->net_timeout;
471 do_ldap_option(LDAP_OPT_NETWORK_TIMEOUT, "net_timeout", &tv);
473 do_ldap_option(LDAP_OPT_TIMELIMIT, "timelimit", &(inst->timelimit));
475 ldap_version = LDAP_VERSION3;
476 do_ldap_option(LDAP_OPT_PROTOCOL_VERSION, "ldap_version", &ldap_version);
478 #ifdef LDAP_OPT_X_KEEPALIVE_IDLE
479 do_ldap_option(LDAP_OPT_X_KEEPALIVE_IDLE, "keepalive idle", &(inst->keepalive_idle));
482 #ifdef LDAP_OPT_X_KEEPALIVE_PROBES
483 do_ldap_option(LDAP_OPT_X_KEEPALIVE_PROBES, "keepalive probes", &(inst->keepalive_probes));
486 #ifdef LDAP_OPT_X_KEEPALIVE_INTERVAL
487 do_ldap_option(LDAP_OPT_X_KEEPALIVE_INTERVAL, "keepalive interval", &(inst->keepalive_interval));
490 #ifdef HAVE_LDAP_START_TLS
492 * Set all of the TLS options
494 if (inst->tls_mode) {
495 do_ldap_option(LDAP_OPT_X_TLS, "tls_mode", &(inst->tls_mode));
498 #define maybe_ldap_option(_option, _name, _value) if (_value) do_ldap_option(_option, _name, _value)
500 maybe_ldap_option(LDAP_OPT_X_TLS_CACERTFILE,
501 "cacertfile", inst->tls_cacertfile);
502 maybe_ldap_option(LDAP_OPT_X_TLS_CACERTDIR,
503 "cacertdir", inst->tls_cacertdir);
505 #ifdef HAVE_LDAP_INT_TLS_CONFIG
506 if (ldap_int_tls_config(NULL, LDAP_OPT_X_TLS_REQUIRE_CERT,
507 (inst->tls_require_cert)) != LDAP_OPT_SUCCESS) {
508 ldap_get_option(handle, LDAP_OPT_ERROR_NUMBER, &ldap_errno);
509 radlog(L_ERR, " [%s] could not set ",
510 "LDAP_OPT_X_TLS_REQUIRE_CERT option to %s: %s",
512 inst->tls_require_cert,
513 ldap_err2string(ldap_errno));
517 maybe_ldap_option(LDAP_OPT_X_TLS_CERTFILE,
518 "certfile", inst->tls_certfile);
519 maybe_ldap_option(LDAP_OPT_X_TLS_KEYFILE,
520 "keyfile", inst->tls_keyfile);
521 maybe_ldap_option(LDAP_OPT_X_TLS_RANDOM_FILE,
522 "randfile", inst->tls_randfile);
525 * And finally start the TLS code.
527 if (inst->start_tls && (inst->port != 636)) {
528 ldap_errno = ldap_start_tls_s(handle, NULL, NULL);
529 if (ldap_errno != LDAP_SUCCESS) {
530 ldap_get_option(handle, LDAP_OPT_ERROR_NUMBER,
532 radlog(L_ERR, " [%s] could not start TLS: %s",
534 ldap_err2string(ldap_errno));
538 #endif /* HAVE_LDAP_START_TLS */
540 conn = rad_malloc(sizeof(*conn));
542 conn->handle = handle;
543 conn->rebound = FALSE;
544 conn->referred = FALSE;
546 module_rcode = ldap_bind_wrapper(&conn, inst->login, inst->password,
548 if (module_rcode != RLM_MODULE_OK) {
549 radlog(L_ERR, " [%s] Failed binding to LDAP server: %s",
550 inst->xlat_name, error);
553 * FIXME: print "check config, morians!
562 /*************************************************************************
564 * Function: ldap_conn_delete
566 * Purpose: Close and delete a connection
568 *************************************************************************/
569 static int ldap_conn_delete(UNUSED void *ctx, void *connection)
571 LDAP_CONN *conn = connection;
573 ldap_unbind_s(conn->handle);
580 /*************************************************************************
582 * Function: ldap_get_socket
584 * Purpose: Gets an LDAP socket from the connection pool
586 *************************************************************************/
587 static LDAP_CONN *ldap_get_socket(ldap_instance *inst)
591 conn = fr_connection_get(inst->pool);
593 radlog(L_ERR, " [%s] All ldap connections are in use",
601 /*************************************************************************
603 * Function: ldap_release_socket
605 * Purpose: Frees an LDAP socket back to the connection pool
607 *************************************************************************/
608 static void ldap_release_socket(ldap_instance *inst, LDAP_CONN *conn)
611 * Could have already been free'd due to a previous error.
616 * We chased a referral to another server.
618 * This connection is no longer part of the pool which is
619 * connected to and bound to the configured server.
622 * Note that we do NOT close it if it was bound to
623 * another user. Instead, we let the next caller do the
626 if (conn->referred) {
627 fr_connection_del(inst->pool, conn);
631 fr_connection_release(inst->pool, conn);
636 /*************************************************************************
638 * Function: ldap_escape_func
640 * Purpose: Converts "bad" strings into ones which are safe for LDAP
642 *************************************************************************/
643 static size_t ldap_escape_func(UNUSED REQUEST *request, char *out,
644 size_t outlen, const char *in, UNUSED void *arg)
650 * Encode unsafe characters.
653 ((in[0] == ' ') || (in[0] == '#'))) ||
654 (strchr(",+\"\\<>;*=()", *in))) {
655 static const char hex[] = "0123456789abcdef";
658 * Only 3 or less bytes available.
665 *(out++) = hex[((*in) >> 4) & 0x0f];
666 *(out++) = hex[(*in) & 0x0f];
674 * Only one byte left.
691 /*************************************************************************
693 * Function: perform_search
695 * Purpose: Do a search and get a response
697 *************************************************************************/
698 static int perform_search(ldap_instance *inst, LDAP_CONN **pconn,
699 const char *search_basedn, int scope,
700 const char *filter, const char * const *attrs,
701 LDAPMessage **presult)
704 int reconnect = FALSE;
705 LDAP_CONN *conn = *pconn;
709 * OpenLDAP library doesn't declare attrs array as const, but
710 * it really should be *sigh*.
713 memcpy(&search_attrs, &attrs, sizeof(attrs));
718 * Do all searches as the default admin user.
721 ldap_errno = ldap_bind_wrapper(pconn,
722 inst->login, inst->password,
724 if (ldap_errno != RLM_MODULE_OK) {
728 rad_assert(*pconn != NULL);
730 conn->rebound = FALSE;
733 tv.tv_sec = inst->timeout;
735 DEBUG2(" [%s] Performing search in '%s' with filter '%s'", inst->xlat_name,
736 search_basedn ? search_basedn : "(null)" , filter);
739 ldap_errno = ldap_search_ext_s(conn->handle, search_basedn, scope,
740 filter, search_attrs, 0, NULL, NULL,
742 switch (ldap_errno) {
744 case LDAP_NO_SUCH_OBJECT:
747 case LDAP_SERVER_DOWN:
749 ldap_msgfree(*presult);
751 if (reconnect) return -1;
754 conn = fr_connection_reconnect(inst->pool, conn);
755 *pconn = conn; /* tell the caller we have a new connection */
756 if (!conn) return -1;
759 case LDAP_INSUFFICIENT_ACCESS:
760 radlog(L_ERR, " [%s] ldap_search() failed: Insufficient access. Check the identity and password configuration directives.", inst->xlat_name);
761 ldap_msgfree(*presult);
765 exec_trigger(NULL, inst->cs, "modules.ldap.timeout", TRUE);
766 radlog(L_ERR, " [%s] ldap_search() failed: Timed out while waiting for server to respond. Please increase the timeout.", inst->xlat_name);
767 ldap_msgfree(*presult);
770 case LDAP_FILTER_ERROR:
771 radlog(L_ERR, " [%s] ldap_search() failed: Bad search filter: %s", inst->xlat_name,filter);
772 ldap_msgfree(*presult);
775 case LDAP_TIMELIMIT_EXCEEDED:
776 exec_trigger(NULL, inst->cs, "modules.ldap.timeout", TRUE);
779 case LDAP_UNAVAILABLE:
781 * Reconnect. There's an issue with the socket
784 ldap_get_option(conn->handle, LDAP_OPT_ERROR_NUMBER,
786 radlog(L_ERR, " [%s] ldap_search() failed: %s",
787 inst->xlat_name, ldap_err2string(ldap_errno));
791 ldap_get_option(conn->handle, LDAP_OPT_ERROR_NUMBER,
793 radlog(L_ERR, " [%s] ldap_search() failed: %s",
794 inst->xlat_name, ldap_err2string(ldap_errno));
795 ldap_msgfree(*presult);
799 ldap_errno = ldap_count_entries(conn->handle, *presult);
800 if (ldap_errno == 0) {
801 ldap_msgfree(*presult);
802 DEBUG(" [%s] object not found", inst->xlat_name);
806 if (ldap_errno != 1) {
807 ldap_msgfree(*presult);
808 DEBUG(" [%s] got ambiguous search result (%d results)",
809 inst->xlat_name, ldap_errno);
816 /*************************************************************************
818 * Function: ldap_xlat
820 * Purpose: Expand an LDAP URL into a query, and return a string
821 * result from that query.
823 *************************************************************************/
824 static size_t ldap_xlat(void *instance, REQUEST *request, const char *fmt,
825 char *out, size_t freespace)
829 ldap_instance *inst = instance;
830 LDAPURLDesc *ldap_url;
831 LDAPMessage *result = NULL;
832 LDAPMessage *entry = NULL;
837 char buffer[MAX_FILTER_STR_LEN];
839 if (strchr(fmt, '%') != NULL) {
840 if (!radius_xlat(buffer, sizeof(buffer), fmt, request, ldap_escape_func, NULL)) {
841 radlog (L_ERR, " [%s] Unable to create LDAP URL.", inst->xlat_name);
849 if (!ldap_is_ldap_url(url)) {
850 radlog (L_ERR, " [%s] String passed does not look like an LDAP URL.",
855 if (ldap_url_parse(url, &ldap_url)){
856 radlog (L_ERR, " [%s] LDAP URL parse failed.", inst->xlat_name);
861 * Nothing, empty string, "*" string, or got 2 things, die.
863 if (!ldap_url->lud_attrs || !ldap_url->lud_attrs[0] ||
864 !*ldap_url->lud_attrs[0] || (strcmp(ldap_url->lud_attrs[0], "*") == 0) ||
865 ldap_url->lud_attrs[1]) {
866 radlog (L_ERR, " [%s] Invalid Attribute(s) request.",
871 if (ldap_url->lud_host &&
872 ((strncmp(inst->server, ldap_url->lud_host, strlen(inst->server)) != 0) ||
873 (ldap_url->lud_port != inst->port))) {
874 DEBUG(" [%s] Requested server/port is .", inst->xlat_name);
878 conn = ldap_get_socket(inst);
879 if (!conn) goto free_urldesc;
881 memcpy(&attrs, &ldap_url->lud_attrs, sizeof(attrs));
883 rcode = perform_search(inst, &conn, ldap_url->lud_dn, ldap_url->lud_scope,
884 ldap_url->lud_filter, attrs, &result);
887 DEBUG(" [%s] Search returned not found", inst->xlat_name);
890 DEBUG(" [%s] Search returned error", inst->xlat_name);
894 entry = ldap_first_entry(conn->handle, result);
896 DEBUG(" [%s] ldap_first_entry() failed", inst->xlat_name);
900 vals = ldap_get_values(conn->handle, entry, ldap_url->lud_attrs[0]);
902 DEBUG(" [%s] ldap_get_values failed", inst->xlat_name);
906 length = strlen(vals[0]);
907 if (length >= freespace){
912 strlcpy(out, vals[0], freespace);
915 ldap_value_free(vals);
917 ldap_msgfree(result);
919 ldap_release_socket(inst, conn);
921 ldap_free_urldesc(ldap_url);
927 static char *get_userdn(LDAP_CONN **pconn, REQUEST *request, int *module_rcode)
931 ldap_instance *inst = (*pconn)->inst;
932 LDAPMessage *result, *entry;
933 static char firstattr[] = "uid";
935 const char *attrs[] = {firstattr, NULL};
936 char filter[MAX_FILTER_STR_LEN];
937 char basedn[MAX_FILTER_STR_LEN];
939 *module_rcode = RLM_MODULE_FAIL;
941 vp = pairfind(request->config_items, PW_LDAP_USERDN, 0);
942 if (vp) return vp->vp_strvalue;
944 if (!radius_xlat(filter, sizeof(filter), inst->filter,
945 request, ldap_escape_func, NULL)) {
946 radlog(L_ERR, " [%s] unable to create filter.", inst->xlat_name);
947 *module_rcode = RLM_MODULE_INVALID;
951 if (!radius_xlat(basedn, sizeof(basedn), inst->basedn,
952 request, ldap_escape_func, NULL)) {
953 radlog(L_ERR, " [%s] unable to create basedn.", inst->xlat_name);
954 *module_rcode = RLM_MODULE_INVALID;
958 rcode = perform_search(inst, pconn, basedn, LDAP_SCOPE_SUBTREE,
959 filter, attrs, &result);
962 *module_rcode = RLM_MODULE_NOTFOUND;
968 if ((entry = ldap_first_entry((*pconn)->handle, result)) == NULL) {
969 ldap_msgfree(result);
973 if ((user_dn = ldap_get_dn((*pconn)->handle, entry)) == NULL) {
974 ldap_msgfree(result);
978 vp = pairmake("LDAP-UserDn", user_dn, T_OP_EQ);
980 ldap_memfree(user_dn);
981 ldap_msgfree(result);
985 pairadd(&request->config_items, vp);
986 ldap_memfree(user_dn);
987 ldap_msgfree(result);
989 return vp->vp_strvalue;
993 /*****************************************************************************
995 * Perform LDAP-Group comparison checking
997 *****************************************************************************/
998 static int ldap_groupcmp(void *instance, REQUEST *request,
999 UNUSED VALUE_PAIR *thing, VALUE_PAIR *check,
1000 UNUSED VALUE_PAIR *check_pairs,
1001 UNUSED VALUE_PAIR **reply_pairs)
1003 ldap_instance *inst = instance;
1004 int i, rcode, found;
1005 LDAPMessage *result = NULL;
1006 LDAPMessage *entry = NULL;
1007 static char firstattr[] = "dn";
1008 const char *attrs[] = {firstattr, NULL};
1010 const char *group_attrs[] = {inst->groupmemb_attr, NULL};
1014 char gr_filter[MAX_FILTER_STR_LEN];
1015 char filter[MAX_FILTER_STR_LEN];
1016 char basedn[MAX_FILTER_STR_LEN];
1018 if (check->length == 0) {
1019 RDEBUG("Cannot do comparison: group name is empty");
1023 conn = ldap_get_socket(inst);
1024 if (!conn) return 1;
1027 * This is used in the default membership filter.
1029 user_dn = get_userdn(&conn, request, &module_rcode);
1031 ldap_release_socket(inst, conn);
1035 if (!inst->groupmemb_filt) goto check_attr;
1037 if (!radius_xlat(filter, sizeof(filter),
1038 inst->groupmemb_filt, request, ldap_escape_func, NULL)) {
1039 RDEBUG("Failed creating group filter");
1044 * If it's a DN, use that.
1046 if (strchr(check->vp_strvalue,',') != NULL) {
1047 strlcpy(filter, gr_filter, sizeof(filter));
1048 strlcpy(basedn, check->vp_strvalue, sizeof(basedn));
1051 snprintf(filter, sizeof(filter), "(&(%s=%s)%s)",
1052 inst->groupname_attr,
1053 check->vp_strvalue, gr_filter);
1056 * get_userdn does this, too. Oh well.
1058 if (!radius_xlat(basedn, sizeof(basedn), inst->basedn,
1059 request, ldap_escape_func, NULL)) {
1060 radlog(L_ERR, " [%s] unable to create basedn.\n",
1066 rcode = perform_search(inst, &conn, basedn, LDAP_SCOPE_SUBTREE,
1067 filter, attrs, &result);
1069 ldap_release_socket(inst, conn);
1070 ldap_msgfree(result);
1071 RDEBUG("User found in group %s", check->vp_strvalue);
1076 ldap_release_socket(inst, conn);
1077 RDEBUG("Failed performing search");
1081 /* else the search returned -2, for "not found" */
1084 * Else the search returned NOTFOUND. See if we're
1085 * configured to search for group membership using user
1088 if (!inst->groupmemb_attr) {
1089 ldap_release_socket(inst, conn);
1090 RDEBUG("Group %s was not found, or user is not a member",
1091 check->vp_strvalue);
1096 snprintf(filter ,sizeof(filter), "(objectclass=*)");
1098 rcode = perform_search(inst, &conn, user_dn, LDAP_SCOPE_BASE,
1099 filter, group_attrs, &result);
1101 RDEBUG("Search failed for group attrs");
1102 ldap_release_socket(inst, conn);
1106 entry = ldap_first_entry(conn->handle, result);
1108 RDEBUG("First entry failed for group attrs");
1109 ldap_release_socket(inst, conn);
1110 ldap_msgfree(result);
1114 vals = ldap_get_values(conn->handle, entry, inst->groupmemb_attr);
1116 RDEBUG("Get values failed for group attrs");
1117 ldap_release_socket(inst, conn);
1118 ldap_msgfree(result);
1123 * Loop over the list of groups the user is a member of,
1124 * looking for a match.
1127 for (i = 0; i < ldap_count_values(vals); i++){
1128 LDAPMessage *gr_result = NULL;
1130 if (strcmp(vals[i], check->vp_strvalue) == 0){
1136 * The group isn't a DN: ignore it.
1138 if (strchr(vals[i], ',') == NULL) continue;
1140 /* This looks like a DN. Do tons more work. */
1141 snprintf(filter,sizeof(filter), "(%s=%s)",
1142 inst->groupname_attr, check->vp_strvalue);
1144 rcode = perform_search(inst, &conn, vals[i], LDAP_SCOPE_BASE,
1145 filter, attrs, &gr_result);
1147 RDEBUG("Failed doing group search");
1148 ldap_value_free(vals);
1149 ldap_msgfree(result);
1150 ldap_release_socket(inst, conn);
1154 ldap_msgfree(gr_result);
1158 ldap_value_free(vals);
1159 ldap_msgfree(result);
1160 ldap_release_socket(inst, conn);
1163 RDEBUG("groupcmp: Group %s not found, or user is not a member",
1164 check->vp_strvalue);
1172 * Verify that the ldap update section makes sense, and add attribute names
1173 * to array of attributes for efficient querying later.
1175 static int build_attrmap(CONF_SECTION *cs, VALUE_PAIR_MAP **head)
1177 const char *cs_list, *p;
1179 request_refs_t request_def = REQUEST_CURRENT;
1180 pair_lists_t list_def = PAIR_LIST_REQUEST;
1182 CONF_ITEM *ci = cf_sectiontoitem(cs);
1185 unsigned int total = 0;
1186 VALUE_PAIR_MAP **tail, *map;
1192 cs_list = p = cf_section_name2(cs);
1194 request_def = radius_request_name(&p, REQUEST_UNKNOWN);
1195 if (request_def == REQUEST_UNKNOWN) {
1196 cf_log_err(ci, "rlm_ldap: Default request specified "
1197 "in mapping section is invalid");
1201 list_def = fr_str2int(pair_lists, p, PAIR_LIST_UNKNOWN);
1202 if (list_def == PAIR_LIST_UNKNOWN) {
1203 cf_log_err(ci, "rlm_ldap: Default list specified "
1204 "in mapping section is invalid");
1209 for (ci = cf_item_find_next(cs, NULL);
1211 ci = cf_item_find_next(cs, ci)) {
1212 if (total++ == MAX_ATTRMAP) {
1213 cf_log_err(ci, "rlm_ldap: Attribute map size exceeded");
1217 if (!cf_item_is_pair(ci)) {
1218 cf_log_err(ci, "rlm_ldap: Entry is not in \"attribute ="
1219 " ldap-attribute\" format");
1223 cp = cf_itemtopair(ci);
1224 map = radius_cp2map(cp, REQUEST_CURRENT, list_def);
1230 tail = &(map->next);
1236 radius_mapfree(head);
1240 /*****************************************************************************
1242 * Detach from the LDAP server and cleanup internal state.
1244 *****************************************************************************/
1245 static int ldap_detach(void *instance)
1247 ldap_instance *inst = instance;
1249 fr_connection_pool_delete(inst->pool);
1251 if (inst->user_map) {
1252 radius_mapfree(&inst->user_map);
1260 /*************************************************************************
1262 * Function: rlm_ldap_instantiate
1264 * Purpose: Uses section of radiusd config file passed as parameter
1265 * to create an instance of the module.
1267 *************************************************************************/
1268 static int ldap_instantiate(CONF_SECTION * conf, void **instance)
1270 ldap_instance *inst;
1273 inst = rad_malloc(sizeof *inst);
1277 memset(inst, 0, sizeof(*inst));
1280 inst->chase_referrals = 2; /* use OpenLDAP defaults */
1283 if (cf_section_parse(conf, inst, module_config) < 0) {
1288 if (inst->server == NULL) {
1289 radlog(L_ERR, "rlm_ldap: missing 'server' directive.");
1295 * Check for URLs. If they're used and the library doesn't
1296 * support them, then complain.
1299 if (ldap_is_ldap_url(inst->server)) {
1300 #ifdef HAVE_LDAP_INITIALIZE
1304 radlog(L_ERR, "rlm_ldap: 'server' directive is in URL form but "
1305 "ldap_initialize() is not available.");
1311 /* workaround for servers which support LDAPS but not START TLS */
1312 if (inst->port == LDAPS_PORT || inst->tls_mode) {
1313 inst->tls_mode = LDAP_OPT_X_TLS_HARD;
1318 inst->xlat_name = cf_section_name2(conf);
1319 if (!inst->xlat_name) inst->xlat_name = cf_section_name1(conf);
1321 #if LDAP_SET_REBIND_PROC_ARGS != 3
1323 * The 2-argument rebind doesn't take an instance
1324 * variable. Our rebind function needs the instance
1325 * variable for the username, password, etc.
1327 if (inst->rebind == 1) {
1328 radlog(L_ERR, "%s: Cannot use 'rebind' directive as this "
1329 "version of libldap does not support the API that "
1330 "we need.", inst->xlat-name);
1337 * Build the attribute map
1339 cs = cf_section_sub_find(conf, "update");
1341 if (build_attrmap(cs, &(inst->user_map)) < 0) {
1348 * Group comparison checks.
1350 paircompare_register(PW_LDAP_GROUP, PW_USER_NAME, ldap_groupcmp, inst);
1351 if (cf_section_name2(conf)) {
1356 snprintf(buffer, sizeof(buffer), "%s-Ldap-Group", inst->xlat_name);
1357 memset(&flags, 0, sizeof(flags));
1359 dict_addattr(buffer, -1, 0, PW_TYPE_STRING, flags);
1360 da = dict_attrbyname(buffer);
1362 radlog(L_ERR, "%s: Failed creating attribute %s",
1363 inst->xlat_name, buffer);
1368 paircompare_register(da->attr, PW_USER_NAME, ldap_groupcmp, inst);
1371 xlat_register(inst->xlat_name, ldap_xlat, inst);
1374 * Initialize the socket pool.
1376 inst->pool = fr_connection_pool_init(inst->cs, inst,
1390 static void module_failure_msg(VALUE_PAIR **vps, const char *fmt, ...)
1396 vp = paircreate(PW_MODULE_FAILURE_MESSAGE, 0, PW_TYPE_STRING);
1402 vsnprintf(vp->vp_strvalue, sizeof(vp->vp_strvalue), fmt, ap);
1408 static int check_access(ldap_instance *inst, LDAP_CONN *conn, LDAPMessage *entry)
1413 vals = ldap_get_values(conn->handle, entry, inst->access_attr);
1415 if (inst->positive_access_attr) {
1416 if (strncmp(vals[0], "FALSE", 5) == 0) {
1417 DEBUG("dialup access disabled");
1424 DEBUG("%s attribute exists - access denied by default",
1428 ldap_value_free(vals);
1430 } else if (inst->positive_access_attr) {
1431 DEBUG("No %s attribute - access denied by default", inst->access_attr);
1441 static VALUE_PAIR *ldap_getvalue(REQUEST *request, VALUE_PAIR_TMPL *dst,
1444 rlm_ldap_result_t *self = ctx;
1445 VALUE_PAIR *head, **tail, *vp;
1454 * Iterate over all the retrieved values,
1455 * don't try and be clever about changing operators
1456 * just use whatever was set in the attribute map.
1458 for (i = 0; i < self->count; i++) {
1459 vp = pairalloc(dst->da);
1462 pairparsevalue(vp, self->values[i]);
1472 static void xlat_attrsfree(const xlat_attrs_t *expanded)
1474 const VALUE_PAIR_MAP *map;
1475 unsigned int total = 0;
1479 for (map = expanded->maps; map != NULL; map = map->next)
1481 memcpy(&name, &(expanded->attrs[total++]), sizeof(name));
1485 if (map->src.do_xlat) {
1492 static int xlat_attrs(REQUEST *request, const VALUE_PAIR_MAP *maps,
1493 xlat_attrs_t *expanded)
1495 const VALUE_PAIR_MAP *map;
1496 unsigned int total = 0;
1501 for (map = maps; map != NULL; map = map->next)
1503 if (map->src.do_xlat) {
1504 buffer = rad_malloc(MAX_ATTR_STR_LEN);
1505 len = radius_xlat(buffer, MAX_ATTR_STR_LEN,
1506 map->src.name, request, NULL, NULL);
1509 DEBUG2("WARNING: Expansion of LDAP attribute "
1510 "\"%s\" failed", map->src.name);
1512 expanded->attrs[total] = NULL;
1514 xlat_attrsfree(expanded);
1519 expanded->attrs[total++] = buffer;
1521 expanded->attrs[total++] = map->src.name;
1525 expanded->attrs[total] = NULL;
1526 expanded->maps = maps;
1532 /** Convert attribute map into valuepairs
1534 * Use the attribute map built earlier to convert LDAP values into valuepairs
1535 * and insert them into whichever list they need to go into.
1537 * This is *NOT* atomic, but there's no condition in which we should error
1540 static void do_attrmap(UNUSED ldap_instance *inst, REQUEST *request,
1541 LDAP *handle, const xlat_attrs_t *expanded,
1544 const VALUE_PAIR_MAP *map;
1545 unsigned int total = 0;
1547 rlm_ldap_result_t result;
1550 for (map = expanded->maps; map != NULL; map = map->next)
1552 name = expanded->attrs[total++];
1554 result.values = ldap_get_values(handle, entry, name);
1555 if (!result.values) {
1556 DEBUG2("WARNING: Attribute \"%s\" not found in LDAP "
1563 * Find out how many values there are for the
1564 * attribute and extract all of them.
1566 result.count = ldap_count_values(result.values);
1569 * If something bad happened, just skip, this is probably
1570 * a case of the dst being incorrect for the current
1573 if (radius_map2request(request, map, name, ldap_getvalue,
1580 ldap_value_free(result.values);
1585 static void do_check_reply(ldap_instance *inst, REQUEST *request)
1588 * More warning messages for people who can't be bothered
1589 * to read the documentation.
1591 if (inst->expect_password && (debug_flag > 1)) {
1592 if (!pairfind(request->config_items, PW_CLEARTEXT_PASSWORD, 0) &&
1593 !pairfind(request->config_items, PW_NT_PASSWORD, 0) &&
1594 !pairfind(request->config_items, PW_USER_PASSWORD, 0) &&
1595 !pairfind(request->config_items, PW_PASSWORD_WITH_HEADER, 0) &&
1596 !pairfind(request->config_items, PW_CRYPT_PASSWORD, 0)) {
1597 DEBUG("WARNING: No \"known good\" password was found in LDAP. Are you sure that the user is configured correctly?");
1603 static void apply_profile(ldap_instance *inst, REQUEST *request,
1604 LDAP_CONN **pconn, const char *profile,
1605 const xlat_attrs_t *expanded)
1608 LDAPMessage *result, *entry;
1609 char filter[MAX_FILTER_STR_LEN];
1611 if (!profile || !*profile) return;
1613 strlcpy(filter, inst->base_filter, sizeof(filter));
1615 rcode = perform_search(inst, pconn, profile, LDAP_SCOPE_BASE,
1616 filter, expanded->attrs, &result);
1619 RDEBUG("FAILED Searching profile %s", profile);
1623 entry = ldap_first_entry((*pconn)->handle, result);
1624 if (!entry) goto free_result;
1626 do_attrmap(inst, request, (*pconn)->handle, expanded, entry);
1629 ldap_msgfree(result);
1633 /******************************************************************************
1635 * Function: ldap_authorize
1637 * Purpose: Check if user is authorized for remote access
1639 ******************************************************************************/
1640 static int ldap_authorize(void *instance, REQUEST * request)
1643 int module_rcode = RLM_MODULE_OK;
1644 ldap_instance *inst = instance;
1649 LDAPMessage *result, *entry;
1650 char filter[MAX_FILTER_STR_LEN];
1651 char basedn[MAX_FILTER_STR_LEN];
1652 xlat_attrs_t expanded; /* faster that mallocing every time */
1654 if (!request->username) {
1655 RDEBUG2("attribute \"User-Name\" is required for authorization.\n");
1656 return RLM_MODULE_NOOP;
1660 * Check for valid input, zero length names not permitted
1662 if (request->username->length == 0) {
1663 RDEBUG2("zero length username not permitted\n");
1664 return RLM_MODULE_INVALID;
1667 if (!radius_xlat(filter, sizeof(filter), inst->filter,
1668 request, ldap_escape_func, NULL)) {
1669 radlog(L_ERR, " [%s] Failed creating filter.\n", inst->xlat_name);
1670 return RLM_MODULE_INVALID;
1673 if (!radius_xlat(basedn, sizeof(basedn), inst->basedn,
1674 request, ldap_escape_func, NULL)) {
1675 radlog(L_ERR, " [%s] Failed creating basedn.\n", inst->xlat_name);
1676 return RLM_MODULE_INVALID;
1679 conn = ldap_get_socket(inst);
1680 if (!conn) return RLM_MODULE_FAIL;
1682 if (xlat_attrs(request, inst->user_map, &expanded) < 0) {
1683 return RLM_MODULE_FAIL;
1686 rcode = perform_search(inst, &conn, basedn, LDAP_SCOPE_SUBTREE, filter,
1687 expanded.attrs, &result);
1691 module_failure_msg(&request->packet->vps,
1692 "[%s] Search returned not found",
1694 DEBUG(" [%s] Search returned not found", inst->xlat_name);
1695 module_rcode = RLM_MODULE_NOTFOUND;
1698 DEBUG(" [%s] Search returned error", inst->xlat_name);
1702 entry = ldap_first_entry(conn->handle, result);
1704 RDEBUG2("ldap_first_entry() failed");
1708 user_dn = ldap_get_dn(conn->handle, entry);
1710 RDEBUG2("ldap_get_dn() failed");
1714 RDEBUG2("User found, dn is \"%s\"", user_dn);
1716 * Adding attribute containing the Users' DN.
1718 pairadd(&request->config_items, pairmake("Ldap-UserDn", user_dn, T_OP_EQ));
1719 ldap_memfree(user_dn);
1724 if (inst->access_attr) {
1725 if (check_access(inst, conn, entry) < 0) {
1726 module_rcode = RLM_MODULE_USERLOCK;
1732 * Apply ONE user profile, or a default user profile.
1734 vp = pairfind(request->config_items, PW_USER_PROFILE, 0);
1735 if (vp || inst->default_profile) {
1736 char *profile = inst->default_profile;
1738 if (vp) profile = vp->vp_strvalue;
1740 apply_profile(inst, request, &conn, profile, &expanded);
1744 * Apply a SET of user profiles.
1746 if (inst->profile_attr &&
1747 (vals = ldap_get_values(conn->handle, entry, inst->profile_attr)) != NULL) {
1751 for (i = 0; (vals[i] != NULL) && (*vals[i] != '\0'); i++) {
1752 apply_profile(inst, request, &conn, vals[i], &expanded);
1755 ldap_value_free(vals);
1758 if (inst->user_map) {
1759 do_attrmap(inst, request, conn->handle, &expanded, entry);
1760 do_check_reply(inst, request);
1764 xlat_attrsfree(&expanded);
1765 ldap_msgfree(result);
1767 ldap_release_socket(inst, conn);
1769 return module_rcode;
1773 /*****************************************************************************
1775 * Function: ldap_authenticate
1777 * Purpose: Check the user's password against ldap database
1779 *****************************************************************************/
1780 static int ldap_authenticate(void *instance, REQUEST * request)
1783 const char *user_dn;
1784 ldap_instance *inst = instance;
1788 * Ensure that we're being passed a plain-text password, and not
1792 if (!request->username) {
1793 radlog(L_AUTH, " [%s] Attribute \"User-Name\" is required for authentication.", inst->xlat_name);
1794 return RLM_MODULE_INVALID;
1797 if (!request->password) {
1798 radlog(L_AUTH, " [%s] Attribute \"User-Password\" is required for authentication.", inst->xlat_name);
1799 RDEBUG2(" You seem to have set \"Auth-Type := LDAP\" somewhere.");
1800 RDEBUG2(" *******************************************************");
1801 RDEBUG2(" * THAT CONFIGURATION IS WRONG. DELETE IT.");
1802 RDEBUG2(" * YOU ARE PREVENTING THE SERVER FROM WORKING PROPERLY.");
1803 RDEBUG2(" *******************************************************");
1804 return RLM_MODULE_INVALID;
1807 if (request->password->attribute != PW_USER_PASSWORD) {
1808 radlog(L_AUTH, " [%s] Attribute \"User-Password\" is required for authentication. Cannot use \"%s\".", inst->xlat_name, request->password->name);
1809 return RLM_MODULE_INVALID;
1812 if (request->password->length == 0) {
1813 module_failure_msg(&request->packet->vps,
1814 "[%s] empty password supplied", inst->xlat_name);
1815 return RLM_MODULE_INVALID;
1818 conn = ldap_get_socket(inst);
1819 if (!conn) return RLM_MODULE_FAIL;
1821 RDEBUG("login attempt by \"%s\" with password \"%s\"",
1822 request->username->vp_strvalue, request->password->vp_strvalue);
1825 * Get the DN by doing a search.
1827 user_dn = get_userdn(&conn, request, &module_rcode);
1829 ldap_release_socket(inst, conn);
1830 return module_rcode;
1836 conn->rebound = TRUE;
1837 module_rcode = ldap_bind_wrapper(&conn, user_dn,
1838 request->password->vp_strvalue,
1840 if (module_rcode == RLM_MODULE_OK) {
1841 RDEBUG(" [%s] Bind as user '%s' was successful", inst->xlat_name,
1845 ldap_release_socket(inst, conn);
1846 return module_rcode;
1850 /* globally exported name */
1851 module_t rlm_ldap = {
1854 RLM_TYPE_THREAD_SAFE, /* type: reserved */
1855 ldap_instantiate, /* instantiation */
1856 ldap_detach, /* detach */
1858 ldap_authenticate, /* authentication */
1859 ldap_authorize, /* authorization */
1860 NULL, /* preaccounting */
1861 NULL, /* accounting */
1862 NULL, /* checksimul */
1863 NULL, /* pre-proxy */
1864 NULL, /* post-proxy */