* Add support for group membership attribute inside the user entry in ldap_groupcmp...
[freeradius.git] / src / modules / rlm_ldap / rlm_ldap.c
1 /*
2  * rlm_ldap.c LDAP authorization and authentication module.
3  * 
4  * 
5  * This module is based on LDAP patch to Cistron radiusd by James Golovich 
6  * <james@wwnet.net>, which in turn was based mostly on a Mysql+Cistron patch 
7  * from <oyarzun@wilmington.net>
8  * 
9  * 17 Jan 2000, Adrian Pavlykevych <pam@polynet.lviv.ua>
10  *      - OpenLDAP SDK porting, basic TLS support, LDAP authorization,
11  *        fault tolerance with multiple LDAP server support 
12  * 24 May 2000, Adrian Pavlykevych <pam@polynet.lviv.ua> 
13  *      - Converting to new configuration file format, futher improvements
14  *        in fault tolerance, threaded operation
15  * 12 Dec 2000, Adrian Pavlykevych <pam@polynet.lviv.ua> 
16  *      - Added preliminary support for multiple instances
17  *      - moved all instance configuration into dynamicly allocated structure
18  *      - Removed connection maintenance thread and all attempts for multihreading
19  *        the module itself. OpenLDAP SDK is not thread safe when used with shared
20  *        LDAP connection.
21  *      - Added configuration option for defining LDAP attribute of user object,
22  *        which controls remote access.
23  * 16 Feb 2001, Hannu Laurila <hannu.laurila@japo.fi>
24  *      - LDAP<->RADIUS attribute mappings are now read from a file
25  *      - Support for generic RADIUS check and reply attribute.
26  * Jun 2001, Kostas Kalevras <kkalev@noc.ntua.gr>
27  *      - Fix: check and reply attributes from LDAP _replace_ existing ones
28  *      - Added "default_profile" directive, which points to radiusProfile 
29  *        object, which contains default values for RADIUS users
30  *      - Added "profile_attribute" directive, which specifies user object 
31  *        attribute pointing to radiusProfile object.
32  * Nov 2001, Kostas Kalevras <kkalev@noc.ntua.gr>
33  *      - Added support for adding the user password to the check. Based on
34  *        the password_header directive rlm_ldap will strip the
35  *        password header if needed. This will make support for CHAP much easier.
36  *      - Added module messages when we reject a user.
37  *      - Added ldap_groupcmp to allow searching for user group membership.
38  *      - Added ldap_xlat to allow ldap urls in xlat strings. Something like:
39  *        %{ldap:ldap:///dc=company,dc=com?cn?sub?uid=user}
40  * Nov 2001, Gordon Tetlow <gordont@gnf.org>
41  *      - Do an xlat on the access_group attribute.
42  * Dec 2001, Kostas Kalevras <kkalev@noc.ntua.gr>
43  *      - Added ldap caching for the default/regular profiles and group entries.
44  *      - Fixed a memory leak in ldap_xlat.
45  *      - Removed dict_attrbyname from ldap_pairget. They are not needed.
46  *      - Moved the radius_xlat's for filter and basedn in ldap_authenticate() to
47  *        the right place.
48  *      - Made the module thread safe. We create a connection pool and each thread
49  *        will call ldap_get_conn to lock one of the ldap connections and release with
50  *        a call to ldap_release_conn when it has finished.
51  *      - Request only the user attributes that interest us (radius attributes,regular
52  *        profile,user password and access attribute).
53  * Mar 2002, Kostas Kalevras <kkalev@noc.ntua.gr>
54  *      - Fixed a bug where the ldap server will kill the idle connections from the ldap
55  *        connection pool. We now check if ldap_search returns LDAP_SERVER_DOWN and try to
56  *        reconnect if it does. Bug noted by Dan Perik <dan_perik-work@ntm.org.pg>
57  * May 2002, Kostas Kalevras <kkalev@noc.ntua.gr>
58  *      - Instead of the Group attribute we now have the Ldap-Group attribute, to avoid
59  *        collisions with other modules
60  *      - If perform_search fails check the ld != NULL before using it. Based on a bug report
61  *        by John <jhogenmiller@pennswoods.net>
62  * Jun 2002, Kostas Kalevras <kkalev@noc.ntua.gr>
63  *      - Add the ability to do a paircmp on the check items. Add a compare_check_items boolean
64  *        configuration directive which defaults to no. If it is set then we will do a compare
65  *      - Add another configuration directive. access_attr_used_for_allow. If it is set to yes
66  *        then the access_attr will be used to allow user access. If it is set to no then it will
67  *        be used to deny user access.
68  *      - Remember to free inst->atts in ldap_detach()
69  *      - Add a forgotten ldap_free_urldesc in ldap_xlat()
70  *      - Add a variable locked in the LDAP_CONN structure. We use this to avoid deadlocks. The mutex
71  *        we are using is of type fast and can deadlock if the same thread tries to relock it. That
72  *        could happen in case of calls to xlat.
73  *      - When ldap_search returns NO_SUCH_OBJECT don't return fail but notfound
74  * Jul 2002, Kostas Kalevras <kkalev@noc.ntua.gr>
75  *      - Fix the logic when we get an LDAP_SERVER_DOWN or we have conn->ld == NULL in perform_search
76  *      - Try to minimize the penalty of having the ldap server go down. The comments before
77  *        MAX_FAILED_CONNS_* definitions should explain things.
78  *      - Check for a number of error codes from ldap_search and log corresponding error messages
79  *        We should only reconnect when that can help things.
80  *      - In ldap_groupcmp instead of first searching for the group object and then checking user
81  *        group membership combine them in one ldap search operation. That should make group
82  *        membership checks a lot faster.
83  *      - Remember to do ldap_release_conn and ldap_msgfree when we do paircmp and the result is reject
84  * Aug 2002, Kostas Kalevras <kkalev@noc.ntua.gr>
85  *      - Add support for group membership attribute inside the user entry in ldap_groupcmp. The attribute
86  *        can either contain the name or the DN of the group. Added the groupmembership_attribute
87  *        configuration directive
88  *      - Move the ldap_{get,release}_conn in ldap_groupcmp so that we hold a connection for the minimum time.
89  */
90 static const char rcsid[] = "$Id$";
91
92 #include "autoconf.h"
93
94 #include        <sys/types.h>
95 #include        <sys/socket.h>
96 #include        <sys/time.h>
97 #include        <netinet/in.h>
98
99 #include        <stdio.h>
100 #include        <stdlib.h>
101 #include        <netdb.h>
102 #include        <pwd.h>
103 #include        <time.h>
104 #include        <ctype.h>
105 #include        <string.h>
106
107 #include        <lber.h>
108 #include        <ldap.h>
109
110 #include        <errno.h>
111 #include        <unistd.h>
112 #include        <pthread.h>
113
114 #include        "libradius.h"
115 #include        "radiusd.h"
116 #include        "conffile.h"
117 #include        "modules.h"
118 #include        "rad_assert.h"
119
120
121 #define MAX_AUTH_QUERY_LEN      256
122 #define MAX_GROUP_STR_LEN       1024
123 #define TIMELIMIT 5
124
125 /*
126  * These are used in case ldap_search returns LDAP_SERVER_DOWN
127  * In that case we do conn->failed_conns++ and then check it:
128  * If conn->failed_conns <= MAX_FAILED_CONNS_START then we try
129  * to reconnect
130  * conn->failed_conns is also checked on entrance in perform_search:
131  * If conn->failed_conns > MAX_FAILED_CONNS_START then we don't
132  * try to do anything and we just do conn->failed_conns++ and
133  * return RLM_MODULE_FAIL
134  * if conn->failed_conns >= MAX_FAILED_CONNS_END then we give it
135  * another chance and we set it to MAX_FAILED_CONNS_RESTART and
136  * try to reconnect.
137  *
138  *
139  * We are assuming that the majority of the LDAP_SERVER_DOWN cases
140  * will either be an ldap connection timeout or a temporary ldap
141  * server problem.
142  * As a result we make a few attempts to reconnect hoping that the problem
143  * will soon go away. If it does not go away then we just return
144  * RLM_MODULE_FAIL on entrance in perform_search until conn->failed_conns
145  * gets to MAX_FAILED_CONNS_END. After that we give it one more chance by
146  * going back to MAX_FAILED_CONNS_RESTART
147  *
148  */
149
150 #define MAX_FAILED_CONNS_END            20
151 #define MAX_FAILED_CONNS_RESTART        4
152 #define MAX_FAILED_CONNS_START          5
153
154 /* linked list of mappings between RADIUS attributes and LDAP attributes */
155 struct TLDAP_RADIUS {
156         char*                 attr;
157         char*                 radius_attr;
158         struct TLDAP_RADIUS*  next;
159 };
160 typedef struct TLDAP_RADIUS TLDAP_RADIUS;
161
162 typedef struct ldap_conn {
163         LDAP            *ld;
164         char            bound;
165         char            locked;
166         int             failed_conns;
167         pthread_mutex_t mutex;
168 } LDAP_CONN;
169
170 #define MAX_SERVER_LINE 1024
171
172 typedef struct {
173         char           *server;
174         int             port;
175         int             timelimit;
176         struct timeval  net_timeout;
177         struct timeval  timeout;
178         int             debug;
179         int             tls_mode;
180         int             start_tls;
181         int             num_conns;
182         int             cache_timeout;
183         int             cache_size;
184         int             do_comp;
185         int             default_allow;
186         char           *login;
187         char           *password;
188         char           *filter;
189         char           *basedn;
190         char           *default_profile;
191         char           *profile_attr;
192         char           *access_group;
193         char           *access_attr;
194         char           *passwd_hdr;
195         char           *passwd_attr;
196         char           *dictionary_mapping;
197         char           *groupname_attr;
198         char           *groupmemb_filt;
199         char           *groupmemb_attr;
200         char            **atts;
201         TLDAP_RADIUS   *check_item_map;
202         TLDAP_RADIUS   *reply_item_map;
203         LDAP_CONN       *conns;
204         int             ldap_debug; /* Debug flag for LDAP SDK */
205         char            *xlat_name; /* name used to xlat */
206 }               ldap_instance;
207
208 static CONF_PARSER module_config[] = {
209         {"server", PW_TYPE_STRING_PTR, offsetof(ldap_instance,server), NULL, NULL},
210         {"port", PW_TYPE_INTEGER, offsetof(ldap_instance,port), NULL, "389"},
211         /* wait forever on network activity */
212         {"net_timeout", PW_TYPE_INTEGER, offsetof(ldap_instance,net_timeout.tv_sec), NULL, "10"},
213         /* wait forever for search results */
214         {"timeout", PW_TYPE_INTEGER, offsetof(ldap_instance,timeout.tv_sec), NULL, "20"},
215         /* allow server unlimited time for search (server-side limit) */
216         {"timelimit", PW_TYPE_INTEGER, offsetof(ldap_instance,timelimit), NULL, "20"},
217         {"ldap_cache_timeout", PW_TYPE_INTEGER, offsetof(ldap_instance,cache_timeout), NULL, "0"},
218         {"ldap_cache_size", PW_TYPE_INTEGER, offsetof(ldap_instance,cache_size), NULL, "0"},
219         {"identity", PW_TYPE_STRING_PTR, offsetof(ldap_instance,login), NULL, ""},
220         {"start_tls", PW_TYPE_BOOLEAN, offsetof(ldap_instance,start_tls), NULL, "no"},
221         {"password", PW_TYPE_STRING_PTR, offsetof(ldap_instance,password), NULL, ""},
222         {"basedn", PW_TYPE_STRING_PTR, offsetof(ldap_instance,basedn), NULL, NULL},
223         {"filter", PW_TYPE_STRING_PTR, offsetof(ldap_instance,filter), NULL, "(uid=%u)"},
224         {"default_profile", PW_TYPE_STRING_PTR, offsetof(ldap_instance,default_profile), NULL, NULL},
225         {"profile_attribute", PW_TYPE_STRING_PTR, offsetof(ldap_instance,profile_attr), NULL, NULL},
226         {"access_group", PW_TYPE_STRING_PTR, offsetof(ldap_instance,access_group), NULL, NULL},
227         {"password_header", PW_TYPE_STRING_PTR, offsetof(ldap_instance,passwd_hdr), NULL, NULL},
228         {"password_attribute", PW_TYPE_STRING_PTR, offsetof(ldap_instance,passwd_attr), NULL, NULL},
229         /* LDAP attribute name that controls remote access */
230         {"access_attr", PW_TYPE_STRING_PTR, offsetof(ldap_instance,access_attr), NULL, NULL},
231         /* file with mapping between LDAP and RADIUS attributes */
232         {"groupname_attribute", PW_TYPE_STRING_PTR, offsetof(ldap_instance,groupname_attr), NULL, "cn"},
233         {"groupmembership_filter", PW_TYPE_STRING_PTR, offsetof(ldap_instance,groupmemb_filt), NULL, "(|(&(objectClass=GroupOfNames)(member=%{Ldap-UserDn}))(&(objectClass=GroupOfUniqueNames)(uniquemember=%{Ldap-UserDn})))"},
234         {"groupmembership_attribute", PW_TYPE_STRING_PTR, offsetof(ldap_instance,groupmemb_attr), NULL, NULL},
235         {"dictionary_mapping", PW_TYPE_STRING_PTR, offsetof(ldap_instance,dictionary_mapping), NULL, "${confdir}/ldap.attrmap"},
236         {"ldap_debug", PW_TYPE_INTEGER, offsetof(ldap_instance,ldap_debug), NULL, "0x0000"},
237         {"ldap_connections_number", PW_TYPE_INTEGER, offsetof(ldap_instance,num_conns), NULL, "5"},
238         {"compare_check_items", PW_TYPE_BOOLEAN, offsetof(ldap_instance,do_comp), NULL, "no"},
239         {"access_attr_used_for_allow", PW_TYPE_BOOLEAN, offsetof(ldap_instance,default_allow), NULL, "yes"},
240
241         {NULL, -1, 0, NULL, NULL}
242 };
243
244 #define ld_valid                ld_options.ldo_valid
245 #define LDAP_VALID_SESSION      0x2
246 #define LDAP_VALID(ld)  ( (ld)->ld_valid == LDAP_VALID_SESSION )
247
248 #ifdef FIELDCPY
249 static void     fieldcpy(char *, char **);
250 #endif
251 static VALUE_PAIR *ldap_pairget(LDAP *, LDAPMessage *, TLDAP_RADIUS *,VALUE_PAIR **);
252 static int ldap_groupcmp(void *, REQUEST *, VALUE_PAIR *, VALUE_PAIR *, VALUE_PAIR *, VALUE_PAIR **);
253 static int ldap_xlat(void *,REQUEST *, char *, char *,int, RADIUS_ESCAPE_STRING);
254 static LDAP    *ldap_connect(void *instance, const char *, const char *, int, int *);
255 static int     read_mappings(ldap_instance* inst);
256
257 static inline int ldap_get_conn(LDAP_CONN *conns,LDAP_CONN **ret,void *instance)
258 {
259         ldap_instance *inst = instance;
260         register int i = 0;
261
262         for(;i<inst->num_conns;i++){
263                 if (conns[i].locked == 0 && pthread_mutex_trylock(&(conns[i].mutex)) == 0){
264                         *ret = &conns[i];
265                         conns[i].locked = 1;
266                         DEBUG("ldap_get_conn: Got Id: %d",i);
267                         return i;
268                 }
269         }
270
271         return -1;
272 }
273         
274 static inline void ldap_release_conn(int i, LDAP_CONN *conns)
275 {
276         DEBUG("ldap_release_conn: Release Id: %d",i);
277         conns[i].locked = 0;
278         pthread_mutex_unlock(&(conns[i].mutex));
279 }
280
281 /*************************************************************************
282  *
283  *      Function: rlm_ldap_instantiate
284  *
285  *      Purpose: Uses section of radiusd config file passed as parameter
286  *               to create an instance of the module.
287  *
288  *************************************************************************/
289 static int 
290 ldap_instantiate(CONF_SECTION * conf, void **instance)
291 {
292         ldap_instance  *inst;
293         int i = 0;
294         int atts_num = 0;
295         int reply_map_num = 0;
296         int check_map_num = 0;
297         int att_map[3] = {0,0,0};
298         TLDAP_RADIUS *pair;
299         char *xlat_name;
300
301         inst = rad_malloc(sizeof *inst);
302
303         if (cf_section_parse(conf, inst, module_config) < 0) {
304                 free(inst);
305                 return -1;
306         }
307
308         if (inst->server == NULL) {
309                 radlog(L_ERR, "rlm_ldap: missing 'server' directive.");
310                 free(inst);
311                 return -1;
312         }
313  
314         inst->timeout.tv_usec = 0;
315         inst->net_timeout.tv_usec = 0;
316         /* workaround for servers which support LDAPS but not START TLS */
317         if(inst->port == LDAPS_PORT)
318                 inst->tls_mode = LDAP_OPT_X_TLS_HARD;
319          else
320                 inst->tls_mode = LDAP_OPT_X_TLS_TRY;
321         inst->reply_item_map = NULL;
322         inst->check_item_map = NULL;
323         inst->conns = NULL;
324
325         paircompare_register(PW_LDAP_GROUP, PW_USER_NAME, ldap_groupcmp, inst);
326         DEBUG("conns: %p",inst->conns);
327
328         xlat_name = cf_section_name2(conf);
329         if (xlat_name == NULL) {
330                 xlat_name = cf_section_name1(conf);
331                 rad_assert(xlat_name != NULL); /* or all hell breaks loose */
332         }
333         inst->xlat_name = strdup(xlat_name);
334         xlat_register(xlat_name,ldap_xlat,inst);
335
336         if (inst->num_conns <= 0){
337                 radlog(L_ERR, "rlm_ldap: Invalid ldap connections number passed.");
338                 free(inst);
339                 return -1;
340         }
341         inst->conns = (LDAP_CONN *)malloc(sizeof(LDAP_CONN)*inst->num_conns);
342         if (inst->conns == NULL){
343                 radlog(L_ERR, "rlm_ldap: Could not allocate memory. Aborting.");
344                 free(inst);
345                 return -1;
346         }
347         for(;i<inst->num_conns;i++){
348                 inst->conns[i].bound = 0;
349                 inst->conns[i].locked = 0;
350                 inst->conns[i].failed_conns = 0;
351                 inst->conns[i].ld = NULL;
352                 pthread_mutex_init(&inst->conns[i].mutex, NULL);
353         }       
354
355         if (read_mappings(inst) != 0) {
356                 radlog(L_ERR, "rlm_ldap: Reading dictionary mappings from file %s failed",
357                        inst->dictionary_mapping);
358                 radlog(L_ERR, "rlm_ldap: Proceeding with no mappings");
359         }
360         
361         pair = inst->check_item_map;
362         while(pair != NULL){
363                 atts_num++;
364                 pair = pair->next;
365         }
366         check_map_num = (atts_num - 1);
367         pair = inst->reply_item_map;
368         while(pair != NULL){
369                 atts_num++;
370                 pair = pair->next;
371         }
372         reply_map_num = (atts_num - 1);
373         if (inst->profile_attr)
374                 atts_num++;
375         if (inst->passwd_attr)
376                 atts_num++;
377         if (inst->access_attr)
378                 atts_num++;
379         inst->atts = (char **)malloc(sizeof(char *)*(atts_num + 1));
380         if (inst->atts == NULL){
381                 radlog(L_ERR, "rlm_ldap: Could not allocate memory. Aborting.");
382                 free(inst);
383                 return -1;
384         }
385         pair = inst->check_item_map;
386         for(i=0;i<atts_num;i++){
387                 if (i <= check_map_num ){
388                         inst->atts[i] = pair->attr;
389                         if (i == check_map_num)
390                                 pair = inst->reply_item_map;
391                         else
392                                 pair = pair->next;
393                 }
394                 else if (i <= reply_map_num){
395                         inst->atts[i] = pair->attr;
396                         pair = pair->next;
397                 }
398                 else{
399                         if (inst->profile_attr && !att_map[0]){
400                                 inst->atts[i] = inst->profile_attr;
401                                 att_map[0] = 1;
402                         }
403                         else if (inst->passwd_attr && !att_map[1]){
404                                 inst->atts[i] = inst->passwd_attr;
405                                 att_map[1] = 1;
406                         }
407                         else if (inst->access_attr && !att_map[2]){
408                                 inst->atts[i] = inst->access_attr;
409                                 att_map[2] = 1;
410                         }
411                 }
412         }
413         inst->atts[atts_num] = NULL;            
414
415         DEBUG("conns: %p",inst->conns);
416
417         *instance = inst;
418
419
420         return 0;
421 }
422
423
424 /*
425  * read_mappings(...) reads a ldap<->radius mappings file to inst->reply_item_map and inst->check_item_map
426  */
427
428 #define MAX_LINE_LEN 160
429 #define GENERIC_ATTRIBUTE_ID "$GENERIC$"
430
431 static int
432 read_mappings(ldap_instance* inst)
433 {
434         FILE* mapfile;
435         char *filename;
436         /* all buffers are of MAX_LINE_LEN so we can use sscanf without being afraid of buffer overflows */
437         char buf[MAX_LINE_LEN], itemType[MAX_LINE_LEN], radiusAttribute[MAX_LINE_LEN], ldapAttribute[MAX_LINE_LEN];
438         int linenumber;
439
440         /* open the mappings file for reading */
441
442         filename = inst->dictionary_mapping;
443         DEBUG("rlm_ldap: reading ldap<->radius mappings from file %s", filename);
444         mapfile = fopen(filename, "r");
445
446         if (mapfile == NULL) {
447                 radlog(L_ERR, "rlm_ldap: Opening file %s failed", filename);
448                 return -1; /* error */
449         }
450
451         /* read file line by line. Note that if line length exceed MAX_LINE_LEN, line numbers will be mixed up */
452
453         linenumber = 0;
454
455         while (fgets(buf, sizeof buf, mapfile)!=NULL) {
456                 char* ptr;
457                 int token_count;
458                 TLDAP_RADIUS* pair;
459
460                 linenumber++;
461
462                 /* strip comments */
463                 ptr = strchr(buf, '#');
464                 if (ptr) *ptr = 0;
465                 
466                 /* empty line */
467                 if (buf[0] == 0) continue;
468                 
469                 /* extract tokens from the string */            
470                 token_count = sscanf(buf, "%s %s %s", itemType, radiusAttribute, ldapAttribute);
471
472                 if (token_count <= 0) /* no tokens */                   
473                         continue;
474
475                 if (token_count != 3) {
476                         radlog(L_ERR, "rlm_ldap: Skipping %s line %i: %s", filename, linenumber, buf);
477                         radlog(L_ERR, "rlm_ldap: Expected 3 tokens "
478                                "(Item type, RADIUS Attribute and LDAP Attribute) but found only %i", token_count);
479                         continue;
480                 }
481
482                 /* create new TLDAP_RADIUS list node */
483                 pair = rad_malloc(sizeof(TLDAP_RADIUS));
484
485                 pair->attr = strdup(ldapAttribute);
486                 pair->radius_attr = strdup(radiusAttribute);
487
488                 if ( (pair->attr == NULL) || (pair->radius_attr == NULL) ) {
489                         radlog(L_ERR, "rlm_ldap: Out of memory");
490                         if (pair->attr) free(pair->attr);
491                         if (pair->radius_attr) free(pair->radius_attr);
492                         free(pair);
493                         fclose(mapfile);
494                         return -1;
495                 }
496                         
497                 /* push node to correct list */
498                 if (strcasecmp(itemType, "checkItem") == 0) {
499                         pair->next = inst->check_item_map;
500                         inst->check_item_map = pair;
501                 } else if (strcasecmp(itemType, "replyItem") == 0) {
502                         pair->next = inst->reply_item_map;
503                         inst->reply_item_map = pair;
504                 } else {
505                         radlog(L_ERR, "rlm_ldap: file %s: skipping line %i: unknown itemType %s", 
506                                filename, linenumber, itemType);
507                         free(pair->attr);
508                         free(pair->radius_attr);
509                         free(pair);
510                         continue;
511                 }
512
513                 DEBUG("rlm_ldap: LDAP %s mapped to RADIUS %s",
514                       pair->attr, pair->radius_attr);
515         }
516         
517         fclose(mapfile);
518
519         return 0; /* success */
520 }
521
522 static int 
523 perform_search(void *instance, LDAP_CONN *conn, char *search_basedn, int scope, char *filter, 
524                 char **attrs, LDAPMessage ** result)
525 {
526         int             res = RLM_MODULE_OK;
527         int             ldap_errno = 0;
528         ldap_instance  *inst = instance;
529         int             search_retry = 0;
530
531         *result = NULL;
532
533         if (!conn){
534                 radlog(L_ERR, "rlm_ldap: NULL connection handle passed");
535                 return RLM_MODULE_FAIL;
536         }
537         if (conn->failed_conns > MAX_FAILED_CONNS_START){
538                 conn->failed_conns++;
539                 if (conn->failed_conns >= MAX_FAILED_CONNS_END){
540                         conn->failed_conns = MAX_FAILED_CONNS_RESTART;
541                         conn->bound = 0;
542                 }
543         }
544 retry:
545         if (!conn->bound || conn->ld == NULL) {
546                 DEBUG2("rlm_ldap: attempting LDAP reconnection");
547                 if (conn->ld){
548                         DEBUG2("rlm_ldap: closing existing LDAP connection");
549                         if (inst->cache_timeout >0)
550                                 ldap_destroy_cache(conn->ld);
551                         ldap_unbind_s(conn->ld);
552                 }
553                 if ((conn->ld = ldap_connect(instance, inst->login, inst->password, 0, &res)) == NULL) {
554                         radlog(L_ERR, "rlm_ldap: (re)connection attempt failed");
555                         if (search_retry == 0)
556                                 conn->failed_conns++;
557                         return (RLM_MODULE_FAIL);
558                 }
559                 conn->bound = 1;
560                 conn->failed_conns = 0;
561         }
562         DEBUG2("rlm_ldap: performing search in %s, with filter %s", search_basedn ? search_basedn : "(null)" , filter);
563         switch (ldap_search_st(conn->ld, search_basedn, scope, filter, attrs, 0, &(inst->timeout), result)) {
564         case LDAP_SUCCESS:
565         case LDAP_NO_SUCH_OBJECT:
566                 break;
567         case LDAP_SERVER_DOWN:
568                 radlog(L_ERR, "rlm_ldap: ldap_search() failed: LDAP connection lost.");
569                 conn->failed_conns++;
570                 if (search_retry == 0){
571                         if (conn->failed_conns <= MAX_FAILED_CONNS_START){
572                                 radlog(L_INFO, "rlm_ldap: Attempting reconnect");
573                                 search_retry = 1;
574                                 conn->bound = 0;
575                                 ldap_msgfree(*result);  
576                                 goto retry;
577                         }
578                 }
579                 ldap_msgfree(*result);
580                 return RLM_MODULE_FAIL;
581         case LDAP_INSUFFICIENT_ACCESS:
582                 radlog(L_ERR, "rlm_ldap: ldap_search() failed: Insufficient access. Check the identity and password configuration directives.");
583                 ldap_msgfree(*result);
584                 return RLM_MODULE_FAIL;
585         case LDAP_TIMEOUT:
586                 radlog(L_ERR, "rlm_ldap: ldap_search() failed: Timed out while waiting for server to respond. Please increase the timeout.");
587                 ldap_msgfree(*result);
588                 return RLM_MODULE_FAIL;
589         case LDAP_TIMELIMIT_EXCEEDED:
590         case LDAP_BUSY:
591         case LDAP_UNAVAILABLE:
592                 /* We don't need to reconnect in these cases so we don't set conn->bound */
593                 ldap_get_option(conn->ld, LDAP_OPT_ERROR_NUMBER, &ldap_errno);
594                 radlog(L_ERR, "rlm_ldap: ldap_search() failed: %s", ldap_err2string(ldap_errno));
595                 ldap_msgfree(*result);  
596                 return (RLM_MODULE_FAIL);
597         default:
598                 ldap_get_option(conn->ld, LDAP_OPT_ERROR_NUMBER, &ldap_errno);
599                 radlog(L_ERR, "rlm_ldap: ldap_search() failed: %s", ldap_err2string(ldap_errno));
600                 conn->bound = 0;
601                 ldap_msgfree(*result);  
602                 return (RLM_MODULE_FAIL);
603         }
604
605         if ((ldap_count_entries(conn->ld, *result)) != 1) {
606                 DEBUG("rlm_ldap: object not found or got ambiguous search result");
607                 res = RLM_MODULE_NOTFOUND;
608                 ldap_msgfree(*result);  
609         }
610         return res;
611 }
612
613
614 /*
615  * ldap_groupcmp(). Implement the Ldap-Group == "group" filter
616  */
617
618 static int ldap_groupcmp(void *instance, REQUEST *req, VALUE_PAIR *request, VALUE_PAIR *check,
619                 VALUE_PAIR *check_pairs, VALUE_PAIR **reply_pairs)
620 {
621         char            filter[MAX_GROUP_STR_LEN];
622         char            gr_filter[MAX_AUTH_QUERY_LEN];
623         int             res;
624         LDAPMessage     *result = NULL;
625         LDAPMessage     *msg = NULL;
626         char            basedn[1024];
627         char            *attrs[] = {"dn",NULL};
628         ldap_instance   *inst = instance;
629         LDAP_CONN       *conn;
630         int             conn_id = -1;
631
632         check_pairs = check_pairs;
633         reply_pairs = reply_pairs;
634
635         DEBUG("rlm_ldap: Entering ldap_groupcmp()");
636
637         if (check->strvalue == NULL || check->length == 0){
638                 DEBUG("rlm_ldap::ldap_groupcmp: Illegal group name");
639                 return 1;
640         }
641
642         if (req == NULL){
643                 DEBUG("rlm_ldap::ldap_groupcmp: NULL request");
644                 return 1;
645         }
646
647         if (!radius_xlat(basedn, sizeof(basedn), inst->basedn, req, NULL)) {
648                 DEBUG("rlm_ldap::ldap_groupcmp: unable to create basedn.");
649                 return 1;
650         }
651
652         if ((pairfind(req->packet->vps, PW_LDAP_USERDN)) == NULL){
653                 char            *user_dn = NULL;
654
655                 if (!radius_xlat(filter, MAX_AUTH_QUERY_LEN, inst->filter, req, NULL)) {
656                         DEBUG("rlm_ldap::ldap_groupcmp: unable to create filter");
657                         return 1;
658                 }
659                 if ((conn_id = ldap_get_conn(inst->conns,&conn,inst)) == -1){
660                         radlog(L_ERR, "rlm_ldap: All ldap connections are in use");
661                         return 1;
662                 }
663                 if ((res = perform_search(inst, conn, basedn, LDAP_SCOPE_SUBTREE, filter, attrs, &result)) != RLM_MODULE_OK) {
664                         DEBUG("rlm_ldap::ldap_groupcmp: search failed");
665                         ldap_release_conn(conn_id,inst->conns);
666                         return 1;
667                 }
668                 if ((msg = ldap_first_entry(conn->ld, result)) == NULL) {
669                         DEBUG("rlm_ldap::ldap_groupcmp: ldap_first_entry() failed");
670                         ldap_release_conn(conn_id,inst->conns);
671                         ldap_msgfree(result);
672                         return 1;
673                 }
674                 if ((user_dn = ldap_get_dn(conn->ld, msg)) == NULL) {
675                         DEBUG("rlm_ldap:ldap_groupcmp:: ldap_get_dn() failed");
676                         ldap_release_conn(conn_id,inst->conns);
677                         ldap_msgfree(result);
678                         return 1;
679                 }
680                 ldap_release_conn(conn_id,inst->conns);
681                 /*
682                 * Adding new attribute containing DN for LDAP object associated with
683                 * given username
684                 */
685                 pairadd(&req->packet->vps, pairmake("Ldap-UserDn", user_dn, T_OP_EQ));
686                 ldap_memfree(user_dn);
687                 ldap_msgfree(result);
688         }
689
690         if(!radius_xlat(gr_filter, MAX_GROUP_STR_LEN, inst->groupmemb_filt, req, NULL)){
691                 DEBUG("rlm_ldap::ldap_groupcmp: unable to create filter.");
692                 return 1;
693         }
694
695         snprintf(filter,MAX_GROUP_STR_LEN - 1, "(&(%s=%s)%s)",inst->groupname_attr,(char *)check->strvalue,gr_filter);
696
697         if ((conn_id = ldap_get_conn(inst->conns,&conn,inst)) == -1){
698                 radlog(L_ERR, "rlm_ldap: All ldap connections are in use");
699                 return 1;
700         }
701
702         if ((res = perform_search(inst, conn, basedn, LDAP_SCOPE_SUBTREE, filter, attrs, &result)) != RLM_MODULE_OK){
703                 if (res != RLM_MODULE_NOTFOUND){
704                         DEBUG("rlm_ldap::ldap_groupcmp: Search returned error");
705                         ldap_release_conn(conn_id,inst->conns);
706                         return 1;
707                 }
708         }
709         if (res != RLM_MODULE_NOTFOUND)
710                 ldap_msgfree(result);
711         ldap_release_conn(conn_id,inst->conns);
712
713         if (res == RLM_MODULE_NOTFOUND){
714                 if (inst->groupmemb_attr == NULL){
715                         DEBUG("rlm_ldap::ldap_groupcmp: Group %s not found or user is not a member.",(char *)check->strvalue);
716                         return 1;
717                 }
718                 else{
719                         VALUE_PAIR *user_dn;
720                         char *group_attrs[] = {inst->groupmemb_attr,NULL};
721
722                         user_dn = pairfind(req->packet->vps, PW_LDAP_USERDN);
723                         if (user_dn != NULL){
724                                 char **vals;
725
726                                 snprintf(filter,MAX_GROUP_STR_LEN - 1, "(objectclass=*)");
727                                 if ((conn_id = ldap_get_conn(inst->conns,&conn,inst)) == -1){
728                                         radlog(L_ERR, "rlm_ldap: Add ldap connections are in use");
729                                         return 1;
730                                 }
731                                 if ((res = perform_search(inst, conn, user_dn->strvalue, LDAP_SCOPE_BASE, filter, group_attrs, &result)) != RLM_MODULE_OK){
732                                         DEBUG("rlm_ldap::ldap_groupcmp: Search returned error");
733                                         ldap_release_conn(conn_id, inst->conns);
734                                         return 1;
735                                 }               
736
737                                 if ((msg = ldap_first_entry(conn->ld, result)) == NULL) {
738                                         DEBUG("rlm_ldap::ldap_groupcmp: ldap_first_entry() failed");
739                                         ldap_release_conn(conn_id,inst->conns);
740                                         ldap_msgfree(result);
741                                         return 1;
742                                 }
743                                 if ((vals = ldap_get_values(conn->ld, msg, inst->groupmemb_attr)) != NULL) {
744                                         unsigned int i = 0;
745                                         char found = 0;
746
747                                         for (;i < ldap_count_values(vals);i++){
748                                                 if (strchr(vals[i],',') != NULL){ /* This looks like a DN */
749                                                         LDAPMessage *gr_result = NULL;
750
751                                                         snprintf(filter,MAX_GROUP_STR_LEN - 1, "(%s=%s)",inst->groupname_attr,(char *)check->strvalue);
752                                                         if ((res = perform_search(inst, conn, vals[i], LDAP_SCOPE_BASE, filter, attrs, &gr_result)) != RLM_MODULE_OK){
753                                                                 if (res != RLM_MODULE_NOTFOUND){
754                                                                         DEBUG("rlm_ldap::ldap_groupcmp: Search returned error");
755                                                                         ldap_msgfree(result);
756                                                                         ldap_value_free(vals);
757                                                                         ldap_release_conn(conn_id, inst->conns);
758                                                                         return 1;
759                                                                 }
760                                                         }
761                                                         else{
762                                                                 ldap_msgfree(gr_result);
763                                                                 found = 1;
764                                                                 break;
765                                                         }
766                                                 }
767                                                 else{
768                                                         if (strcmp(vals[i],(char *)check->strvalue) == 0){
769                                                                 found = 1;
770                                                                 break;
771                                                         }
772                                                 }
773                                         }
774                                         ldap_value_free(vals);
775                                         ldap_msgfree(result);
776                                         if (found == 0){
777                                                 DEBUG("rlm_ldap::groupcmp: Group %s not found or user not a member",
778                                                         (char *)check->strvalue);
779                                                 ldap_release_conn(conn_id,inst->conns);
780                                                 return 1;
781                                         }
782                                 }
783                                 else{
784                                         DEBUG("rlm_ldap::ldap_groupcmp: ldap_get_values() failed");
785                                         ldap_release_conn(conn_id,inst->conns);
786                                         ldap_msgfree(result);
787                                         return 1;
788                                 }
789                         }
790                 }
791         }
792
793
794         DEBUG("rlm_ldap::ldap_groupcmp: User found in group %s",(char *)check->strvalue);
795         ldap_release_conn(conn_id,inst->conns);
796
797         return 0;
798 }
799
800 /*
801  * ldap_xlat()
802  * Do an xlat on an LDAP URL
803  */
804
805 static int ldap_xlat(void *instance, REQUEST *request, char *fmt, char *out, int freespace,
806                                 RADIUS_ESCAPE_STRING func)
807 {
808         char url[MAX_STRING_LEN];
809         int res;
810         int ret = 0;
811         ldap_instance *inst = instance;
812         LDAPURLDesc *ldap_url;
813         LDAPMessage *result = NULL;
814         LDAPMessage *msg = NULL;
815         char **vals;
816         int conn_id = -1;
817         LDAP_CONN *conn;
818
819         DEBUG("rlm_ldap: - ldap_xlat");
820         if (!radius_xlat(url, sizeof(url), fmt, request, func)) {
821                 radlog (L_ERR, "rlm_ldap: Unable to create LDAP URL.\n");
822                 return 0;
823         }
824         if (!ldap_is_ldap_url(url)){
825                 radlog (L_ERR, "rlm_ldap: String passed does not look like an LDAP URL.\n");
826                 return 0;
827         }
828         if (ldap_url_parse(url,&ldap_url)){
829                 radlog (L_ERR, "rlm_ldap: LDAP URL parse failed.\n");
830                 return 0;
831         }
832         if (ldap_url->lud_attrs == NULL || ldap_url->lud_attrs[0] == NULL || \
833                 ( ldap_url->lud_attrs[1] != NULL || ( ! strlen(ldap_url->lud_attrs[0]) || \
834                 ! strcmp(ldap_url->lud_attrs[0],"*") ) ) ){
835                 radlog (L_ERR, "rlm_ldap: Invalid Attribute(s) request.\n");
836                 ldap_free_urldesc(ldap_url);
837                 return 0;
838         }
839         if (ldap_url->lud_host){
840                 if (strncmp(inst->server,ldap_url->lud_host,strlen(inst->server)) != 0 || \
841                                 ldap_url->lud_port != inst->port){
842                         DEBUG("rlm_ldap: Requested server/port is not known to this module instance.");
843                         ldap_free_urldesc(ldap_url);
844                         return 0;
845                 }
846         }
847         if ((conn_id = ldap_get_conn(inst->conns,&conn,inst)) == -1){
848                 radlog(L_ERR, "rlm_ldap: All ldap connections are in use");
849                 ldap_free_urldesc(ldap_url);
850                 return 0;
851         }
852         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){
853                 if (res == RLM_MODULE_NOTFOUND){
854                         DEBUG("rlm_ldap: Search returned not found");
855                         ldap_free_urldesc(ldap_url);
856                         ldap_release_conn(conn_id,inst->conns);
857                         return 0;
858                 }
859                 DEBUG("rlm_ldap: Search returned error");
860                 ldap_free_urldesc(ldap_url);
861                 ldap_release_conn(conn_id,inst->conns);
862                 return 0;
863         }
864         if ((msg = ldap_first_entry(conn->ld, result)) == NULL){
865                 DEBUG("rlm_ldap: ldap_first_entry() failed");
866                 ldap_msgfree(result);
867                 ldap_free_urldesc(ldap_url);
868                 ldap_release_conn(conn_id,inst->conns);
869                 return 0;
870         }
871         if ((vals = ldap_get_values(conn->ld, msg, ldap_url->lud_attrs[0])) != NULL) {
872                 ret = strlen(vals[0]);
873                 if (ret > freespace){
874                         DEBUG("rlm_ldap: Insufficient string space");
875                         ldap_free_urldesc(ldap_url);
876                         ldap_value_free(vals);
877                         ldap_msgfree(result);
878                         ldap_release_conn(conn_id,inst->conns);
879                         return 0;
880                 }
881                 DEBUG("rlm_ldap: Adding attribute %s, value: %s",ldap_url->lud_attrs[0],vals[0]);
882                 strncpy(out,vals[0],ret);
883                 ldap_value_free(vals);
884         }
885         else
886                 ret = 0;
887
888         ldap_msgfree(result);
889         ldap_free_urldesc(ldap_url);
890         ldap_release_conn(conn_id,inst->conns);
891
892         DEBUG("rlm_ldap: - ldap_xlat end");
893
894         return ret;
895 }
896
897
898 /******************************************************************************
899  *
900  *      Function: rlm_ldap_authorize
901  *
902  *      Purpose: Check if user is authorized for remote access
903  *
904  ******************************************************************************/
905 static int 
906 ldap_authorize(void *instance, REQUEST * request)
907 {
908         LDAPMessage     *result = NULL;
909         LDAPMessage     *msg = NULL;
910         LDAPMessage     *def_msg = NULL;
911         LDAPMessage     *def_attr_msg = NULL;
912         LDAPMessage     *gr_result = NULL;
913         LDAPMessage     *def_result = NULL;
914         LDAPMessage     *def_attr_result = NULL;
915         ldap_instance   *inst = instance;
916         char            *user_dn = NULL;
917         char            filter[MAX_AUTH_QUERY_LEN];
918         char            basedn[1024];
919         VALUE_PAIR      *check_tmp;
920         VALUE_PAIR      *reply_tmp;
921         int             res;
922         VALUE_PAIR      **check_pairs, **reply_pairs;
923         char            **vals;
924         VALUE_PAIR      *module_fmsg_vp;
925         VALUE_PAIR      *user_profile;
926         char            module_fmsg[MAX_STRING_LEN];
927         LDAP_CONN       *conn;
928         int             conn_id = -1;
929
930         DEBUG("rlm_ldap: - authorize");
931
932         if (!request->username){
933                 radlog(L_AUTH, "rlm_ldap: Attribute \"User-Name\" is required for authentication.\n");
934                 return RLM_MODULE_INVALID;
935         }
936
937         check_pairs = &request->config_items;
938         reply_pairs = &request->reply->vps;
939
940         /*
941          * Check for valid input, zero length names not permitted
942          */
943         if (request->username->strvalue == 0) {
944                 radlog(L_ERR, "rlm_ldap: zero length username not permitted\n");
945                 return RLM_MODULE_INVALID;
946         }
947         DEBUG("rlm_ldap: performing user authorization for %s",
948                request->username->strvalue);
949
950         if (!radius_xlat(filter, sizeof(filter), inst->filter,
951                          request, NULL)) {
952                 radlog (L_ERR, "rlm_ldap: unable to create filter.\n");
953                 return RLM_MODULE_INVALID;
954         }
955
956         if (!radius_xlat(basedn, sizeof(basedn), inst->basedn,
957                          request, NULL)) {
958                 radlog (L_ERR, "rlm_ldap: unable to create basedn.\n");
959                 return RLM_MODULE_INVALID;
960         }
961
962         if ((conn_id = ldap_get_conn(inst->conns,&conn,inst)) == -1){
963                 radlog(L_ERR, "rlm_ldap: All ldap connections are in use");
964                 return RLM_MODULE_FAIL;
965         }
966         if ((res = perform_search(instance, conn, basedn, LDAP_SCOPE_SUBTREE, filter, inst->atts, &result)) != RLM_MODULE_OK) {
967                 DEBUG("rlm_ldap: search failed");
968                 if (res == RLM_MODULE_NOTFOUND){
969                         snprintf(module_fmsg,sizeof(module_fmsg),"rlm_ldap: User not found");
970                         module_fmsg_vp = pairmake("Module-Failure-Message", module_fmsg, T_OP_EQ);
971                         pairadd(&request->packet->vps, module_fmsg_vp);
972                 }
973                 ldap_release_conn(conn_id,inst->conns);
974                 return (res);
975         }
976         if ((msg = ldap_first_entry(conn->ld, result)) == NULL) {
977                 DEBUG("rlm_ldap: ldap_first_entry() failed");
978                 ldap_msgfree(result);
979                 ldap_release_conn(conn_id,inst->conns);
980                 return RLM_MODULE_FAIL;
981         }
982         if ((user_dn = ldap_get_dn(conn->ld, msg)) == NULL) {
983                 DEBUG("rlm_ldap: ldap_get_dn() failed");
984                 ldap_msgfree(result);
985                 ldap_release_conn(conn_id,inst->conns);
986                 return RLM_MODULE_FAIL;
987         }
988         /*
989          * Adding new attribute containing DN for LDAP object associated with
990          * given username
991          */
992         pairadd(&request->packet->vps, pairmake("Ldap-UserDn", user_dn, T_OP_EQ));
993         ldap_memfree(user_dn);
994
995
996         /* Remote access is controled by attribute of the user object */
997         if (inst->access_attr) {
998                 if ((vals = ldap_get_values(conn->ld, msg, inst->access_attr)) != NULL) {
999                         if (inst->default_allow){
1000                                 DEBUG("rlm_ldap: checking if remote access for %s is allowed by %s", request->username->strvalue, inst->access_attr);
1001                                 if (!strncmp(vals[0], "FALSE", 5)) {
1002                                         DEBUG("rlm_ldap: dialup access disabled");
1003                                         snprintf(module_fmsg,sizeof(module_fmsg),"rlm_ldap: Access Attribute denies access");
1004                                         module_fmsg_vp = pairmake("Module-Failure-Message", module_fmsg, T_OP_EQ);
1005                                         pairadd(&request->packet->vps, module_fmsg_vp);
1006                                         ldap_msgfree(result);
1007                                         ldap_value_free(vals);
1008                                         ldap_release_conn(conn_id,inst->conns);
1009                                         return RLM_MODULE_USERLOCK;
1010                                 }
1011                                 ldap_value_free(vals);
1012                         }
1013                         else{
1014                                 DEBUG("rlm_ldap: %s attribute exists - access denied by default", inst->access_attr);
1015                                 snprintf(module_fmsg,sizeof(module_fmsg),"rlm_ldap: Access Attribute denies access");
1016                                 module_fmsg_vp = pairmake("Module-Failure-Message", module_fmsg, T_OP_EQ);
1017                                 pairadd(&request->packet->vps, module_fmsg_vp);
1018                                 ldap_msgfree(result);
1019                                 ldap_value_free(vals);
1020                                 ldap_release_conn(conn_id,inst->conns);
1021                                 return RLM_MODULE_USERLOCK;
1022                         }
1023                 } else {
1024                         if (inst->default_allow){
1025                                 DEBUG("rlm_ldap: no %s attribute - access denied by default", inst->access_attr);
1026                                 snprintf(module_fmsg,sizeof(module_fmsg),"rlm_ldap: Access Attribute denies access");
1027                                 module_fmsg_vp = pairmake("Module-Failure-Message", module_fmsg, T_OP_EQ);
1028                                 pairadd(&request->packet->vps, module_fmsg_vp);
1029                                 ldap_msgfree(result);
1030                                 ldap_release_conn(conn_id,inst->conns);
1031                                 return RLM_MODULE_USERLOCK;
1032                         }
1033                 }
1034         }
1035         if (inst->cache_timeout >0)
1036                 ldap_enable_cache(conn->ld, inst->cache_timeout, inst->cache_size);
1037
1038         /* Remote access controled by group membership of the user object */
1039         if (inst->access_group != NULL) {
1040                 static char     group[MAX_AUTH_QUERY_LEN];
1041                 static char     *attrs[] = {"dn", NULL};
1042
1043                 DEBUG("rlm_ldap: checking user membership in dialup-enabling group %s", inst->access_group);
1044                 /*
1045                  * uniquemember appears in Netscape Directory Server's groups
1046                  * since we have objectclass groupOfNames and
1047                  * groupOfUniqueNames
1048                  */
1049                 if(!radius_xlat(group, MAX_AUTH_QUERY_LEN, inst->access_group,
1050                                 request, NULL)) 
1051                         radlog (L_ERR, "rlm_ldap: unable to munge group.\n"); 
1052
1053                 if(!radius_xlat(filter, MAX_AUTH_QUERY_LEN, inst->groupmemb_filt,
1054                                 request, NULL)) 
1055                         radlog (L_ERR, "rlm_ldap: unable to create filter.\n"); 
1056
1057                 if ((res = perform_search(instance, conn, group, LDAP_SCOPE_BASE, filter, attrs, &gr_result)) != RLM_MODULE_OK) {
1058                         if (inst->cache_timeout >0 && conn->ld != NULL)
1059                                 ldap_disable_cache(conn->ld);
1060                         ldap_msgfree(result);
1061                         ldap_release_conn(conn_id,inst->conns);
1062                         if (res == RLM_MODULE_NOTFOUND){
1063                                 snprintf(module_fmsg,sizeof(module_fmsg),"rlm_ldap: User is not an access group member");
1064                                 module_fmsg_vp = pairmake("Module-Failure-Message", module_fmsg, T_OP_EQ);
1065                                 pairadd(&request->packet->vps, module_fmsg_vp);
1066                                 return (RLM_MODULE_USERLOCK);
1067                         }
1068                         else
1069                                 return (res);
1070                 } else 
1071                         ldap_msgfree(gr_result);
1072         }
1073
1074         /*
1075          * Check for the default profile entry. If it exists then add the 
1076          * attributes it contains in the check and reply pairs
1077          */
1078
1079         user_profile = pairfind(request->config_items, PW_USER_PROFILE);
1080         if (inst->default_profile || user_profile){
1081                 char *profile = inst->default_profile;
1082
1083                 strncpy(filter,"(objectclass=radiusprofile)",MAX_AUTH_QUERY_LEN);
1084                 if (user_profile)
1085                         profile = user_profile->strvalue;
1086                 if (profile && strlen(profile)){
1087                         if ((res = perform_search(instance, conn,
1088                                 profile, LDAP_SCOPE_BASE, 
1089                                 filter, inst->atts, &def_result)) == RLM_MODULE_OK){
1090                                 if ((def_msg = ldap_first_entry(conn->ld,def_result))){
1091                                         if ((check_tmp = ldap_pairget(conn->ld,def_msg,inst->check_item_map,check_pairs)))
1092                                                 pairadd(check_pairs,check_tmp);
1093                                         if ((reply_tmp = ldap_pairget(conn->ld,def_msg,inst->reply_item_map,reply_pairs)))
1094                                                 pairadd(reply_pairs,reply_tmp);
1095                                 }
1096                                 ldap_msgfree(def_result);
1097                         } else 
1098                                 DEBUG("rlm_ldap: default_profile/user-profile search failed");
1099                 }
1100         }
1101
1102         /*
1103          * Check for the profile attribute. If it exists, we assume that it 
1104          * contains the DN of an entry containg a profile for the user. That
1105          * way we can have different general profiles for various user groups
1106          * (students,faculty,staff etc)
1107          */
1108
1109         if (inst->profile_attr){
1110                 if ((vals = ldap_get_values(conn->ld, msg, inst->profile_attr)) != NULL && strlen(vals[0])) {
1111                         strncpy(filter,"(objectclass=radiusprofile)",MAX_AUTH_QUERY_LEN);
1112                         if ((res = perform_search(instance, conn,
1113                                 vals[0], LDAP_SCOPE_BASE, 
1114                                 filter, inst->atts, &def_attr_result)) == RLM_MODULE_OK){
1115                                 if ((def_attr_msg = ldap_first_entry(conn->ld,def_attr_result))){
1116                                         if ((check_tmp = ldap_pairget(conn->ld,def_attr_msg,inst->check_item_map,check_pairs)))
1117                                                 pairadd(check_pairs,check_tmp);
1118                                         if ((reply_tmp = ldap_pairget(conn->ld,def_attr_msg,inst->reply_item_map,reply_pairs)))
1119                                                 pairadd(reply_pairs,reply_tmp);
1120                                 }
1121                                 ldap_msgfree(def_attr_result);
1122                         } else 
1123                                 DEBUG("rlm_ldap: profile_attribute search failed");
1124                         ldap_value_free(vals);
1125                 }
1126         }
1127         if (inst->cache_timeout >0)
1128                 ldap_disable_cache(conn->ld);
1129         if (inst->passwd_attr && strlen(inst->passwd_attr)){
1130                 VALUE_PAIR *passwd_item;
1131
1132                 if ((passwd_item = pairfind(request->config_items, PW_PASSWORD)) == NULL){
1133                         char **passwd_vals;
1134                         char *passwd_val = NULL;
1135                         int passwd_len;
1136
1137                         if ((passwd_vals = ldap_get_values(conn->ld,msg,inst->passwd_attr)) != NULL){
1138                                 unsigned int i=0;
1139                                 while(passwd_vals[i] != NULL){
1140                                         if (strlen(passwd_vals[i])){
1141                                                 passwd_val = passwd_vals[i];
1142
1143                                                 if (inst->passwd_hdr && strlen(inst->passwd_hdr)){
1144                                                         passwd_val = strstr(passwd_val,inst->passwd_hdr);
1145                                                         if (passwd_val != NULL)
1146                                                                 passwd_val += strlen(inst->passwd_hdr);
1147                                                         else
1148                                                                 DEBUG("rlm_ldap: Password header not found in password %s for user %s", passwd_vals[0],request->username->strvalue);
1149                                                 }
1150                                                 if (passwd_val){
1151                                                         if ((passwd_item = paircreate(PW_PASSWORD,PW_TYPE_STRING)) == NULL){
1152                                                                 radlog(L_ERR|L_CONS, "no memory");
1153                                                                 ldap_value_free(passwd_vals);
1154                                                                 ldap_msgfree(result);
1155                                                                 ldap_release_conn(conn_id,inst->conns);
1156                                                                 return RLM_MODULE_FAIL;
1157                                                         }
1158                                                         passwd_len = strlen(passwd_val);
1159                                                         strncpy(passwd_item->strvalue,passwd_val,MAX_STRING_LEN - 1);
1160                                                         passwd_item->length = (passwd_len > (MAX_STRING_LEN - 1)) ? (MAX_STRING_LEN - 1) : passwd_len;
1161                                                         pairadd(&request->config_items,passwd_item);
1162                                                         DEBUG("rlm_ldap: Added password %s in check items",passwd_item->strvalue);
1163                                                 }
1164                                         }
1165                                         i++;
1166                                 }
1167                                 ldap_value_free(passwd_vals);
1168                         }
1169                 }
1170         }
1171
1172
1173
1174         DEBUG("rlm_ldap: looking for check items in directory...");
1175
1176         if ((check_tmp = ldap_pairget(conn->ld, msg, inst->check_item_map,check_pairs)) != NULL)
1177                 pairadd(check_pairs, check_tmp);
1178
1179
1180         DEBUG("rlm_ldap: looking for reply items in directory...");
1181
1182
1183         if ((reply_tmp = ldap_pairget(conn->ld, msg, inst->reply_item_map,reply_pairs)) != NULL)
1184                 pairadd(reply_pairs, reply_tmp);
1185
1186        if (inst->do_comp && paircmp(request,request->packet->vps,*check_pairs,reply_pairs) != 0){
1187                 DEBUG("rlm_ldap: Pairs do not match. Rejecting user.");
1188                 snprintf(module_fmsg,sizeof(module_fmsg),"rlm_ldap: Pairs do not match");
1189                 module_fmsg_vp = pairmake("Module-Failure-Message", module_fmsg, T_OP_EQ);
1190                 pairadd(&request->packet->vps, module_fmsg_vp);
1191                 ldap_msgfree(result);
1192                 ldap_release_conn(conn_id,inst->conns);
1193
1194                 return RLM_MODULE_REJECT;
1195         }
1196
1197         /*
1198          * Module should default to LDAP authentication if no Auth-Type
1199          * specified
1200          */
1201         if (pairfind(*check_pairs, PW_AUTHTYPE) == NULL)
1202                 pairadd(check_pairs, pairmake("Auth-Type", "LDAP", T_OP_EQ));
1203
1204
1205         DEBUG("rlm_ldap: user %s authorized to use remote access",
1206               request->username->strvalue);
1207         ldap_msgfree(result);
1208         ldap_release_conn(conn_id,inst->conns);
1209
1210         return RLM_MODULE_OK;
1211 }
1212
1213 /*****************************************************************************
1214  *
1215  *      Function: rlm_ldap_authenticate
1216  *
1217  *      Purpose: Check the user's password against ldap database
1218  *
1219  *****************************************************************************/
1220 static int 
1221 ldap_authenticate(void *instance, REQUEST * request)
1222 {
1223         LDAP           *ld_user;
1224         LDAPMessage    *result, *msg;
1225         ldap_instance  *inst = instance;
1226         char           *user_dn, *attrs[] = {"uid", NULL};
1227         char            filter[MAX_AUTH_QUERY_LEN];
1228         char            basedn[1024];
1229         int             res;
1230         VALUE_PAIR     *vp_user_dn;
1231         VALUE_PAIR      *module_fmsg_vp;
1232         char            module_fmsg[MAX_STRING_LEN];
1233         LDAP_CONN       *conn;
1234         int             conn_id = -1;
1235
1236         DEBUG("rlm_ldap: - authenticate");
1237         /*
1238          * Ensure that we're being passed a plain-text password, and not
1239          * anything else.
1240          */
1241
1242         if (!request->username) {
1243                 radlog(L_AUTH, "rlm_ldap: Attribute \"User-Name\" is required for authentication.\n");
1244                 return RLM_MODULE_INVALID;
1245         }
1246
1247         if (!request->password){
1248                 radlog(L_AUTH, "rlm_ldap: Attribute \"User-Password\" is required for authentication.");
1249                 return RLM_MODULE_INVALID;
1250         }
1251
1252         if(request->password->attribute != PW_PASSWORD) {
1253                 radlog(L_AUTH, "rlm_ldap: Attribute \"User-Password\" is required for authentication. Cannot use \"%s\".", request->password->name);
1254                 return RLM_MODULE_INVALID;
1255         }
1256
1257         if (request->password->length == 0) {
1258                 radlog(L_ERR, "rlm_ldap: empty password supplied");
1259                 return RLM_MODULE_INVALID;
1260         }
1261
1262         DEBUG("rlm_ldap: login attempt by \"%s\" with password \"%s\"", 
1263                request->username->strvalue, request->password->strvalue);
1264
1265         while((vp_user_dn = pairfind(request->packet->vps, PW_LDAP_USERDN)) == NULL) {
1266                 if (!radius_xlat(filter, sizeof(filter), inst->filter,
1267                                 request, NULL)) {
1268                         radlog (L_ERR, "rlm_ldap: unable to create filter.\n"); 
1269                         return RLM_MODULE_INVALID;
1270                 }
1271
1272                 if (!radius_xlat(basedn, sizeof(basedn), inst->basedn,
1273                                 request, NULL)) {
1274                         radlog (L_ERR, "rlm_ldap: unable to create basedn.\n");
1275                         return RLM_MODULE_INVALID;
1276                 }
1277
1278                 if ((conn_id = ldap_get_conn(inst->conns,&conn,inst)) == -1){
1279                         radlog(L_ERR, "rlm_ldap: All ldap connections are in use");
1280                         return RLM_MODULE_FAIL;
1281                 }
1282                 if ((res = perform_search(instance, conn, basedn, LDAP_SCOPE_SUBTREE, filter, attrs, &result)) != RLM_MODULE_OK) {
1283                         if (res == RLM_MODULE_NOTFOUND){
1284                                 snprintf(module_fmsg,sizeof(module_fmsg),"rlm_ldap: User not found");
1285                                 module_fmsg_vp = pairmake("Module-Failure-Message", module_fmsg, T_OP_EQ);
1286                                 pairadd(&request->packet->vps, module_fmsg_vp);
1287                         }
1288                         ldap_release_conn(conn_id,inst->conns);
1289                         return (res);
1290                 }
1291                 if ((msg = ldap_first_entry(conn->ld, result)) == NULL) {
1292                         ldap_msgfree(result);
1293                         ldap_release_conn(conn_id,inst->conns);
1294                         return RLM_MODULE_FAIL;
1295                 }
1296                 if ((user_dn = ldap_get_dn(conn->ld, msg)) == NULL) {
1297                         DEBUG("rlm_ldap: ldap_get_dn() failed");
1298                         ldap_msgfree(result);
1299                         ldap_release_conn(conn_id,inst->conns);
1300                         return RLM_MODULE_FAIL;
1301                 }
1302                 ldap_release_conn(conn_id,inst->conns);
1303                 pairadd(&request->packet->vps, pairmake("Ldap-UserDn", user_dn, T_OP_EQ));
1304                 ldap_memfree(user_dn);
1305                 ldap_msgfree(result);
1306         }
1307
1308         user_dn = vp_user_dn->strvalue;
1309
1310         DEBUG("rlm_ldap: user DN: %s", user_dn);
1311
1312         ld_user = ldap_connect(instance, user_dn, request->password->strvalue,
1313                                1, &res);
1314         if (ld_user == NULL){
1315                 snprintf(module_fmsg,sizeof(module_fmsg),"rlm_ldap: Bind as user failed");
1316                 module_fmsg_vp = pairmake("Module-Failure-Message", module_fmsg, T_OP_EQ);
1317                 pairadd(&request->packet->vps, module_fmsg_vp);
1318                 return (res);
1319         }
1320
1321         DEBUG("rlm_ldap: user %s authenticated succesfully",
1322               request->username->strvalue);
1323         ldap_unbind_s(ld_user);
1324
1325         return RLM_MODULE_OK;
1326 }
1327
1328 static LDAP    *
1329 ldap_connect(void *instance, const char *dn, const char *password, int auth, int *result)
1330 {
1331         ldap_instance  *inst = instance;
1332         LDAP           *ld;
1333         int             msgid, rc, ldap_version;
1334         int             ldap_errno = 0;
1335         LDAPMessage    *res;
1336
1337         DEBUG("rlm_ldap: (re)connect to %s:%d, authentication %d", inst->server, inst->port, auth);
1338         if ((ld = ldap_init(inst->server, inst->port)) == NULL) {
1339                 radlog(L_ERR, "rlm_ldap: ldap_init() failed");
1340                 *result = RLM_MODULE_FAIL;
1341                 return (NULL);
1342         }
1343         if (ldap_set_option(ld, LDAP_OPT_NETWORK_TIMEOUT, (void *) &(inst->net_timeout)) != LDAP_OPT_SUCCESS) {
1344                 radlog(L_ERR, "rlm_ldap: Could not set LDAP_OPT_NETWORK_TIMEOUT %ld.%ld", inst->net_timeout.tv_sec, inst->net_timeout.tv_usec);
1345         }
1346         if (ldap_set_option(ld, LDAP_OPT_TIMELIMIT, (void *) &(inst->timelimit)) != LDAP_OPT_SUCCESS) {
1347                 radlog(L_ERR, "rlm_ldap: Could not set LDAP_OPT_TIMELIMIT %d", inst->timelimit);
1348         }
1349         if (inst->ldap_debug && ldap_set_option(NULL, LDAP_OPT_DEBUG_LEVEL, &(inst->ldap_debug)) != LDAP_OPT_SUCCESS) {
1350                 radlog(L_ERR, "rlm_ldap: Could not set LDAP_OPT_DEBUG_LEVEL %d", inst->ldap_debug);
1351         }
1352 #ifdef HAVE_LDAP_START_TLS
1353         if(inst->tls_mode) {
1354                 DEBUG("rlm_ldap: setting TLS mode to %d", inst->tls_mode);
1355                 if(ldap_set_option(ld, LDAP_OPT_X_TLS,
1356                            (void *) &(inst->tls_mode)) != LDAP_OPT_SUCCESS) {
1357                         ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &ldap_errno);
1358                         radlog(L_ERR, "rlm_ldap: could not set LDAP_OPT_X_TLS option %s", ldap_err2string(ldap_errno));
1359                 }
1360         }
1361
1362         if (inst->start_tls) {
1363                 DEBUG("rlm_ldap: starting TLS");
1364                 ldap_version = LDAP_VERSION3;
1365                 if (ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, &ldap_version) == LDAP_SUCCESS) {
1366                         rc = ldap_start_tls_s(ld, NULL, NULL);
1367                         if (rc != LDAP_SUCCESS) {
1368                                 DEBUG("rlm_ldap: ldap_start_tls_s()");
1369                                 ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &ldap_errno);
1370                                 radlog(L_ERR, "rlm_ldap: could not start TLS %s", ldap_err2string(ldap_errno));
1371                                 *result = RLM_MODULE_FAIL;
1372                                 ldap_unbind_s(ld);
1373                                 return (NULL);
1374                         }
1375                 }
1376         }
1377 #endif /* HAVE_LDAP_START_TLS */
1378
1379         DEBUG("rlm_ldap: bind as %s/%s to %s:%d", dn, password, inst->server, inst->port);
1380         msgid = ldap_bind(ld, dn, password,LDAP_AUTH_SIMPLE);
1381         if (msgid == -1) {
1382                 ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &ldap_errno);
1383                 radlog(L_ERR, "rlm_ldap: %s bind to %s:%d failed: %s",
1384                          dn, inst->server, inst->port,
1385                          ldap_err2string(ldap_errno));
1386                 *result = RLM_MODULE_FAIL;
1387                 ldap_unbind_s(ld);
1388                 return (NULL);
1389         }
1390         DEBUG("rlm_ldap: waiting for bind result ...");
1391
1392         rc = ldap_result(ld, msgid, 1, &(inst->timeout), &res);
1393
1394         if(rc < 1) {
1395                 DEBUG("rlm_ldap: ldap_result()");
1396                 ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &ldap_errno);
1397                 radlog(L_ERR, "rlm_ldap: %s bind to %s:%d failed: %s",
1398                         dn, inst->server, inst->port,
1399                         (rc == 0) ? "timeout" : ldap_err2string(ldap_errno));
1400                 *result = RLM_MODULE_FAIL;
1401                 ldap_unbind_s(ld);
1402                 return (NULL);
1403         }
1404         ldap_errno = ldap_result2error(ld, res, 1);
1405         switch (ldap_errno) {
1406         case LDAP_SUCCESS:
1407                 *result = RLM_MODULE_OK;
1408                 break;
1409
1410         case LDAP_INVALID_CREDENTIALS:
1411                 if (auth) 
1412                         *result = RLM_MODULE_REJECT;
1413                 else {
1414                         radlog(L_ERR, "rlm_ldap: LDAP login failed: check login, password settings in ldap section of radiusd.conf");
1415                         *result = RLM_MODULE_FAIL;
1416                 }               
1417                 break;
1418                 
1419         default:
1420                 radlog(L_ERR,"rlm_ldap: %s bind to %s:%d failed %s",
1421                         dn, inst->server, inst->port,
1422                         ldap_err2string(ldap_errno));
1423                 *result = RLM_MODULE_FAIL;
1424         }
1425
1426         if (*result != RLM_MODULE_OK) {
1427                 ldap_unbind_s(ld);
1428                 ld = NULL;
1429         }
1430         return ld;
1431 }
1432
1433 /*****************************************************************************
1434  *
1435  *      Detach from the LDAP server and cleanup internal state.
1436  *
1437  *****************************************************************************/
1438 static int 
1439 ldap_detach(void *instance)
1440 {
1441         ldap_instance  *inst = instance;
1442         TLDAP_RADIUS *pair, *nextpair;
1443
1444         if (inst->server)
1445                 free((char *) inst->server);
1446         if (inst->login)
1447                 free((char *) inst->login);
1448         if (inst->password)
1449                 free((char *) inst->password);
1450         if (inst->basedn)
1451                 free((char *) inst->basedn);
1452         if (inst->access_group)
1453                 free((char *) inst->access_group);
1454         if (inst->dictionary_mapping)
1455                 free(inst->dictionary_mapping);
1456         if (inst->filter)
1457                 free((char *) inst->filter);
1458         if (inst->passwd_hdr)
1459                 free((char *) inst->passwd_hdr);
1460         if (inst->passwd_attr)
1461                 free((char *) inst->passwd_attr);
1462         if (inst->groupname_attr)
1463                 free((char *) inst->groupname_attr);
1464         if (inst->groupmemb_filt)
1465                 free((char *) inst->groupmemb_filt);
1466         if (inst->conns){
1467                 int i=0;
1468
1469                 for(;i<inst->num_conns;i++){
1470                         if (inst->conns[i].ld){
1471                                 if (inst->cache_timeout >0)
1472                                         ldap_destroy_cache(inst->conns[i].ld);
1473                                 ldap_unbind_s(inst->conns[i].ld);
1474                         }
1475                         pthread_mutex_destroy(&inst->conns[i].mutex);
1476                 }
1477                 free(inst->conns);
1478         }
1479
1480         pair = inst->check_item_map;
1481         
1482         while (pair != NULL) {
1483                 nextpair = pair->next;
1484                 free(pair->attr);
1485                 free(pair->radius_attr);
1486                 free(pair);
1487                 pair = nextpair;
1488         }
1489
1490         pair = inst->reply_item_map;
1491
1492         while (pair != NULL) {
1493                 nextpair = pair->next;
1494                 free(pair->attr);
1495                 free(pair->radius_attr);
1496                 free(pair);
1497                 pair = nextpair;
1498         }
1499
1500         if (inst->atts){
1501                 int i = 0;
1502
1503                 while(inst->atts[i])
1504                         free(inst->atts[i++]);
1505                 free(inst->atts);
1506         }
1507
1508         paircompare_unregister(PW_LDAP_GROUP, ldap_groupcmp);
1509         xlat_unregister(inst->xlat_name,ldap_xlat);
1510         free(inst->xlat_name);
1511
1512         free(inst);
1513
1514         return 0;
1515 }
1516
1517 #ifdef FIELDCPY
1518 static void 
1519 fieldcpy(char *string, char **uptr)
1520 {
1521         char           *ptr;
1522
1523         ptr = *uptr;
1524         while (*ptr == ' ' || *ptr == '\t') {
1525                 ptr++;
1526         }
1527         if (*ptr == '"') {
1528                 ptr++;
1529                 while (*ptr != '"' && *ptr != '\0' && *ptr != '\n') {
1530                         *string++ = *ptr++;
1531                 }
1532                 *string = '\0';
1533                 if (*ptr == '"') {
1534                         ptr++;
1535                 }
1536                 *uptr = ptr;
1537                 return;
1538         }
1539         while (*ptr != ' ' && *ptr != '\t' && *ptr != '\0' && *ptr != '\n' &&
1540                *ptr != '=' && *ptr != ',') {
1541                 *string++ = *ptr++;
1542         }
1543         *string = '\0';
1544         *uptr = ptr;
1545         return;
1546 }
1547 #endif
1548 /*****************************************************************************
1549  *      Get RADIUS attributes from LDAP object
1550  *      ( according to draft-adoba-radius-05.txt
1551  *        <http://www.ietf.org/internet-drafts/draft-adoba-radius-05.txt> )
1552  *
1553  *****************************************************************************/
1554
1555 static VALUE_PAIR *
1556 ldap_pairget(LDAP * ld, LDAPMessage * entry,
1557              TLDAP_RADIUS * item_map, VALUE_PAIR **pairs)
1558 {
1559         char          **vals;
1560         int             vals_count;
1561         int             vals_idx;
1562         char           *ptr;
1563         TLDAP_RADIUS   *element;
1564         LRAD_TOKEN      token;
1565         int             is_generic_attribute;
1566         char            value[64];
1567         VALUE_PAIR     *pairlist = NULL;
1568         VALUE_PAIR     *newpair = NULL;
1569
1570         /* check if there is a mapping from this LDAP attribute to a RADIUS attribute */
1571         for (element = item_map; element != NULL; element = element->next) {
1572         if ((vals = ldap_get_values(ld,entry,element->attr)) != NULL){
1573                         /* check whether this is a one-to-one-mapped ldap attribute or a generic
1574                            attribute and set flag accordingly */
1575
1576                         if (strcasecmp(element->radius_attr, GENERIC_ATTRIBUTE_ID)==0)
1577                                 is_generic_attribute = 1;
1578                         else
1579                                 is_generic_attribute = 0;
1580
1581                         /* find out how many values there are for the attribute and extract all of them */
1582
1583                         vals_count = ldap_count_values(vals);
1584
1585                         for (vals_idx = 0; vals_idx < vals_count; vals_idx++) {
1586                                 ptr = vals[vals_idx];
1587
1588                                 if (is_generic_attribute) {
1589                                         /* this is a generic attribute */
1590                                         LRAD_TOKEN dummy; /* makes pairread happy */
1591                                         
1592                                         /* not sure if using pairread here is ok ... */
1593                                         if ( (newpair = pairread(&ptr, &dummy)) != NULL) {
1594                                                 DEBUG("rlm_ldap: extracted attribute %s from generic item %s", 
1595                                                       newpair->name, vals[vals_idx]);
1596                                                 if (! vals_idx){
1597                                                         pairdelete(pairs,newpair->attribute);
1598                                                 }
1599                                                 pairadd(&pairlist, newpair);
1600                                         } else {
1601                                                 radlog(L_ERR, "rlm_ldap: parsing %s failed: %s", 
1602                                                        element->attr, vals[vals_idx]);
1603                                         }
1604                                 } else {
1605                                         /* this is a one-to-one-mapped attribute */
1606                                         token = gettoken(&ptr, value, sizeof(value));
1607                                         if (token < T_EQSTART || token > T_EQEND) {
1608                                                 token = T_OP_EQ;
1609                                         } else {
1610                                                 gettoken(&ptr, value, sizeof(value));
1611                                         }
1612                                         if (value[0] == 0) {
1613                                                 DEBUG("rlm_ldap: Attribute %s has no value", element->attr);
1614                                                 break;
1615                                         }
1616                                         DEBUG("rlm_ldap: Adding %s as %s, value %s & op=%d", element->attr, element->radius_attr, value, token);
1617                                                 if ((newpair = pairmake(element->radius_attr, value, token)) == NULL)
1618                                                 continue;
1619                                         if (! vals_idx){
1620                                                 pairdelete(pairs,newpair->attribute);
1621                                         }
1622                                         pairadd(&pairlist, newpair);
1623                                 }
1624                         }
1625                         ldap_value_free(vals);
1626                 }
1627         }
1628
1629         return (pairlist);
1630 }
1631
1632 /* globally exported name */
1633 module_t        rlm_ldap = {
1634         "LDAP",
1635         RLM_TYPE_THREAD_SAFE,   /* type: reserved        */
1636         NULL,                   /* initialization        */
1637         ldap_instantiate,       /* instantiation         */
1638         {
1639                 ldap_authenticate,      /* authentication        */
1640                 ldap_authorize,         /* authorization         */
1641                 NULL,                   /* preaccounting         */
1642                 NULL,                   /* accounting            */
1643                 NULL                    /* checksimul            */
1644         },
1645         ldap_detach,            /* detach                */
1646         NULL,                   /* destroy               */
1647 };