Removed extraneous bracket
[freeradius.git] / src / modules / rlm_ldap / rlm_ldap.c
1 /*
2  * rlm_ldap.c   LDAP authorization and authentication module.
3  *
4  *   This program is free software; you can redistribute it and/or modify
5  *   it under the terms of the GNU General Public License as published by
6  *   the Free Software Foundation; either version 2 of the License, or
7  *   (at your option) any later version.
8  *
9  *   This program is distributed in the hope that it will be useful,
10  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  *   GNU General Public License for more details.
13  *
14  *   You should have received a copy of the GNU General Public License
15  *   along with this program; if not, write to the Free Software
16  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17  *
18  *   Copyright 2004 The FreeRADIUS Server Project.
19  */
20 static const char rcsid[] = "$Id$";
21
22 #include "autoconf.h"
23
24 #include        <sys/types.h>
25 #include        <sys/socket.h>
26 #include        <sys/time.h>
27 #include        <netinet/in.h>
28
29 #include        <stdio.h>
30 #include        <stdlib.h>
31 #include        <netdb.h>
32 #include        <pwd.h>
33 #include        <time.h>
34 #include        <ctype.h>
35 #include        <string.h>
36
37 #include        <lber.h>
38 #include        <ldap.h>
39
40 #include        <errno.h>
41 #include        <unistd.h>
42 #include        <pthread.h>
43
44 #include        "libradius.h"
45 #include        "radiusd.h"
46 #include        "conffile.h"
47 #include        "modules.h"
48 #include        "rad_assert.h"
49
50 #ifndef HAVE_PTHREAD_H
51 /*
52  *      This is a lot simpler than putting ifdef's around
53  *      every use of the pthread functions.
54  */
55 #define pthread_mutex_lock(a)
56 #define pthread_mutex_unlock(a)
57 #define pthread_mutex_init(a,b)
58 #define pthread_mutex_destroy(a)
59 #endif
60
61
62 #define MAX_FILTER_STR_LEN      1024
63 #define TIMELIMIT 5
64
65 /*
66  * These are used in case ldap_search returns LDAP_SERVER_DOWN
67  * In that case we do conn->failed_conns++ and then check it:
68  * If conn->failed_conns <= MAX_FAILED_CONNS_START then we try
69  * to reconnect
70  * conn->failed_conns is also checked on entrance in perform_search:
71  * If conn->failed_conns > MAX_FAILED_CONNS_START then we don't
72  * try to do anything and we just do conn->failed_conns++ and
73  * return RLM_MODULE_FAIL
74  * if conn->failed_conns >= MAX_FAILED_CONNS_END then we give it
75  * another chance and we set it to MAX_FAILED_CONNS_RESTART and
76  * try to reconnect.
77  *
78  *
79  * We are assuming that the majority of the LDAP_SERVER_DOWN cases
80  * will either be an ldap connection timeout or a temporary ldap
81  * server problem.
82  * As a result we make a few attempts to reconnect hoping that the problem
83  * will soon go away. If it does not go away then we just return
84  * RLM_MODULE_FAIL on entrance in perform_search until conn->failed_conns
85  * gets to MAX_FAILED_CONNS_END. After that we give it one more chance by
86  * going back to MAX_FAILED_CONNS_RESTART
87  *
88  */
89
90 #define MAX_FAILED_CONNS_END            20
91 #define MAX_FAILED_CONNS_RESTART        4
92 #define MAX_FAILED_CONNS_START          5
93
94 /* linked list of mappings between RADIUS attributes and LDAP attributes */
95 struct TLDAP_RADIUS {
96         char*                 attr;
97         char*                 radius_attr;
98         LRAD_TOKEN            operator;
99         struct TLDAP_RADIUS*  next;
100 };
101 typedef struct TLDAP_RADIUS TLDAP_RADIUS;
102
103 typedef struct ldap_conn {
104         LDAP            *ld;
105         char            bound;
106         char            locked;
107         int             failed_conns;
108 #ifdef HAVE_PTHREAD_H
109         pthread_mutex_t mutex;
110 #endif
111 } LDAP_CONN;
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             do_comp;
124         int             do_xlat;
125         int             default_allow;
126         int             failed_conns;
127         int             is_url;
128         char           *login;
129         char           *password;
130         char           *filter;
131         char           *base_filter;
132         char           *basedn;
133         char           *default_profile;
134         char           *profile_attr;
135         char           *access_attr;
136         char           *passwd_hdr;
137         char           *passwd_attr;
138         char           *dictionary_mapping;
139         char           *groupname_attr;
140         char           *groupmemb_filt;
141         char           *groupmemb_attr;
142         char            **atts;
143         TLDAP_RADIUS   *check_item_map;
144         TLDAP_RADIUS   *reply_item_map;
145         LDAP_CONN       *conns;
146         int             ldap_debug; /* Debug flag for LDAP SDK */
147         char            *xlat_name; /* name used to xlat */
148         char            *tls_cacertfile;
149         char            *tls_cacertdir;
150         char            *tls_certfile;
151         char            *tls_keyfile;
152         char            *tls_randfile;
153         char            *tls_require_cert;
154 }  ldap_instance;
155
156 /* The default setting for TLS Certificate Verification */
157 #define TLS_DEFAULT_VERIFY "allow"
158
159 static CONF_PARSER module_config[] = {
160         {"server", PW_TYPE_STRING_PTR, offsetof(ldap_instance,server), NULL, "localhost"},
161         {"port", PW_TYPE_INTEGER, offsetof(ldap_instance,port), NULL, "389"},
162         /* wait forever on network activity */
163         {"net_timeout", PW_TYPE_INTEGER, offsetof(ldap_instance,net_timeout.tv_sec), NULL, "10"},
164         /* wait forever for search results */
165         {"timeout", PW_TYPE_INTEGER, offsetof(ldap_instance,timeout.tv_sec), NULL, "20"},
166         /* allow server unlimited time for search (server-side limit) */
167         {"timelimit", PW_TYPE_INTEGER, offsetof(ldap_instance,timelimit), NULL, "20"},
168         {"identity", PW_TYPE_STRING_PTR, offsetof(ldap_instance,login), NULL, ""},
169         {"tls_mode", PW_TYPE_BOOLEAN, offsetof(ldap_instance,tls_mode), NULL, "no"},
170         {"start_tls", PW_TYPE_BOOLEAN, offsetof(ldap_instance,start_tls), NULL, "no"},
171         {"tls_cacertfile", PW_TYPE_STRING_PTR, offsetof(ldap_instance,tls_cacertfile), NULL, NULL},
172         {"tls_cacertdir", PW_TYPE_STRING_PTR, offsetof(ldap_instance,tls_cacertdir), NULL, NULL},
173         {"tls_certfile", PW_TYPE_STRING_PTR, offsetof(ldap_instance,tls_certfile), NULL, NULL},
174         {"tls_keyfile", PW_TYPE_STRING_PTR, offsetof(ldap_instance,tls_keyfile), NULL, NULL},
175         {"tls_randfile", PW_TYPE_STRING_PTR, offsetof(ldap_instance,tls_randfile), NULL, NULL},
176         {"tls_require_cert", PW_TYPE_STRING_PTR, offsetof(ldap_instance,tls_require_cert), NULL, TLS_DEFAULT_VERIFY},
177         {"password", PW_TYPE_STRING_PTR, offsetof(ldap_instance,password), NULL, ""},
178         {"basedn", PW_TYPE_STRING_PTR, offsetof(ldap_instance,basedn), NULL, "o=notexist"},
179         {"filter", PW_TYPE_STRING_PTR, offsetof(ldap_instance,filter), NULL, "(uid=%u)"},
180         {"base_filter", PW_TYPE_STRING_PTR, offsetof(ldap_instance,base_filter), NULL, "(objectclass=radiusprofile)"},
181         {"default_profile", PW_TYPE_STRING_PTR, offsetof(ldap_instance,default_profile), NULL, NULL},
182         {"profile_attribute", PW_TYPE_STRING_PTR, offsetof(ldap_instance,profile_attr), NULL, NULL},
183         {"password_header", PW_TYPE_STRING_PTR, offsetof(ldap_instance,passwd_hdr), NULL, NULL},
184         {"password_attribute", PW_TYPE_STRING_PTR, offsetof(ldap_instance,passwd_attr), NULL, NULL},
185         /* LDAP attribute name that controls remote access */
186         {"access_attr", PW_TYPE_STRING_PTR, offsetof(ldap_instance,access_attr), NULL, NULL},
187         /* file with mapping between LDAP and RADIUS attributes */
188         {"groupname_attribute", PW_TYPE_STRING_PTR, offsetof(ldap_instance,groupname_attr), NULL, "cn"},
189         {"groupmembership_filter", PW_TYPE_STRING_PTR, offsetof(ldap_instance,groupmemb_filt), NULL, "(|(&(objectClass=GroupOfNames)(member=%{Ldap-UserDn}))(&(objectClass=GroupOfUniqueNames)(uniquemember=%{Ldap-UserDn})))"},
190         {"groupmembership_attribute", PW_TYPE_STRING_PTR, offsetof(ldap_instance,groupmemb_attr), NULL, NULL},
191         {"dictionary_mapping", PW_TYPE_STRING_PTR, offsetof(ldap_instance,dictionary_mapping), NULL, "${confdir}/ldap.attrmap"},
192         {"ldap_debug", PW_TYPE_INTEGER, offsetof(ldap_instance,ldap_debug), NULL, "0x0000"},
193         {"ldap_connections_number", PW_TYPE_INTEGER, offsetof(ldap_instance,num_conns), NULL, "5"},
194         {"compare_check_items", PW_TYPE_BOOLEAN, offsetof(ldap_instance,do_comp), NULL, "no"},
195         {"access_attr_used_for_allow", PW_TYPE_BOOLEAN, offsetof(ldap_instance,default_allow), NULL, "yes"},
196         {"do_xlat", PW_TYPE_BOOLEAN, offsetof(ldap_instance,do_xlat), NULL, "yes"},
197
198         {NULL, -1, 0, NULL, NULL}
199 };
200
201 #define ld_valid                ld_options.ldo_valid
202 #define LDAP_VALID_SESSION      0x2
203 #define LDAP_VALID(ld)  ( (ld)->ld_valid == LDAP_VALID_SESSION )
204
205 #ifdef FIELDCPY
206 static void     fieldcpy(char *, char **);
207 #endif
208 static VALUE_PAIR *ldap_pairget(LDAP *, LDAPMessage *, TLDAP_RADIUS *,VALUE_PAIR **,char);
209 static int ldap_groupcmp(void *, REQUEST *, VALUE_PAIR *, VALUE_PAIR *, VALUE_PAIR *, VALUE_PAIR **);
210 static int ldap_xlat(void *,REQUEST *, char *, char *,int, RADIUS_ESCAPE_STRING);
211 static LDAP    *ldap_connect(void *instance, const char *, const char *, int, int *);
212 static int     read_mappings(ldap_instance* inst);
213
214 static inline int ldap_get_conn(LDAP_CONN *conns,LDAP_CONN **ret,void *instance)
215 {
216         ldap_instance *inst = instance;
217         register int i = 0;
218
219         for(i=0;i<inst->num_conns;i++){
220                 DEBUG("rlm_ldap: ldap_get_conn: Checking Id: %d",i);
221                 if ((conns[i].locked == 0) &&
222                     (pthread_mutex_trylock(&(conns[i].mutex)) == 0)) {
223                         *ret = &conns[i];
224                         conns[i].locked = 1;
225                         DEBUG("rlm_ldap: ldap_get_conn: Got Id: %d",i);
226                         return i;
227                 }
228         }
229
230         return -1;
231 }
232
233 static inline void ldap_release_conn(int i, LDAP_CONN *conns)
234 {
235         DEBUG("rlm_ldap: ldap_release_conn: Release Id: %d",i);
236         conns[i].locked = 0;
237         pthread_mutex_unlock(&(conns[i].mutex));
238 }
239
240 /*************************************************************************
241  *
242  *      Function: rlm_ldap_instantiate
243  *
244  *      Purpose: Uses section of radiusd config file passed as parameter
245  *               to create an instance of the module.
246  *
247  *************************************************************************/
248 static int
249 ldap_instantiate(CONF_SECTION * conf, void **instance)
250 {
251         ldap_instance  *inst;
252         int i = 0;
253         int atts_num = 0;
254         int reply_map_num = 0;
255         int check_map_num = 0;
256         int att_map[3] = {0,0,0};
257         TLDAP_RADIUS *pair;
258         ATTR_FLAGS flags;
259         char *xlat_name;
260
261         inst = rad_malloc(sizeof *inst);
262         if (!inst) {
263                 return -1;
264         }
265         memset(inst, 0, sizeof(*inst));
266
267         if (cf_section_parse(conf, inst, module_config) < 0) {
268                 free(inst);
269                 return -1;
270         }
271
272         if (inst->server == NULL) {
273                 radlog(L_ERR, "rlm_ldap: missing 'server' directive.");
274                 free(inst);
275                 return -1;
276         }
277         inst->is_url = 0;
278         if (ldap_is_ldap_url(inst->server)){
279 #ifdef HAVE_LDAP_INITIALIZE
280                 inst->is_url = 1;
281                 inst->port = 0;
282 #else
283                 radlog(L_ERR, "rlm_ldap: 'server' directive is in URL form but ldap_initialize() is not available.");
284                 free(inst);
285                 return -1;
286 #endif
287         }
288
289         inst->timeout.tv_usec = 0;
290         inst->net_timeout.tv_usec = 0;
291         /* workaround for servers which support LDAPS but not START TLS */
292         if(inst->port == LDAPS_PORT || inst->tls_mode)
293                 inst->tls_mode = LDAP_OPT_X_TLS_HARD;
294         else
295                 inst->tls_mode = 0;
296         inst->reply_item_map = NULL;
297         inst->check_item_map = NULL;
298         inst->conns = NULL;
299         inst->failed_conns = 0;
300
301         DEBUG("rlm_ldap: Registering ldap_groupcmp for Ldap-Group");
302         paircompare_register(PW_LDAP_GROUP, PW_USER_NAME, ldap_groupcmp, inst);
303
304         xlat_name = cf_section_name2(conf);
305         if (xlat_name != NULL){
306                 char *group_name;
307                 DICT_ATTR *dattr;
308
309                 /*
310                  * Allocate room for <instance>-Ldap-Group
311                  */
312                 group_name = malloc((strlen(xlat_name) + 1 + 11) * sizeof(char));
313                 rad_assert(group_name != NULL);
314                 sprintf(group_name,"%s-Ldap-Group",xlat_name);
315                 DEBUG("rlm_ldap: Creating new attribute %s",group_name);
316                 dict_addattr(group_name, 0, PW_TYPE_STRING, -1, flags);
317                 dattr = dict_attrbyname(group_name);
318                 if (dattr == NULL){
319                         radlog(L_ERR, "rlm_ldap: Failed to create attribute %s",group_name);
320                         free(inst);
321                         return -1;
322                 }
323                 DEBUG("rlm_ldap: Registering ldap_groupcmp for %s",group_name);
324                 paircompare_register(dattr->attr, PW_USER_NAME, ldap_groupcmp, inst);
325         }
326         else {
327                 xlat_name = cf_section_name1(conf);
328                 rad_assert(xlat_name != NULL); /* or all hell breaks loose */
329         }
330         inst->xlat_name = strdup(xlat_name);
331         DEBUG("rlm_ldap: Registering ldap_xlat with xlat_name %s",xlat_name);
332         xlat_register(xlat_name,ldap_xlat,inst);
333
334         if (inst->num_conns <= 0){
335                 radlog(L_ERR, "rlm_ldap: Invalid ldap connections number passed.");
336                 free(inst);
337                 return -1;
338         }
339         inst->conns = (LDAP_CONN *)malloc(sizeof(LDAP_CONN)*inst->num_conns);
340         if (inst->conns == NULL){
341                 radlog(L_ERR, "rlm_ldap: Could not allocate memory. Aborting.");
342                 free(inst);
343                 return -1;
344         }
345         for(;i<inst->num_conns;i++){
346                 inst->conns[i].bound = 0;
347                 inst->conns[i].locked = 0;
348                 inst->conns[i].failed_conns = 0;
349                 inst->conns[i].ld = NULL;
350                 pthread_mutex_init(&inst->conns[i].mutex, NULL);
351         }
352
353         if (read_mappings(inst) != 0) {
354                 radlog(L_ERR, "rlm_ldap: Reading dictionary mappings from file %s failed",
355                        inst->dictionary_mapping);
356                 free(inst);
357                 return -1;
358         }
359         if ((inst->check_item_map == NULL) &&
360             (inst->reply_item_map == NULL)) {
361                 radlog(L_ERR, "rlm_ldap: dictionary mappings file %s did not contain any mappings",
362                         inst->dictionary_mapping);
363                 free(inst);
364                 return -1;
365         }
366
367         pair = inst->check_item_map;
368         while(pair != NULL){
369                 atts_num++;
370                 pair = pair->next;
371         }
372         check_map_num = (atts_num - 1);
373         pair = inst->reply_item_map;
374         while(pair != NULL){
375                 atts_num++;
376                 pair = pair->next;
377         }
378         reply_map_num = (atts_num - 1);
379         if (inst->profile_attr)
380                 atts_num++;
381         if (inst->passwd_attr)
382                 atts_num++;
383         if (inst->access_attr)
384                 atts_num++;
385         inst->atts = (char **)malloc(sizeof(char *)*(atts_num + 1));
386         if (inst->atts == NULL){
387                 radlog(L_ERR, "rlm_ldap: Could not allocate memory. Aborting.");
388                 free(inst);
389                 return -1;
390         }
391         pair = inst->check_item_map;
392         if (pair == NULL)
393                 pair = inst->reply_item_map;
394         for(i=0;i<atts_num;i++){
395                 if (i <= check_map_num ){
396                         inst->atts[i] = pair->attr;
397                         if (i == check_map_num)
398                                 pair = inst->reply_item_map;
399                         else
400                                 pair = pair->next;
401                 }
402                 else if (i <= reply_map_num){
403                         inst->atts[i] = pair->attr;
404                         pair = pair->next;
405                 }
406                 else{
407                         if (inst->profile_attr && !att_map[0]){
408                                 inst->atts[i] = inst->profile_attr;
409                                 att_map[0] = 1;
410                         }
411                         else if (inst->passwd_attr && !att_map[1]){
412                                 inst->atts[i] = inst->passwd_attr;
413                                 att_map[1] = 1;
414                         }
415                         else if (inst->access_attr && !att_map[2]){
416                                 inst->atts[i] = inst->access_attr;
417                                 att_map[2] = 1;
418                         }
419                 }
420         }
421         inst->atts[atts_num] = NULL;
422
423         DEBUG("conns: %p",inst->conns);
424
425         *instance = inst;
426
427
428         return 0;
429 }
430
431
432 /*
433  * read_mappings(...) reads a ldap<->radius mappings file to inst->reply_item_map and inst->check_item_map
434  */
435
436 #define MAX_LINE_LEN 160
437 #define GENERIC_ATTRIBUTE_ID "$GENERIC$"
438
439 static int
440 read_mappings(ldap_instance* inst)
441 {
442         FILE* mapfile;
443         char *filename;
444         /* all buffers are of MAX_LINE_LEN so we can use sscanf without being afraid of buffer overflows */
445         char buf[MAX_LINE_LEN], itemType[MAX_LINE_LEN];
446         char radiusAttribute[MAX_LINE_LEN], ldapAttribute[MAX_LINE_LEN];
447         int linenumber;
448         LRAD_TOKEN operator;
449         char opstring[MAX_LINE_LEN];
450
451         /* open the mappings file for reading */
452
453         filename = inst->dictionary_mapping;
454         DEBUG("rlm_ldap: reading ldap<->radius mappings from file %s", filename);
455         mapfile = fopen(filename, "r");
456
457         if (mapfile == NULL) {
458                 radlog(L_ERR, "rlm_ldap: Opening file %s failed", filename);
459                 return -1; /* error */
460         }
461
462         /* read file line by line. Note that if line length exceed MAX_LINE_LEN, line numbers will be mixed up */
463
464         linenumber = 0;
465
466         while (fgets(buf, sizeof buf, mapfile)!=NULL) {
467                 char* ptr;
468                 int token_count;
469                 TLDAP_RADIUS* pair;
470
471                 linenumber++;
472
473                 /* strip comments */
474                 ptr = strchr(buf, '#');
475                 if (ptr) *ptr = 0;
476
477                 /* empty line */
478                 if (buf[0] == 0) continue;
479
480                 /* extract tokens from the string */
481                 token_count = sscanf(buf, "%s %s %s %s",
482                                      itemType, radiusAttribute,
483                                      ldapAttribute, opstring);
484
485                 if (token_count <= 0) /* no tokens */
486                         continue;
487
488                 if ((token_count < 3) || (token_count > 4)) {
489                         radlog(L_ERR, "rlm_ldap: Skipping %s line %i: %s",
490                                filename, linenumber, buf);
491                         radlog(L_ERR, "rlm_ldap: Expected 3 to 4 tokens "
492                                "(Item type, RADIUS Attribute and LDAP Attribute) but found only %i", token_count);
493                         continue;
494                 }
495
496                 if (token_count == 3) {
497                         operator = T_INVALID; /* use defaults */
498                 } else {
499                         char *ptr;
500                         
501                         ptr = opstring;
502                         operator = gettoken(&ptr, buf, sizeof(buf));
503                         if ((operator < T_OP_ADD) || (operator > T_OP_CMP_EQ)) {
504                                 radlog(L_ERR, "rlm_ldap: file %s: skipping line %i: unknown or invalid operator %s",
505                                        filename, linenumber, opstring);
506                                 free(pair->attr);
507                                 free(pair->radius_attr);
508                                 free(pair);
509                                 continue;
510                         }
511                 }
512
513                 /* create new TLDAP_RADIUS list node */
514                 pair = rad_malloc(sizeof(TLDAP_RADIUS));
515
516                 pair->attr = strdup(ldapAttribute);
517                 pair->radius_attr = strdup(radiusAttribute);
518                 pair->operator = operator;
519
520                 if ( (pair->attr == NULL) || (pair->radius_attr == NULL) ) {
521                         radlog(L_ERR, "rlm_ldap: Out of memory");
522                         if (pair->attr) free(pair->attr);
523                         if (pair->radius_attr) free(pair->radius_attr);
524                         free(pair);
525                         fclose(mapfile);
526                         return -1;
527                 }
528
529                 /* push node to correct list */
530                 if (strcasecmp(itemType, "checkItem") == 0) {
531                         pair->next = inst->check_item_map;
532                         inst->check_item_map = pair;
533                 } else if (strcasecmp(itemType, "replyItem") == 0) {
534                         pair->next = inst->reply_item_map;
535                         inst->reply_item_map = pair;
536                 } else {
537                         radlog(L_ERR, "rlm_ldap: file %s: skipping line %i: unknown itemType %s",
538                                filename, linenumber, itemType);
539                         free(pair->attr);
540                         free(pair->radius_attr);
541                         free(pair);
542                         continue;
543                 }
544
545                 DEBUG("rlm_ldap: LDAP %s mapped to RADIUS %s",
546                       pair->attr, pair->radius_attr);
547         }
548
549         fclose(mapfile);
550
551         return 0; /* success */
552 }
553
554 static int
555 perform_search(void *instance, LDAP_CONN *conn, char *search_basedn, int scope, char *filter,
556                 char **attrs, LDAPMessage ** result)
557 {
558         int             res = RLM_MODULE_OK;
559         int             ldap_errno = 0;
560         ldap_instance  *inst = instance;
561         int             search_retry = 0;
562
563         *result = NULL;
564
565         if (!conn){
566                 radlog(L_ERR, "rlm_ldap: NULL connection handle passed");
567                 return RLM_MODULE_FAIL;
568         }
569         if (conn->failed_conns > MAX_FAILED_CONNS_START){
570                 conn->failed_conns++;
571                 if (conn->failed_conns >= MAX_FAILED_CONNS_END){
572                         conn->failed_conns = MAX_FAILED_CONNS_RESTART;
573                         conn->bound = 0;
574                 }
575         }
576 retry:
577         if (!conn->bound || conn->ld == NULL) {
578                 DEBUG2("rlm_ldap: attempting LDAP reconnection");
579                 if (conn->ld){
580                         DEBUG2("rlm_ldap: closing existing LDAP connection");
581                         ldap_unbind_s(conn->ld);
582                 }
583                 if ((conn->ld = ldap_connect(instance, inst->login,
584                                              inst->password, 0, &res)) == NULL) {
585                         radlog(L_ERR, "rlm_ldap: (re)connection attempt failed");
586                         if (search_retry == 0)
587                                 conn->failed_conns++;
588                         return (RLM_MODULE_FAIL);
589                 }
590                 conn->bound = 1;
591                 conn->failed_conns = 0;
592         }
593         DEBUG2("rlm_ldap: performing search in %s, with filter %s",
594                search_basedn ? search_basedn : "(null)" , filter);
595         switch (ldap_search_st(conn->ld, search_basedn, scope, filter,
596                                attrs, 0, &(inst->timeout), result)) {
597         case LDAP_SUCCESS:
598         case LDAP_NO_SUCH_OBJECT:
599                 break;
600         case LDAP_SERVER_DOWN:
601                 radlog(L_ERR, "rlm_ldap: ldap_search() failed: LDAP connection lost.");
602                 conn->failed_conns++;
603                 if (search_retry == 0){
604                         if (conn->failed_conns <= MAX_FAILED_CONNS_START){
605                                 radlog(L_INFO, "rlm_ldap: Attempting reconnect");
606                                 search_retry = 1;
607                                 conn->bound = 0;
608                                 ldap_msgfree(*result);
609                                 goto retry;
610                         }
611                 }
612                 ldap_msgfree(*result);
613                 return RLM_MODULE_FAIL;
614         case LDAP_INSUFFICIENT_ACCESS:
615                 radlog(L_ERR, "rlm_ldap: ldap_search() failed: Insufficient access. Check the identity and password configuration directives.");
616                 ldap_msgfree(*result);
617                 return RLM_MODULE_FAIL;
618         case LDAP_TIMEOUT:
619                 radlog(L_ERR, "rlm_ldap: ldap_search() failed: Timed out while waiting for server to respond. Please increase the timeout.");
620                 ldap_msgfree(*result);
621                 return RLM_MODULE_FAIL;
622         case LDAP_FILTER_ERROR:
623                 radlog(L_ERR, "rlm_ldap: ldap_search() failed: Bad search filter: %s",filter);
624                 ldap_msgfree(*result);
625                 return RLM_MODULE_FAIL;
626         case LDAP_TIMELIMIT_EXCEEDED:
627         case LDAP_BUSY:
628         case LDAP_UNAVAILABLE:
629                 /* We don't need to reconnect in these cases so we don't set conn->bound */
630                 ldap_get_option(conn->ld, LDAP_OPT_ERROR_NUMBER, &ldap_errno);
631                 radlog(L_ERR, "rlm_ldap: ldap_search() failed: %s",
632                        ldap_err2string(ldap_errno));
633                 ldap_msgfree(*result);
634                 return (RLM_MODULE_FAIL);
635         default:
636                 ldap_get_option(conn->ld, LDAP_OPT_ERROR_NUMBER, &ldap_errno);
637                 radlog(L_ERR, "rlm_ldap: ldap_search() failed: %s",
638                        ldap_err2string(ldap_errno));
639                 conn->bound = 0;
640                 ldap_msgfree(*result);
641                 return (RLM_MODULE_FAIL);
642         }
643
644         if ((ldap_count_entries(conn->ld, *result)) != 1) {
645                 DEBUG("rlm_ldap: object not found or got ambiguous search result");
646                 res = RLM_MODULE_NOTFOUND;
647                 ldap_msgfree(*result);
648         }
649         return res;
650 }
651
652
653 /*
654  *      Translate the LDAP queries.
655  */
656 static int ldap_escape_func(char *out, int outlen, const char *in)
657 {
658         int len = 0;
659
660         while (in[0]) {
661                 /*
662                  *  Only one byte left.
663                  */
664                 if (outlen <= 1) {
665                         break;
666                 }
667
668                 if (strchr("*", *in)) {
669                         in++;
670                         outlen--;
671                         continue;
672                 }
673
674                 /*
675                  *      Else it's a nice character.
676                  */
677                 *out = *in;
678                 out++;
679                 in++;
680                 outlen--;
681                 len++;
682         }
683         *out = '\0';
684         return len;
685 }
686
687 /*
688  * ldap_groupcmp(). Implement the Ldap-Group == "group" filter
689  */
690
691 static int ldap_groupcmp(void *instance, REQUEST *req, VALUE_PAIR *request,
692                          VALUE_PAIR *check, VALUE_PAIR *check_pairs,
693                          VALUE_PAIR **reply_pairs)
694 {
695         char            filter[MAX_FILTER_STR_LEN];
696         char            gr_filter[MAX_FILTER_STR_LEN];
697         int             res;
698         LDAPMessage     *result = NULL;
699         LDAPMessage     *msg = NULL;
700         char            basedn[MAX_FILTER_STR_LEN];
701         char            *attrs[] = {"dn",NULL};
702         char            **vals;
703         ldap_instance   *inst = instance;
704         char            *group_attrs[] = {inst->groupmemb_attr,NULL};
705         LDAP_CONN       *conn;
706         int             conn_id = -1;
707         VALUE_PAIR      *vp_user_dn;
708         VALUE_PAIR      **request_pairs;
709
710         request_pairs = &req->config_items;
711
712         DEBUG("rlm_ldap: Entering ldap_groupcmp()");
713
714         if (check->strvalue == NULL || check->length == 0){
715                 DEBUG("rlm_ldap::ldap_groupcmp: Illegal group name");
716                 return 1;
717         }
718
719         if (req == NULL){
720                 DEBUG("rlm_ldap::ldap_groupcmp: NULL request");
721                 return 1;
722         }
723
724         if (!radius_xlat(basedn, sizeof(basedn), inst->basedn, req, NULL)) {
725                 DEBUG("rlm_ldap::ldap_groupcmp: unable to create basedn.");
726                 return 1;
727         }
728
729         while((vp_user_dn = pairfind(*request_pairs, PW_LDAP_USERDN)) == NULL){
730                 char            *user_dn = NULL;
731
732                 if (!radius_xlat(filter, sizeof(filter), inst->filter,
733                                         req, ldap_escape_func)){
734                         DEBUG("rlm_ldap::ldap_groupcmp: unable to create filter");
735                         return 1;
736                 }
737                 if ((conn_id = ldap_get_conn(inst->conns,&conn,inst)) == -1){
738                         radlog(L_ERR, "rlm_ldap: All ldap connections are in use");
739                         return 1;
740                 }
741                 if ((res = perform_search(inst, conn, basedn, LDAP_SCOPE_SUBTREE,
742                                         filter, attrs, &result)) != RLM_MODULE_OK){
743                         DEBUG("rlm_ldap::ldap_groupcmp: search failed");
744                         ldap_release_conn(conn_id,inst->conns);
745                         return 1;
746                 }
747                 if ((msg = ldap_first_entry(conn->ld, result)) == NULL) {
748                         DEBUG("rlm_ldap::ldap_groupcmp: ldap_first_entry() failed");
749                         ldap_release_conn(conn_id,inst->conns);
750                         ldap_msgfree(result);
751                         return 1;
752                 }
753                 if ((user_dn = ldap_get_dn(conn->ld, msg)) == NULL) {
754                         DEBUG("rlm_ldap:ldap_groupcmp:: ldap_get_dn() failed");
755                         ldap_release_conn(conn_id,inst->conns);
756                         ldap_msgfree(result);
757                         return 1;
758                 }
759                 ldap_release_conn(conn_id,inst->conns);
760                 /*
761                 * Adding new attribute containing DN for LDAP object associated with
762                 * given username
763                 */
764                 pairadd(request_pairs, pairmake("Ldap-UserDn", user_dn,
765                                                 T_OP_EQ));
766                 ldap_memfree(user_dn);
767                 ldap_msgfree(result);
768         }
769
770         if(!radius_xlat(gr_filter, sizeof(gr_filter),
771                         inst->groupmemb_filt, req, NULL)) {
772                 DEBUG("rlm_ldap::ldap_groupcmp: unable to create filter.");
773                 return 1;
774         }
775
776         if (strchr((char *)check->strvalue,',') != NULL) {
777                 /* This looks like a DN */
778                 snprintf(filter,sizeof(filter), "%s",gr_filter);
779                 snprintf(basedn,sizeof(basedn), "%s",(char *)check->strvalue);
780         } else
781                 snprintf(filter,sizeof(filter), "(&(%s=%s)%s)",
782                          inst->groupname_attr,
783                          (char *)check->strvalue,gr_filter);
784
785         if ((conn_id = ldap_get_conn(inst->conns,&conn,inst)) == -1) {
786                 radlog(L_ERR, "rlm_ldap: All ldap connections are in use");
787                 return 1;
788         }
789
790         if ((res = perform_search(inst, conn, basedn, LDAP_SCOPE_SUBTREE,
791                                 filter, attrs, &result)) == RLM_MODULE_OK) {
792                 DEBUG("rlm_ldap::ldap_groupcmp: User found in group %s",
793                                 (char *)check->strvalue);
794                 ldap_msgfree(result);
795                 ldap_release_conn(conn_id,inst->conns);
796                 return 0;
797         }
798
799         ldap_release_conn(conn_id,inst->conns);
800
801         if (res != RLM_MODULE_NOTFOUND ) {
802                 DEBUG("rlm_ldap::ldap_groupcmp: Search returned error");
803                 return 1;
804         }
805
806         if (inst->groupmemb_attr == NULL){
807                 /* search returned NOTFOUND and searching for membership
808                  * using user object attributes is not specified in config
809                  * file
810                  */
811                 DEBUG("rlm_ldap::ldap_groupcmp: Group %s not found or user is not a member.",(char *)check->strvalue);
812                 return 1;
813         }
814
815         snprintf(filter,sizeof(filter), "(objectclass=*)");
816         if ((conn_id = ldap_get_conn(inst->conns,&conn,inst)) == -1){
817                 radlog(L_ERR, "rlm_ldap: Add ldap connections are in use");
818                 return 1;
819         }
820         if ((res = perform_search(inst, conn, vp_user_dn->strvalue,
821                                   LDAP_SCOPE_BASE, filter, group_attrs,
822                                   &result)) != RLM_MODULE_OK) {
823                 DEBUG("rlm_ldap::ldap_groupcmp: Search returned error");
824                 ldap_release_conn(conn_id, inst->conns);
825                 return 1;
826         }
827
828         if ((msg = ldap_first_entry(conn->ld, result)) == NULL) {
829                 DEBUG("rlm_ldap::ldap_groupcmp: ldap_first_entry() failed");
830                 ldap_release_conn(conn_id,inst->conns);
831                 ldap_msgfree(result);
832                 return 1;
833         }
834         if ((vals = ldap_get_values(conn->ld, msg,
835                                     inst->groupmemb_attr)) != NULL) {
836                 unsigned int i = 0;
837                 char found = 0;
838
839                 for (;i < ldap_count_values(vals);i++){
840                         if (strchr(vals[i],',') != NULL){
841                                 /* This looks like a DN */
842                                 LDAPMessage *gr_result = NULL;
843                                 snprintf(filter,sizeof(filter), "(%s=%s)",
844                                         inst->groupname_attr,
845                                         (char *)check->strvalue);
846                                 if ((res = perform_search(inst, conn, vals[i],
847                                                 LDAP_SCOPE_BASE, filter,
848                                                 attrs, &gr_result)) != RLM_MODULE_OK){
849                                         if (res != RLM_MODULE_NOTFOUND) {
850                                                 DEBUG("rlm_ldap::ldap_groupcmp: Search returned error");
851                                                 ldap_value_free(vals);
852                                                 ldap_msgfree(result);
853                                                 ldap_release_conn(conn_id,inst->conns);
854                                                 return 1;
855                                         }
856                                 } else {
857                                         ldap_msgfree(gr_result);
858                                         found = 1;
859                                         break;
860                                 }
861                         } else {
862                                 if (strcmp(vals[i],(char *)check->strvalue) == 0){
863                                         found = 1;
864                                         break;
865                                 }
866                         }
867                 }
868                 ldap_value_free(vals);
869                 ldap_msgfree(result);
870                 if (found == 0){
871                         DEBUG("rlm_ldap::groupcmp: Group %s not found or user not a member",
872                                 (char *)check->strvalue);
873                         ldap_release_conn(conn_id,inst->conns);
874                         return 1;
875                 }
876         } else {
877                         DEBUG("rlm_ldap::ldap_groupcmp: ldap_get_values() failed");
878                         ldap_msgfree(result);
879                         ldap_release_conn(conn_id,inst->conns);
880                         return 1;
881         }
882
883         DEBUG("rlm_ldap::ldap_groupcmp: User found in group %s",(char *)check->strvalue);
884         ldap_release_conn(conn_id,inst->conns);
885
886         return 0;
887 }
888
889 /*
890  * ldap_xlat()
891  * Do an xlat on an LDAP URL
892  */
893
894 static int ldap_xlat(void *instance, REQUEST *request, char *fmt, char *out, int freespace,
895                                 RADIUS_ESCAPE_STRING func)
896 {
897         char url[MAX_FILTER_STR_LEN];
898         int res;
899         int ret = 0;
900         ldap_instance *inst = instance;
901         LDAPURLDesc *ldap_url;
902         LDAPMessage *result = NULL;
903         LDAPMessage *msg = NULL;
904         char **vals;
905         int conn_id = -1;
906         LDAP_CONN *conn;
907
908         DEBUG("rlm_ldap: - ldap_xlat");
909         if (!radius_xlat(url, sizeof(url), fmt, request, func)) {
910                 radlog (L_ERR, "rlm_ldap: Unable to create LDAP URL.\n");
911                 return 0;
912         }
913         if (!ldap_is_ldap_url(url)){
914                 radlog (L_ERR, "rlm_ldap: String passed does not look like an LDAP URL.\n");
915                 return 0;
916         }
917         if (ldap_url_parse(url,&ldap_url)){
918                 radlog (L_ERR, "rlm_ldap: LDAP URL parse failed.\n");
919                 return 0;
920         }
921         if (ldap_url->lud_attrs == NULL || ldap_url->lud_attrs[0] == NULL ||
922             ( ldap_url->lud_attrs[1] != NULL ||
923               ( ! strlen(ldap_url->lud_attrs[0]) ||
924                 ! strcmp(ldap_url->lud_attrs[0],"*") ) ) ){
925                 radlog (L_ERR, "rlm_ldap: Invalid Attribute(s) request.\n");
926                 ldap_free_urldesc(ldap_url);
927                 return 0;
928         }
929         if (ldap_url->lud_host){
930                 if (strncmp(inst->server,ldap_url->lud_host,
931                             strlen(inst->server)) != 0 ||
932                     ldap_url->lud_port != inst->port) {
933                         DEBUG("rlm_ldap: Requested server/port is not known to this module instance.");
934                         ldap_free_urldesc(ldap_url);
935                         return 0;
936                 }
937         }
938         if ((conn_id = ldap_get_conn(inst->conns,&conn,inst)) == -1){
939                 radlog(L_ERR, "rlm_ldap: All ldap connections are in use");
940                 ldap_free_urldesc(ldap_url);
941                 return 0;
942         }
943         if ((res = perform_search(inst, conn, ldap_url->lud_dn, ldap_url->lud_scope, ldap_url->lud_filter, ldap_url->lud_attrs, &result)) != RLM_MODULE_OK){
944                 if (res == RLM_MODULE_NOTFOUND){
945                         DEBUG("rlm_ldap: Search returned not found");
946                         ldap_free_urldesc(ldap_url);
947                         ldap_release_conn(conn_id,inst->conns);
948                         return 0;
949                 }
950                 DEBUG("rlm_ldap: Search returned error");
951                 ldap_free_urldesc(ldap_url);
952                 ldap_release_conn(conn_id,inst->conns);
953                 return 0;
954         }
955         if ((msg = ldap_first_entry(conn->ld, result)) == NULL){
956                 DEBUG("rlm_ldap: ldap_first_entry() failed");
957                 ldap_msgfree(result);
958                 ldap_free_urldesc(ldap_url);
959                 ldap_release_conn(conn_id,inst->conns);
960                 return 0;
961         }
962         if ((vals = ldap_get_values(conn->ld, msg, ldap_url->lud_attrs[0])) != NULL) {
963                 ret = strlen(vals[0]);
964                 if (ret > freespace){
965                         DEBUG("rlm_ldap: Insufficient string space");
966                         ldap_free_urldesc(ldap_url);
967                         ldap_value_free(vals);
968                         ldap_msgfree(result);
969                         ldap_release_conn(conn_id,inst->conns);
970                         return 0;
971                 }
972                 DEBUG("rlm_ldap: Adding attribute %s, value: %s",ldap_url->lud_attrs[0],vals[0]);
973                 strncpy(out,vals[0],ret);
974                 ldap_value_free(vals);
975         }
976         else
977                 ret = 0;
978
979         ldap_msgfree(result);
980         ldap_free_urldesc(ldap_url);
981         ldap_release_conn(conn_id,inst->conns);
982
983         DEBUG("rlm_ldap: - ldap_xlat end");
984
985         return ret;
986 }
987
988
989 /******************************************************************************
990  *
991  *      Function: rlm_ldap_authorize
992  *
993  *      Purpose: Check if user is authorized for remote access
994  *
995  ******************************************************************************/
996 static int
997 ldap_authorize(void *instance, REQUEST * request)
998 {
999         LDAPMessage     *result = NULL;
1000         LDAPMessage     *msg = NULL;
1001         LDAPMessage     *def_msg = NULL;
1002         LDAPMessage     *def_attr_msg = NULL;
1003         LDAPMessage     *def_result = NULL;
1004         LDAPMessage     *def_attr_result = NULL;
1005         ldap_instance   *inst = instance;
1006         char            *user_dn = NULL;
1007         char            filter[MAX_FILTER_STR_LEN];
1008         char            basedn[MAX_FILTER_STR_LEN];
1009         VALUE_PAIR      *check_tmp;
1010         VALUE_PAIR      *reply_tmp;
1011         int             res;
1012         VALUE_PAIR      **check_pairs, **reply_pairs;
1013         char            **vals;
1014         VALUE_PAIR      *module_fmsg_vp;
1015         VALUE_PAIR      *user_profile;
1016         char            module_fmsg[MAX_STRING_LEN];
1017         LDAP_CONN       *conn;
1018         int             conn_id = -1;
1019
1020         DEBUG("rlm_ldap: - authorize");
1021
1022         if (!request->username){
1023                 radlog(L_AUTH, "rlm_ldap: Attribute \"User-Name\" is required for authentication.\n");
1024                 return RLM_MODULE_INVALID;
1025         }
1026
1027         check_pairs = &request->config_items;
1028         reply_pairs = &request->reply->vps;
1029
1030         /*
1031          * Check for valid input, zero length names not permitted
1032          */
1033         if (request->username->strvalue == 0) {
1034                 radlog(L_ERR, "rlm_ldap: zero length username not permitted\n");
1035                 return RLM_MODULE_INVALID;
1036         }
1037         DEBUG("rlm_ldap: performing user authorization for %s",
1038                request->username->strvalue);
1039
1040         if (!radius_xlat(filter, sizeof(filter), inst->filter,
1041                          request, ldap_escape_func)) {
1042                 radlog (L_ERR, "rlm_ldap: unable to create filter.\n");
1043                 return RLM_MODULE_INVALID;
1044         }
1045
1046         if (!radius_xlat(basedn, sizeof(basedn), inst->basedn,
1047                          request, NULL)) {
1048                 radlog (L_ERR, "rlm_ldap: unable to create basedn.\n");
1049                 return RLM_MODULE_INVALID;
1050         }
1051
1052         if ((conn_id = ldap_get_conn(inst->conns,&conn,inst)) == -1){
1053                 radlog(L_ERR, "rlm_ldap: All ldap connections are in use");
1054                 return RLM_MODULE_FAIL;
1055         }
1056         if ((res = perform_search(instance, conn, basedn, LDAP_SCOPE_SUBTREE, filter, inst->atts, &result)) != RLM_MODULE_OK) {
1057                 DEBUG("rlm_ldap: search failed");
1058                 if (res == RLM_MODULE_NOTFOUND){
1059                         snprintf(module_fmsg,sizeof(module_fmsg),"rlm_ldap: User not found");
1060                         module_fmsg_vp = pairmake("Module-Failure-Message", module_fmsg, T_OP_EQ);
1061                         pairadd(&request->packet->vps, module_fmsg_vp);
1062                 }
1063                 ldap_release_conn(conn_id,inst->conns);
1064                 return (res);
1065         }
1066         if ((msg = ldap_first_entry(conn->ld, result)) == NULL) {
1067                 DEBUG("rlm_ldap: ldap_first_entry() failed");
1068                 ldap_msgfree(result);
1069                 ldap_release_conn(conn_id,inst->conns);
1070                 return RLM_MODULE_FAIL;
1071         }
1072         if ((user_dn = ldap_get_dn(conn->ld, msg)) == NULL) {
1073                 DEBUG("rlm_ldap: ldap_get_dn() failed");
1074                 ldap_msgfree(result);
1075                 ldap_release_conn(conn_id,inst->conns);
1076                 return RLM_MODULE_FAIL;
1077         }
1078         /*
1079          * Adding new attribute containing DN for LDAP object associated with
1080          * given username
1081          */
1082         pairadd(check_pairs, pairmake("Ldap-UserDn", user_dn, T_OP_EQ));
1083         ldap_memfree(user_dn);
1084
1085
1086         /* Remote access is controled by attribute of the user object */
1087         if (inst->access_attr) {
1088                 if ((vals = ldap_get_values(conn->ld, msg, inst->access_attr)) != NULL) {
1089                         if (inst->default_allow){
1090                                 DEBUG("rlm_ldap: checking if remote access for %s is allowed by %s", request->username->strvalue, inst->access_attr);
1091                                 if (!strncmp(vals[0], "FALSE", 5)) {
1092                                         DEBUG("rlm_ldap: dialup access disabled");
1093                                         snprintf(module_fmsg,sizeof(module_fmsg),"rlm_ldap: Access Attribute denies access");
1094                                         module_fmsg_vp = pairmake("Module-Failure-Message", module_fmsg, T_OP_EQ);
1095                                         pairadd(&request->packet->vps, module_fmsg_vp);
1096                                         ldap_msgfree(result);
1097                                         ldap_value_free(vals);
1098                                         ldap_release_conn(conn_id,inst->conns);
1099                                         return RLM_MODULE_USERLOCK;
1100                                 }
1101                                 ldap_value_free(vals);
1102                         }
1103                         else{
1104                                 DEBUG("rlm_ldap: %s attribute exists - access denied by default", inst->access_attr);
1105                                 snprintf(module_fmsg,sizeof(module_fmsg),"rlm_ldap: Access Attribute denies access");
1106                                 module_fmsg_vp = pairmake("Module-Failure-Message", module_fmsg, T_OP_EQ);
1107                                 pairadd(&request->packet->vps, module_fmsg_vp);
1108                                 ldap_msgfree(result);
1109                                 ldap_value_free(vals);
1110                                 ldap_release_conn(conn_id,inst->conns);
1111                                 return RLM_MODULE_USERLOCK;
1112                         }
1113                 } else {
1114                         if (inst->default_allow){
1115                                 DEBUG("rlm_ldap: no %s attribute - access denied by default", inst->access_attr);
1116                                 snprintf(module_fmsg,sizeof(module_fmsg),"rlm_ldap: Access Attribute denies access");
1117                                 module_fmsg_vp = pairmake("Module-Failure-Message", module_fmsg, T_OP_EQ);
1118                                 pairadd(&request->packet->vps, module_fmsg_vp);
1119                                 ldap_msgfree(result);
1120                                 ldap_release_conn(conn_id,inst->conns);
1121                                 return RLM_MODULE_USERLOCK;
1122                         }
1123                 }
1124         }
1125
1126         /*
1127          * Check for the default profile entry. If it exists then add the
1128          * attributes it contains in the check and reply pairs
1129          */
1130
1131         user_profile = pairfind(request->config_items, PW_USER_PROFILE);
1132         if (inst->default_profile || user_profile){
1133                 char *profile = inst->default_profile;
1134
1135                 strNcpy(filter,inst->base_filter,sizeof(filter));
1136                 if (user_profile)
1137                         profile = user_profile->strvalue;
1138                 if (profile && strlen(profile)){
1139                         if ((res = perform_search(instance, conn,
1140                                 profile, LDAP_SCOPE_BASE,
1141                                 filter, inst->atts, &def_result)) == RLM_MODULE_OK){
1142                                 if ((def_msg = ldap_first_entry(conn->ld,def_result))){
1143                                         if ((check_tmp = ldap_pairget(conn->ld,def_msg,inst->check_item_map,check_pairs,1))) {
1144                                                 if (inst->do_xlat){
1145                                                         pairxlatmove(request, check_pairs, &check_tmp);
1146                                                         pairfree(&check_tmp);
1147                                                 }
1148                                                 else
1149                                                         pairadd(check_pairs,check_tmp);
1150                                         }
1151                                         if ((reply_tmp = ldap_pairget(conn->ld,def_msg,inst->reply_item_map,reply_pairs,0))) {
1152                                                 if (inst->do_xlat){
1153                                                         pairxlatmove(request, reply_pairs, &reply_tmp);
1154                                                         pairfree(&reply_tmp);
1155                                                 }
1156                                                 else
1157                                                         pairadd(reply_pairs,reply_tmp);
1158                                         }
1159                                 }
1160                                 ldap_msgfree(def_result);
1161                         } else
1162                                 DEBUG("rlm_ldap: default_profile/user-profile search failed");
1163                 }
1164         }
1165
1166         /*
1167          * Check for the profile attribute. If it exists, we assume that it
1168          * contains the DN of an entry containg a profile for the user. That
1169          * way we can have different general profiles for various user groups
1170          * (students,faculty,staff etc)
1171          */
1172
1173         if (inst->profile_attr){
1174                 if ((vals = ldap_get_values(conn->ld, msg, inst->profile_attr)) != NULL) {
1175                         unsigned int i=0;
1176                         strNcpy(filter,inst->base_filter,sizeof(filter));
1177                         while(vals[i] != NULL && strlen(vals[i])){
1178                                 if ((res = perform_search(instance, conn,
1179                                         vals[i], LDAP_SCOPE_BASE,
1180                                         filter, inst->atts, &def_attr_result)) == RLM_MODULE_OK){
1181                                         if ((def_attr_msg = ldap_first_entry(conn->ld,def_attr_result))){
1182                                                 if ((check_tmp = ldap_pairget(conn->ld,def_attr_msg,inst->check_item_map,check_pairs,1))) {
1183                                                         if (inst->do_xlat){
1184                                                                 pairxlatmove(request, check_pairs, &check_tmp);
1185                                                                 pairfree(&check_tmp);
1186                                                         }
1187                                                         else
1188                                                                 pairadd(check_pairs,check_tmp);
1189                                                 }
1190                                                 if ((reply_tmp = ldap_pairget(conn->ld,def_attr_msg,inst->reply_item_map,reply_pairs,0))) {
1191                                                         if (inst->do_xlat){
1192                                                                 pairxlatmove(request, reply_pairs, &reply_tmp);
1193                                                                 pairfree(&reply_tmp);
1194                                                         }
1195                                                         else
1196                                                                 pairadd(reply_pairs,reply_tmp);
1197                                                 }
1198                                         }
1199                                         ldap_msgfree(def_attr_result);
1200                                 } else
1201                                         DEBUG("rlm_ldap: profile_attribute search failed");
1202                                 i++;
1203                         }
1204                         ldap_value_free(vals);
1205                 }
1206         }
1207         if (inst->passwd_attr && strlen(inst->passwd_attr)){
1208                 VALUE_PAIR *passwd_item;
1209
1210                 if ((passwd_item = pairfind(request->config_items, PW_PASSWORD)) == NULL){
1211                         char **passwd_vals;
1212                         char *passwd_val = NULL;
1213                         int passwd_len;
1214
1215                         if ((passwd_vals = ldap_get_values(conn->ld,msg,inst->passwd_attr)) != NULL){
1216                                 unsigned int i=0;
1217                                 while(passwd_vals[i] != NULL){
1218                                         if (strlen(passwd_vals[i])){
1219                                                 passwd_val = passwd_vals[i];
1220
1221                                                 if (inst->passwd_hdr && strlen(inst->passwd_hdr)){
1222                                                         passwd_val = strstr(passwd_val,inst->passwd_hdr);
1223                                                         if (passwd_val != NULL)
1224                                                                 passwd_val += strlen(inst->passwd_hdr);
1225                                                         else
1226                                                                 DEBUG("rlm_ldap: Password header not found in password %s for user %s", passwd_vals[0],request->username->strvalue);
1227                                                 }
1228                                                 if (passwd_val){
1229                                                         if ((passwd_item = paircreate(PW_PASSWORD,PW_TYPE_STRING)) == NULL){
1230                                                                 radlog(L_ERR|L_CONS, "no memory");
1231                                                                 ldap_value_free(passwd_vals);
1232                                                                 ldap_msgfree(result);
1233                                                                 ldap_release_conn(conn_id,inst->conns);
1234                                                                 return RLM_MODULE_FAIL;
1235                                                         }
1236                                                         passwd_len = strlen(passwd_val);
1237                                                         strncpy(passwd_item->strvalue,passwd_val,MAX_STRING_LEN - 1);
1238                                                         passwd_item->length = (passwd_len > (MAX_STRING_LEN - 1)) ? (MAX_STRING_LEN - 1) : passwd_len;
1239                                                         pairadd(&request->config_items,passwd_item);
1240                                                         DEBUG("rlm_ldap: Added password %s in check items",passwd_item->strvalue);
1241                                                 }
1242                                         }
1243                                         i++;
1244                                 }
1245                                 ldap_value_free(passwd_vals);
1246                         }
1247                 }
1248         }
1249
1250
1251
1252         DEBUG("rlm_ldap: looking for check items in directory...");
1253
1254         if ((check_tmp = ldap_pairget(conn->ld, msg, inst->check_item_map,check_pairs,1)) != NULL) {
1255                 if (inst->do_xlat){
1256                         pairxlatmove(request, check_pairs, &check_tmp);
1257                         pairfree(&check_tmp);
1258                 }
1259                 else
1260                         pairadd(check_pairs,check_tmp);
1261         }
1262
1263
1264         DEBUG("rlm_ldap: looking for reply items in directory...");
1265
1266
1267         if ((reply_tmp = ldap_pairget(conn->ld, msg, inst->reply_item_map,reply_pairs,0)) != NULL) {
1268                 if (inst->do_xlat){
1269                         pairxlatmove(request, reply_pairs, &reply_tmp);
1270                         pairfree(&reply_tmp);
1271                 }
1272                 else
1273                         pairadd(reply_pairs,reply_tmp);
1274         }
1275
1276        if (inst->do_comp && paircmp(request,request->packet->vps,*check_pairs,reply_pairs) != 0){
1277                 DEBUG("rlm_ldap: Pairs do not match. Rejecting user.");
1278                 snprintf(module_fmsg,sizeof(module_fmsg),"rlm_ldap: Pairs do not match");
1279                 module_fmsg_vp = pairmake("Module-Failure-Message", module_fmsg, T_OP_EQ);
1280                 pairadd(&request->packet->vps, module_fmsg_vp);
1281                 ldap_msgfree(result);
1282                 ldap_release_conn(conn_id,inst->conns);
1283
1284                 return RLM_MODULE_REJECT;
1285         }
1286
1287         /*
1288          * Module should default to LDAP authentication if no Auth-Type
1289          * specified
1290          */
1291         if ((pairfind(*check_pairs, PW_AUTH_TYPE) == NULL) &&
1292             request->password &&
1293             (request->password->attribute == PW_USER_PASSWORD))
1294                 pairadd(check_pairs, pairmake("Auth-Type", "LDAP", T_OP_EQ));
1295
1296
1297         DEBUG("rlm_ldap: user %s authorized to use remote access",
1298               request->username->strvalue);
1299         ldap_msgfree(result);
1300         ldap_release_conn(conn_id,inst->conns);
1301
1302         return RLM_MODULE_OK;
1303 }
1304
1305 /*****************************************************************************
1306  *
1307  *      Function: rlm_ldap_authenticate
1308  *
1309  *      Purpose: Check the user's password against ldap database
1310  *
1311  *****************************************************************************/
1312 static int
1313 ldap_authenticate(void *instance, REQUEST * request)
1314 {
1315         LDAP           *ld_user;
1316         LDAPMessage    *result, *msg;
1317         ldap_instance  *inst = instance;
1318         char           *user_dn, *attrs[] = {"uid", NULL};
1319         char            filter[MAX_FILTER_STR_LEN];
1320         char            basedn[MAX_FILTER_STR_LEN];
1321         int             res;
1322         VALUE_PAIR     *vp_user_dn;
1323         VALUE_PAIR      *module_fmsg_vp;
1324         char            module_fmsg[MAX_STRING_LEN];
1325         LDAP_CONN       *conn;
1326         int             conn_id = -1;
1327
1328         DEBUG("rlm_ldap: - authenticate");
1329
1330         /*
1331          * Ensure that we're being passed a plain-text password, and not
1332          * anything else.
1333          */
1334
1335         if (!request->username) {
1336                 radlog(L_AUTH, "rlm_ldap: Attribute \"User-Name\" is required for authentication.\n");
1337                 return RLM_MODULE_INVALID;
1338         }
1339
1340         if (!request->password){
1341                 radlog(L_AUTH, "rlm_ldap: Attribute \"User-Password\" is required for authentication.");
1342                 DEBUG2("  You seem to have set \"Auth-Type := LDAP\" somewhere.");
1343                 DEBUG2("  THAT CONFIGURATION IS WRONG.  DELETE IT.");
1344                 DEBUG2("  YOU ARE PREVENTING THE SERVER FROM WORKING PROPERLY.");
1345                 return RLM_MODULE_INVALID;
1346         }
1347
1348         if(request->password->attribute != PW_PASSWORD) {
1349                 radlog(L_AUTH, "rlm_ldap: Attribute \"User-Password\" is required for authentication. Cannot use \"%s\".", request->password->name);
1350                 return RLM_MODULE_INVALID;
1351         }
1352
1353         if (request->password->length == 0) {
1354                 snprintf(module_fmsg,sizeof(module_fmsg),"rlm_ldap: empty password supplied");
1355                 module_fmsg_vp = pairmake("Module-Failure-Message", module_fmsg, T_OP_EQ);
1356                 pairadd(&request->packet->vps, module_fmsg_vp);
1357                 return RLM_MODULE_INVALID;
1358         }
1359
1360         /*
1361          * Check that we don't have any failed connections. If we do there's no real need
1362          * of runing. Also give it another chance if we have a lot of failed connections.
1363          */
1364         if (inst->failed_conns > MAX_FAILED_CONNS_END)
1365                 inst->failed_conns = 0;
1366         if (inst->failed_conns > MAX_FAILED_CONNS_START){
1367                 inst->failed_conns++;
1368                 return RLM_MODULE_FAIL;
1369         }
1370
1371
1372         DEBUG("rlm_ldap: login attempt by \"%s\" with password \"%s\"",
1373                request->username->strvalue, request->password->strvalue);
1374
1375         while ((vp_user_dn = pairfind(request->config_items,
1376                                       PW_LDAP_USERDN)) == NULL) {
1377                 if (!radius_xlat(filter, sizeof(filter), inst->filter,
1378                                 request, NULL)) {
1379                         radlog (L_ERR, "rlm_ldap: unable to create filter.\n");
1380                         return RLM_MODULE_INVALID;
1381                 }
1382
1383                 if (!radius_xlat(basedn, sizeof(basedn), inst->basedn,
1384                                 request, NULL)) {
1385                         radlog (L_ERR, "rlm_ldap: unable to create basedn.\n");
1386                         return RLM_MODULE_INVALID;
1387                 }
1388
1389                 if ((conn_id = ldap_get_conn(inst->conns,&conn,inst)) == -1){
1390                         radlog(L_ERR, "rlm_ldap: All ldap connections are in use");
1391                         return RLM_MODULE_FAIL;
1392                 }
1393                 if ((res = perform_search(instance, conn, basedn, LDAP_SCOPE_SUBTREE, filter, attrs, &result)) != RLM_MODULE_OK) {
1394                         if (res == RLM_MODULE_NOTFOUND){
1395                                 snprintf(module_fmsg,sizeof(module_fmsg),"rlm_ldap: User not found");
1396                                 module_fmsg_vp = pairmake("Module-Failure-Message", module_fmsg, T_OP_EQ);
1397                                 pairadd(&request->packet->vps, module_fmsg_vp);
1398                         }
1399                         ldap_release_conn(conn_id,inst->conns);
1400                         return (res);
1401                 }
1402                 if ((msg = ldap_first_entry(conn->ld, result)) == NULL) {
1403                         ldap_msgfree(result);
1404                         ldap_release_conn(conn_id,inst->conns);
1405                         return RLM_MODULE_FAIL;
1406                 }
1407                 if ((user_dn = ldap_get_dn(conn->ld, msg)) == NULL) {
1408                         DEBUG("rlm_ldap: ldap_get_dn() failed");
1409                         ldap_msgfree(result);
1410                         ldap_release_conn(conn_id,inst->conns);
1411                         return RLM_MODULE_FAIL;
1412                 }
1413                 ldap_release_conn(conn_id,inst->conns);
1414                 pairadd(&request->config_items, pairmake("Ldap-UserDn", user_dn, T_OP_EQ));
1415                 ldap_memfree(user_dn);
1416                 ldap_msgfree(result);
1417         }
1418
1419         user_dn = vp_user_dn->strvalue;
1420
1421         DEBUG("rlm_ldap: user DN: %s", user_dn);
1422
1423         ld_user = ldap_connect(instance, user_dn, request->password->strvalue,
1424                                1, &res);
1425         if (ld_user == NULL){
1426                 if (res == RLM_MODULE_REJECT){
1427                         inst->failed_conns = 0;
1428                         snprintf(module_fmsg,sizeof(module_fmsg),"rlm_ldap: Bind as user failed");
1429                         module_fmsg_vp = pairmake("Module-Failure-Message", module_fmsg, T_OP_EQ);
1430                         pairadd(&request->packet->vps, module_fmsg_vp);
1431                 }
1432                 if (res == RLM_MODULE_FAIL){
1433                         DEBUG("rlm_ldap: ldap_connect() failed");
1434                         inst->failed_conns++;
1435                 }
1436                 return (res);
1437         }
1438
1439         DEBUG("rlm_ldap: user %s authenticated succesfully",
1440               request->username->strvalue);
1441         ldap_unbind_s(ld_user);
1442         inst->failed_conns = 0;
1443
1444         return RLM_MODULE_OK;
1445 }
1446
1447 static LDAP    *
1448 ldap_connect(void *instance, const char *dn, const char *password, int auth, int *result)
1449 {
1450         ldap_instance  *inst = instance;
1451         LDAP           *ld = NULL;
1452         int             msgid, rc, ldap_version;
1453         int             ldap_errno = 0;
1454         LDAPMessage    *res;
1455
1456         if (inst->is_url){
1457 #ifdef HAVE_LDAP_INITIALIZE
1458                 DEBUG("rlm_ldap: (re)connect to %s, authentication %d", inst->server, auth);
1459                 if (ldap_initialize(&ld, inst->server) != LDAP_SUCCESS) {
1460                         radlog(L_ERR, "rlm_ldap: ldap_initialize() failed");
1461                         *result = RLM_MODULE_FAIL;
1462                         return (NULL);
1463                 }
1464 #endif
1465         } else {
1466                 DEBUG("rlm_ldap: (re)connect to %s:%d, authentication %d", inst->server, inst->port, auth);
1467                 if ((ld = ldap_init(inst->server, inst->port)) == NULL) {
1468                         radlog(L_ERR, "rlm_ldap: ldap_init() failed");
1469                         *result = RLM_MODULE_FAIL;
1470                         return (NULL);
1471                 }
1472         }
1473         if (ldap_set_option(ld, LDAP_OPT_NETWORK_TIMEOUT,
1474                             (void *) &(inst->net_timeout)) != LDAP_OPT_SUCCESS) {
1475                 radlog(L_ERR, "rlm_ldap: Could not set LDAP_OPT_NETWORK_TIMEOUT %ld.%ld", inst->net_timeout.tv_sec, inst->net_timeout.tv_usec);
1476         }
1477
1478         if (ldap_set_option(ld, LDAP_OPT_TIMELIMIT, (void *) &(inst->timelimit)) != LDAP_OPT_SUCCESS) {
1479                 radlog(L_ERR, "rlm_ldap: Could not set LDAP_OPT_TIMELIMIT %d", inst->timelimit);
1480         }
1481
1482         if (inst->ldap_debug && ldap_set_option(NULL, LDAP_OPT_DEBUG_LEVEL, &(inst->ldap_debug)) != LDAP_OPT_SUCCESS) {
1483                 radlog(L_ERR, "rlm_ldap: Could not set LDAP_OPT_DEBUG_LEVEL %d", inst->ldap_debug);
1484         }
1485
1486         ldap_version = LDAP_VERSION3;
1487         if (ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, &ldap_version) != LDAP_OPT_SUCCESS) {
1488                 radlog(L_ERR, "rlm_ldap: Could not set LDAP version to V3");
1489         }
1490
1491 #ifdef HAVE_LDAP_START_TLS
1492         if(inst->tls_mode) {
1493                 DEBUG("rlm_ldap: setting TLS mode to %d", inst->tls_mode);
1494                 if(ldap_set_option(ld, LDAP_OPT_X_TLS,
1495                            (void *) &(inst->tls_mode)) != LDAP_OPT_SUCCESS) {
1496                         ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &ldap_errno);
1497                         radlog(L_ERR, "rlm_ldap: could not set LDAP_OPT_X_TLS option %s", ldap_err2string(ldap_errno));
1498                 }
1499         }
1500
1501         if(inst->tls_cacertfile != NULL) {
1502                 DEBUG("rlm_ldap: setting TLS CACert File to %s", inst->tls_cacertfile);
1503
1504                 if ( ldap_set_option( NULL, LDAP_OPT_X_TLS_CACERTFILE,
1505                                       (void *) inst->tls_cacertfile )
1506                      != LDAP_OPT_SUCCESS) {
1507                         radlog(L_ERR, "rlm_ldap: could not set "
1508                                "LDAP_OPT_X_TLS_CACERTFILE option to %s", inst->tls_cacertfile);
1509                 }
1510         }
1511         
1512         if(inst->tls_cacertdir != NULL) {
1513                 DEBUG("rlm_ldap: setting TLS CACert File to %s", inst->tls_cacertdir);
1514                 
1515                 if ( ldap_set_option( NULL, LDAP_OPT_X_TLS_CACERTDIR,
1516                                       (void *) inst->tls_cacertdir )
1517                      != LDAP_OPT_SUCCESS) {
1518                         radlog(L_ERR, "rlm_ldap: could not set "
1519                                "LDAP_OPT_X_TLS_CACERTDIR option to %s", inst->tls_cacertdir);
1520                 }
1521         }
1522
1523         if( strcmp( TLS_DEFAULT_VERIFY, inst->tls_require_cert ) != 0 ) {
1524                 DEBUG("rlm_ldap: setting TLS Require Cert to %s",
1525                       inst->tls_require_cert);
1526         }
1527
1528
1529 #ifdef HAVE_INT_TLS_CONFIG
1530         if ( ldap_int_tls_config( NULL, LDAP_OPT_X_TLS_REQUIRE_CERT,
1531                                   (inst->tls_require_cert) )
1532              != LDAP_OPT_SUCCESS) {
1533                 radlog(L_ERR, "rlm_ldap: could not set "
1534                        "LDAP_OPT_X_TLS_REQUIRE_CERT option to %s",
1535                        inst->tls_require_cert);
1536         }
1537 #endif
1538
1539         if(inst->tls_certfile != NULL) {
1540                 DEBUG("rlm_ldap: setting TLS Cert File to %s", inst->tls_certfile);
1541
1542                 if ( ldap_set_option( NULL, LDAP_OPT_X_TLS_CERTFILE,
1543                                                           (void *) inst->tls_certfile )
1544                          != LDAP_OPT_SUCCESS) {
1545                         radlog(L_ERR, "rlm_ldap: could not set "
1546                                    "LDAP_OPT_X_TLS_CERTFILE option to %s",
1547                                    inst->tls_certfile);
1548                 }
1549         }
1550
1551         if (inst->tls_keyfile != NULL) {
1552                 DEBUG("rlm_ldap: setting TLS Key File to %s",
1553                       inst->tls_keyfile);
1554
1555                 if ( ldap_set_option( NULL, LDAP_OPT_X_TLS_KEYFILE,
1556                                       (void *) inst->tls_keyfile )
1557                      != LDAP_OPT_SUCCESS) {
1558                         radlog(L_ERR, "rlm_ldap: could not set "
1559                                "LDAP_OPT_X_TLS_KEYFILE option to %s",
1560                                inst->tls_keyfile);
1561                 }
1562         }
1563
1564         if (inst->tls_randfile != NULL) {
1565                 DEBUG("rlm_ldap: setting TLS Key File to %s",
1566                       inst->tls_randfile);
1567                 
1568                 if (ldap_set_option( NULL, LDAP_OPT_X_TLS_RANDOM_FILE,
1569                                      (void *) inst->tls_randfile)
1570                     != LDAP_OPT_SUCCESS) {
1571                         radlog(L_ERR, "rlm_ldap: could not set "
1572                                "LDAP_OPT_X_TLS_RANDOM_FILE option to %s",
1573                                inst->tls_randfile);
1574                 }
1575         }
1576
1577         if (inst->start_tls) {
1578                 DEBUG("rlm_ldap: starting TLS");
1579                 rc = ldap_start_tls_s(ld, NULL, NULL);
1580                 if (rc != LDAP_SUCCESS) {
1581                         DEBUG("rlm_ldap: ldap_start_tls_s()");
1582                         ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER,
1583                                         &ldap_errno);
1584                         radlog(L_ERR, "rlm_ldap: could not start TLS %s",
1585                                ldap_err2string(ldap_errno));
1586                         *result = RLM_MODULE_FAIL;
1587                         ldap_unbind_s(ld);
1588                         return (NULL);
1589                 }
1590         }
1591 #endif /* HAVE_LDAP_START_TLS */
1592
1593         if (inst->is_url){
1594                 DEBUG("rlm_ldap: bind as %s/%s to %s",
1595                       dn, password, inst->server);
1596         } else {
1597                 DEBUG("rlm_ldap: bind as %s/%s to %s:%d",
1598                       dn, password, inst->server, inst->port);
1599         }
1600
1601         msgid = ldap_bind(ld, dn, password,LDAP_AUTH_SIMPLE);
1602         if (msgid == -1) {
1603                 ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &ldap_errno);
1604                 if (inst->is_url) {
1605                         radlog(L_ERR, "rlm_ldap: %s bind to %s failed: %s",
1606                                 dn, inst->server, ldap_err2string(ldap_errno));
1607                 } else {
1608                         radlog(L_ERR, "rlm_ldap: %s bind to %s:%d failed: %s",
1609                                 dn, inst->server, inst->port,
1610                                 ldap_err2string(ldap_errno));
1611                 }
1612                 *result = RLM_MODULE_FAIL;
1613                 ldap_unbind_s(ld);
1614                 return (NULL);
1615         }
1616         DEBUG("rlm_ldap: waiting for bind result ...");
1617
1618         rc = ldap_result(ld, msgid, 1, &(inst->timeout), &res);
1619
1620         if (rc < 1) {
1621                 DEBUG("rlm_ldap: ldap_result()");
1622                 ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &ldap_errno);
1623                 if (inst->is_url) {
1624                         radlog(L_ERR, "rlm_ldap: %s bind to %s failed: %s",
1625                                 dn, inst->server, (rc == 0) ? "timeout" : ldap_err2string(ldap_errno));
1626                 } else {
1627                         radlog(L_ERR, "rlm_ldap: %s bind to %s:%d failed: %s",
1628                                dn, inst->server, inst->port,
1629                                 (rc == 0) ? "timeout" : ldap_err2string(ldap_errno));
1630                 }
1631                 *result = RLM_MODULE_FAIL;
1632                 ldap_unbind_s(ld);
1633                 return (NULL);
1634         }
1635
1636         ldap_errno = ldap_result2error(ld, res, 1);
1637         switch (ldap_errno) {
1638         case LDAP_SUCCESS:
1639                 DEBUG("rlm_ldap: Bind was successful");
1640                 *result = RLM_MODULE_OK;
1641                 break;
1642
1643         case LDAP_INVALID_CREDENTIALS:
1644                 if (auth){
1645                         DEBUG("rlm_ldap: Bind failed with invalid credentials");
1646                         *result = RLM_MODULE_REJECT;
1647                 } else {
1648                         radlog(L_ERR, "rlm_ldap: LDAP login failed: check identity, password settings in ldap section of radiusd.conf");
1649                         *result = RLM_MODULE_FAIL;
1650                 }
1651                 break;
1652
1653         default:
1654                 if (inst->is_url) {
1655                         radlog(L_ERR,"rlm_ldap: %s bind to %s failed %s",
1656                                 dn, inst->server, ldap_err2string(ldap_errno));
1657                 } else {
1658                         radlog(L_ERR,"rlm_ldap: %s bind to %s:%d failed %s",
1659                                 dn, inst->server, inst->port,
1660                                 ldap_err2string(ldap_errno));
1661                 }
1662                 *result = RLM_MODULE_FAIL;
1663         }
1664
1665         if (*result != RLM_MODULE_OK) {
1666                 ldap_unbind_s(ld);
1667                 ld = NULL;
1668         }
1669         return ld;
1670 }
1671
1672 /*****************************************************************************
1673  *
1674  *      Detach from the LDAP server and cleanup internal state.
1675  *
1676  *****************************************************************************/
1677 static int
1678 ldap_detach(void *instance)
1679 {
1680         ldap_instance  *inst = instance;
1681         TLDAP_RADIUS *pair, *nextpair;
1682
1683         if (inst->server)
1684                 free((char *) inst->server);
1685         if (inst->login)
1686                 free((char *) inst->login);
1687         if (inst->password)
1688                 free((char *) inst->password);
1689         if (inst->basedn)
1690                 free((char *) inst->basedn);
1691         if (inst->dictionary_mapping)
1692                 free(inst->dictionary_mapping);
1693         if (inst->filter)
1694                 free((char *) inst->filter);
1695         if (inst->base_filter)
1696                 free((char *) inst->base_filter);
1697         if (inst->passwd_hdr)
1698                 free((char *) inst->passwd_hdr);
1699         if (inst->passwd_attr)
1700                 free((char *) inst->passwd_attr);
1701         if (inst->groupname_attr)
1702                 free((char *) inst->groupname_attr);
1703         if (inst->groupmemb_filt)
1704                 free((char *) inst->groupmemb_filt);
1705         if (inst->groupmemb_attr)
1706                 free((char *) inst->groupmemb_attr);
1707         if (inst->access_attr)
1708                 free((char *) inst->access_attr);
1709         if (inst->profile_attr)
1710                 free((char *) inst->profile_attr);
1711
1712         if (inst->conns) {
1713                 int i;
1714
1715                 for(i = 0;i < inst->num_conns; i++){
1716                         if (inst->conns[i].ld){
1717                                 ldap_unbind_s(inst->conns[i].ld);
1718                         }
1719                         pthread_mutex_destroy(&inst->conns[i].mutex);
1720                 }
1721                 free(inst->conns);
1722         }
1723
1724         pair = inst->check_item_map;
1725
1726         while (pair != NULL) {
1727                 nextpair = pair->next;
1728                 free(pair->attr);
1729                 free(pair->radius_attr);
1730                 free(pair);
1731                 pair = nextpair;
1732         }
1733
1734         pair = inst->reply_item_map;
1735
1736         while (pair != NULL) {
1737                 nextpair = pair->next;
1738                 free(pair->attr);
1739                 free(pair->radius_attr);
1740                 free(pair);
1741                 pair = nextpair;
1742         }
1743
1744         if (inst->atts)
1745                 free(inst->atts);
1746
1747         paircompare_unregister(PW_LDAP_GROUP, ldap_groupcmp);
1748         xlat_unregister(inst->xlat_name,ldap_xlat);
1749         free(inst->xlat_name);
1750
1751         free(inst);
1752
1753         return 0;
1754 }
1755
1756 #ifdef FIELDCPY
1757 static void
1758 fieldcpy(char *string, char **uptr)
1759 {
1760         char           *ptr;
1761
1762         ptr = *uptr;
1763         while (*ptr == ' ' || *ptr == '\t') {
1764                 ptr++;
1765         }
1766         if (*ptr == '"') {
1767                 ptr++;
1768                 while (*ptr != '"' && *ptr != '\0' && *ptr != '\n') {
1769                         *string++ = *ptr++;
1770                 }
1771                 *string = '\0';
1772                 if (*ptr == '"') {
1773                         ptr++;
1774                 }
1775                 *uptr = ptr;
1776                 return;
1777         }
1778         while (*ptr != ' ' && *ptr != '\t' && *ptr != '\0' && *ptr != '\n' &&
1779                *ptr != '=' && *ptr != ',') {
1780                 *string++ = *ptr++;
1781         }
1782         *string = '\0';
1783         *uptr = ptr;
1784         return;
1785 }
1786 #endif
1787 /*****************************************************************************
1788  *      Get RADIUS attributes from LDAP object
1789  *      ( according to draft-adoba-radius-05.txt
1790  *        <http://www.ietf.org/internet-drafts/draft-adoba-radius-05.txt> )
1791  *
1792  *****************************************************************************/
1793
1794 static VALUE_PAIR *
1795 ldap_pairget(LDAP * ld, LDAPMessage * entry,
1796              TLDAP_RADIUS * item_map, VALUE_PAIR **pairs,char is_check)
1797 {
1798         char          **vals;
1799         int             vals_count;
1800         int             vals_idx;
1801         char           *ptr;
1802         TLDAP_RADIUS   *element;
1803         LRAD_TOKEN      token;
1804         int             is_generic_attribute;
1805         char            value[256];
1806         VALUE_PAIR     *pairlist = NULL;
1807         VALUE_PAIR     *newpair = NULL;
1808
1809         /* check if there is a mapping from this LDAP attribute to a RADIUS attribute */
1810         for (element = item_map; element != NULL; element = element->next) {
1811         if ((vals = ldap_get_values(ld,entry,element->attr)) != NULL) {
1812                         /* check whether this is a one-to-one-mapped ldap attribute or a generic
1813                            attribute and set flag accordingly */
1814
1815                         if (strcasecmp(element->radius_attr, GENERIC_ATTRIBUTE_ID)==0)
1816                                 is_generic_attribute = 1;
1817                         else
1818                                 is_generic_attribute = 0;
1819
1820                         /* find out how many values there are for the attribute and extract all of them */
1821
1822                         vals_count = ldap_count_values(vals);
1823
1824                         for (vals_idx = 0; vals_idx < vals_count; vals_idx++) {
1825                                 ptr = vals[vals_idx];
1826
1827                                 if (is_generic_attribute) {
1828                                         /* this is a generic attribute */
1829                                         LRAD_TOKEN dummy; /* makes pairread happy */
1830
1831                                         /* not sure if using pairread here is ok ... */
1832                                         if ( (newpair = pairread(&ptr, &dummy)) != NULL) {
1833                                                 DEBUG("rlm_ldap: extracted attribute %s from generic item %s",
1834                                                       newpair->name, vals[vals_idx]);
1835                                                 pairadd(&pairlist, newpair);
1836                                         } else {
1837                                                 radlog(L_ERR, "rlm_ldap: parsing %s failed: %s",
1838                                                        element->attr, vals[vals_idx]);
1839                                         }
1840                                 } else {
1841                                         /* this is a one-to-one-mapped attribute */
1842                                         token = gettoken(&ptr, value, sizeof(value) - 1);
1843                                         if (token < T_EQSTART || token > T_EQEND) {
1844                                                 if (is_check) {
1845                                                         token = T_OP_CMP_EQ;
1846                                                 } else {
1847                                                         token = T_OP_EQ;
1848                                                 }
1849
1850                                                 if (element->operator != T_INVALID) {
1851                                                         token = element->operator;
1852                                                 }
1853                                         } else {
1854                                                 gettoken(&ptr, value, sizeof(value) - 1);
1855                                         }
1856                                         if (value[0] == 0) {
1857                                                 DEBUG("rlm_ldap: Attribute %s has no value", element->attr);
1858                                                 break;
1859                                         }
1860                                         DEBUG("rlm_ldap: Adding %s as %s, value %s & op=%d", element->attr, element->radius_attr, value, token);
1861                                                 if ((newpair = pairmake(element->radius_attr, value, token)) == NULL)
1862                                                 continue;
1863                                         if (! vals_idx){
1864                                                 pairdelete(pairs,newpair->attribute);
1865                                         }
1866                                         pairadd(&pairlist, newpair);
1867                                 }
1868                         }
1869                         ldap_value_free(vals);
1870                 }
1871         }
1872
1873         return (pairlist);
1874 }
1875
1876 /* globally exported name */
1877 module_t        rlm_ldap = {
1878         "LDAP",
1879         RLM_TYPE_THREAD_SAFE,   /* type: reserved        */
1880         NULL,                   /* initialization        */
1881         ldap_instantiate,       /* instantiation         */
1882         {
1883                 ldap_authenticate,      /* authentication        */
1884                 ldap_authorize,         /* authorization         */
1885                 NULL,                   /* preaccounting         */
1886                 NULL,                   /* accounting            */
1887                 NULL,                   /* checksimul            */
1888                 NULL,                   /* pre-proxy             */
1889                 NULL,                   /* post-proxy            */
1890                 NULL                    /* post-auth             */
1891         },
1892         ldap_detach,            /* detach                */
1893         NULL,                   /* destroy               */
1894 };