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