Don't reference interp if USE_ITHREADS isn't defined.
[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 <freeradius-devel/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        <freeradius-devel/radiusd.h>
45 #include        <freeradius-devel/conffile.h>
46 #include        <freeradius-devel/modules.h>
47 #include        <freeradius-devel/rad_assert.h>
48
49 #ifndef HAVE_PTHREAD_H
50 /*
51  *      This is a lot simpler than putting ifdef's around
52  *      every use of the pthread functions.
53  */
54 #define pthread_mutex_lock(a)
55 #define pthread_mutex_trylock(a) (0)
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         int             auto_header;
151         char           *dictionary_mapping;
152         char           *groupname_attr;
153         char           *groupmemb_filt;
154         char           *groupmemb_attr;
155         char            **atts;
156         TLDAP_RADIUS   *check_item_map;
157         TLDAP_RADIUS   *reply_item_map;
158         LDAP_CONN       *conns;
159 #ifdef NOVELL
160         LDAP_CONN *apc_conns;
161 #endif
162         int             ldap_debug; /* Debug flag for LDAP SDK */
163         char            *xlat_name; /* name used to xlat */
164         char            *tls_cacertfile;
165         char            *tls_cacertdir;
166         char            *tls_certfile;
167         char            *tls_keyfile;
168         char            *tls_randfile;
169         char            *tls_require_cert;
170 #ifdef NOVELL
171         int                     edir_account_policy_check;
172 #endif
173 }  ldap_instance;
174
175 /* The default setting for TLS Certificate Verification */
176 #define TLS_DEFAULT_VERIFY "allow"
177
178 static CONF_PARSER tls_config[] = {
179         {"start_tls", PW_TYPE_BOOLEAN,
180          offsetof(ldap_instance,start_tls), NULL, "no"},
181         {"cacertfile", PW_TYPE_FILENAME,
182          offsetof(ldap_instance,tls_cacertfile), NULL, NULL},
183         {"cacertdir", PW_TYPE_FILENAME,
184          offsetof(ldap_instance,tls_cacertdir), NULL, NULL},
185         {"certfile", PW_TYPE_FILENAME,
186          offsetof(ldap_instance,tls_certfile), NULL, NULL},
187         {"keyfile", PW_TYPE_FILENAME,
188          offsetof(ldap_instance,tls_keyfile), NULL, NULL},
189         {"randfile", PW_TYPE_STRING_PTR, /* OK if it changes on HUP */
190          offsetof(ldap_instance,tls_randfile), NULL, NULL},
191         {"require_cert", PW_TYPE_STRING_PTR,
192          offsetof(ldap_instance,tls_require_cert), NULL, TLS_DEFAULT_VERIFY},
193         { NULL, -1, 0, NULL, NULL }
194 };
195
196 static const CONF_PARSER module_config[] = {
197         {"server", PW_TYPE_STRING_PTR,
198          offsetof(ldap_instance,server), NULL, "localhost"},
199         {"port", PW_TYPE_INTEGER,
200          offsetof(ldap_instance,port), NULL, "389"},
201         {"password", PW_TYPE_STRING_PTR,
202          offsetof(ldap_instance,password), NULL, ""},
203         {"identity", PW_TYPE_STRING_PTR,
204          offsetof(ldap_instance,login), NULL, ""},
205
206         /*
207          *      Timeouts & stuff.
208          */
209         /* wait forever on network activity */
210         {"net_timeout", PW_TYPE_INTEGER,
211          offsetof(ldap_instance,net_timeout.tv_sec), NULL, "10"},
212         /* wait forever for search results */
213         {"timeout", PW_TYPE_INTEGER,
214          offsetof(ldap_instance,timeout.tv_sec), NULL, "20"},
215         /* allow server unlimited time for search (server-side limit) */
216         {"timelimit", PW_TYPE_INTEGER,
217          offsetof(ldap_instance,timelimit), NULL, "20"},
218
219         /*
220          *      TLS configuration  The first few are here for backwards
221          *      compatibility.  The last is the new subsection.
222          */
223         {"tls_mode", PW_TYPE_BOOLEAN,
224          offsetof(ldap_instance,tls_mode), NULL, "no"},
225
226         {"start_tls", PW_TYPE_BOOLEAN,
227          offsetof(ldap_instance,start_tls), NULL, "no"},
228         {"tls_cacertfile", PW_TYPE_FILENAME,
229          offsetof(ldap_instance,tls_cacertfile), NULL, NULL},
230         {"tls_cacertdir", PW_TYPE_FILENAME,
231          offsetof(ldap_instance,tls_cacertdir), NULL, NULL},
232         {"tls_certfile", PW_TYPE_FILENAME,
233          offsetof(ldap_instance,tls_certfile), NULL, NULL},
234         {"tls_keyfile", PW_TYPE_FILENAME,
235          offsetof(ldap_instance,tls_keyfile), NULL, NULL},
236         {"tls_randfile", PW_TYPE_STRING_PTR, /* OK if it changes on HUP */
237          offsetof(ldap_instance,tls_randfile), NULL, NULL},
238         {"tls_require_cert", PW_TYPE_STRING_PTR,
239          offsetof(ldap_instance,tls_require_cert), NULL, TLS_DEFAULT_VERIFY},
240         { "tls", PW_TYPE_SUBSECTION, 0, NULL, (const void *) tls_config },
241
242         /*
243          *      DN's and filters.
244          */
245         {"basedn", PW_TYPE_STRING_PTR,
246          offsetof(ldap_instance,basedn), NULL, "o=notexist"},
247         {"filter", PW_TYPE_STRING_PTR,
248          offsetof(ldap_instance,filter), NULL, "(uid=%u)"},
249         {"base_filter", PW_TYPE_STRING_PTR,
250          offsetof(ldap_instance,base_filter), NULL, "(objectclass=radiusprofile)"},
251         {"default_profile", PW_TYPE_STRING_PTR,
252          offsetof(ldap_instance,default_profile), NULL, NULL},
253         {"profile_attribute", PW_TYPE_STRING_PTR,
254          offsetof(ldap_instance,profile_attr), NULL, NULL},
255
256         /*
257          *      Getting passwords from the database
258          */
259         {"password_header", PW_TYPE_STRING_PTR,
260          offsetof(ldap_instance,passwd_hdr), NULL, NULL},
261         {"password_attribute", PW_TYPE_STRING_PTR,
262          offsetof(ldap_instance,passwd_attr), NULL, NULL},
263         {"auto_header", PW_TYPE_BOOLEAN,
264          offsetof(ldap_instance,auto_header), NULL, "no"},
265
266         /*
267          *      Access limitations
268          */
269         /* LDAP attribute name that controls remote access */
270         {"access_attr", PW_TYPE_STRING_PTR,
271          offsetof(ldap_instance,access_attr), NULL, NULL},
272         {"access_attr_used_for_allow", PW_TYPE_BOOLEAN,
273          offsetof(ldap_instance,default_allow), NULL, "yes"},
274
275         /*
276          *      Group checks.  These could probably be done
277          *      via dynamic xlat's.
278          */
279         {"groupname_attribute", PW_TYPE_STRING_PTR,
280          offsetof(ldap_instance,groupname_attr), NULL, "cn"},
281         {"groupmembership_filter", PW_TYPE_STRING_PTR,
282          offsetof(ldap_instance,groupmemb_filt), NULL, "(|(&(objectClass=GroupOfNames)(member=%{Ldap-UserDn}))(&(objectClass=GroupOfUniqueNames)(uniquemember=%{Ldap-UserDn})))"},
283         {"groupmembership_attribute", PW_TYPE_STRING_PTR,
284          offsetof(ldap_instance,groupmemb_attr), NULL, NULL},
285
286         /* file with mapping between LDAP and RADIUS attributes */
287         {"dictionary_mapping", PW_TYPE_FILENAME,
288          offsetof(ldap_instance,dictionary_mapping), NULL, "${confdir}/ldap.attrmap"},
289
290         /*
291          *      Debugging flags to the server
292          */
293         {"ldap_debug", PW_TYPE_INTEGER,
294          offsetof(ldap_instance,ldap_debug), NULL, "0x0000"},
295         {"ldap_connections_number", PW_TYPE_INTEGER,
296          offsetof(ldap_instance,num_conns), NULL, "5"},
297         {"compare_check_items", PW_TYPE_BOOLEAN,
298          offsetof(ldap_instance,do_comp), NULL, "no"},
299         {"do_xlat", PW_TYPE_BOOLEAN,
300          offsetof(ldap_instance,do_xlat), NULL, "yes"},
301
302 #ifdef NOVELL
303         /*
304          *      Novell magic.
305          */
306         {"edir_account_policy_check", PW_TYPE_BOOLEAN,
307          offsetof(ldap_instance,edir_account_policy_check), NULL, "yes"},
308 #endif
309
310         {NULL, -1, 0, NULL, NULL}
311 };
312
313 #define ld_valid                ld_options.ldo_valid
314 #define LDAP_VALID_SESSION      0x2
315 #define LDAP_VALID(ld)  ( (ld)->ld_valid == LDAP_VALID_SESSION )
316
317 #ifdef FIELDCPY
318 static void     fieldcpy(char *, char **);
319 #endif
320 static VALUE_PAIR *ldap_pairget(LDAP *, LDAPMessage *, TLDAP_RADIUS *,VALUE_PAIR **,int);
321 static int ldap_groupcmp(void *, REQUEST *, VALUE_PAIR *, VALUE_PAIR *, VALUE_PAIR *, VALUE_PAIR **);
322 static int ldap_xlat(void *, REQUEST *, char *, char *, size_t, RADIUS_ESCAPE_STRING);
323 static LDAP    *ldap_connect(void *instance, const char *, const char *, int, int *, char **);
324 static int     read_mappings(ldap_instance* inst);
325
326 static inline int ldap_get_conn(LDAP_CONN *conns,LDAP_CONN **ret,void *instance)
327 {
328         ldap_instance *inst = instance;
329         register int i = 0;
330
331         for(i=0;i<inst->num_conns;i++){
332                 DEBUG("rlm_ldap: ldap_get_conn: Checking Id: %d",i);
333                 if ((pthread_mutex_trylock(&conns[i].mutex) == 0)) {
334                         if (conns[i].locked == 1) {
335                                 /* connection is already being used */
336                                 pthread_mutex_unlock(&(conns[i].mutex));
337                                 continue;
338                         }
339                         /* found an unused connection */
340                         *ret = &conns[i];
341                         conns[i].locked = 1;
342                         DEBUG("rlm_ldap: ldap_get_conn: Got Id: %d",i);
343                         return i;
344                 }
345         }
346
347         return -1;
348 }
349
350 static inline void ldap_release_conn(int i, LDAP_CONN *conns)
351 {
352         DEBUG("rlm_ldap: ldap_release_conn: Release Id: %d",i);
353         conns[i].locked = 0;
354         pthread_mutex_unlock(&(conns[i].mutex));
355 }
356
357 /*************************************************************************
358  *
359  *      Function: rlm_ldap_instantiate
360  *
361  *      Purpose: Uses section of radiusd config file passed as parameter
362  *               to create an instance of the module.
363  *
364  *************************************************************************/
365 static int
366 ldap_instantiate(CONF_SECTION * conf, void **instance)
367 {
368         ldap_instance  *inst;
369         int i = 0;
370         int atts_num = 0;
371         int reply_map_num = 0;
372         int check_map_num = 0;
373         int att_map[3] = {0,0,0};
374         TLDAP_RADIUS *pair;
375         ATTR_FLAGS flags;
376         const char *xlat_name;
377
378         inst = rad_malloc(sizeof *inst);
379         if (!inst) {
380                 return -1;
381         }
382         memset(inst, 0, sizeof(*inst));
383
384         if (cf_section_parse(conf, inst, module_config) < 0) {
385                 free(inst);
386                 return -1;
387         }
388
389         if (inst->server == NULL) {
390                 radlog(L_ERR, "rlm_ldap: missing 'server' directive.");
391                 free(inst);     /* FIXME: detach */
392                 return -1;
393         }
394         inst->is_url = 0;
395         if (ldap_is_ldap_url(inst->server)){
396 #ifdef HAVE_LDAP_INITIALIZE
397                 inst->is_url = 1;
398                 inst->port = 0;
399 #else
400                 radlog(L_ERR, "rlm_ldap: 'server' directive is in URL form but ldap_initialize() is not available.");
401                 free(inst);     /* FIXME: detach */
402                 return -1;
403 #endif
404         }
405
406         inst->timeout.tv_usec = 0;
407         inst->net_timeout.tv_usec = 0;
408         /* workaround for servers which support LDAPS but not START TLS */
409         if(inst->port == LDAPS_PORT || inst->tls_mode)
410                 inst->tls_mode = LDAP_OPT_X_TLS_HARD;
411         else
412                 inst->tls_mode = 0;
413         inst->reply_item_map = NULL;
414         inst->check_item_map = NULL;
415         inst->conns = NULL;
416         inst->failed_conns = 0;
417
418         DEBUG("rlm_ldap: Registering ldap_groupcmp for Ldap-Group");
419         paircompare_register(PW_LDAP_GROUP, PW_USER_NAME, ldap_groupcmp, inst);
420
421         xlat_name = cf_section_name2(conf);
422         if (xlat_name != NULL){
423                 char *group_name;
424                 DICT_ATTR *dattr;
425
426                 /*
427                  * Allocate room for <instance>-Ldap-Group
428                  */
429                 group_name = rad_malloc((strlen(xlat_name) + 1 + 11) * sizeof(char));
430                 sprintf(group_name,"%s-Ldap-Group",xlat_name);
431                 DEBUG("rlm_ldap: Creating new attribute %s",group_name);
432                 dict_addattr(group_name, 0, PW_TYPE_STRING, -1, flags);
433                 dattr = dict_attrbyname(group_name);
434                 if (dattr == NULL){
435                         radlog(L_ERR, "rlm_ldap: Failed to create attribute %s",group_name);
436                         free(group_name);
437                         free(inst);     /* FIXME: detach */
438                         return -1;
439                 }
440                 DEBUG("rlm_ldap: Registering ldap_groupcmp for %s",group_name);
441                 paircompare_register(dattr->attr, PW_USER_NAME, ldap_groupcmp, inst);
442                 free(group_name);
443         }
444         else {
445                 xlat_name = cf_section_name1(conf);
446                 rad_assert(xlat_name != NULL); /* or all hell breaks loose */
447         }
448         inst->xlat_name = strdup(xlat_name);
449         DEBUG("rlm_ldap: Registering ldap_xlat with xlat_name %s",xlat_name);
450         xlat_register(xlat_name,ldap_xlat,inst);
451
452 #ifdef NOVELL
453         /*
454          *      (LDAP_Instance, V1) attribute-value pair in the config
455          *      items list means that the 'authorize' method of the
456          *      instance 'V1' of the LDAP module has processed this
457          *      request.
458          */
459         dict_addattr("LDAP-Instance", 0, PW_TYPE_STRING, -1, flags);
460
461         /*
462          *      ('eDir-APC', '1') in config items list
463          *      Do not perform eDirectory account policy check (APC)
464          *                                           
465          *      ('eDir-APC', '2') in config items list
466          *      Perform eDirectory APC
467          *
468          *      ('eDir-APC', '3') in config items list
469          *      eDirectory APC has been completed
470          */
471         dict_addattr("eDir-APC", 0, PW_TYPE_INTEGER, -1, flags);
472 #endif
473
474         if (inst->num_conns <= 0){
475                 radlog(L_ERR, "rlm_ldap: Invalid ldap connections number passed.");
476                 free(inst);     /* FIXME: detach */
477                 return -1;
478         }
479         inst->conns = malloc(sizeof(*(inst->conns))*inst->num_conns);
480         if (inst->conns == NULL){
481                 radlog(L_ERR, "rlm_ldap: Could not allocate memory. Aborting.");
482                 free(inst);     /* FIXME: detach */
483                 return -1;
484         }
485         for(i = 0; i < inst->num_conns; i++){
486                 inst->conns[i].bound = 0;
487                 inst->conns[i].locked = 0;
488                 inst->conns[i].failed_conns = 0;
489                 inst->conns[i].ld = NULL;
490                 pthread_mutex_init(&inst->conns[i].mutex, NULL);
491         }
492
493 #ifdef NOVELL
494         /*
495          *      'inst->apc_conns' is a separate connection pool to be
496          *      used for performing eDirectory account policy check in
497          *      the 'postauth' method. This avoids changing the
498          *      (RADIUS server) credentials associated with the
499          *      'inst->conns' connection pool.
500          */
501         inst->apc_conns = malloc(sizeof(*(inst->apc_conns))*inst->num_conns);
502         if (inst->apc_conns == NULL){
503                 radlog(L_ERR, "rlm_ldap: Could not allocate memory. Aborting.");
504                 free(inst);     /* FIXME: detach */
505                 return -1;
506         }
507         for(i = 0; i < inst->num_conns; i++){
508                 inst->apc_conns[i].bound = 0;
509                 inst->apc_conns[i].locked = 0;
510                 inst->apc_conns[i].failed_conns = 0;
511                 inst->apc_conns[i].ld = NULL;
512                 pthread_mutex_init(&inst->apc_conns[i].mutex, NULL);
513         }
514 #endif
515
516         if (read_mappings(inst) != 0) {
517                 radlog(L_ERR, "rlm_ldap: Reading dictionary mappings from file %s failed",
518                        inst->dictionary_mapping);
519                 free(inst);     /* FIXME: detach */
520                 return -1;
521         }
522         if ((inst->check_item_map == NULL) &&
523             (inst->reply_item_map == NULL)) {
524                 radlog(L_ERR, "rlm_ldap: dictionary mappings file %s did not contain any mappings",
525                         inst->dictionary_mapping);
526                 free(inst);     /* FIXME: detach */
527                 return -1;
528         }
529
530         pair = inst->check_item_map;
531         while(pair != NULL){
532                 atts_num++;
533                 pair = pair->next;
534         }
535         check_map_num = (atts_num - 1);
536         pair = inst->reply_item_map;
537         while(pair != NULL){
538                 atts_num++;
539                 pair = pair->next;
540         }
541         reply_map_num = (atts_num - 1);
542         if (inst->profile_attr)
543                 atts_num++;
544         if (inst->passwd_attr)
545                 atts_num++;
546         if (inst->access_attr)
547                 atts_num++;
548         inst->atts = (char **)malloc(sizeof(char *)*(atts_num + 1));
549         if (inst->atts == NULL){
550                 radlog(L_ERR, "rlm_ldap: Could not allocate memory. Aborting.");
551                 free(inst);     /* FIXME: detach */
552                 return -1;
553         }
554         pair = inst->check_item_map;
555         if (pair == NULL)
556                 pair = inst->reply_item_map;
557         for(i=0;i<atts_num;i++){
558                 if (i <= check_map_num ){
559                         inst->atts[i] = pair->attr;
560                         if (i == check_map_num)
561                                 pair = inst->reply_item_map;
562                         else
563                                 pair = pair->next;
564                 }
565                 else if (i <= reply_map_num){
566                         inst->atts[i] = pair->attr;
567                         pair = pair->next;
568                 }
569                 else{
570                         if (inst->profile_attr && !att_map[0]){
571                                 inst->atts[i] = inst->profile_attr;
572                                 att_map[0] = 1;
573                         }
574                         else if (inst->passwd_attr && !att_map[1]){
575                                 inst->atts[i] = inst->passwd_attr;
576                                 att_map[1] = 1;
577                         }
578                         else if (inst->access_attr && !att_map[2]){
579                                 inst->atts[i] = inst->access_attr;
580                                 att_map[2] = 1;
581                         }
582                 }
583         }
584         inst->atts[atts_num] = NULL;
585
586         DEBUG("conns: %p",inst->conns);
587
588         *instance = inst;
589
590
591         return 0;
592 }
593
594
595 /*
596  *      read_mappings(...) reads a ldap<->radius mappings file to
597  *      inst->reply_item_map and inst->check_item_map
598  */
599 #define MAX_LINE_LEN 160
600 #define GENERIC_ATTRIBUTE_ID "$GENERIC$"
601
602 static int
603 read_mappings(ldap_instance* inst)
604 {
605         FILE* mapfile;
606         char *filename;
607
608         /*
609          *      All buffers are of MAX_LINE_LEN so we can use sscanf
610          *      without being afraid of buffer overflows
611          */
612         char buf[MAX_LINE_LEN], itemType[MAX_LINE_LEN];
613         char radiusAttribute[MAX_LINE_LEN], ldapAttribute[MAX_LINE_LEN];
614         int linenumber;
615         LRAD_TOKEN operator;
616         char opstring[MAX_LINE_LEN];
617
618         /* open the mappings file for reading */
619
620         filename = inst->dictionary_mapping;
621         DEBUG("rlm_ldap: reading ldap<->radius mappings from file %s", filename);
622         mapfile = fopen(filename, "r");
623
624         if (mapfile == NULL) {
625                 radlog(L_ERR, "rlm_ldap: Opening file %s failed", filename);
626                 return -1; /* error */
627         }
628
629         /*
630          *      read file line by line. Note that if line length
631          *      exceeds MAX_LINE_LEN, line numbers will be mixed up
632          */
633         linenumber = 0;
634
635         while (fgets(buf, sizeof buf, mapfile)!=NULL) {
636                 char* ptr;
637                 int token_count;
638                 TLDAP_RADIUS* pair;
639
640                 linenumber++;
641
642                 /* strip comments */
643                 ptr = strchr(buf, '#');
644                 if (ptr) *ptr = 0;
645
646                 /* empty line */
647                 if (buf[0] == 0) continue;
648
649                 /* extract tokens from the string */
650                 token_count = sscanf(buf, "%s %s %s %s",
651                                      itemType, radiusAttribute,
652                                      ldapAttribute, opstring);
653
654                 if (token_count <= 0) /* no tokens */
655                         continue;
656
657                 if ((token_count < 3) || (token_count > 4)) {
658                         radlog(L_ERR, "rlm_ldap: Skipping %s line %i: %s",
659                                filename, linenumber, buf);
660                         radlog(L_ERR, "rlm_ldap: Expected 3 to 4 tokens "
661                                "(Item type, RADIUS Attribute and LDAP Attribute) but found only %i", token_count);
662                         continue;
663                 }
664
665                 if (token_count == 3) {
666                         operator = T_OP_INVALID; /* use defaults */
667                 } else {
668                         char *ptr;
669                         
670                         ptr = opstring;
671                         operator = gettoken(&ptr, buf, sizeof(buf));
672                         if ((operator < T_OP_ADD) || (operator > T_OP_CMP_EQ)) {
673                                 radlog(L_ERR, "rlm_ldap: file %s: skipping line %i: unknown or invalid operator %s",
674                                        filename, linenumber, opstring);
675                                 continue;
676                         }
677                 }
678
679                 /* create new TLDAP_RADIUS list node */
680                 pair = rad_malloc(sizeof(*pair));
681
682                 pair->attr = strdup(ldapAttribute);
683                 pair->radius_attr = strdup(radiusAttribute);
684                 pair->operator = operator;
685
686                 if ( (pair->attr == NULL) || (pair->radius_attr == NULL) ) {
687                         radlog(L_ERR, "rlm_ldap: Out of memory");
688                         if (pair->attr) free(pair->attr);
689                         if (pair->radius_attr) free(pair->radius_attr);
690                         free(pair);
691                         fclose(mapfile);
692                         return -1;
693                 }
694
695                 /* push node to correct list */
696                 if (strcasecmp(itemType, "checkItem") == 0) {
697                         pair->next = inst->check_item_map;
698                         inst->check_item_map = pair;
699                 } else if (strcasecmp(itemType, "replyItem") == 0) {
700                         pair->next = inst->reply_item_map;
701                         inst->reply_item_map = pair;
702                 } else {
703                         radlog(L_ERR, "rlm_ldap: file %s: skipping line %i: unknown itemType %s",
704                                filename, linenumber, itemType);
705                         free(pair->attr);
706                         free(pair->radius_attr);
707                         free(pair);
708                         continue;
709                 }
710
711                 DEBUG("rlm_ldap: LDAP %s mapped to RADIUS %s",
712                       pair->attr, pair->radius_attr);
713         }
714
715         fclose(mapfile);
716
717         return 0; /* success */
718 }
719
720 static int perform_search(void *instance, LDAP_CONN *conn,
721                           char *search_basedn, int scope, char *filter,
722                           char **attrs, LDAPMessage ** result)
723 {
724         int             res = RLM_MODULE_OK;
725         int             ldap_errno = 0;
726         ldap_instance  *inst = instance;
727         int             search_retry = 0;
728
729         *result = NULL;
730
731         if (!conn){
732                 radlog(L_ERR, "rlm_ldap: NULL connection handle passed");
733                 return RLM_MODULE_FAIL;
734         }
735         if (conn->failed_conns > MAX_FAILED_CONNS_START){
736                 conn->failed_conns++;
737                 if (conn->failed_conns >= MAX_FAILED_CONNS_END){
738                         conn->failed_conns = MAX_FAILED_CONNS_RESTART;
739                         conn->bound = 0;
740                 }
741         }
742 retry:
743         if (!conn->bound || conn->ld == NULL) {
744                 DEBUG2("rlm_ldap: attempting LDAP reconnection");
745                 if (conn->ld){
746                         DEBUG2("rlm_ldap: closing existing LDAP connection");
747                         ldap_unbind_s(conn->ld);
748                 }
749                 if ((conn->ld = ldap_connect(instance, inst->login,
750                                              inst->password, 0, &res, NULL)) == NULL) {
751                         radlog(L_ERR, "rlm_ldap: (re)connection attempt failed");
752                         if (search_retry == 0)
753                                 conn->failed_conns++;
754                         return (RLM_MODULE_FAIL);
755                 }
756                 conn->bound = 1;
757                 conn->failed_conns = 0;
758         }
759         DEBUG2("rlm_ldap: performing search in %s, with filter %s",
760                search_basedn ? search_basedn : "(null)" , filter);
761         switch (ldap_search_st(conn->ld, search_basedn, scope, filter,
762                                attrs, 0, &(inst->timeout), result)) {
763         case LDAP_SUCCESS:
764         case LDAP_NO_SUCH_OBJECT:
765                 break;
766         case LDAP_SERVER_DOWN:
767                 radlog(L_ERR, "rlm_ldap: ldap_search() failed: LDAP connection lost.");
768                 conn->failed_conns++;
769                 if (search_retry == 0){
770                         if (conn->failed_conns <= MAX_FAILED_CONNS_START){
771                                 radlog(L_INFO, "rlm_ldap: Attempting reconnect");
772                                 search_retry = 1;
773                                 conn->bound = 0;
774                                 ldap_msgfree(*result);
775                                 goto retry;
776                         }
777                 }
778                 ldap_msgfree(*result);
779                 return RLM_MODULE_FAIL;
780         case LDAP_INSUFFICIENT_ACCESS:
781                 radlog(L_ERR, "rlm_ldap: ldap_search() failed: Insufficient access. Check the identity and password configuration directives.");
782                 ldap_msgfree(*result);
783                 return RLM_MODULE_FAIL;
784         case LDAP_TIMEOUT:
785                 radlog(L_ERR, "rlm_ldap: ldap_search() failed: Timed out while waiting for server to respond. Please increase the timeout.");
786                 ldap_msgfree(*result);
787                 return RLM_MODULE_FAIL;
788         case LDAP_FILTER_ERROR:
789                 radlog(L_ERR, "rlm_ldap: ldap_search() failed: Bad search filter: %s",filter);
790                 ldap_msgfree(*result);
791                 return RLM_MODULE_FAIL;
792         case LDAP_TIMELIMIT_EXCEEDED:
793         case LDAP_BUSY:
794         case LDAP_UNAVAILABLE:
795                 /* We don't need to reconnect in these cases so we don't set conn->bound */
796                 ldap_get_option(conn->ld, LDAP_OPT_ERROR_NUMBER, &ldap_errno);
797                 radlog(L_ERR, "rlm_ldap: ldap_search() failed: %s",
798                        ldap_err2string(ldap_errno));
799                 ldap_msgfree(*result);
800                 return (RLM_MODULE_FAIL);
801         default:
802                 ldap_get_option(conn->ld, LDAP_OPT_ERROR_NUMBER, &ldap_errno);
803                 radlog(L_ERR, "rlm_ldap: ldap_search() failed: %s",
804                        ldap_err2string(ldap_errno));
805                 conn->bound = 0;
806                 ldap_msgfree(*result);
807                 return (RLM_MODULE_FAIL);
808         }
809
810         if ((ldap_count_entries(conn->ld, *result)) != 1) {
811                 DEBUG("rlm_ldap: object not found or got ambiguous search result");
812                 res = RLM_MODULE_NOTFOUND;
813                 ldap_msgfree(*result);
814         }
815         return res;
816 }
817
818
819 /*
820  *      Translate the LDAP queries.
821  */
822 static int ldap_escape_func(char *out, int outlen, const char *in)
823 {
824         int len = 0;
825
826         while (in[0]) {
827                 /*
828                  *      Encode unsafe characters.
829                  */
830                 if (strchr("*=\\,()", *in)) {
831                         static const char hex[] = "0123456789abcdef";
832
833                         /*
834                          *      Only 3 or less bytes available.
835                          */
836                         if (outlen <= 3) {
837                                 break;
838                         }
839
840                         *(out++) = '\\';
841                         *(out++) = hex[((*in) >> 4) & 0x0f];
842                         *(out++) = hex[(*in) & 0x0f];
843                         outlen -= 3;
844                         len += 3;
845                         in++;
846                         continue;
847                 }
848
849                 /*
850                  *      Only one byte left.
851                  */
852                 if (outlen <= 1) {
853                         break;
854                 }
855
856                 /*
857                  *      Allowed character.
858                  */
859                 *(out++) = *(in++);
860                 outlen--;
861                 len++;
862         }
863         *out = '\0';
864         return len;
865 }
866
867 /*
868  *      ldap_groupcmp(). Implement the Ldap-Group == "group" filter
869  */
870 static int ldap_groupcmp(void *instance, REQUEST *req,
871                          UNUSED VALUE_PAIR *request, VALUE_PAIR *check,
872                          UNUSED VALUE_PAIR *check_pairs,
873                          UNUSED VALUE_PAIR **reply_pairs)
874 {
875         char            filter[MAX_FILTER_STR_LEN];
876         char            gr_filter[MAX_FILTER_STR_LEN];
877         int             res;
878         LDAPMessage     *result = NULL;
879         LDAPMessage     *msg = NULL;
880         char            basedn[MAX_FILTER_STR_LEN];
881         char            *attrs[] = {"dn",NULL};
882         char            **vals;
883         ldap_instance   *inst = instance;
884         char            *group_attrs[] = {inst->groupmemb_attr,NULL};
885         LDAP_CONN       *conn;
886         int             conn_id = -1;
887         VALUE_PAIR      *vp_user_dn;
888         VALUE_PAIR      **request_pairs;
889
890         request_pairs = &req->config_items;
891
892         DEBUG("rlm_ldap: Entering ldap_groupcmp()");
893
894         if (check->vp_strvalue == NULL || check->length == 0){
895                 DEBUG("rlm_ldap::ldap_groupcmp: Illegal group name");
896                 return 1;
897         }
898
899         if (req == NULL){
900                 DEBUG("rlm_ldap::ldap_groupcmp: NULL request");
901                 return 1;
902         }
903
904         if (!radius_xlat(basedn, sizeof(basedn), inst->basedn, req, NULL)) {
905                 DEBUG("rlm_ldap::ldap_groupcmp: unable to create basedn.");
906                 return 1;
907         }
908
909         while((vp_user_dn = pairfind(*request_pairs, PW_LDAP_USERDN)) == NULL){
910                 char            *user_dn = NULL;
911
912                 if (!radius_xlat(filter, sizeof(filter), inst->filter,
913                                         req, ldap_escape_func)){
914                         DEBUG("rlm_ldap::ldap_groupcmp: unable to create filter");
915                         return 1;
916                 }
917                 if ((conn_id = ldap_get_conn(inst->conns,&conn,inst)) == -1){
918                         radlog(L_ERR, "rlm_ldap: All ldap connections are in use");
919                         return 1;
920                 }
921                 if ((res = perform_search(inst, conn, basedn, LDAP_SCOPE_SUBTREE,
922                                         filter, attrs, &result)) != RLM_MODULE_OK){
923                         DEBUG("rlm_ldap::ldap_groupcmp: search failed");
924                         ldap_release_conn(conn_id,inst->conns);
925                         return 1;
926                 }
927                 if ((msg = ldap_first_entry(conn->ld, result)) == NULL) {
928                         DEBUG("rlm_ldap::ldap_groupcmp: ldap_first_entry() failed");
929                         ldap_release_conn(conn_id,inst->conns);
930                         ldap_msgfree(result);
931                         return 1;
932                 }
933                 if ((user_dn = ldap_get_dn(conn->ld, msg)) == NULL) {
934                         DEBUG("rlm_ldap:ldap_groupcmp:: ldap_get_dn() failed");
935                         ldap_release_conn(conn_id,inst->conns);
936                         ldap_msgfree(result);
937                         return 1;
938                 }
939                 ldap_release_conn(conn_id,inst->conns);
940
941                 /*
942                  *      Adding new attribute containing DN for LDAP
943                  *      object associated with given username
944                  */
945                 pairadd(request_pairs, pairmake("Ldap-UserDn", user_dn,
946                                                 T_OP_EQ));
947                 ldap_memfree(user_dn);
948                 ldap_msgfree(result);
949         }
950
951         if(!radius_xlat(gr_filter, sizeof(gr_filter),
952                         inst->groupmemb_filt, req, NULL)) {
953                 DEBUG("rlm_ldap::ldap_groupcmp: unable to create filter.");
954                 return 1;
955         }
956
957         if (strchr((char *)check->vp_strvalue,',') != NULL) {
958                 /* This looks like a DN */
959                 snprintf(filter,sizeof(filter), "%s",gr_filter);
960                 snprintf(basedn,sizeof(basedn), "%s",(char *)check->vp_strvalue);
961         } else
962                 snprintf(filter,sizeof(filter), "(&(%s=%s)%s)",
963                          inst->groupname_attr,
964                          (char *)check->vp_strvalue,gr_filter);
965
966         if ((conn_id = ldap_get_conn(inst->conns,&conn,inst)) == -1) {
967                 radlog(L_ERR, "rlm_ldap: All ldap connections are in use");
968                 return 1;
969         }
970
971         if ((res = perform_search(inst, conn, basedn, LDAP_SCOPE_SUBTREE,
972                                 filter, attrs, &result)) == RLM_MODULE_OK) {
973                 DEBUG("rlm_ldap::ldap_groupcmp: User found in group %s",
974                                 (char *)check->vp_strvalue);
975                 ldap_msgfree(result);
976                 ldap_release_conn(conn_id,inst->conns);
977                 return 0;
978         }
979
980         ldap_release_conn(conn_id,inst->conns);
981
982         if (res != RLM_MODULE_NOTFOUND ) {
983                 DEBUG("rlm_ldap::ldap_groupcmp: Search returned error");
984                 return 1;
985         }
986
987         if (inst->groupmemb_attr == NULL){
988                 /*
989                  *      Search returned NOTFOUND and searching for
990                  *      membership using user object attributes is not
991                  *      specified in config file
992                  */
993                 DEBUG("rlm_ldap::ldap_groupcmp: Group %s not found or user is not a member.",(char *)check->vp_strvalue);
994                 return 1;
995         }
996
997         snprintf(filter,sizeof(filter), "(objectclass=*)");
998         if ((conn_id = ldap_get_conn(inst->conns,&conn,inst)) == -1){
999                 radlog(L_ERR, "rlm_ldap: Add ldap connections are in use");
1000                 return 1;
1001         }
1002         if ((res = perform_search(inst, conn, vp_user_dn->vp_strvalue,
1003                                   LDAP_SCOPE_BASE, filter, group_attrs,
1004                                   &result)) != RLM_MODULE_OK) {
1005                 DEBUG("rlm_ldap::ldap_groupcmp: Search returned error");
1006                 ldap_release_conn(conn_id, inst->conns);
1007                 return 1;
1008         }
1009
1010         if ((msg = ldap_first_entry(conn->ld, result)) == NULL) {
1011                 DEBUG("rlm_ldap::ldap_groupcmp: ldap_first_entry() failed");
1012                 ldap_release_conn(conn_id,inst->conns);
1013                 ldap_msgfree(result);
1014                 return 1;
1015         }
1016         if ((vals = ldap_get_values(conn->ld, msg,
1017                                     inst->groupmemb_attr)) != NULL) {
1018                 unsigned int i = 0;
1019                 char found = 0;
1020
1021                 for (;i < ldap_count_values(vals);i++){
1022                         if (strchr(vals[i],',') != NULL){
1023                                 /* This looks like a DN */
1024                                 LDAPMessage *gr_result = NULL;
1025                                 snprintf(filter,sizeof(filter), "(%s=%s)",
1026                                         inst->groupname_attr,
1027                                         (char *)check->vp_strvalue);
1028                                 if ((res = perform_search(inst, conn, vals[i],
1029                                                 LDAP_SCOPE_BASE, filter,
1030                                                 attrs, &gr_result)) != RLM_MODULE_OK){
1031                                         if (res != RLM_MODULE_NOTFOUND) {
1032                                                 DEBUG("rlm_ldap::ldap_groupcmp: Search returned error");
1033                                                 ldap_value_free(vals);
1034                                                 ldap_msgfree(result);
1035                                                 ldap_release_conn(conn_id,inst->conns);
1036                                                 return 1;
1037                                         }
1038                                 } else {
1039                                         ldap_msgfree(gr_result);
1040                                         found = 1;
1041                                         break;
1042                                 }
1043                         } else {
1044                                 if (strcmp(vals[i],(char *)check->vp_strvalue) == 0){
1045                                         found = 1;
1046                                         break;
1047                                 }
1048                         }
1049                 }
1050                 ldap_value_free(vals);
1051                 ldap_msgfree(result);
1052                 if (found == 0){
1053                         DEBUG("rlm_ldap::groupcmp: Group %s not found or user not a member",
1054                                 (char *)check->vp_strvalue);
1055                         ldap_release_conn(conn_id,inst->conns);
1056                         return 1;
1057                 }
1058         } else {
1059                         DEBUG("rlm_ldap::ldap_groupcmp: ldap_get_values() failed");
1060                         ldap_msgfree(result);
1061                         ldap_release_conn(conn_id,inst->conns);
1062                         return 1;
1063         }
1064
1065         DEBUG("rlm_ldap::ldap_groupcmp: User found in group %s",(char *)check->vp_strvalue);
1066         ldap_release_conn(conn_id,inst->conns);
1067
1068         return 0;
1069 }
1070
1071 /*
1072  * ldap_xlat()
1073  * Do an xlat on an LDAP URL
1074  */
1075 static int ldap_xlat(void *instance, REQUEST *request, char *fmt,
1076                      char *out, size_t freespace, RADIUS_ESCAPE_STRING func)
1077 {
1078         char url[MAX_FILTER_STR_LEN];
1079         int res;
1080         int ret = 0;
1081         ldap_instance *inst = instance;
1082         LDAPURLDesc *ldap_url;
1083         LDAPMessage *result = NULL;
1084         LDAPMessage *msg = NULL;
1085         char **vals;
1086         int conn_id = -1;
1087         LDAP_CONN *conn;
1088
1089         DEBUG("rlm_ldap: - ldap_xlat");
1090         if (!radius_xlat(url, sizeof(url), fmt, request, func)) {
1091                 radlog (L_ERR, "rlm_ldap: Unable to create LDAP URL.\n");
1092                 return 0;
1093         }
1094         if (!ldap_is_ldap_url(url)){
1095                 radlog (L_ERR, "rlm_ldap: String passed does not look like an LDAP URL.\n");
1096                 return 0;
1097         }
1098         if (ldap_url_parse(url,&ldap_url)){
1099                 radlog (L_ERR, "rlm_ldap: LDAP URL parse failed.\n");
1100                 return 0;
1101         }
1102         if (ldap_url->lud_attrs == NULL || ldap_url->lud_attrs[0] == NULL ||
1103             ( ldap_url->lud_attrs[1] != NULL ||
1104               ( ! strlen(ldap_url->lud_attrs[0]) ||
1105                 ! strcmp(ldap_url->lud_attrs[0],"*") ) ) ){
1106                 radlog (L_ERR, "rlm_ldap: Invalid Attribute(s) request.\n");
1107                 ldap_free_urldesc(ldap_url);
1108                 return 0;
1109         }
1110         if (ldap_url->lud_host){
1111                 if (strncmp(inst->server,ldap_url->lud_host,
1112                             strlen(inst->server)) != 0 ||
1113                     ldap_url->lud_port != inst->port) {
1114                         DEBUG("rlm_ldap: Requested server/port is not known to this module instance.");
1115                         ldap_free_urldesc(ldap_url);
1116                         return 0;
1117                 }
1118         }
1119         if ((conn_id = ldap_get_conn(inst->conns,&conn,inst)) == -1){
1120                 radlog(L_ERR, "rlm_ldap: All ldap connections are in use");
1121                 ldap_free_urldesc(ldap_url);
1122                 return 0;
1123         }
1124         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){
1125                 if (res == RLM_MODULE_NOTFOUND){
1126                         DEBUG("rlm_ldap: Search returned not found");
1127                         ldap_free_urldesc(ldap_url);
1128                         ldap_release_conn(conn_id,inst->conns);
1129                         return 0;
1130                 }
1131                 DEBUG("rlm_ldap: Search returned error");
1132                 ldap_free_urldesc(ldap_url);
1133                 ldap_release_conn(conn_id,inst->conns);
1134                 return 0;
1135         }
1136         if ((msg = ldap_first_entry(conn->ld, result)) == NULL){
1137                 DEBUG("rlm_ldap: ldap_first_entry() failed");
1138                 ldap_msgfree(result);
1139                 ldap_free_urldesc(ldap_url);
1140                 ldap_release_conn(conn_id,inst->conns);
1141                 return 0;
1142         }
1143         if ((vals = ldap_get_values(conn->ld, msg, ldap_url->lud_attrs[0])) != NULL) {
1144                 ret = strlen(vals[0]);
1145                 if (ret > freespace){
1146                         DEBUG("rlm_ldap: Insufficient string space");
1147                         ldap_free_urldesc(ldap_url);
1148                         ldap_value_free(vals);
1149                         ldap_msgfree(result);
1150                         ldap_release_conn(conn_id,inst->conns);
1151                         return 0;
1152                 }
1153                 DEBUG("rlm_ldap: Adding attribute %s, value: %s",ldap_url->lud_attrs[0],vals[0]);
1154                 strncpy(out,vals[0],ret);
1155                 ldap_value_free(vals);
1156         }
1157         else
1158                 ret = 0;
1159
1160         ldap_msgfree(result);
1161         ldap_free_urldesc(ldap_url);
1162         ldap_release_conn(conn_id,inst->conns);
1163
1164         DEBUG("rlm_ldap: - ldap_xlat end");
1165
1166         return ret;
1167 }
1168
1169
1170 /*
1171  *      For auto-header discovery.
1172  */
1173 static const LRAD_NAME_NUMBER header_names[] = {
1174         { "{clear}",    PW_USER_PASSWORD },
1175         { "{cleartext}", PW_USER_PASSWORD },
1176         { "{md5}",      PW_MD5_PASSWORD },
1177         { "{smd5}",     PW_SMD5_PASSWORD },
1178         { "{crypt}",    PW_CRYPT_PASSWORD },
1179         { "{sha}",      PW_SHA_PASSWORD },
1180         { "{ssha}",     PW_SSHA_PASSWORD },
1181         { "{nt}",       PW_NT_PASSWORD },
1182         { "{ns-mta-md5}", PW_NS_MTA_MD5_PASSWORD },
1183         { NULL, 0 }
1184 };
1185
1186
1187 /******************************************************************************
1188  *
1189  *      Function: rlm_ldap_authorize
1190  *
1191  *      Purpose: Check if user is authorized for remote access
1192  *
1193  ******************************************************************************/
1194 static int ldap_authorize(void *instance, REQUEST * request)
1195 {
1196         LDAPMessage     *result = NULL;
1197         LDAPMessage     *msg = NULL;
1198         LDAPMessage     *def_msg = NULL;
1199         LDAPMessage     *def_attr_msg = NULL;
1200         LDAPMessage     *def_result = NULL;
1201         LDAPMessage     *def_attr_result = NULL;
1202         ldap_instance   *inst = instance;
1203         char            *user_dn = NULL;
1204         char            filter[MAX_FILTER_STR_LEN];
1205         char            basedn[MAX_FILTER_STR_LEN];
1206         VALUE_PAIR      *check_tmp;
1207         VALUE_PAIR      *reply_tmp;
1208         int             res;
1209         VALUE_PAIR      **check_pairs, **reply_pairs;
1210         char            **vals;
1211         VALUE_PAIR      *module_fmsg_vp;
1212         VALUE_PAIR      *user_profile;
1213         char            module_fmsg[MAX_STRING_LEN];
1214         LDAP_CONN       *conn;
1215         int             conn_id = -1;
1216
1217         DEBUG("rlm_ldap: - authorize");
1218
1219         if (!request->username){
1220                 radlog(L_AUTH, "rlm_ldap: Attribute \"User-Name\" is required for authentication.\n");
1221                 return RLM_MODULE_INVALID;
1222         }
1223
1224         check_pairs = &request->config_items;
1225         reply_pairs = &request->reply->vps;
1226
1227         /*
1228          * Check for valid input, zero length names not permitted
1229          */
1230         if (request->username->vp_strvalue == 0) {
1231                 radlog(L_ERR, "rlm_ldap: zero length username not permitted\n");
1232                 return RLM_MODULE_INVALID;
1233         }
1234         DEBUG("rlm_ldap: performing user authorization for %s",
1235                request->username->vp_strvalue);
1236
1237         if (!radius_xlat(filter, sizeof(filter), inst->filter,
1238                          request, ldap_escape_func)) {
1239                 radlog (L_ERR, "rlm_ldap: unable to create filter.\n");
1240                 return RLM_MODULE_INVALID;
1241         }
1242
1243         if (!radius_xlat(basedn, sizeof(basedn), inst->basedn,
1244                          request, NULL)) {
1245                 radlog (L_ERR, "rlm_ldap: unable to create basedn.\n");
1246                 return RLM_MODULE_INVALID;
1247         }
1248
1249         if ((conn_id = ldap_get_conn(inst->conns,&conn,inst)) == -1){
1250                 radlog(L_ERR, "rlm_ldap: All ldap connections are in use");
1251                 return RLM_MODULE_FAIL;
1252         }
1253         if ((res = perform_search(instance, conn, basedn, LDAP_SCOPE_SUBTREE, filter, inst->atts, &result)) != RLM_MODULE_OK) {
1254                 DEBUG("rlm_ldap: search failed");
1255                 if (res == RLM_MODULE_NOTFOUND){
1256                         snprintf(module_fmsg,sizeof(module_fmsg),"rlm_ldap: User not found");
1257                         module_fmsg_vp = pairmake("Module-Failure-Message", module_fmsg, T_OP_EQ);
1258                         pairadd(&request->packet->vps, module_fmsg_vp);
1259                 }
1260                 ldap_release_conn(conn_id,inst->conns);
1261                 return (res);
1262         }
1263         if ((msg = ldap_first_entry(conn->ld, result)) == NULL) {
1264                 DEBUG("rlm_ldap: ldap_first_entry() failed");
1265                 ldap_msgfree(result);
1266                 ldap_release_conn(conn_id,inst->conns);
1267                 return RLM_MODULE_FAIL;
1268         }
1269         if ((user_dn = ldap_get_dn(conn->ld, msg)) == NULL) {
1270                 DEBUG("rlm_ldap: ldap_get_dn() failed");
1271                 ldap_msgfree(result);
1272                 ldap_release_conn(conn_id,inst->conns);
1273                 return RLM_MODULE_FAIL;
1274         }
1275         /*
1276          * Adding new attribute containing DN for LDAP object associated with
1277          * given username
1278          */
1279         pairadd(check_pairs, pairmake("Ldap-UserDn", user_dn, T_OP_EQ));
1280         ldap_memfree(user_dn);
1281
1282
1283         /* Remote access is controled by attribute of the user object */
1284         if (inst->access_attr) {
1285                 if ((vals = ldap_get_values(conn->ld, msg, inst->access_attr)) != NULL) {
1286                         if (inst->default_allow){
1287                                 DEBUG("rlm_ldap: checking if remote access for %s is allowed by %s", request->username->vp_strvalue, inst->access_attr);
1288                                 if (!strncmp(vals[0], "FALSE", 5)) {
1289                                         DEBUG("rlm_ldap: dialup access disabled");
1290                                         snprintf(module_fmsg,sizeof(module_fmsg),"rlm_ldap: Access Attribute denies access");
1291                                         module_fmsg_vp = pairmake("Module-Failure-Message", module_fmsg, T_OP_EQ);
1292                                         pairadd(&request->packet->vps, module_fmsg_vp);
1293                                         ldap_msgfree(result);
1294                                         ldap_value_free(vals);
1295                                         ldap_release_conn(conn_id,inst->conns);
1296                                         return RLM_MODULE_USERLOCK;
1297                                 }
1298                                 ldap_value_free(vals);
1299                         }
1300                         else{
1301                                 DEBUG("rlm_ldap: %s attribute exists - access denied by default", inst->access_attr);
1302                                 snprintf(module_fmsg,sizeof(module_fmsg),"rlm_ldap: Access Attribute denies access");
1303                                 module_fmsg_vp = pairmake("Module-Failure-Message", module_fmsg, T_OP_EQ);
1304                                 pairadd(&request->packet->vps, module_fmsg_vp);
1305                                 ldap_msgfree(result);
1306                                 ldap_value_free(vals);
1307                                 ldap_release_conn(conn_id,inst->conns);
1308                                 return RLM_MODULE_USERLOCK;
1309                         }
1310                 } else {
1311                         if (inst->default_allow){
1312                                 DEBUG("rlm_ldap: no %s attribute - access denied by default", inst->access_attr);
1313                                 snprintf(module_fmsg,sizeof(module_fmsg),"rlm_ldap: Access Attribute denies access");
1314                                 module_fmsg_vp = pairmake("Module-Failure-Message", module_fmsg, T_OP_EQ);
1315                                 pairadd(&request->packet->vps, module_fmsg_vp);
1316                                 ldap_msgfree(result);
1317                                 ldap_release_conn(conn_id,inst->conns);
1318                                 return RLM_MODULE_USERLOCK;
1319                         }
1320                 }
1321         }
1322
1323         /*
1324          * Check for the default profile entry. If it exists then add the
1325          * attributes it contains in the check and reply pairs
1326          */
1327
1328         user_profile = pairfind(request->config_items, PW_USER_PROFILE);
1329         if (inst->default_profile || user_profile){
1330                 char *profile = inst->default_profile;
1331
1332                 strNcpy(filter,inst->base_filter,sizeof(filter));
1333                 if (user_profile)
1334                         profile = user_profile->vp_strvalue;
1335                 if (profile && strlen(profile)){
1336                         if ((res = perform_search(instance, conn,
1337                                 profile, LDAP_SCOPE_BASE,
1338                                 filter, inst->atts, &def_result)) == RLM_MODULE_OK){
1339                                 if ((def_msg = ldap_first_entry(conn->ld,def_result))){
1340                                         if ((check_tmp = ldap_pairget(conn->ld,def_msg,inst->check_item_map,check_pairs,1))) {
1341                                                 if (inst->do_xlat){
1342                                                         pairxlatmove(request, check_pairs, &check_tmp);
1343                                                         pairfree(&check_tmp);
1344                                                 }
1345                                                 else
1346                                                         pairadd(check_pairs,check_tmp);
1347                                         }
1348                                         if ((reply_tmp = ldap_pairget(conn->ld,def_msg,inst->reply_item_map,reply_pairs,0))) {
1349                                                 if (inst->do_xlat){
1350                                                         pairxlatmove(request, reply_pairs, &reply_tmp);
1351                                                         pairfree(&reply_tmp);
1352                                                 }
1353                                                 else
1354                                                         pairadd(reply_pairs,reply_tmp);
1355                                         }
1356                                 }
1357                                 ldap_msgfree(def_result);
1358                         } else
1359                                 DEBUG("rlm_ldap: default_profile/user-profile search failed");
1360                 }
1361         }
1362
1363         /*
1364          * Check for the profile attribute. If it exists, we assume that it
1365          * contains the DN of an entry containg a profile for the user. That
1366          * way we can have different general profiles for various user groups
1367          * (students,faculty,staff etc)
1368          */
1369
1370         if (inst->profile_attr){
1371                 if ((vals = ldap_get_values(conn->ld, msg, inst->profile_attr)) != NULL) {
1372                         unsigned int i=0;
1373                         strNcpy(filter,inst->base_filter,sizeof(filter));
1374                         while(vals[i] != NULL && strlen(vals[i])){
1375                                 if ((res = perform_search(instance, conn,
1376                                         vals[i], LDAP_SCOPE_BASE,
1377                                         filter, inst->atts, &def_attr_result)) == RLM_MODULE_OK){
1378                                         if ((def_attr_msg = ldap_first_entry(conn->ld,def_attr_result))){
1379                                                 if ((check_tmp = ldap_pairget(conn->ld,def_attr_msg,inst->check_item_map,check_pairs,1))) {
1380                                                         if (inst->do_xlat){
1381                                                                 pairxlatmove(request, check_pairs, &check_tmp);
1382                                                                 pairfree(&check_tmp);
1383                                                         }
1384                                                         else
1385                                                                 pairadd(check_pairs,check_tmp);
1386                                                 }
1387                                                 if ((reply_tmp = ldap_pairget(conn->ld,def_attr_msg,inst->reply_item_map,reply_pairs,0))) {
1388                                                         if (inst->do_xlat){
1389                                                                 pairxlatmove(request, reply_pairs, &reply_tmp);
1390                                                                 pairfree(&reply_tmp);
1391                                                         }
1392                                                         else
1393                                                                 pairadd(reply_pairs,reply_tmp);
1394                                                 }
1395                                         }
1396                                         ldap_msgfree(def_attr_result);
1397                                 } else
1398                                         DEBUG("rlm_ldap: profile_attribute search failed");
1399                                 i++;
1400                         }
1401                         ldap_value_free(vals);
1402                 }
1403         }
1404         if (inst->passwd_attr && strlen(inst->passwd_attr)) {
1405 #ifdef NOVELL_UNIVERSAL_PASSWORD
1406                 if (strcasecmp(inst->passwd_attr,"nspmPassword") != 0) {
1407 #endif
1408                         VALUE_PAIR *passwd_item;
1409                         char **passwd_vals;
1410                         char *value = NULL;
1411                         int i;
1412                         
1413                         /*
1414                          *      Read the password from the DB, and
1415                          *      add it to the request.
1416                          */
1417                         passwd_vals = ldap_get_values(conn->ld,msg,
1418                                                       inst->passwd_attr);
1419
1420                         /*
1421                          *      Loop over what we received, and parse it.
1422                          */
1423                         if (passwd_vals) for (i = 0;
1424                                               passwd_vals[i] != NULL;
1425                                               i++) {
1426                                 int attr = PW_USER_PASSWORD;
1427                                 
1428                                 if (strlen(passwd_vals[i]) == 0)
1429                                         continue;
1430                                 
1431                                 value = passwd_vals[i];
1432
1433                                 if (inst->auto_header) {
1434                                         char *p;
1435                                         char autobuf[16];
1436
1437                                         p = strchr(value, '}');
1438                                         if (!p) continue;
1439                                         if ((p - value + 1) >= sizeof(autobuf))
1440                                                 continue; /* paranoia */
1441                                         memcpy(autobuf, value, p - value + 1);
1442                                         autobuf[p - value + 1] = '\0';
1443                                 
1444                                         attr = lrad_str2int(header_names,
1445                                                             autobuf, 0);
1446                                         if (!attr) continue;
1447                                         value = p + 1;
1448                                         goto create_attr;
1449
1450                                 } else if (inst->passwd_hdr &&
1451                                            strlen(inst->passwd_hdr)) {
1452                                         if (strncasecmp(value,
1453                                                         inst->passwd_hdr,
1454                                                         strlen(inst->passwd_hdr)) == 0) {
1455                                                 value += strlen(inst->passwd_hdr);
1456                                         } else {
1457                                                 DEBUG("rlm_ldap: Password header not found in password %s for user %s", passwd_vals[0], request->username->vp_strvalue);
1458                                         }
1459                                 }
1460                                 if (!value) continue;
1461                                 
1462                         create_attr:
1463                                 passwd_item = paircreate(attr, PW_TYPE_STRING);
1464                                 if (!passwd_item) {
1465                                         radlog(L_ERR|L_CONS, "no memory");
1466                                         ldap_value_free(passwd_vals);
1467                                         ldap_msgfree(result);
1468                                         ldap_release_conn(conn_id,inst->conns);
1469                                         return RLM_MODULE_FAIL;
1470                                 }
1471                                 strNcpy(passwd_item->vp_strvalue, value,
1472                                         sizeof(passwd_item->vp_strvalue));
1473                                 passwd_item->length = strlen(passwd_item->vp_strvalue);
1474                                 pairadd(&request->config_items,passwd_item);
1475                                 DEBUG("rlm_ldap: Added %s = %s in check items",
1476                                       passwd_item->name,
1477                                       passwd_item->vp_strvalue);
1478                         }
1479                         ldap_value_free(passwd_vals);
1480 #ifdef NOVELL_UNIVERSAL_PASSWORD
1481                 }
1482                 else{
1483                 /*
1484                 * Read Universal Password from eDirectory
1485                 */
1486                         VALUE_PAIR      *passwd_item;
1487                         VALUE_PAIR      *vp_user_dn;
1488                         int             passwd_len;
1489                         char            *universal_password = NULL;
1490                         int             universal_password_len = UNIVERSAL_PASS_LEN;
1491                         char            *passwd_val = NULL;
1492
1493                         res = 0;
1494
1495                         if ((passwd_item = pairfind(request->config_items, PW_USER_PASSWORD)) == NULL){
1496                         
1497                                 universal_password = rad_malloc(universal_password_len);
1498                                 memset(universal_password, 0, universal_password_len);
1499
1500                                 vp_user_dn = pairfind(request->config_items,PW_LDAP_USERDN);
1501                                 res = nmasldap_get_password(conn->ld,vp_user_dn->vp_strvalue,&universal_password_len,universal_password);
1502
1503                                 if (res == 0){
1504                                         passwd_val = universal_password;
1505
1506                                         if (inst->passwd_hdr && strlen(inst->passwd_hdr)){
1507                                                 passwd_val = strstr(passwd_val,inst->passwd_hdr);
1508
1509                                                 if (passwd_val != NULL)
1510                                                         passwd_val += strlen((char*)inst->passwd_hdr);
1511                                                 else
1512                                                         DEBUG("rlm_ldap: Password header not found in password %s for user %s ",passwd_val,request->username->vp_strvalue);
1513                                         }
1514
1515                                         if (passwd_val){
1516                                                 if ((passwd_item = paircreate(PW_USER_PASSWORD,PW_TYPE_STRING)) == NULL){
1517                                                         radlog(L_ERR, "rlm_ldap: Could not allocate memory. Aborting.");
1518                                                         ldap_msgfree(result);
1519                                                         ldap_release_conn(conn_id,inst->conns);
1520                                                         memset(universal_password, 0, universal_password_len);
1521                                                         free(universal_password);
1522                                                         return RLM_MODULE_FAIL;
1523                                                 }
1524
1525                                                 passwd_len = strlen(passwd_val);
1526                                                 strncpy(passwd_item->vp_strvalue,passwd_val,MAX_STRING_LEN - 1);
1527                                                 passwd_item->length = (passwd_len > (MAX_STRING_LEN - 1)) ? (MAX_STRING_LEN - 1) : passwd_len;
1528                                                 pairadd(&request->config_items,passwd_item);
1529
1530 #ifdef NOVELL
1531                                                 {
1532                                                         DICT_ATTR *dattr;
1533                                                         VALUE_PAIR      *vp_inst, *vp_apc;
1534                                                         int inst_attr, apc_attr;
1535
1536                                                         dattr = dict_attrbyname("LDAP-Instance");
1537                                                         inst_attr = dattr->attr;
1538                                                         dattr = dict_attrbyname("eDir-APC");
1539                                                         apc_attr = dattr->attr;
1540
1541                                                         vp_inst = pairfind(request->config_items, inst_attr);
1542                                                         if(vp_inst == NULL){
1543                                                                 /*
1544                                                                  * The authorize method of no other LDAP module instance has
1545                                                                  * processed this request.
1546                                                                  */
1547                                                                 if ((vp_inst = paircreate(inst_attr, PW_TYPE_STRING)) == NULL){
1548                                                                         radlog(L_ERR, "rlm_ldap: Could not allocate memory. Aborting.");
1549                                                                         ldap_msgfree(result);
1550                                                                         ldap_release_conn(conn_id, inst->conns);
1551                                                                         memset(universal_password, 0, universal_password_len);
1552                                                                         free(universal_password);
1553                                                                         return RLM_MODULE_FAIL;
1554                                                                 }
1555                                                                 strcpy(vp_inst->vp_strvalue, inst->xlat_name);
1556                                                                 vp_inst->length = strlen(vp_inst->vp_strvalue);
1557                                                                 pairadd(&request->config_items, vp_inst);
1558
1559                                                                 /*
1560                                                                  * Inform the authenticate / post-auth method about the presence
1561                                                                  * of UP in the config items list and whether eDirectory account
1562                                                                  * policy check is to be performed or not.
1563                                                                  */
1564                                                                 if ((vp_apc = paircreate(apc_attr, PW_TYPE_INTEGER)) == NULL){
1565                                                                         radlog(L_ERR, "rlm_ldap: Could not allocate memory. Aborting.");
1566                                                                         ldap_msgfree(result);
1567                                                                         ldap_release_conn(conn_id, inst->conns);
1568                                                                         memset(universal_password, 0, universal_password_len);
1569                                                                         free(universal_password);
1570                                                                         return RLM_MODULE_FAIL;
1571                                                                 }
1572
1573                                                                 if(!inst->edir_account_policy_check){
1574                                                                         /* Do nothing */
1575                                                                         strcpy(vp_apc->vp_strvalue, "1");
1576                                                                 }else{
1577                                                                         /* Perform eDirectory account-policy check */
1578                                                                         strcpy(vp_apc->vp_strvalue, "2");
1579                                                                 }
1580                                                                 vp_apc->length = 1;
1581                                                                 pairadd(&request->config_items, vp_apc);
1582                                                         }
1583                                                 }
1584 #endif
1585
1586                                                 DEBUG("rlm_ldap: Added the eDirectory password %s in check items as %s",passwd_item->vp_strvalue,passwd_item->name);
1587                                         }
1588                                 }
1589                                 else {
1590                                         DEBUG("rlm_ldap: Error reading Universal Password.Return Code = %d",res);
1591                                 }
1592
1593                                 memset(universal_password, 0, universal_password_len);
1594                                 free(universal_password);
1595                         }
1596                 }                       
1597 #endif
1598         }
1599
1600
1601
1602         DEBUG("rlm_ldap: looking for check items in directory...");
1603
1604         if ((check_tmp = ldap_pairget(conn->ld, msg, inst->check_item_map,check_pairs,1)) != NULL) {
1605                 if (inst->do_xlat){
1606                         pairxlatmove(request, check_pairs, &check_tmp);
1607                         pairfree(&check_tmp);
1608                 }
1609                 else
1610                         pairadd(check_pairs,check_tmp);
1611         }
1612
1613
1614         DEBUG("rlm_ldap: looking for reply items in directory...");
1615
1616
1617         if ((reply_tmp = ldap_pairget(conn->ld, msg, inst->reply_item_map,reply_pairs,0)) != NULL) {
1618                 if (inst->do_xlat){
1619                         pairxlatmove(request, reply_pairs, &reply_tmp);
1620                         pairfree(&reply_tmp);
1621                 }
1622                 else
1623                         pairadd(reply_pairs,reply_tmp);
1624         }
1625
1626        if (inst->do_comp && paircompare(request,request->packet->vps,*check_pairs,reply_pairs) != 0){
1627 #ifdef NOVELL
1628                 /* Don't perform eDirectory APC if RADIUS authorize fails */
1629                 int apc_attr;
1630                 VALUE_PAIR *vp_apc;
1631                 DICT_ATTR *dattr;
1632
1633                 dattr = dict_attrbyname("eDir-APC");
1634                 apc_attr = dattr->attr;
1635
1636                 vp_apc = pairfind(request->config_items, apc_attr);
1637                 if(vp_apc)
1638                         vp_apc->vp_strvalue[0] = '1';
1639 #endif
1640
1641                 DEBUG("rlm_ldap: Pairs do not match. Rejecting user.");
1642                 snprintf(module_fmsg,sizeof(module_fmsg),"rlm_ldap: Pairs do not match");
1643                 module_fmsg_vp = pairmake("Module-Failure-Message", module_fmsg, T_OP_EQ);
1644                 pairadd(&request->packet->vps, module_fmsg_vp);
1645                 ldap_msgfree(result);
1646                 ldap_release_conn(conn_id,inst->conns);
1647
1648                 return RLM_MODULE_REJECT;
1649         }
1650
1651         /*
1652          * Module should default to LDAP authentication if no Auth-Type
1653          * specified
1654          */
1655         if ((pairfind(*check_pairs, PW_AUTH_TYPE) == NULL) &&
1656             request->password &&
1657             (request->password->attribute == PW_USER_PASSWORD))
1658                 pairadd(check_pairs, pairmake("Auth-Type", "LDAP", T_OP_EQ));
1659
1660
1661         DEBUG("rlm_ldap: user %s authorized to use remote access",
1662               request->username->vp_strvalue);
1663         ldap_msgfree(result);
1664         ldap_release_conn(conn_id,inst->conns);
1665
1666         return RLM_MODULE_OK;
1667 }
1668
1669 /*****************************************************************************
1670  *
1671  *      Function: rlm_ldap_authenticate
1672  *
1673  *      Purpose: Check the user's password against ldap database
1674  *
1675  *****************************************************************************/
1676 static int ldap_authenticate(void *instance, REQUEST * request)
1677 {
1678         LDAP           *ld_user;
1679         LDAPMessage    *result, *msg;
1680         ldap_instance  *inst = instance;
1681         char           *user_dn, *attrs[] = {"uid", NULL};
1682         char            filter[MAX_FILTER_STR_LEN];
1683         char            basedn[MAX_FILTER_STR_LEN];
1684         int             res;
1685         VALUE_PAIR     *vp_user_dn;
1686         VALUE_PAIR      *module_fmsg_vp;
1687         char            module_fmsg[MAX_STRING_LEN];
1688         LDAP_CONN       *conn;
1689         int             conn_id = -1;
1690 #ifdef NOVELL
1691         char            *err = NULL;
1692 #endif
1693
1694         DEBUG("rlm_ldap: - authenticate");
1695
1696         /*
1697          * Ensure that we're being passed a plain-text password, and not
1698          * anything else.
1699          */
1700
1701         if (!request->username) {
1702                 radlog(L_AUTH, "rlm_ldap: Attribute \"User-Name\" is required for authentication.\n");
1703                 return RLM_MODULE_INVALID;
1704         }
1705
1706         if (!request->password){
1707                 radlog(L_AUTH, "rlm_ldap: Attribute \"User-Password\" is required for authentication.");
1708                 DEBUG2("  You seem to have set \"Auth-Type := LDAP\" somewhere.");
1709                 DEBUG2("  THAT CONFIGURATION IS WRONG.  DELETE IT.");
1710                 DEBUG2("  YOU ARE PREVENTING THE SERVER FROM WORKING PROPERLY.");
1711                 return RLM_MODULE_INVALID;
1712         }
1713
1714         if(request->password->attribute != PW_PASSWORD) {
1715                 radlog(L_AUTH, "rlm_ldap: Attribute \"User-Password\" is required for authentication. Cannot use \"%s\".", request->password->name);
1716                 return RLM_MODULE_INVALID;
1717         }
1718
1719         if (request->password->length == 0) {
1720                 snprintf(module_fmsg,sizeof(module_fmsg),"rlm_ldap: empty password supplied");
1721                 module_fmsg_vp = pairmake("Module-Failure-Message", module_fmsg, T_OP_EQ);
1722                 pairadd(&request->packet->vps, module_fmsg_vp);
1723                 return RLM_MODULE_INVALID;
1724         }
1725
1726         /*
1727          * Check that we don't have any failed connections. If we do there's no real need
1728          * of runing. Also give it another chance if we have a lot of failed connections.
1729          */
1730         if (inst->failed_conns > MAX_FAILED_CONNS_END)
1731                 inst->failed_conns = 0;
1732         if (inst->failed_conns > MAX_FAILED_CONNS_START){
1733                 inst->failed_conns++;
1734                 return RLM_MODULE_FAIL;
1735         }
1736
1737
1738         DEBUG("rlm_ldap: login attempt by \"%s\" with password \"%s\"",
1739                request->username->vp_strvalue, request->password->vp_strvalue);
1740
1741         while ((vp_user_dn = pairfind(request->config_items,
1742                                       PW_LDAP_USERDN)) == NULL) {
1743                 if (!radius_xlat(filter, sizeof(filter), inst->filter,
1744                                 request, NULL)) {
1745                         radlog (L_ERR, "rlm_ldap: unable to create filter.\n");
1746                         return RLM_MODULE_INVALID;
1747                 }
1748
1749                 if (!radius_xlat(basedn, sizeof(basedn), inst->basedn,
1750                                 request, NULL)) {
1751                         radlog (L_ERR, "rlm_ldap: unable to create basedn.\n");
1752                         return RLM_MODULE_INVALID;
1753                 }
1754
1755                 if ((conn_id = ldap_get_conn(inst->conns,&conn,inst)) == -1){
1756                         radlog(L_ERR, "rlm_ldap: All ldap connections are in use");
1757                         return RLM_MODULE_FAIL;
1758                 }
1759                 if ((res = perform_search(instance, conn, basedn, LDAP_SCOPE_SUBTREE, filter, attrs, &result)) != RLM_MODULE_OK) {
1760                         if (res == RLM_MODULE_NOTFOUND){
1761                                 snprintf(module_fmsg,sizeof(module_fmsg),"rlm_ldap: User not found");
1762                                 module_fmsg_vp = pairmake("Module-Failure-Message", module_fmsg, T_OP_EQ);
1763                                 pairadd(&request->packet->vps, module_fmsg_vp);
1764                         }
1765                         ldap_release_conn(conn_id,inst->conns);
1766                         return (res);
1767                 }
1768                 if ((msg = ldap_first_entry(conn->ld, result)) == NULL) {
1769                         ldap_msgfree(result);
1770                         ldap_release_conn(conn_id,inst->conns);
1771                         return RLM_MODULE_FAIL;
1772                 }
1773                 if ((user_dn = ldap_get_dn(conn->ld, msg)) == NULL) {
1774                         DEBUG("rlm_ldap: ldap_get_dn() failed");
1775                         ldap_msgfree(result);
1776                         ldap_release_conn(conn_id,inst->conns);
1777                         return RLM_MODULE_FAIL;
1778                 }
1779                 ldap_release_conn(conn_id,inst->conns);
1780                 pairadd(&request->config_items, pairmake("Ldap-UserDn", user_dn, T_OP_EQ));
1781                 ldap_memfree(user_dn);
1782                 ldap_msgfree(result);
1783         }
1784
1785         user_dn = vp_user_dn->vp_strvalue;
1786
1787         DEBUG("rlm_ldap: user DN: %s", user_dn);
1788
1789 #ifndef NOVELL
1790         ld_user = ldap_connect(instance, user_dn, request->password->vp_strvalue,
1791                                1, &res, NULL);
1792 #else
1793         
1794         ld_user = ldap_connect(instance, user_dn, request->password->vp_strvalue,
1795                         1, &res, &err);
1796
1797         if(err != NULL){
1798                 /* 'err' contains the LDAP connection error description */
1799                 DEBUG("rlm_ldap: %s", err);
1800                 pairadd(&request->reply->vps, pairmake("Reply-Message", err, T_OP_EQ));
1801                 ldap_memfree((void *)err);
1802         }
1803
1804         /* Don't perform eDirectory APC again after attempting to bind here. */
1805         {
1806                 int apc_attr;
1807                 DICT_ATTR *dattr;
1808                 VALUE_PAIR *vp_apc;
1809
1810                 dattr = dict_attrbyname("eDir-APC");
1811                 apc_attr = dattr->attr;
1812                 vp_apc = pairfind(request->config_items, apc_attr);
1813                 if(vp_apc && vp_apc->vp_strvalue[0] == '2')
1814                         vp_apc->vp_strvalue[0] = '3';
1815         }
1816 #endif
1817
1818         if (ld_user == NULL){
1819                 if (res == RLM_MODULE_REJECT){
1820                         inst->failed_conns = 0;
1821                         snprintf(module_fmsg,sizeof(module_fmsg),"rlm_ldap: Bind as user failed");
1822                         module_fmsg_vp = pairmake("Module-Failure-Message", module_fmsg, T_OP_EQ);
1823                         pairadd(&request->packet->vps, module_fmsg_vp);
1824                 }
1825                 if (res == RLM_MODULE_FAIL){
1826                         DEBUG("rlm_ldap: ldap_connect() failed");
1827                         inst->failed_conns++;
1828                 }
1829                 return (res);
1830         }
1831
1832         DEBUG("rlm_ldap: user %s authenticated succesfully",
1833               request->username->vp_strvalue);
1834         ldap_unbind_s(ld_user);
1835         inst->failed_conns = 0;
1836
1837         return RLM_MODULE_OK;
1838 }
1839
1840 #ifdef NOVELL
1841 /*****************************************************************************
1842  *
1843  *      Function: rlm_ldap_postauth
1844  *
1845  *      Purpose: Perform eDirectory account policy check and failed-login reporting
1846  *      to eDirectory.
1847  *
1848  *****************************************************************************/
1849 static int ldap_postauth(void *instance, REQUEST * request)
1850 {
1851         int res = RLM_MODULE_FAIL;
1852         int inst_attr, apc_attr;
1853         char password[UNIVERSAL_PASS_LEN];
1854         ldap_instance  *inst = instance;
1855         LDAP_CONN       *conn;
1856         VALUE_PAIR *vp_inst, *vp_apc;
1857         DICT_ATTR *dattr;
1858
1859         dattr = dict_attrbyname("LDAP-Instance");
1860         inst_attr = dattr->attr;
1861         dattr = dict_attrbyname("eDir-APC");
1862         apc_attr = dattr->attr;
1863
1864         vp_inst = pairfind(request->config_items, inst_attr);
1865
1866         /*
1867          * Check if the password in the config items list is the user's UP which has
1868          * been read in the authorize method of this instance of the LDAP module.
1869          */
1870         if((vp_inst == NULL) || strcmp(vp_inst->vp_strvalue, inst->xlat_name))
1871                 return RLM_MODULE_NOOP;
1872
1873         vp_apc = pairfind(request->config_items, apc_attr);
1874
1875         switch(vp_apc->vp_strvalue[0]){
1876                 case '1':
1877                         /* Account policy check not enabled */
1878                 case '3':
1879                         /* Account policy check has been completed */
1880                         res = RLM_MODULE_NOOP;
1881                         break;
1882                 case '2':
1883                         {
1884                                 int err, conn_id = -1;
1885                                 char *error_msg = NULL;
1886                                 VALUE_PAIR *vp_fdn, *vp_pwd;
1887                                 DICT_ATTR *da;
1888
1889                                 if (request->reply->code == PW_AUTHENTICATION_REJECT) {
1890                                   /* Bind to eDirectory as the RADIUS user with a wrong password. */
1891                                   vp_pwd = pairfind(request->config_items, PW_PASSWORD);
1892                                   strcpy(password, vp_pwd->vp_strvalue);
1893                                   if (strlen(password) > 0) {
1894                                           if (password[0] != 'a') {
1895                                                   password[0] = 'a';
1896                                           } else {
1897                                                   password[0] = 'b';
1898                                           }
1899                                   } else {
1900                                           strcpy(password, "dummy_password");
1901                                   }
1902                                   res = RLM_MODULE_REJECT;
1903                                 } else {
1904                                         /* Bind to eDirectory as the RADIUS user using the user's UP */
1905                                         vp_pwd = pairfind(request->config_items, PW_PASSWORD);
1906                                         if (vp_pwd == NULL) {
1907                                                 DEBUG("rlm_ldap: User's Universal Password not in config items list.");
1908                                                 return RLM_MODULE_FAIL;
1909                                         }
1910                                         strcpy(password, vp_pwd->vp_strvalue);
1911                                 }
1912
1913                                 if ((da = dict_attrbyname("Ldap-UserDn")) == NULL) {
1914                                         DEBUG("rlm_ldap: Attribute for user FDN not found in dictionary. Unable to proceed");
1915                                         return RLM_MODULE_FAIL;
1916                                 }
1917                                 
1918                                 vp_fdn = pairfind(request->packet->vps, da->attr);
1919                                 if (vp_fdn == NULL) {
1920                                         DEBUG("rlm_ldap: User's FQDN not in config items list.");
1921                                         return RLM_MODULE_FAIL;
1922                                 }
1923                                 
1924                                 if ((conn_id = ldap_get_conn(inst->apc_conns, &conn, inst)) == -1){
1925                                         radlog(L_ERR, "rlm_ldap: All ldap connections are in use");
1926                                         return RLM_MODULE_FAIL;
1927                                 }
1928
1929                                 /*
1930                                  *      If there is an existing LDAP
1931                                  *      connection to the directory,
1932                                  *      bind over it. Otherwise,
1933                                  *      establish a new connection.
1934                                  */
1935                         postauth_reconnect:
1936                                 if (!conn->bound || conn->ld == NULL) {
1937                                         DEBUG2("rlm_ldap: attempting LDAP reconnection");
1938                                         if (conn->ld){
1939                                                 DEBUG2("rlm_ldap: closing existing LDAP connection");
1940                                                 ldap_unbind_s(conn->ld);
1941                                         }
1942                                         if ((conn->ld = ldap_connect(instance, (char *)vp_fdn->vp_strvalue, password, 0, &res, &error_msg)) == NULL) {
1943                                                 radlog(L_ERR, "rlm_ldap: eDirectory account policy check failed.");
1944                                                 
1945                                                 if (error_msg != NULL) {
1946                                                         DEBUG("rlm_ldap: %s", error_msg);
1947                                                         pairadd(&request->reply->vps, pairmake("Reply-Message", error_msg, T_OP_EQ));
1948                                                         ldap_memfree((void *)error_msg);
1949                                                 }
1950                                                 
1951                                                 vp_apc->vp_strvalue[0] = '3';
1952                                                 ldap_release_conn(conn_id, inst->apc_conns);
1953                                                 return RLM_MODULE_REJECT;
1954                                         }
1955                                         conn->bound = 1;
1956                                 } else if((err = ldap_simple_bind_s(conn->ld, (char *)vp_fdn->vp_strvalue, password)) != LDAP_SUCCESS) {
1957                                         if (err == LDAP_SERVER_DOWN) {
1958                                                 conn->bound = 0;
1959                                                 goto postauth_reconnect;
1960                                         }
1961                                         DEBUG("rlm_ldap: eDirectory account policy check failed.");
1962                                         ldap_get_option(conn->ld, LDAP_OPT_ERROR_STRING, &error_msg);
1963                                         if (error_msg != NULL) {
1964                                                 DEBUG("rlm_ldap: %s", error_msg);
1965                                                 pairadd(&request->reply->vps, pairmake("Reply-Message", error_msg, T_OP_EQ));
1966                                                 ldap_memfree((void *)error_msg);
1967                                         }
1968                                         vp_apc->vp_strvalue[0] = '3';
1969                                         ldap_release_conn(conn_id, inst->apc_conns);
1970                                         return RLM_MODULE_REJECT;
1971                                 }
1972                                 vp_apc->vp_strvalue[0] = '3';
1973                                 ldap_release_conn(conn_id, inst->apc_conns);
1974                                 return RLM_MODULE_OK;
1975                         }
1976         }
1977         return res;
1978 }
1979 #endif
1980
1981 static LDAP *ldap_connect(void *instance, const char *dn, const char *password,
1982                           int auth, int *result, char **err)
1983 {
1984         ldap_instance  *inst = instance;
1985         LDAP           *ld = NULL;
1986         int             msgid, rc, ldap_version;
1987         int             ldap_errno = 0;
1988         LDAPMessage    *res;
1989
1990         if (inst->is_url){
1991 #ifdef HAVE_LDAP_INITIALIZE
1992                 DEBUG("rlm_ldap: (re)connect to %s, authentication %d", inst->server, auth);
1993                 if (ldap_initialize(&ld, inst->server) != LDAP_SUCCESS) {
1994                         radlog(L_ERR, "rlm_ldap: ldap_initialize() failed");
1995                         *result = RLM_MODULE_FAIL;
1996                         return (NULL);
1997                 }
1998 #endif
1999         } else {
2000                 DEBUG("rlm_ldap: (re)connect to %s:%d, authentication %d", inst->server, inst->port, auth);
2001                 if ((ld = ldap_init(inst->server, inst->port)) == NULL) {
2002                         radlog(L_ERR, "rlm_ldap: ldap_init() failed");
2003                         *result = RLM_MODULE_FAIL;
2004                         return (NULL);
2005                 }
2006         }
2007         if (ldap_set_option(ld, LDAP_OPT_NETWORK_TIMEOUT,
2008                             (void *) &(inst->net_timeout)) != LDAP_OPT_SUCCESS) {
2009                 radlog(L_ERR, "rlm_ldap: Could not set LDAP_OPT_NETWORK_TIMEOUT %ld.%ld", inst->net_timeout.tv_sec, inst->net_timeout.tv_usec);
2010         }
2011
2012         if (ldap_set_option(ld, LDAP_OPT_TIMELIMIT,
2013                             (void *) &(inst->timelimit)) != LDAP_OPT_SUCCESS) {
2014                 radlog(L_ERR, "rlm_ldap: Could not set LDAP_OPT_TIMELIMIT %d", inst->timelimit);
2015         }
2016
2017         if (inst->ldap_debug && ldap_set_option(NULL, LDAP_OPT_DEBUG_LEVEL, &(inst->ldap_debug)) != LDAP_OPT_SUCCESS) {
2018                 radlog(L_ERR, "rlm_ldap: Could not set LDAP_OPT_DEBUG_LEVEL %d", inst->ldap_debug);
2019         }
2020
2021         ldap_version = LDAP_VERSION3;
2022         if (ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION,
2023                             &ldap_version) != LDAP_OPT_SUCCESS) {
2024                 radlog(L_ERR, "rlm_ldap: Could not set LDAP version to V3");
2025         }
2026
2027 #ifdef HAVE_LDAP_START_TLS
2028         if (inst->tls_mode) {
2029                 DEBUG("rlm_ldap: setting TLS mode to %d", inst->tls_mode);
2030                 if (ldap_set_option(ld, LDAP_OPT_X_TLS,
2031                                     (void *) &(inst->tls_mode)) != LDAP_OPT_SUCCESS) {
2032                         ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &ldap_errno);
2033                         radlog(L_ERR, "rlm_ldap: could not set LDAP_OPT_X_TLS option %s", ldap_err2string(ldap_errno));
2034                 }
2035         }
2036
2037         if (inst->tls_cacertfile != NULL) {
2038                 DEBUG("rlm_ldap: setting TLS CACert File to %s", inst->tls_cacertfile);
2039
2040                 if ( ldap_set_option( NULL, LDAP_OPT_X_TLS_CACERTFILE,
2041                                       (void *) inst->tls_cacertfile )
2042                      != LDAP_OPT_SUCCESS) {
2043                         radlog(L_ERR, "rlm_ldap: could not set "
2044                                "LDAP_OPT_X_TLS_CACERTFILE option to %s", inst->tls_cacertfile);
2045                 }
2046         }
2047         
2048         if (inst->tls_cacertdir != NULL) {
2049                 DEBUG("rlm_ldap: setting TLS CACert File to %s", inst->tls_cacertdir);
2050                 
2051                 if ( ldap_set_option( NULL, LDAP_OPT_X_TLS_CACERTDIR,
2052                                       (void *) inst->tls_cacertdir )
2053                      != LDAP_OPT_SUCCESS) {
2054                         radlog(L_ERR, "rlm_ldap: could not set "
2055                                "LDAP_OPT_X_TLS_CACERTDIR option to %s", inst->tls_cacertdir);
2056                 }
2057         }
2058
2059         if (strcmp(TLS_DEFAULT_VERIFY, inst->tls_require_cert ) != 0 ) {
2060                 DEBUG("rlm_ldap: setting TLS Require Cert to %s",
2061                       inst->tls_require_cert);
2062         }
2063
2064
2065 #ifdef HAVE_LDAP_INT_TLS_CONFIG
2066         if (ldap_int_tls_config(NULL, LDAP_OPT_X_TLS_REQUIRE_CERT,
2067                                 (inst->tls_require_cert)) != LDAP_OPT_SUCCESS) {
2068                 radlog(L_ERR, "rlm_ldap: could not set "
2069                        "LDAP_OPT_X_TLS_REQUIRE_CERT option to %s",
2070                        inst->tls_require_cert);
2071         }
2072 #endif
2073
2074         if (inst->tls_certfile != NULL) {
2075                 DEBUG("rlm_ldap: setting TLS Cert File to %s", inst->tls_certfile);
2076
2077                 if (ldap_set_option(NULL, LDAP_OPT_X_TLS_CERTFILE,
2078                                     (void *) inst->tls_certfile)
2079                     != LDAP_OPT_SUCCESS) {
2080                         radlog(L_ERR, "rlm_ldap: could not set "
2081                                "LDAP_OPT_X_TLS_CERTFILE option to %s",
2082                                inst->tls_certfile);
2083                 }
2084         }
2085         
2086         if (inst->tls_keyfile != NULL) {
2087                 DEBUG("rlm_ldap: setting TLS Key File to %s",
2088                       inst->tls_keyfile);
2089                 
2090                 if ( ldap_set_option( NULL, LDAP_OPT_X_TLS_KEYFILE,
2091                                       (void *) inst->tls_keyfile )
2092                      != LDAP_OPT_SUCCESS) {
2093                         radlog(L_ERR, "rlm_ldap: could not set "
2094                                "LDAP_OPT_X_TLS_KEYFILE option to %s",
2095                                inst->tls_keyfile);
2096                 }
2097         }
2098         
2099         if (inst->tls_randfile != NULL) {
2100                 DEBUG("rlm_ldap: setting TLS Key File to %s",
2101                       inst->tls_randfile);
2102                 
2103                 if (ldap_set_option(NULL, LDAP_OPT_X_TLS_RANDOM_FILE,
2104                                     (void *) inst->tls_randfile)
2105                     != LDAP_OPT_SUCCESS) {
2106                         radlog(L_ERR, "rlm_ldap: could not set "
2107                                "LDAP_OPT_X_TLS_RANDOM_FILE option to %s",
2108                                inst->tls_randfile);
2109                 }
2110         }
2111
2112         if (inst->start_tls) {
2113                 DEBUG("rlm_ldap: starting TLS");
2114                 rc = ldap_start_tls_s(ld, NULL, NULL);
2115                 if (rc != LDAP_SUCCESS) {
2116                         DEBUG("rlm_ldap: ldap_start_tls_s()");
2117                         ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER,
2118                                         &ldap_errno);
2119                         radlog(L_ERR, "rlm_ldap: could not start TLS %s",
2120                                ldap_err2string(ldap_errno));
2121                         *result = RLM_MODULE_FAIL;
2122                         ldap_unbind_s(ld);
2123                         return (NULL);
2124                 }
2125         }
2126 #endif /* HAVE_LDAP_START_TLS */
2127
2128         if (inst->is_url){
2129                 DEBUG("rlm_ldap: bind as %s/%s to %s",
2130                       dn, password, inst->server);
2131         } else {
2132                 DEBUG("rlm_ldap: bind as %s/%s to %s:%d",
2133                       dn, password, inst->server, inst->port);
2134         }
2135
2136         msgid = ldap_bind(ld, dn, password,LDAP_AUTH_SIMPLE);
2137         if (msgid == -1) {
2138                 ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &ldap_errno);
2139                 if(err != NULL){
2140                         ldap_get_option(ld, LDAP_OPT_ERROR_STRING, err);
2141                 }
2142                 if (inst->is_url) {
2143                         radlog(L_ERR, "rlm_ldap: %s bind to %s failed: %s",
2144                                 dn, inst->server, ldap_err2string(ldap_errno));
2145                 } else {
2146                         radlog(L_ERR, "rlm_ldap: %s bind to %s:%d failed: %s",
2147                                 dn, inst->server, inst->port,
2148                                 ldap_err2string(ldap_errno));
2149                 }
2150                 *result = RLM_MODULE_FAIL;
2151                 ldap_unbind_s(ld);
2152                 return (NULL);
2153         }
2154         DEBUG("rlm_ldap: waiting for bind result ...");
2155
2156         rc = ldap_result(ld, msgid, 1, &(inst->timeout), &res);
2157
2158         if (rc < 1) {
2159                 DEBUG("rlm_ldap: ldap_result()");
2160                 ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &ldap_errno);
2161                 if(err != NULL){
2162                         ldap_get_option(ld, LDAP_OPT_ERROR_STRING, err);
2163                 }
2164                 if (inst->is_url) {
2165                         radlog(L_ERR, "rlm_ldap: %s bind to %s failed: %s",
2166                                 dn, inst->server, (rc == 0) ? "timeout" : ldap_err2string(ldap_errno));
2167                 } else {
2168                         radlog(L_ERR, "rlm_ldap: %s bind to %s:%d failed: %s",
2169                                dn, inst->server, inst->port,
2170                                 (rc == 0) ? "timeout" : ldap_err2string(ldap_errno));
2171                 }
2172                 *result = RLM_MODULE_FAIL;
2173                 ldap_unbind_s(ld);
2174                 return (NULL);
2175         }
2176
2177         ldap_errno = ldap_result2error(ld, res, 1);
2178         switch (ldap_errno) {
2179         case LDAP_SUCCESS:
2180                 DEBUG("rlm_ldap: Bind was successful");
2181                 *result = RLM_MODULE_OK;
2182                 break;
2183
2184         case LDAP_INVALID_CREDENTIALS:
2185                 if (auth){
2186                         DEBUG("rlm_ldap: Bind failed with invalid credentials");
2187                         *result = RLM_MODULE_REJECT;
2188                 } else {
2189                         radlog(L_ERR, "rlm_ldap: LDAP login failed: check identity, password settings in ldap section of radiusd.conf");
2190                         *result = RLM_MODULE_FAIL;
2191                 }
2192                 if(err != NULL){
2193                         ldap_get_option(ld, LDAP_OPT_ERROR_STRING, err);
2194                 }
2195                 break;
2196
2197         default:
2198                 if (inst->is_url) {
2199                         radlog(L_ERR,"rlm_ldap: %s bind to %s failed %s",
2200                                 dn, inst->server, ldap_err2string(ldap_errno));
2201                 } else {
2202                         radlog(L_ERR,"rlm_ldap: %s bind to %s:%d failed %s",
2203                                 dn, inst->server, inst->port,
2204                                 ldap_err2string(ldap_errno));
2205                 }
2206                 *result = RLM_MODULE_FAIL;
2207                 if(err != NULL){
2208                         ldap_get_option(ld, LDAP_OPT_ERROR_STRING, err);
2209                 }
2210         }
2211
2212         if (*result != RLM_MODULE_OK) {
2213                 ldap_unbind_s(ld);
2214                 ld = NULL;
2215         }
2216         return ld;
2217 }
2218
2219 /*****************************************************************************
2220  *
2221  *      Detach from the LDAP server and cleanup internal state.
2222  *
2223  *****************************************************************************/
2224 static int
2225 ldap_detach(void *instance)
2226 {
2227         ldap_instance  *inst = instance;
2228         TLDAP_RADIUS *pair, *nextpair;
2229
2230         if (inst->server)
2231                 free((char *) inst->server);
2232         if (inst->login)
2233                 free((char *) inst->login);
2234         if (inst->password)
2235                 free((char *) inst->password);
2236         if (inst->basedn)
2237                 free((char *) inst->basedn);
2238         if (inst->dictionary_mapping)
2239                 free(inst->dictionary_mapping);
2240         if (inst->filter)
2241                 free((char *) inst->filter);
2242         if (inst->base_filter)
2243                 free((char *) inst->base_filter);
2244         if (inst->passwd_hdr)
2245                 free((char *) inst->passwd_hdr);
2246         if (inst->passwd_attr)
2247                 free((char *) inst->passwd_attr);
2248         if (inst->groupname_attr)
2249                 free((char *) inst->groupname_attr);
2250         if (inst->groupmemb_filt)
2251                 free((char *) inst->groupmemb_filt);
2252         if (inst->groupmemb_attr)
2253                 free((char *) inst->groupmemb_attr);
2254         if (inst->access_attr)
2255                 free((char *) inst->access_attr);
2256         if (inst->profile_attr)
2257                 free((char *) inst->profile_attr);
2258
2259         if (inst->conns) {
2260                 int i;
2261                 
2262                 for (i = 0;i < inst->num_conns; i++) {
2263                         if (inst->conns[i].ld){
2264                                 ldap_unbind_s(inst->conns[i].ld);
2265                         }
2266                         pthread_mutex_destroy(&inst->conns[i].mutex);
2267                 }
2268                 free(inst->conns);
2269         }
2270
2271 #ifdef NOVELL
2272         if (inst->apc_conns){ 
2273                 int i;
2274
2275                 for (i = 0; i < inst->num_conns; i++) {
2276                         if (inst->apc_conns[i].ld){
2277                                 ldap_unbind_s(inst->apc_conns[i].ld);
2278                         }
2279                         pthread_mutex_destroy(&inst->apc_conns[i].mutex);
2280                 }
2281                 free(inst->apc_conns);
2282         }
2283 #endif
2284
2285         pair = inst->check_item_map;
2286
2287         while (pair != NULL) {
2288                 nextpair = pair->next;
2289                 free(pair->attr);
2290                 free(pair->radius_attr);
2291                 free(pair);
2292                 pair = nextpair;
2293         }
2294
2295         pair = inst->reply_item_map;
2296
2297         while (pair != NULL) {
2298                 nextpair = pair->next;
2299                 free(pair->attr);
2300                 free(pair->radius_attr);
2301                 free(pair);
2302                 pair = nextpair;
2303         }
2304
2305         if (inst->atts)
2306                 free(inst->atts);
2307
2308         paircompare_unregister(PW_LDAP_GROUP, ldap_groupcmp);
2309         xlat_unregister(inst->xlat_name,ldap_xlat);
2310         free(inst->xlat_name);
2311
2312         free(inst);
2313
2314         return 0;
2315 }
2316
2317
2318 #ifdef FIELDCPY
2319 static void
2320 fieldcpy(char *string, char **uptr)
2321 {
2322         char           *ptr;
2323
2324         ptr = *uptr;
2325         while (*ptr == ' ' || *ptr == '\t') {
2326                 ptr++;
2327         }
2328         if (*ptr == '"') {
2329                 ptr++;
2330                 while (*ptr != '"' && *ptr != '\0' && *ptr != '\n') {
2331                         *string++ = *ptr++;
2332                 }
2333                 *string = '\0';
2334                 if (*ptr == '"') {
2335                         ptr++;
2336                 }
2337                 *uptr = ptr;
2338                 return;
2339         }
2340         while (*ptr != ' ' && *ptr != '\t' && *ptr != '\0' && *ptr != '\n' &&
2341                *ptr != '=' && *ptr != ',') {
2342                 *string++ = *ptr++;
2343         }
2344         *string = '\0';
2345         *uptr = ptr;
2346         return;
2347 }
2348 #endif
2349
2350 /*
2351  *      Copied from src/lib/token.c
2352  */
2353 static const LRAD_NAME_NUMBER tokens[] = {
2354         { "=~", T_OP_REG_EQ,    }, /* order is important! */
2355         { "!~", T_OP_REG_NE,    },
2356         { "{",  T_LCBRACE,      },
2357         { "}",  T_RCBRACE,      },
2358         { "(",  T_LBRACE,       },
2359         { ")",  T_RBRACE,       },
2360         { ",",  T_COMMA,        },
2361         { "+=", T_OP_ADD,       },
2362         { "-=", T_OP_SUB,       },
2363         { ":=", T_OP_SET,       },
2364         { "=*", T_OP_CMP_TRUE,  },
2365         { "!*", T_OP_CMP_FALSE, },
2366         { "==", T_OP_CMP_EQ,    },
2367         { "=",  T_OP_EQ,        },
2368         { "!=", T_OP_NE,        },
2369         { ">=", T_OP_GE,        },
2370         { ">",  T_OP_GT,        },
2371         { "<=", T_OP_LE,        },
2372         { "<",  T_OP_LT,        },
2373         { NULL, 0}
2374 };
2375
2376 /*****************************************************************************
2377  *      Get RADIUS attributes from LDAP object
2378  *      ( according to draft-adoba-radius-05.txt
2379  *        <http://www.ietf.org/internet-drafts/draft-adoba-radius-05.txt> )
2380  *
2381  *****************************************************************************/
2382 static VALUE_PAIR *ldap_pairget(LDAP *ld, LDAPMessage *entry,
2383                                 TLDAP_RADIUS *item_map,
2384                                 VALUE_PAIR **pairs, int is_check)
2385 {
2386         char          **vals;
2387         int             vals_count;
2388         int             vals_idx;
2389         char           *ptr;
2390         char           *value;
2391         TLDAP_RADIUS   *element;
2392         LRAD_TOKEN      token, operator;
2393         int             is_generic_attribute;
2394         char            buf[MAX_STRING_LEN];
2395         VALUE_PAIR     *pairlist = NULL;
2396         VALUE_PAIR     *newpair = NULL;
2397         char            do_xlat = FALSE;
2398
2399         /*
2400          *      check if there is a mapping from this LDAP attribute
2401          *      to a RADIUS attribute
2402          */
2403         for (element = item_map; element != NULL; element = element->next) {
2404                 /*
2405                  *      No mapping, skip it.
2406                  */
2407                 if ((vals = ldap_get_values(ld,entry,element->attr)) == NULL)
2408                         continue;
2409
2410                 /*
2411                  *      Check whether this is a one-to-one-mapped ldap
2412                  *      attribute or a generic attribute and set flag
2413                  *      accordingly.
2414                  */
2415                 if (strcasecmp(element->radius_attr, GENERIC_ATTRIBUTE_ID)==0)
2416                         is_generic_attribute = 1;
2417                 else
2418                         is_generic_attribute = 0;
2419
2420                 /*
2421                  *      Find out how many values there are for the
2422                  *      attribute and extract all of them.
2423                  */
2424                 vals_count = ldap_count_values(vals);
2425
2426                 for (vals_idx = 0; vals_idx < vals_count; vals_idx++) {
2427                         value = vals[vals_idx];
2428
2429                         if (is_generic_attribute) {
2430                                 /*
2431                                  *      This is a generic attribute.
2432                                  */
2433                                 LRAD_TOKEN dummy; /* makes pairread happy */
2434
2435                                 /* not sure if using pairread here is ok ... */
2436                                 if ( (newpair = pairread(&value, &dummy)) != NULL) {
2437                                         DEBUG("rlm_ldap: extracted attribute %s from generic item %s",
2438                                               newpair->name, vals[vals_idx]);
2439                                         pairadd(&pairlist, newpair);
2440                                 } else {
2441                                         radlog(L_ERR, "rlm_ldap: parsing %s failed: %s",
2442                                                element->attr, vals[vals_idx]);
2443                                 }
2444                         } else {
2445                                 /*
2446                                  *      This is a one-to-one-mapped attribute
2447                                  */
2448                                 ptr = value;
2449                                 operator = gettoken(&ptr, buf, sizeof(buf));
2450                                 if (operator < T_EQSTART || operator > T_EQEND) {
2451                                         /* no leading operator found */
2452                                         if (element->operator != T_OP_INVALID)
2453                                                 operator = element->operator;
2454                                         else if (is_check)
2455                                                 operator = T_OP_CMP_EQ;
2456                                         else
2457                                                 operator = T_OP_EQ;
2458                                 } else {
2459                                         /* the value is after the operator */
2460                                         value = ptr;
2461                                 }
2462
2463                                 /*
2464                                  *      Do xlat if the *entire* string
2465                                  *      is quoted.
2466                                  */
2467                                 if ((value[0] == '\'' || value[0] == '"' ||
2468                                      value[0] == '`') &&
2469                                     (value[0] == value[strlen(value)-1])) {
2470                                         ptr = value;
2471                                         token = gettoken(&ptr, buf, sizeof(buf));
2472                                         switch (token) {
2473                                         /* take the unquoted string */
2474                                         case T_SINGLE_QUOTED_STRING:
2475                                         case T_DOUBLE_QUOTED_STRING:
2476                                                 value = buf;
2477                                                 break;
2478
2479                                         /* the value will be xlat'ed later */
2480                                         case T_BACK_QUOTED_STRING:
2481                                                 value = NULL;
2482                                                 do_xlat = TRUE;
2483                                                 break;
2484
2485                                         /* keep the original string */
2486                                         default:
2487                                                 break;
2488                                         }
2489                                 }
2490                                 if (value[0] == '\0') {
2491                                         DEBUG("rlm_ldap: Attribute %s has no value", element->attr);
2492                                         continue;
2493                                 }
2494
2495                                 DEBUG("rlm_ldap: Adding LDAP attribute %s as RADIUS attribute %s %s %s",
2496                                       element->attr, element->radius_attr,
2497                                       lrad_int2str(tokens, operator, "?"),
2498                                       value);
2499
2500                                 /*
2501                                  *      Create the pair.
2502                                  */
2503                                 newpair = pairmake(element->radius_attr,
2504                                                    value, operator);
2505                                 if (newpair == NULL) {
2506                                         radlog(L_ERR, "rlm_ldap: Failed to create the pair: %s", librad_errstr);
2507                                         continue;
2508                                 }
2509                                 if (do_xlat) {
2510                                         newpair->flags.do_xlat = 1;
2511                                         strNcpy(newpair->vp_strvalue, buf,
2512                                                 sizeof(newpair->vp_strvalue));
2513                                         newpair->length = 0;
2514                                 }
2515
2516                                 /*
2517                                  *      Add the pair into the packet.
2518                                  */
2519                                 if (!vals_idx){
2520                                         pairdelete(pairs, newpair->attribute);
2521                                 }
2522                                 pairadd(&pairlist, newpair);
2523                         }
2524                 }
2525                 ldap_value_free(vals);
2526         }
2527
2528         return (pairlist);
2529 }
2530
2531 /* globally exported name */
2532 module_t rlm_ldap = {
2533         RLM_MODULE_INIT,
2534         "LDAP",
2535         RLM_TYPE_THREAD_SAFE,   /* type: reserved        */
2536         ldap_instantiate,       /* instantiation         */
2537         ldap_detach,            /* detach                */
2538         {
2539                 ldap_authenticate,      /* authentication        */
2540                 ldap_authorize,         /* authorization         */
2541                 NULL,                   /* preaccounting         */
2542                 NULL,                   /* accounting            */
2543                 NULL,                   /* checksimul            */
2544                 NULL,                   /* pre-proxy             */
2545                 NULL,                   /* post-proxy            */
2546 #ifdef NOVELL
2547                 ldap_postauth           /* post-auth             */
2548 #else
2549                 NULL
2550 #endif
2551         },
2552 };