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