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