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