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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 * Copyright 2004 The FreeRADIUS Server Project.
20 static const char rcsid[] = "$Id$";
24 #include <sys/types.h>
25 #include <sys/socket.h>
27 #include <netinet/in.h>
44 #include "libradius.h"
48 #include "rad_assert.h"
50 #ifndef HAVE_PTHREAD_H
52 * This is a lot simpler than putting ifdef's around
53 * every use of the pthread functions.
55 #define pthread_mutex_lock(a)
56 #define pthread_mutex_unlock(a)
57 #define pthread_mutex_init(a,b)
58 #define pthread_mutex_destroy(a)
62 #define MAX_FILTER_STR_LEN 1024
66 * These are used in case ldap_search returns LDAP_SERVER_DOWN
67 * In that case we do conn->failed_conns++ and then check it:
68 * If conn->failed_conns <= MAX_FAILED_CONNS_START then we try
70 * conn->failed_conns is also checked on entrance in perform_search:
71 * If conn->failed_conns > MAX_FAILED_CONNS_START then we don't
72 * try to do anything and we just do conn->failed_conns++ and
73 * return RLM_MODULE_FAIL
74 * if conn->failed_conns >= MAX_FAILED_CONNS_END then we give it
75 * another chance and we set it to MAX_FAILED_CONNS_RESTART and
79 * We are assuming that the majority of the LDAP_SERVER_DOWN cases
80 * will either be an ldap connection timeout or a temporary ldap
82 * As a result we make a few attempts to reconnect hoping that the problem
83 * will soon go away. If it does not go away then we just return
84 * RLM_MODULE_FAIL on entrance in perform_search until conn->failed_conns
85 * gets to MAX_FAILED_CONNS_END. After that we give it one more chance by
86 * going back to MAX_FAILED_CONNS_RESTART
90 #define MAX_FAILED_CONNS_END 20
91 #define MAX_FAILED_CONNS_RESTART 4
92 #define MAX_FAILED_CONNS_START 5
94 /* linked list of mappings between RADIUS attributes and LDAP attributes */
99 struct TLDAP_RADIUS* next;
101 typedef struct TLDAP_RADIUS TLDAP_RADIUS;
103 typedef struct ldap_conn {
108 #ifdef HAVE_PTHREAD_H
109 pthread_mutex_t mutex;
117 struct timeval net_timeout;
118 struct timeval timeout;
133 char *default_profile;
138 char *dictionary_mapping;
139 char *groupname_attr;
140 char *groupmemb_filt;
141 char *groupmemb_attr;
143 TLDAP_RADIUS *check_item_map;
144 TLDAP_RADIUS *reply_item_map;
146 int ldap_debug; /* Debug flag for LDAP SDK */
147 char *xlat_name; /* name used to xlat */
148 char *tls_cacertfile;
153 char *tls_require_cert;
156 /* The default setting for TLS Certificate Verification */
157 #define TLS_DEFAULT_VERIFY "allow"
159 static CONF_PARSER module_config[] = {
160 {"server", PW_TYPE_STRING_PTR, offsetof(ldap_instance,server), NULL, "localhost"},
161 {"port", PW_TYPE_INTEGER, offsetof(ldap_instance,port), NULL, "389"},
162 /* wait forever on network activity */
163 {"net_timeout", PW_TYPE_INTEGER, offsetof(ldap_instance,net_timeout.tv_sec), NULL, "10"},
164 /* wait forever for search results */
165 {"timeout", PW_TYPE_INTEGER, offsetof(ldap_instance,timeout.tv_sec), NULL, "20"},
166 /* allow server unlimited time for search (server-side limit) */
167 {"timelimit", PW_TYPE_INTEGER, offsetof(ldap_instance,timelimit), NULL, "20"},
168 {"identity", PW_TYPE_STRING_PTR, offsetof(ldap_instance,login), NULL, ""},
169 {"tls_mode", PW_TYPE_BOOLEAN, offsetof(ldap_instance,tls_mode), NULL, "no"},
170 {"start_tls", PW_TYPE_BOOLEAN, offsetof(ldap_instance,start_tls), NULL, "no"},
171 {"tls_cacertfile", PW_TYPE_STRING_PTR, offsetof(ldap_instance,tls_cacertfile), NULL, NULL},
172 {"tls_cacertdir", PW_TYPE_STRING_PTR, offsetof(ldap_instance,tls_cacertdir), NULL, NULL},
173 {"tls_certfile", PW_TYPE_STRING_PTR, offsetof(ldap_instance,tls_certfile), NULL, NULL},
174 {"tls_keyfile", PW_TYPE_STRING_PTR, offsetof(ldap_instance,tls_keyfile), NULL, NULL},
175 {"tls_randfile", PW_TYPE_STRING_PTR, offsetof(ldap_instance,tls_randfile), NULL, NULL},
176 {"tls_require_cert", PW_TYPE_STRING_PTR, offsetof(ldap_instance,tls_require_cert), NULL, TLS_DEFAULT_VERIFY},
177 {"password", PW_TYPE_STRING_PTR, offsetof(ldap_instance,password), NULL, ""},
178 {"basedn", PW_TYPE_STRING_PTR, offsetof(ldap_instance,basedn), NULL, "o=notexist"},
179 {"filter", PW_TYPE_STRING_PTR, offsetof(ldap_instance,filter), NULL, "(uid=%u)"},
180 {"base_filter", PW_TYPE_STRING_PTR, offsetof(ldap_instance,base_filter), NULL, "(objectclass=radiusprofile)"},
181 {"default_profile", PW_TYPE_STRING_PTR, offsetof(ldap_instance,default_profile), NULL, NULL},
182 {"profile_attribute", PW_TYPE_STRING_PTR, offsetof(ldap_instance,profile_attr), NULL, NULL},
183 {"password_header", PW_TYPE_STRING_PTR, offsetof(ldap_instance,passwd_hdr), NULL, NULL},
184 {"password_attribute", PW_TYPE_STRING_PTR, offsetof(ldap_instance,passwd_attr), NULL, NULL},
185 /* LDAP attribute name that controls remote access */
186 {"access_attr", PW_TYPE_STRING_PTR, offsetof(ldap_instance,access_attr), NULL, NULL},
187 /* file with mapping between LDAP and RADIUS attributes */
188 {"groupname_attribute", PW_TYPE_STRING_PTR, offsetof(ldap_instance,groupname_attr), NULL, "cn"},
189 {"groupmembership_filter", PW_TYPE_STRING_PTR, offsetof(ldap_instance,groupmemb_filt), NULL, "(|(&(objectClass=GroupOfNames)(member=%{Ldap-UserDn}))(&(objectClass=GroupOfUniqueNames)(uniquemember=%{Ldap-UserDn})))"},
190 {"groupmembership_attribute", PW_TYPE_STRING_PTR, offsetof(ldap_instance,groupmemb_attr), NULL, NULL},
191 {"dictionary_mapping", PW_TYPE_STRING_PTR, offsetof(ldap_instance,dictionary_mapping), NULL, "${confdir}/ldap.attrmap"},
192 {"ldap_debug", PW_TYPE_INTEGER, offsetof(ldap_instance,ldap_debug), NULL, "0x0000"},
193 {"ldap_connections_number", PW_TYPE_INTEGER, offsetof(ldap_instance,num_conns), NULL, "5"},
194 {"compare_check_items", PW_TYPE_BOOLEAN, offsetof(ldap_instance,do_comp), NULL, "no"},
195 {"access_attr_used_for_allow", PW_TYPE_BOOLEAN, offsetof(ldap_instance,default_allow), NULL, "yes"},
196 {"do_xlat", PW_TYPE_BOOLEAN, offsetof(ldap_instance,do_xlat), NULL, "yes"},
198 {NULL, -1, 0, NULL, NULL}
201 #define ld_valid ld_options.ldo_valid
202 #define LDAP_VALID_SESSION 0x2
203 #define LDAP_VALID(ld) ( (ld)->ld_valid == LDAP_VALID_SESSION )
206 static void fieldcpy(char *, char **);
208 static VALUE_PAIR *ldap_pairget(LDAP *, LDAPMessage *, TLDAP_RADIUS *,VALUE_PAIR **,char);
209 static int ldap_groupcmp(void *, REQUEST *, VALUE_PAIR *, VALUE_PAIR *, VALUE_PAIR *, VALUE_PAIR **);
210 static int ldap_xlat(void *,REQUEST *, char *, char *,int, RADIUS_ESCAPE_STRING);
211 static LDAP *ldap_connect(void *instance, const char *, const char *, int, int *);
212 static int read_mappings(ldap_instance* inst);
214 static inline int ldap_get_conn(LDAP_CONN *conns,LDAP_CONN **ret,void *instance)
216 ldap_instance *inst = instance;
219 for(i=0;i<inst->num_conns;i++){
220 DEBUG("rlm_ldap: ldap_get_conn: Checking Id: %d",i);
221 if ((conns[i].locked == 0) &&
222 (pthread_mutex_trylock(&(conns[i].mutex)) == 0)) {
225 DEBUG("rlm_ldap: ldap_get_conn: Got Id: %d",i);
233 static inline void ldap_release_conn(int i, LDAP_CONN *conns)
235 DEBUG("rlm_ldap: ldap_release_conn: Release Id: %d",i);
237 pthread_mutex_unlock(&(conns[i].mutex));
240 /*************************************************************************
242 * Function: rlm_ldap_instantiate
244 * Purpose: Uses section of radiusd config file passed as parameter
245 * to create an instance of the module.
247 *************************************************************************/
249 ldap_instantiate(CONF_SECTION * conf, void **instance)
254 int reply_map_num = 0;
255 int check_map_num = 0;
256 int att_map[3] = {0,0,0};
261 inst = rad_malloc(sizeof *inst);
265 memset(inst, 0, sizeof(*inst));
267 if (cf_section_parse(conf, inst, module_config) < 0) {
272 if (inst->server == NULL) {
273 radlog(L_ERR, "rlm_ldap: missing 'server' directive.");
278 if (ldap_is_ldap_url(inst->server)){
279 #ifdef HAVE_LDAP_INITIALIZE
283 radlog(L_ERR, "rlm_ldap: 'server' directive is in URL form but ldap_initialize() is not available.");
289 inst->timeout.tv_usec = 0;
290 inst->net_timeout.tv_usec = 0;
291 /* workaround for servers which support LDAPS but not START TLS */
292 if(inst->port == LDAPS_PORT || inst->tls_mode)
293 inst->tls_mode = LDAP_OPT_X_TLS_HARD;
296 inst->reply_item_map = NULL;
297 inst->check_item_map = NULL;
299 inst->failed_conns = 0;
301 DEBUG("rlm_ldap: Registering ldap_groupcmp for Ldap-Group");
302 paircompare_register(PW_LDAP_GROUP, PW_USER_NAME, ldap_groupcmp, inst);
304 xlat_name = cf_section_name2(conf);
305 if (xlat_name != NULL){
310 * Allocate room for <instance>-Ldap-Group
312 group_name = malloc((strlen(xlat_name) + 1 + 11) * sizeof(char));
313 rad_assert(group_name != NULL);
314 sprintf(group_name,"%s-Ldap-Group",xlat_name);
315 DEBUG("rlm_ldap: Creating new attribute %s",group_name);
316 dict_addattr(group_name, 0, PW_TYPE_STRING, -1, flags);
317 dattr = dict_attrbyname(group_name);
319 radlog(L_ERR, "rlm_ldap: Failed to create attribute %s",group_name);
323 DEBUG("rlm_ldap: Registering ldap_groupcmp for %s",group_name);
324 paircompare_register(dattr->attr, PW_USER_NAME, ldap_groupcmp, inst);
327 xlat_name = cf_section_name1(conf);
328 rad_assert(xlat_name != NULL); /* or all hell breaks loose */
330 inst->xlat_name = strdup(xlat_name);
331 DEBUG("rlm_ldap: Registering ldap_xlat with xlat_name %s",xlat_name);
332 xlat_register(xlat_name,ldap_xlat,inst);
334 if (inst->num_conns <= 0){
335 radlog(L_ERR, "rlm_ldap: Invalid ldap connections number passed.");
339 inst->conns = (LDAP_CONN *)malloc(sizeof(LDAP_CONN)*inst->num_conns);
340 if (inst->conns == NULL){
341 radlog(L_ERR, "rlm_ldap: Could not allocate memory. Aborting.");
345 for(;i<inst->num_conns;i++){
346 inst->conns[i].bound = 0;
347 inst->conns[i].locked = 0;
348 inst->conns[i].failed_conns = 0;
349 inst->conns[i].ld = NULL;
350 pthread_mutex_init(&inst->conns[i].mutex, NULL);
353 if (read_mappings(inst) != 0) {
354 radlog(L_ERR, "rlm_ldap: Reading dictionary mappings from file %s failed",
355 inst->dictionary_mapping);
359 if ((inst->check_item_map == NULL) &&
360 (inst->reply_item_map == NULL)) {
361 radlog(L_ERR, "rlm_ldap: dictionary mappings file %s did not contain any mappings",
362 inst->dictionary_mapping);
367 pair = inst->check_item_map;
372 check_map_num = (atts_num - 1);
373 pair = inst->reply_item_map;
378 reply_map_num = (atts_num - 1);
379 if (inst->profile_attr)
381 if (inst->passwd_attr)
383 if (inst->access_attr)
385 inst->atts = (char **)malloc(sizeof(char *)*(atts_num + 1));
386 if (inst->atts == NULL){
387 radlog(L_ERR, "rlm_ldap: Could not allocate memory. Aborting.");
391 pair = inst->check_item_map;
393 pair = inst->reply_item_map;
394 for(i=0;i<atts_num;i++){
395 if (i <= check_map_num ){
396 inst->atts[i] = pair->attr;
397 if (i == check_map_num)
398 pair = inst->reply_item_map;
402 else if (i <= reply_map_num){
403 inst->atts[i] = pair->attr;
407 if (inst->profile_attr && !att_map[0]){
408 inst->atts[i] = inst->profile_attr;
411 else if (inst->passwd_attr && !att_map[1]){
412 inst->atts[i] = inst->passwd_attr;
415 else if (inst->access_attr && !att_map[2]){
416 inst->atts[i] = inst->access_attr;
421 inst->atts[atts_num] = NULL;
423 DEBUG("conns: %p",inst->conns);
433 * read_mappings(...) reads a ldap<->radius mappings file to inst->reply_item_map and inst->check_item_map
436 #define MAX_LINE_LEN 160
437 #define GENERIC_ATTRIBUTE_ID "$GENERIC$"
440 read_mappings(ldap_instance* inst)
444 /* all buffers are of MAX_LINE_LEN so we can use sscanf without being afraid of buffer overflows */
445 char buf[MAX_LINE_LEN], itemType[MAX_LINE_LEN];
446 char radiusAttribute[MAX_LINE_LEN], ldapAttribute[MAX_LINE_LEN];
449 char opstring[MAX_LINE_LEN];
451 /* open the mappings file for reading */
453 filename = inst->dictionary_mapping;
454 DEBUG("rlm_ldap: reading ldap<->radius mappings from file %s", filename);
455 mapfile = fopen(filename, "r");
457 if (mapfile == NULL) {
458 radlog(L_ERR, "rlm_ldap: Opening file %s failed", filename);
459 return -1; /* error */
462 /* read file line by line. Note that if line length exceed MAX_LINE_LEN, line numbers will be mixed up */
466 while (fgets(buf, sizeof buf, mapfile)!=NULL) {
474 ptr = strchr(buf, '#');
478 if (buf[0] == 0) continue;
480 /* extract tokens from the string */
481 token_count = sscanf(buf, "%s %s %s %s",
482 itemType, radiusAttribute,
483 ldapAttribute, opstring);
485 if (token_count <= 0) /* no tokens */
488 if ((token_count < 3) || (token_count > 4)) {
489 radlog(L_ERR, "rlm_ldap: Skipping %s line %i: %s",
490 filename, linenumber, buf);
491 radlog(L_ERR, "rlm_ldap: Expected 3 to 4 tokens "
492 "(Item type, RADIUS Attribute and LDAP Attribute) but found only %i", token_count);
496 if (token_count == 3) {
497 operator = T_INVALID; /* use defaults */
502 operator = gettoken(&ptr, buf, sizeof(buf));
503 if ((operator < T_OP_ADD) || (operator > T_OP_CMP_EQ)) {
504 radlog(L_ERR, "rlm_ldap: file %s: skipping line %i: unknown or invalid operator %s",
505 filename, linenumber, opstring);
507 free(pair->radius_attr);
513 /* create new TLDAP_RADIUS list node */
514 pair = rad_malloc(sizeof(TLDAP_RADIUS));
516 pair->attr = strdup(ldapAttribute);
517 pair->radius_attr = strdup(radiusAttribute);
518 pair->operator = operator;
520 if ( (pair->attr == NULL) || (pair->radius_attr == NULL) ) {
521 radlog(L_ERR, "rlm_ldap: Out of memory");
522 if (pair->attr) free(pair->attr);
523 if (pair->radius_attr) free(pair->radius_attr);
529 /* push node to correct list */
530 if (strcasecmp(itemType, "checkItem") == 0) {
531 pair->next = inst->check_item_map;
532 inst->check_item_map = pair;
533 } else if (strcasecmp(itemType, "replyItem") == 0) {
534 pair->next = inst->reply_item_map;
535 inst->reply_item_map = pair;
537 radlog(L_ERR, "rlm_ldap: file %s: skipping line %i: unknown itemType %s",
538 filename, linenumber, itemType);
540 free(pair->radius_attr);
545 DEBUG("rlm_ldap: LDAP %s mapped to RADIUS %s",
546 pair->attr, pair->radius_attr);
551 return 0; /* success */
555 perform_search(void *instance, LDAP_CONN *conn, char *search_basedn, int scope, char *filter,
556 char **attrs, LDAPMessage ** result)
558 int res = RLM_MODULE_OK;
560 ldap_instance *inst = instance;
561 int search_retry = 0;
566 radlog(L_ERR, "rlm_ldap: NULL connection handle passed");
567 return RLM_MODULE_FAIL;
569 if (conn->failed_conns > MAX_FAILED_CONNS_START){
570 conn->failed_conns++;
571 if (conn->failed_conns >= MAX_FAILED_CONNS_END){
572 conn->failed_conns = MAX_FAILED_CONNS_RESTART;
577 if (!conn->bound || conn->ld == NULL) {
578 DEBUG2("rlm_ldap: attempting LDAP reconnection");
580 DEBUG2("rlm_ldap: closing existing LDAP connection");
581 ldap_unbind_s(conn->ld);
583 if ((conn->ld = ldap_connect(instance, inst->login,
584 inst->password, 0, &res)) == NULL) {
585 radlog(L_ERR, "rlm_ldap: (re)connection attempt failed");
586 if (search_retry == 0)
587 conn->failed_conns++;
588 return (RLM_MODULE_FAIL);
591 conn->failed_conns = 0;
593 DEBUG2("rlm_ldap: performing search in %s, with filter %s",
594 search_basedn ? search_basedn : "(null)" , filter);
595 switch (ldap_search_st(conn->ld, search_basedn, scope, filter,
596 attrs, 0, &(inst->timeout), result)) {
598 case LDAP_NO_SUCH_OBJECT:
600 case LDAP_SERVER_DOWN:
601 radlog(L_ERR, "rlm_ldap: ldap_search() failed: LDAP connection lost.");
602 conn->failed_conns++;
603 if (search_retry == 0){
604 if (conn->failed_conns <= MAX_FAILED_CONNS_START){
605 radlog(L_INFO, "rlm_ldap: Attempting reconnect");
608 ldap_msgfree(*result);
612 ldap_msgfree(*result);
613 return RLM_MODULE_FAIL;
614 case LDAP_INSUFFICIENT_ACCESS:
615 radlog(L_ERR, "rlm_ldap: ldap_search() failed: Insufficient access. Check the identity and password configuration directives.");
616 ldap_msgfree(*result);
617 return RLM_MODULE_FAIL;
619 radlog(L_ERR, "rlm_ldap: ldap_search() failed: Timed out while waiting for server to respond. Please increase the timeout.");
620 ldap_msgfree(*result);
621 return RLM_MODULE_FAIL;
622 case LDAP_FILTER_ERROR:
623 radlog(L_ERR, "rlm_ldap: ldap_search() failed: Bad search filter: %s",filter);
624 ldap_msgfree(*result);
625 return RLM_MODULE_FAIL;
626 case LDAP_TIMELIMIT_EXCEEDED:
628 case LDAP_UNAVAILABLE:
629 /* We don't need to reconnect in these cases so we don't set conn->bound */
630 ldap_get_option(conn->ld, LDAP_OPT_ERROR_NUMBER, &ldap_errno);
631 radlog(L_ERR, "rlm_ldap: ldap_search() failed: %s",
632 ldap_err2string(ldap_errno));
633 ldap_msgfree(*result);
634 return (RLM_MODULE_FAIL);
636 ldap_get_option(conn->ld, LDAP_OPT_ERROR_NUMBER, &ldap_errno);
637 radlog(L_ERR, "rlm_ldap: ldap_search() failed: %s",
638 ldap_err2string(ldap_errno));
640 ldap_msgfree(*result);
641 return (RLM_MODULE_FAIL);
644 if ((ldap_count_entries(conn->ld, *result)) != 1) {
645 DEBUG("rlm_ldap: object not found or got ambiguous search result");
646 res = RLM_MODULE_NOTFOUND;
647 ldap_msgfree(*result);
654 * Translate the LDAP queries.
656 static int ldap_escape_func(char *out, int outlen, const char *in)
662 * Only one byte left.
668 if (strchr("*", *in)) {
675 * Else it's a nice character.
688 * ldap_groupcmp(). Implement the Ldap-Group == "group" filter
691 static int ldap_groupcmp(void *instance, REQUEST *req, VALUE_PAIR *request,
692 VALUE_PAIR *check, VALUE_PAIR *check_pairs,
693 VALUE_PAIR **reply_pairs)
695 char filter[MAX_FILTER_STR_LEN];
696 char gr_filter[MAX_FILTER_STR_LEN];
698 LDAPMessage *result = NULL;
699 LDAPMessage *msg = NULL;
700 char basedn[MAX_FILTER_STR_LEN];
701 char *attrs[] = {"dn",NULL};
703 ldap_instance *inst = instance;
704 char *group_attrs[] = {inst->groupmemb_attr,NULL};
707 VALUE_PAIR *vp_user_dn;
708 VALUE_PAIR **request_pairs;
710 request_pairs = &req->config_items;
712 DEBUG("rlm_ldap: Entering ldap_groupcmp()");
714 if (check->strvalue == NULL || check->length == 0){
715 DEBUG("rlm_ldap::ldap_groupcmp: Illegal group name");
720 DEBUG("rlm_ldap::ldap_groupcmp: NULL request");
724 if (!radius_xlat(basedn, sizeof(basedn), inst->basedn, req, NULL)) {
725 DEBUG("rlm_ldap::ldap_groupcmp: unable to create basedn.");
729 while((vp_user_dn = pairfind(*request_pairs, PW_LDAP_USERDN)) == NULL){
730 char *user_dn = NULL;
732 if (!radius_xlat(filter, sizeof(filter), inst->filter,
733 req, ldap_escape_func)){
734 DEBUG("rlm_ldap::ldap_groupcmp: unable to create filter");
737 if ((conn_id = ldap_get_conn(inst->conns,&conn,inst)) == -1){
738 radlog(L_ERR, "rlm_ldap: All ldap connections are in use");
741 if ((res = perform_search(inst, conn, basedn, LDAP_SCOPE_SUBTREE,
742 filter, attrs, &result)) != RLM_MODULE_OK){
743 DEBUG("rlm_ldap::ldap_groupcmp: search failed");
744 ldap_release_conn(conn_id,inst->conns);
747 if ((msg = ldap_first_entry(conn->ld, result)) == NULL) {
748 DEBUG("rlm_ldap::ldap_groupcmp: ldap_first_entry() failed");
749 ldap_release_conn(conn_id,inst->conns);
750 ldap_msgfree(result);
753 if ((user_dn = ldap_get_dn(conn->ld, msg)) == NULL) {
754 DEBUG("rlm_ldap:ldap_groupcmp:: ldap_get_dn() failed");
755 ldap_release_conn(conn_id,inst->conns);
756 ldap_msgfree(result);
759 ldap_release_conn(conn_id,inst->conns);
761 * Adding new attribute containing DN for LDAP object associated with
764 pairadd(request_pairs, pairmake("Ldap-UserDn", user_dn,
766 ldap_memfree(user_dn);
767 ldap_msgfree(result);
770 if(!radius_xlat(gr_filter, sizeof(gr_filter),
771 inst->groupmemb_filt, req, NULL)) {
772 DEBUG("rlm_ldap::ldap_groupcmp: unable to create filter.");
776 if (strchr((char *)check->strvalue,',') != NULL) {
777 /* This looks like a DN */
778 snprintf(filter,sizeof(filter), "%s",gr_filter);
779 snprintf(basedn,sizeof(basedn), "%s",(char *)check->strvalue);
781 snprintf(filter,sizeof(filter), "(&(%s=%s)%s)",
782 inst->groupname_attr,
783 (char *)check->strvalue,gr_filter);
785 if ((conn_id = ldap_get_conn(inst->conns,&conn,inst)) == -1) {
786 radlog(L_ERR, "rlm_ldap: All ldap connections are in use");
790 if ((res = perform_search(inst, conn, basedn, LDAP_SCOPE_SUBTREE,
791 filter, attrs, &result)) == RLM_MODULE_OK) {
792 DEBUG("rlm_ldap::ldap_groupcmp: User found in group %s",
793 (char *)check->strvalue);
794 ldap_msgfree(result);
795 ldap_release_conn(conn_id,inst->conns);
799 ldap_release_conn(conn_id,inst->conns);
801 if (res != RLM_MODULE_NOTFOUND ) {
802 DEBUG("rlm_ldap::ldap_groupcmp: Search returned error");
806 if (inst->groupmemb_attr == NULL){
807 /* search returned NOTFOUND and searching for membership
808 * using user object attributes is not specified in config
811 DEBUG("rlm_ldap::ldap_groupcmp: Group %s not found or user is not a member.",(char *)check->strvalue);
815 snprintf(filter,sizeof(filter), "(objectclass=*)");
816 if ((conn_id = ldap_get_conn(inst->conns,&conn,inst)) == -1){
817 radlog(L_ERR, "rlm_ldap: Add ldap connections are in use");
820 if ((res = perform_search(inst, conn, vp_user_dn->strvalue,
821 LDAP_SCOPE_BASE, filter, group_attrs,
822 &result)) != RLM_MODULE_OK) {
823 DEBUG("rlm_ldap::ldap_groupcmp: Search returned error");
824 ldap_release_conn(conn_id, inst->conns);
828 if ((msg = ldap_first_entry(conn->ld, result)) == NULL) {
829 DEBUG("rlm_ldap::ldap_groupcmp: ldap_first_entry() failed");
830 ldap_release_conn(conn_id,inst->conns);
831 ldap_msgfree(result);
834 if ((vals = ldap_get_values(conn->ld, msg,
835 inst->groupmemb_attr)) != NULL) {
839 for (;i < ldap_count_values(vals);i++){
840 if (strchr(vals[i],',') != NULL){
841 /* This looks like a DN */
842 LDAPMessage *gr_result = NULL;
843 snprintf(filter,sizeof(filter), "(%s=%s)",
844 inst->groupname_attr,
845 (char *)check->strvalue);
846 if ((res = perform_search(inst, conn, vals[i],
847 LDAP_SCOPE_BASE, filter,
848 attrs, &gr_result)) != RLM_MODULE_OK){
849 if (res != RLM_MODULE_NOTFOUND) {
850 DEBUG("rlm_ldap::ldap_groupcmp: Search returned error");
851 ldap_value_free(vals);
852 ldap_msgfree(result);
853 ldap_release_conn(conn_id,inst->conns);
857 ldap_msgfree(gr_result);
862 if (strcmp(vals[i],(char *)check->strvalue) == 0){
868 ldap_value_free(vals);
869 ldap_msgfree(result);
871 DEBUG("rlm_ldap::groupcmp: Group %s not found or user not a member",
872 (char *)check->strvalue);
873 ldap_release_conn(conn_id,inst->conns);
877 DEBUG("rlm_ldap::ldap_groupcmp: ldap_get_values() failed");
878 ldap_msgfree(result);
879 ldap_release_conn(conn_id,inst->conns);
883 DEBUG("rlm_ldap::ldap_groupcmp: User found in group %s",(char *)check->strvalue);
884 ldap_release_conn(conn_id,inst->conns);
891 * Do an xlat on an LDAP URL
894 static int ldap_xlat(void *instance, REQUEST *request, char *fmt, char *out, int freespace,
895 RADIUS_ESCAPE_STRING func)
897 char url[MAX_FILTER_STR_LEN];
900 ldap_instance *inst = instance;
901 LDAPURLDesc *ldap_url;
902 LDAPMessage *result = NULL;
903 LDAPMessage *msg = NULL;
908 DEBUG("rlm_ldap: - ldap_xlat");
909 if (!radius_xlat(url, sizeof(url), fmt, request, func)) {
910 radlog (L_ERR, "rlm_ldap: Unable to create LDAP URL.\n");
913 if (!ldap_is_ldap_url(url)){
914 radlog (L_ERR, "rlm_ldap: String passed does not look like an LDAP URL.\n");
917 if (ldap_url_parse(url,&ldap_url)){
918 radlog (L_ERR, "rlm_ldap: LDAP URL parse failed.\n");
921 if (ldap_url->lud_attrs == NULL || ldap_url->lud_attrs[0] == NULL ||
922 ( ldap_url->lud_attrs[1] != NULL ||
923 ( ! strlen(ldap_url->lud_attrs[0]) ||
924 ! strcmp(ldap_url->lud_attrs[0],"*") ) ) ){
925 radlog (L_ERR, "rlm_ldap: Invalid Attribute(s) request.\n");
926 ldap_free_urldesc(ldap_url);
929 if (ldap_url->lud_host){
930 if (strncmp(inst->server,ldap_url->lud_host,
931 strlen(inst->server)) != 0 ||
932 ldap_url->lud_port != inst->port) {
933 DEBUG("rlm_ldap: Requested server/port is not known to this module instance.");
934 ldap_free_urldesc(ldap_url);
938 if ((conn_id = ldap_get_conn(inst->conns,&conn,inst)) == -1){
939 radlog(L_ERR, "rlm_ldap: All ldap connections are in use");
940 ldap_free_urldesc(ldap_url);
943 if ((res = perform_search(inst, conn, ldap_url->lud_dn, ldap_url->lud_scope, ldap_url->lud_filter, ldap_url->lud_attrs, &result)) != RLM_MODULE_OK){
944 if (res == RLM_MODULE_NOTFOUND){
945 DEBUG("rlm_ldap: Search returned not found");
946 ldap_free_urldesc(ldap_url);
947 ldap_release_conn(conn_id,inst->conns);
950 DEBUG("rlm_ldap: Search returned error");
951 ldap_free_urldesc(ldap_url);
952 ldap_release_conn(conn_id,inst->conns);
955 if ((msg = ldap_first_entry(conn->ld, result)) == NULL){
956 DEBUG("rlm_ldap: ldap_first_entry() failed");
957 ldap_msgfree(result);
958 ldap_free_urldesc(ldap_url);
959 ldap_release_conn(conn_id,inst->conns);
962 if ((vals = ldap_get_values(conn->ld, msg, ldap_url->lud_attrs[0])) != NULL) {
963 ret = strlen(vals[0]);
964 if (ret > freespace){
965 DEBUG("rlm_ldap: Insufficient string space");
966 ldap_free_urldesc(ldap_url);
967 ldap_value_free(vals);
968 ldap_msgfree(result);
969 ldap_release_conn(conn_id,inst->conns);
972 DEBUG("rlm_ldap: Adding attribute %s, value: %s",ldap_url->lud_attrs[0],vals[0]);
973 strncpy(out,vals[0],ret);
974 ldap_value_free(vals);
979 ldap_msgfree(result);
980 ldap_free_urldesc(ldap_url);
981 ldap_release_conn(conn_id,inst->conns);
983 DEBUG("rlm_ldap: - ldap_xlat end");
989 /******************************************************************************
991 * Function: rlm_ldap_authorize
993 * Purpose: Check if user is authorized for remote access
995 ******************************************************************************/
997 ldap_authorize(void *instance, REQUEST * request)
999 LDAPMessage *result = NULL;
1000 LDAPMessage *msg = NULL;
1001 LDAPMessage *def_msg = NULL;
1002 LDAPMessage *def_attr_msg = NULL;
1003 LDAPMessage *def_result = NULL;
1004 LDAPMessage *def_attr_result = NULL;
1005 ldap_instance *inst = instance;
1006 char *user_dn = NULL;
1007 char filter[MAX_FILTER_STR_LEN];
1008 char basedn[MAX_FILTER_STR_LEN];
1009 VALUE_PAIR *check_tmp;
1010 VALUE_PAIR *reply_tmp;
1012 VALUE_PAIR **check_pairs, **reply_pairs;
1014 VALUE_PAIR *module_fmsg_vp;
1015 VALUE_PAIR *user_profile;
1016 char module_fmsg[MAX_STRING_LEN];
1020 DEBUG("rlm_ldap: - authorize");
1022 if (!request->username){
1023 radlog(L_AUTH, "rlm_ldap: Attribute \"User-Name\" is required for authentication.\n");
1024 return RLM_MODULE_INVALID;
1027 check_pairs = &request->config_items;
1028 reply_pairs = &request->reply->vps;
1031 * Check for valid input, zero length names not permitted
1033 if (request->username->strvalue == 0) {
1034 radlog(L_ERR, "rlm_ldap: zero length username not permitted\n");
1035 return RLM_MODULE_INVALID;
1037 DEBUG("rlm_ldap: performing user authorization for %s",
1038 request->username->strvalue);
1040 if (!radius_xlat(filter, sizeof(filter), inst->filter,
1041 request, ldap_escape_func)) {
1042 radlog (L_ERR, "rlm_ldap: unable to create filter.\n");
1043 return RLM_MODULE_INVALID;
1046 if (!radius_xlat(basedn, sizeof(basedn), inst->basedn,
1048 radlog (L_ERR, "rlm_ldap: unable to create basedn.\n");
1049 return RLM_MODULE_INVALID;
1052 if ((conn_id = ldap_get_conn(inst->conns,&conn,inst)) == -1){
1053 radlog(L_ERR, "rlm_ldap: All ldap connections are in use");
1054 return RLM_MODULE_FAIL;
1056 if ((res = perform_search(instance, conn, basedn, LDAP_SCOPE_SUBTREE, filter, inst->atts, &result)) != RLM_MODULE_OK) {
1057 DEBUG("rlm_ldap: search failed");
1058 if (res == RLM_MODULE_NOTFOUND){
1059 snprintf(module_fmsg,sizeof(module_fmsg),"rlm_ldap: User not found");
1060 module_fmsg_vp = pairmake("Module-Failure-Message", module_fmsg, T_OP_EQ);
1061 pairadd(&request->packet->vps, module_fmsg_vp);
1063 ldap_release_conn(conn_id,inst->conns);
1066 if ((msg = ldap_first_entry(conn->ld, result)) == NULL) {
1067 DEBUG("rlm_ldap: ldap_first_entry() failed");
1068 ldap_msgfree(result);
1069 ldap_release_conn(conn_id,inst->conns);
1070 return RLM_MODULE_FAIL;
1072 if ((user_dn = ldap_get_dn(conn->ld, msg)) == NULL) {
1073 DEBUG("rlm_ldap: ldap_get_dn() failed");
1074 ldap_msgfree(result);
1075 ldap_release_conn(conn_id,inst->conns);
1076 return RLM_MODULE_FAIL;
1079 * Adding new attribute containing DN for LDAP object associated with
1082 pairadd(check_pairs, pairmake("Ldap-UserDn", user_dn, T_OP_EQ));
1083 ldap_memfree(user_dn);
1086 /* Remote access is controled by attribute of the user object */
1087 if (inst->access_attr) {
1088 if ((vals = ldap_get_values(conn->ld, msg, inst->access_attr)) != NULL) {
1089 if (inst->default_allow){
1090 DEBUG("rlm_ldap: checking if remote access for %s is allowed by %s", request->username->strvalue, inst->access_attr);
1091 if (!strncmp(vals[0], "FALSE", 5)) {
1092 DEBUG("rlm_ldap: dialup access disabled");
1093 snprintf(module_fmsg,sizeof(module_fmsg),"rlm_ldap: Access Attribute denies access");
1094 module_fmsg_vp = pairmake("Module-Failure-Message", module_fmsg, T_OP_EQ);
1095 pairadd(&request->packet->vps, module_fmsg_vp);
1096 ldap_msgfree(result);
1097 ldap_value_free(vals);
1098 ldap_release_conn(conn_id,inst->conns);
1099 return RLM_MODULE_USERLOCK;
1101 ldap_value_free(vals);
1104 DEBUG("rlm_ldap: %s attribute exists - access denied by default", inst->access_attr);
1105 snprintf(module_fmsg,sizeof(module_fmsg),"rlm_ldap: Access Attribute denies access");
1106 module_fmsg_vp = pairmake("Module-Failure-Message", module_fmsg, T_OP_EQ);
1107 pairadd(&request->packet->vps, module_fmsg_vp);
1108 ldap_msgfree(result);
1109 ldap_value_free(vals);
1110 ldap_release_conn(conn_id,inst->conns);
1111 return RLM_MODULE_USERLOCK;
1114 if (inst->default_allow){
1115 DEBUG("rlm_ldap: no %s attribute - access denied by default", inst->access_attr);
1116 snprintf(module_fmsg,sizeof(module_fmsg),"rlm_ldap: Access Attribute denies access");
1117 module_fmsg_vp = pairmake("Module-Failure-Message", module_fmsg, T_OP_EQ);
1118 pairadd(&request->packet->vps, module_fmsg_vp);
1119 ldap_msgfree(result);
1120 ldap_release_conn(conn_id,inst->conns);
1121 return RLM_MODULE_USERLOCK;
1127 * Check for the default profile entry. If it exists then add the
1128 * attributes it contains in the check and reply pairs
1131 user_profile = pairfind(request->config_items, PW_USER_PROFILE);
1132 if (inst->default_profile || user_profile){
1133 char *profile = inst->default_profile;
1135 strNcpy(filter,inst->base_filter,sizeof(filter));
1137 profile = user_profile->strvalue;
1138 if (profile && strlen(profile)){
1139 if ((res = perform_search(instance, conn,
1140 profile, LDAP_SCOPE_BASE,
1141 filter, inst->atts, &def_result)) == RLM_MODULE_OK){
1142 if ((def_msg = ldap_first_entry(conn->ld,def_result))){
1143 if ((check_tmp = ldap_pairget(conn->ld,def_msg,inst->check_item_map,check_pairs,1))) {
1145 pairxlatmove(request, check_pairs, &check_tmp);
1146 pairfree(&check_tmp);
1149 pairadd(check_pairs,check_tmp);
1151 if ((reply_tmp = ldap_pairget(conn->ld,def_msg,inst->reply_item_map,reply_pairs,0))) {
1153 pairxlatmove(request, reply_pairs, &reply_tmp);
1154 pairfree(&reply_tmp);
1157 pairadd(reply_pairs,reply_tmp);
1160 ldap_msgfree(def_result);
1162 DEBUG("rlm_ldap: default_profile/user-profile search failed");
1167 * Check for the profile attribute. If it exists, we assume that it
1168 * contains the DN of an entry containg a profile for the user. That
1169 * way we can have different general profiles for various user groups
1170 * (students,faculty,staff etc)
1173 if (inst->profile_attr){
1174 if ((vals = ldap_get_values(conn->ld, msg, inst->profile_attr)) != NULL) {
1176 strNcpy(filter,inst->base_filter,sizeof(filter));
1177 while(vals[i] != NULL && strlen(vals[i])){
1178 if ((res = perform_search(instance, conn,
1179 vals[i], LDAP_SCOPE_BASE,
1180 filter, inst->atts, &def_attr_result)) == RLM_MODULE_OK){
1181 if ((def_attr_msg = ldap_first_entry(conn->ld,def_attr_result))){
1182 if ((check_tmp = ldap_pairget(conn->ld,def_attr_msg,inst->check_item_map,check_pairs,1))) {
1184 pairxlatmove(request, check_pairs, &check_tmp);
1185 pairfree(&check_tmp);
1188 pairadd(check_pairs,check_tmp);
1190 if ((reply_tmp = ldap_pairget(conn->ld,def_attr_msg,inst->reply_item_map,reply_pairs,0))) {
1192 pairxlatmove(request, reply_pairs, &reply_tmp);
1193 pairfree(&reply_tmp);
1196 pairadd(reply_pairs,reply_tmp);
1199 ldap_msgfree(def_attr_result);
1201 DEBUG("rlm_ldap: profile_attribute search failed");
1204 ldap_value_free(vals);
1207 if (inst->passwd_attr && strlen(inst->passwd_attr)){
1208 VALUE_PAIR *passwd_item;
1210 if ((passwd_item = pairfind(request->config_items, PW_PASSWORD)) == NULL){
1212 char *passwd_val = NULL;
1215 if ((passwd_vals = ldap_get_values(conn->ld,msg,inst->passwd_attr)) != NULL){
1217 while(passwd_vals[i] != NULL){
1218 if (strlen(passwd_vals[i])){
1219 passwd_val = passwd_vals[i];
1221 if (inst->passwd_hdr && strlen(inst->passwd_hdr)){
1222 passwd_val = strstr(passwd_val,inst->passwd_hdr);
1223 if (passwd_val != NULL)
1224 passwd_val += strlen(inst->passwd_hdr);
1226 DEBUG("rlm_ldap: Password header not found in password %s for user %s", passwd_vals[0],request->username->strvalue);
1229 if ((passwd_item = paircreate(PW_PASSWORD,PW_TYPE_STRING)) == NULL){
1230 radlog(L_ERR|L_CONS, "no memory");
1231 ldap_value_free(passwd_vals);
1232 ldap_msgfree(result);
1233 ldap_release_conn(conn_id,inst->conns);
1234 return RLM_MODULE_FAIL;
1236 passwd_len = strlen(passwd_val);
1237 strncpy(passwd_item->strvalue,passwd_val,MAX_STRING_LEN - 1);
1238 passwd_item->length = (passwd_len > (MAX_STRING_LEN - 1)) ? (MAX_STRING_LEN - 1) : passwd_len;
1239 pairadd(&request->config_items,passwd_item);
1240 DEBUG("rlm_ldap: Added password %s in check items",passwd_item->strvalue);
1245 ldap_value_free(passwd_vals);
1252 DEBUG("rlm_ldap: looking for check items in directory...");
1254 if ((check_tmp = ldap_pairget(conn->ld, msg, inst->check_item_map,check_pairs,1)) != NULL) {
1256 pairxlatmove(request, check_pairs, &check_tmp);
1257 pairfree(&check_tmp);
1260 pairadd(check_pairs,check_tmp);
1264 DEBUG("rlm_ldap: looking for reply items in directory...");
1267 if ((reply_tmp = ldap_pairget(conn->ld, msg, inst->reply_item_map,reply_pairs,0)) != NULL) {
1269 pairxlatmove(request, reply_pairs, &reply_tmp);
1270 pairfree(&reply_tmp);
1273 pairadd(reply_pairs,reply_tmp);
1276 if (inst->do_comp && paircmp(request,request->packet->vps,*check_pairs,reply_pairs) != 0){
1277 DEBUG("rlm_ldap: Pairs do not match. Rejecting user.");
1278 snprintf(module_fmsg,sizeof(module_fmsg),"rlm_ldap: Pairs do not match");
1279 module_fmsg_vp = pairmake("Module-Failure-Message", module_fmsg, T_OP_EQ);
1280 pairadd(&request->packet->vps, module_fmsg_vp);
1281 ldap_msgfree(result);
1282 ldap_release_conn(conn_id,inst->conns);
1284 return RLM_MODULE_REJECT;
1288 * Module should default to LDAP authentication if no Auth-Type
1291 if ((pairfind(*check_pairs, PW_AUTH_TYPE) == NULL) &&
1292 request->password &&
1293 (request->password->attribute == PW_USER_PASSWORD))
1294 pairadd(check_pairs, pairmake("Auth-Type", "LDAP", T_OP_EQ));
1297 DEBUG("rlm_ldap: user %s authorized to use remote access",
1298 request->username->strvalue);
1299 ldap_msgfree(result);
1300 ldap_release_conn(conn_id,inst->conns);
1302 return RLM_MODULE_OK;
1305 /*****************************************************************************
1307 * Function: rlm_ldap_authenticate
1309 * Purpose: Check the user's password against ldap database
1311 *****************************************************************************/
1313 ldap_authenticate(void *instance, REQUEST * request)
1316 LDAPMessage *result, *msg;
1317 ldap_instance *inst = instance;
1318 char *user_dn, *attrs[] = {"uid", NULL};
1319 char filter[MAX_FILTER_STR_LEN];
1320 char basedn[MAX_FILTER_STR_LEN];
1322 VALUE_PAIR *vp_user_dn;
1323 VALUE_PAIR *module_fmsg_vp;
1324 char module_fmsg[MAX_STRING_LEN];
1328 DEBUG("rlm_ldap: - authenticate");
1331 * Ensure that we're being passed a plain-text password, and not
1335 if (!request->username) {
1336 radlog(L_AUTH, "rlm_ldap: Attribute \"User-Name\" is required for authentication.\n");
1337 return RLM_MODULE_INVALID;
1340 if (!request->password){
1341 radlog(L_AUTH, "rlm_ldap: Attribute \"User-Password\" is required for authentication.");
1342 DEBUG2(" You seem to have set \"Auth-Type := LDAP\" somewhere.");
1343 DEBUG2(" THAT CONFIGURATION IS WRONG. DELETE IT.");
1344 DEBUG2(" YOU ARE PREVENTING THE SERVER FROM WORKING PROPERLY.");
1345 return RLM_MODULE_INVALID;
1348 if(request->password->attribute != PW_PASSWORD) {
1349 radlog(L_AUTH, "rlm_ldap: Attribute \"User-Password\" is required for authentication. Cannot use \"%s\".", request->password->name);
1350 return RLM_MODULE_INVALID;
1353 if (request->password->length == 0) {
1354 snprintf(module_fmsg,sizeof(module_fmsg),"rlm_ldap: empty password supplied");
1355 module_fmsg_vp = pairmake("Module-Failure-Message", module_fmsg, T_OP_EQ);
1356 pairadd(&request->packet->vps, module_fmsg_vp);
1357 return RLM_MODULE_INVALID;
1361 * Check that we don't have any failed connections. If we do there's no real need
1362 * of runing. Also give it another chance if we have a lot of failed connections.
1364 if (inst->failed_conns > MAX_FAILED_CONNS_END)
1365 inst->failed_conns = 0;
1366 if (inst->failed_conns > MAX_FAILED_CONNS_START){
1367 inst->failed_conns++;
1368 return RLM_MODULE_FAIL;
1372 DEBUG("rlm_ldap: login attempt by \"%s\" with password \"%s\"",
1373 request->username->strvalue, request->password->strvalue);
1375 while ((vp_user_dn = pairfind(request->config_items,
1376 PW_LDAP_USERDN)) == NULL) {
1377 if (!radius_xlat(filter, sizeof(filter), inst->filter,
1379 radlog (L_ERR, "rlm_ldap: unable to create filter.\n");
1380 return RLM_MODULE_INVALID;
1383 if (!radius_xlat(basedn, sizeof(basedn), inst->basedn,
1385 radlog (L_ERR, "rlm_ldap: unable to create basedn.\n");
1386 return RLM_MODULE_INVALID;
1389 if ((conn_id = ldap_get_conn(inst->conns,&conn,inst)) == -1){
1390 radlog(L_ERR, "rlm_ldap: All ldap connections are in use");
1391 return RLM_MODULE_FAIL;
1393 if ((res = perform_search(instance, conn, basedn, LDAP_SCOPE_SUBTREE, filter, attrs, &result)) != RLM_MODULE_OK) {
1394 if (res == RLM_MODULE_NOTFOUND){
1395 snprintf(module_fmsg,sizeof(module_fmsg),"rlm_ldap: User not found");
1396 module_fmsg_vp = pairmake("Module-Failure-Message", module_fmsg, T_OP_EQ);
1397 pairadd(&request->packet->vps, module_fmsg_vp);
1399 ldap_release_conn(conn_id,inst->conns);
1402 if ((msg = ldap_first_entry(conn->ld, result)) == NULL) {
1403 ldap_msgfree(result);
1404 ldap_release_conn(conn_id,inst->conns);
1405 return RLM_MODULE_FAIL;
1407 if ((user_dn = ldap_get_dn(conn->ld, msg)) == NULL) {
1408 DEBUG("rlm_ldap: ldap_get_dn() failed");
1409 ldap_msgfree(result);
1410 ldap_release_conn(conn_id,inst->conns);
1411 return RLM_MODULE_FAIL;
1413 ldap_release_conn(conn_id,inst->conns);
1414 pairadd(&request->config_items, pairmake("Ldap-UserDn", user_dn, T_OP_EQ));
1415 ldap_memfree(user_dn);
1416 ldap_msgfree(result);
1419 user_dn = vp_user_dn->strvalue;
1421 DEBUG("rlm_ldap: user DN: %s", user_dn);
1423 ld_user = ldap_connect(instance, user_dn, request->password->strvalue,
1425 if (ld_user == NULL){
1426 if (res == RLM_MODULE_REJECT){
1427 inst->failed_conns = 0;
1428 snprintf(module_fmsg,sizeof(module_fmsg),"rlm_ldap: Bind as user failed");
1429 module_fmsg_vp = pairmake("Module-Failure-Message", module_fmsg, T_OP_EQ);
1430 pairadd(&request->packet->vps, module_fmsg_vp);
1432 if (res == RLM_MODULE_FAIL){
1433 DEBUG("rlm_ldap: ldap_connect() failed");
1434 inst->failed_conns++;
1439 DEBUG("rlm_ldap: user %s authenticated succesfully",
1440 request->username->strvalue);
1441 ldap_unbind_s(ld_user);
1442 inst->failed_conns = 0;
1444 return RLM_MODULE_OK;
1448 ldap_connect(void *instance, const char *dn, const char *password, int auth, int *result)
1450 ldap_instance *inst = instance;
1452 int msgid, rc, ldap_version;
1457 #ifdef HAVE_LDAP_INITIALIZE
1458 DEBUG("rlm_ldap: (re)connect to %s, authentication %d", inst->server, auth);
1459 if (ldap_initialize(&ld, inst->server) != LDAP_SUCCESS) {
1460 radlog(L_ERR, "rlm_ldap: ldap_initialize() failed");
1461 *result = RLM_MODULE_FAIL;
1466 DEBUG("rlm_ldap: (re)connect to %s:%d, authentication %d", inst->server, inst->port, auth);
1467 if ((ld = ldap_init(inst->server, inst->port)) == NULL) {
1468 radlog(L_ERR, "rlm_ldap: ldap_init() failed");
1469 *result = RLM_MODULE_FAIL;
1473 if (ldap_set_option(ld, LDAP_OPT_NETWORK_TIMEOUT,
1474 (void *) &(inst->net_timeout)) != LDAP_OPT_SUCCESS) {
1475 radlog(L_ERR, "rlm_ldap: Could not set LDAP_OPT_NETWORK_TIMEOUT %ld.%ld", inst->net_timeout.tv_sec, inst->net_timeout.tv_usec);
1478 if (ldap_set_option(ld, LDAP_OPT_TIMELIMIT, (void *) &(inst->timelimit)) != LDAP_OPT_SUCCESS) {
1479 radlog(L_ERR, "rlm_ldap: Could not set LDAP_OPT_TIMELIMIT %d", inst->timelimit);
1482 if (inst->ldap_debug && ldap_set_option(NULL, LDAP_OPT_DEBUG_LEVEL, &(inst->ldap_debug)) != LDAP_OPT_SUCCESS) {
1483 radlog(L_ERR, "rlm_ldap: Could not set LDAP_OPT_DEBUG_LEVEL %d", inst->ldap_debug);
1486 ldap_version = LDAP_VERSION3;
1487 if (ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, &ldap_version) != LDAP_OPT_SUCCESS) {
1488 radlog(L_ERR, "rlm_ldap: Could not set LDAP version to V3");
1491 #ifdef HAVE_LDAP_START_TLS
1492 if(inst->tls_mode) {
1493 DEBUG("rlm_ldap: setting TLS mode to %d", inst->tls_mode);
1494 if(ldap_set_option(ld, LDAP_OPT_X_TLS,
1495 (void *) &(inst->tls_mode)) != LDAP_OPT_SUCCESS) {
1496 ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &ldap_errno);
1497 radlog(L_ERR, "rlm_ldap: could not set LDAP_OPT_X_TLS option %s", ldap_err2string(ldap_errno));
1501 if(inst->tls_cacertfile != NULL) {
1502 DEBUG("rlm_ldap: setting TLS CACert File to %s", inst->tls_cacertfile);
1504 if ( ldap_set_option( NULL, LDAP_OPT_X_TLS_CACERTFILE,
1505 (void *) inst->tls_cacertfile )
1506 != LDAP_OPT_SUCCESS) {
1507 radlog(L_ERR, "rlm_ldap: could not set "
1508 "LDAP_OPT_X_TLS_CACERTFILE option to %s", inst->tls_cacertfile);
1512 if(inst->tls_cacertdir != NULL) {
1513 DEBUG("rlm_ldap: setting TLS CACert File to %s", inst->tls_cacertdir);
1515 if ( ldap_set_option( NULL, LDAP_OPT_X_TLS_CACERTDIR,
1516 (void *) inst->tls_cacertdir )
1517 != LDAP_OPT_SUCCESS) {
1518 radlog(L_ERR, "rlm_ldap: could not set "
1519 "LDAP_OPT_X_TLS_CACERTDIR option to %s", inst->tls_cacertdir);
1523 if( strcmp( TLS_DEFAULT_VERIFY, inst->tls_require_cert ) != 0 ) {
1524 DEBUG("rlm_ldap: setting TLS Require Cert to %s",
1525 inst->tls_require_cert);
1529 #ifdef HAVE_INT_TLS_CONFIG
1530 if ( ldap_int_tls_config( NULL, LDAP_OPT_X_TLS_REQUIRE_CERT,
1531 (inst->tls_require_cert) )
1532 != LDAP_OPT_SUCCESS) {
1533 radlog(L_ERR, "rlm_ldap: could not set "
1534 "LDAP_OPT_X_TLS_REQUIRE_CERT option to %s",
1535 inst->tls_require_cert);
1539 if(inst->tls_certfile != NULL) {
1540 DEBUG("rlm_ldap: setting TLS Cert File to %s", inst->tls_certfile);
1542 if ( ldap_set_option( NULL, LDAP_OPT_X_TLS_CERTFILE,
1543 (void *) inst->tls_certfile )
1544 != LDAP_OPT_SUCCESS) {
1545 radlog(L_ERR, "rlm_ldap: could not set "
1546 "LDAP_OPT_X_TLS_CERTFILE option to %s",
1547 inst->tls_certfile);
1551 if (inst->tls_keyfile != NULL) {
1552 DEBUG("rlm_ldap: setting TLS Key File to %s",
1555 if ( ldap_set_option( NULL, LDAP_OPT_X_TLS_KEYFILE,
1556 (void *) inst->tls_keyfile )
1557 != LDAP_OPT_SUCCESS) {
1558 radlog(L_ERR, "rlm_ldap: could not set "
1559 "LDAP_OPT_X_TLS_KEYFILE option to %s",
1564 if (inst->tls_randfile != NULL) {
1565 DEBUG("rlm_ldap: setting TLS Key File to %s",
1566 inst->tls_randfile);
1568 if (ldap_set_option( NULL, LDAP_OPT_X_TLS_RANDOM_FILE,
1569 (void *) inst->tls_randfile)
1570 != LDAP_OPT_SUCCESS) {
1571 radlog(L_ERR, "rlm_ldap: could not set "
1572 "LDAP_OPT_X_TLS_RANDOM_FILE option to %s",
1573 inst->tls_randfile);
1577 if (inst->start_tls) {
1578 DEBUG("rlm_ldap: starting TLS");
1579 rc = ldap_start_tls_s(ld, NULL, NULL);
1580 if (rc != LDAP_SUCCESS) {
1581 DEBUG("rlm_ldap: ldap_start_tls_s()");
1582 ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER,
1584 radlog(L_ERR, "rlm_ldap: could not start TLS %s",
1585 ldap_err2string(ldap_errno));
1586 *result = RLM_MODULE_FAIL;
1591 #endif /* HAVE_LDAP_START_TLS */
1594 DEBUG("rlm_ldap: bind as %s/%s to %s",
1595 dn, password, inst->server);
1597 DEBUG("rlm_ldap: bind as %s/%s to %s:%d",
1598 dn, password, inst->server, inst->port);
1601 msgid = ldap_bind(ld, dn, password,LDAP_AUTH_SIMPLE);
1603 ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &ldap_errno);
1605 radlog(L_ERR, "rlm_ldap: %s bind to %s failed: %s",
1606 dn, inst->server, ldap_err2string(ldap_errno));
1608 radlog(L_ERR, "rlm_ldap: %s bind to %s:%d failed: %s",
1609 dn, inst->server, inst->port,
1610 ldap_err2string(ldap_errno));
1612 *result = RLM_MODULE_FAIL;
1616 DEBUG("rlm_ldap: waiting for bind result ...");
1618 rc = ldap_result(ld, msgid, 1, &(inst->timeout), &res);
1621 DEBUG("rlm_ldap: ldap_result()");
1622 ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &ldap_errno);
1624 radlog(L_ERR, "rlm_ldap: %s bind to %s failed: %s",
1625 dn, inst->server, (rc == 0) ? "timeout" : ldap_err2string(ldap_errno));
1627 radlog(L_ERR, "rlm_ldap: %s bind to %s:%d failed: %s",
1628 dn, inst->server, inst->port,
1629 (rc == 0) ? "timeout" : ldap_err2string(ldap_errno));
1631 *result = RLM_MODULE_FAIL;
1636 ldap_errno = ldap_result2error(ld, res, 1);
1637 switch (ldap_errno) {
1639 DEBUG("rlm_ldap: Bind was successful");
1640 *result = RLM_MODULE_OK;
1643 case LDAP_INVALID_CREDENTIALS:
1645 DEBUG("rlm_ldap: Bind failed with invalid credentials");
1646 *result = RLM_MODULE_REJECT;
1648 radlog(L_ERR, "rlm_ldap: LDAP login failed: check identity, password settings in ldap section of radiusd.conf");
1649 *result = RLM_MODULE_FAIL;
1655 radlog(L_ERR,"rlm_ldap: %s bind to %s failed %s",
1656 dn, inst->server, ldap_err2string(ldap_errno));
1658 radlog(L_ERR,"rlm_ldap: %s bind to %s:%d failed %s",
1659 dn, inst->server, inst->port,
1660 ldap_err2string(ldap_errno));
1662 *result = RLM_MODULE_FAIL;
1665 if (*result != RLM_MODULE_OK) {
1672 /*****************************************************************************
1674 * Detach from the LDAP server and cleanup internal state.
1676 *****************************************************************************/
1678 ldap_detach(void *instance)
1680 ldap_instance *inst = instance;
1681 TLDAP_RADIUS *pair, *nextpair;
1684 free((char *) inst->server);
1686 free((char *) inst->login);
1688 free((char *) inst->password);
1690 free((char *) inst->basedn);
1691 if (inst->dictionary_mapping)
1692 free(inst->dictionary_mapping);
1694 free((char *) inst->filter);
1695 if (inst->base_filter)
1696 free((char *) inst->base_filter);
1697 if (inst->passwd_hdr)
1698 free((char *) inst->passwd_hdr);
1699 if (inst->passwd_attr)
1700 free((char *) inst->passwd_attr);
1701 if (inst->groupname_attr)
1702 free((char *) inst->groupname_attr);
1703 if (inst->groupmemb_filt)
1704 free((char *) inst->groupmemb_filt);
1705 if (inst->groupmemb_attr)
1706 free((char *) inst->groupmemb_attr);
1707 if (inst->access_attr)
1708 free((char *) inst->access_attr);
1709 if (inst->profile_attr)
1710 free((char *) inst->profile_attr);
1715 for(i = 0;i < inst->num_conns; i++){
1716 if (inst->conns[i].ld){
1717 ldap_unbind_s(inst->conns[i].ld);
1719 pthread_mutex_destroy(&inst->conns[i].mutex);
1724 pair = inst->check_item_map;
1726 while (pair != NULL) {
1727 nextpair = pair->next;
1729 free(pair->radius_attr);
1734 pair = inst->reply_item_map;
1736 while (pair != NULL) {
1737 nextpair = pair->next;
1739 free(pair->radius_attr);
1747 paircompare_unregister(PW_LDAP_GROUP, ldap_groupcmp);
1748 xlat_unregister(inst->xlat_name,ldap_xlat);
1749 free(inst->xlat_name);
1758 fieldcpy(char *string, char **uptr)
1763 while (*ptr == ' ' || *ptr == '\t') {
1768 while (*ptr != '"' && *ptr != '\0' && *ptr != '\n') {
1778 while (*ptr != ' ' && *ptr != '\t' && *ptr != '\0' && *ptr != '\n' &&
1779 *ptr != '=' && *ptr != ',') {
1787 /*****************************************************************************
1788 * Get RADIUS attributes from LDAP object
1789 * ( according to draft-adoba-radius-05.txt
1790 * <http://www.ietf.org/internet-drafts/draft-adoba-radius-05.txt> )
1792 *****************************************************************************/
1795 ldap_pairget(LDAP * ld, LDAPMessage * entry,
1796 TLDAP_RADIUS * item_map, VALUE_PAIR **pairs,char is_check)
1802 TLDAP_RADIUS *element;
1804 int is_generic_attribute;
1806 VALUE_PAIR *pairlist = NULL;
1807 VALUE_PAIR *newpair = NULL;
1809 /* check if there is a mapping from this LDAP attribute to a RADIUS attribute */
1810 for (element = item_map; element != NULL; element = element->next) {
1811 if ((vals = ldap_get_values(ld,entry,element->attr)) != NULL) {
1812 /* check whether this is a one-to-one-mapped ldap attribute or a generic
1813 attribute and set flag accordingly */
1815 if (strcasecmp(element->radius_attr, GENERIC_ATTRIBUTE_ID)==0)
1816 is_generic_attribute = 1;
1818 is_generic_attribute = 0;
1820 /* find out how many values there are for the attribute and extract all of them */
1822 vals_count = ldap_count_values(vals);
1824 for (vals_idx = 0; vals_idx < vals_count; vals_idx++) {
1825 ptr = vals[vals_idx];
1827 if (is_generic_attribute) {
1828 /* this is a generic attribute */
1829 LRAD_TOKEN dummy; /* makes pairread happy */
1831 /* not sure if using pairread here is ok ... */
1832 if ( (newpair = pairread(&ptr, &dummy)) != NULL) {
1833 DEBUG("rlm_ldap: extracted attribute %s from generic item %s",
1834 newpair->name, vals[vals_idx]);
1835 pairadd(&pairlist, newpair);
1837 radlog(L_ERR, "rlm_ldap: parsing %s failed: %s",
1838 element->attr, vals[vals_idx]);
1841 /* this is a one-to-one-mapped attribute */
1842 token = gettoken(&ptr, value, sizeof(value) - 1);
1843 if (token < T_EQSTART || token > T_EQEND) {
1845 token = T_OP_CMP_EQ;
1850 if (element->operator != T_INVALID) {
1851 token = element->operator;
1854 gettoken(&ptr, value, sizeof(value) - 1);
1856 if (value[0] == 0) {
1857 DEBUG("rlm_ldap: Attribute %s has no value", element->attr);
1860 DEBUG("rlm_ldap: Adding %s as %s, value %s & op=%d", element->attr, element->radius_attr, value, token);
1861 if ((newpair = pairmake(element->radius_attr, value, token)) == NULL)
1864 pairdelete(pairs,newpair->attribute);
1866 pairadd(&pairlist, newpair);
1869 ldap_value_free(vals);
1876 /* globally exported name */
1877 module_t rlm_ldap = {
1879 RLM_TYPE_THREAD_SAFE, /* type: reserved */
1880 NULL, /* initialization */
1881 ldap_instantiate, /* instantiation */
1883 ldap_authenticate, /* authentication */
1884 ldap_authorize, /* authorization */
1885 NULL, /* preaccounting */
1886 NULL, /* accounting */
1887 NULL, /* checksimul */
1888 NULL, /* pre-proxy */
1889 NULL, /* post-proxy */
1890 NULL /* post-auth */
1892 ldap_detach, /* detach */