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