Add more LDAP escaping rules from RFC 2253
[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 (((len == 0) &&
852                     ((in[0] == ' ') || (in[0] == '#'))) ||
853                     (strchr(",+\"\\<>;*=()", *in))) {
854                         static const char hex[] = "0123456789abcdef";
855
856                         /*
857                          *      Only 3 or less bytes available.
858                          */
859                         if (outlen <= 3) {
860                                 break;
861                         }
862
863                         *(out++) = '\\';
864                         *(out++) = hex[((*in) >> 4) & 0x0f];
865                         *(out++) = hex[(*in) & 0x0f];
866                         outlen -= 3;
867                         len += 3;
868                         in++;
869                         continue;
870                 }
871
872                 /*
873                  *      Only one byte left.
874                  */
875                 if (outlen <= 1) {
876                         break;
877                 }
878
879                 /*
880                  *      Allowed character.
881                  */
882                 *(out++) = *(in++);
883                 outlen--;
884                 len++;
885         }
886         *out = '\0';
887         return len;
888 }
889
890 /*
891  * ldap_groupcmp(). Implement the Ldap-Group == "group" filter
892  */
893
894 static int ldap_groupcmp(void *instance, REQUEST *req, VALUE_PAIR *request, VALUE_PAIR *check,
895                 VALUE_PAIR *check_pairs, VALUE_PAIR **reply_pairs)
896 {
897         char            filter[MAX_FILTER_STR_LEN];
898         char            gr_filter[MAX_FILTER_STR_LEN];
899         int             res;
900         LDAPMessage     *result = NULL;
901         LDAPMessage     *msg = NULL;
902         char            basedn[MAX_FILTER_STR_LEN];
903         char            *attrs[] = {"dn",NULL};
904         char            **vals;
905         ldap_instance   *inst = instance;
906         char            *group_attrs[] = {inst->groupmemb_attr,NULL};
907         LDAP_CONN       *conn;
908         int             conn_id = -1;
909         VALUE_PAIR      *vp_user_dn;
910         VALUE_PAIR      **request_pairs;
911
912         request_pairs = &req->packet->vps;
913
914         DEBUG("rlm_ldap: Entering ldap_groupcmp()");
915
916         if (check->strvalue == NULL || check->length == 0){
917                 DEBUG("rlm_ldap::ldap_groupcmp: Illegal group name");
918                 return 1;
919         }
920
921         if (req == NULL){
922                 DEBUG("rlm_ldap::ldap_groupcmp: NULL request");
923                 return 1;
924         }
925
926         if (!radius_xlat(basedn, sizeof(basedn), inst->basedn, req, ldap_escape_func)) {
927                 DEBUG("rlm_ldap::ldap_groupcmp: unable to create basedn.");
928                 return 1;
929         }
930
931         while((vp_user_dn = pairfind(*request_pairs, PW_LDAP_USERDN)) == NULL){
932                 char            *user_dn = NULL;
933
934                 if (!radius_xlat(filter, sizeof(filter), inst->filter,
935                                         req, ldap_escape_func)){
936                         DEBUG("rlm_ldap::ldap_groupcmp: unable to create filter");
937                         return 1;
938                 }
939                 if ((conn_id = ldap_get_conn(inst->conns,&conn,inst)) == -1){
940                         radlog(L_ERR, "rlm_ldap: All ldap connections are in use");
941                         return 1;
942                 }
943                 if ((res = perform_search(inst, conn, basedn, LDAP_SCOPE_SUBTREE,
944                                         filter, attrs, &result)) != RLM_MODULE_OK){
945                         DEBUG("rlm_ldap::ldap_groupcmp: search failed");
946                         ldap_release_conn(conn_id,inst->conns);
947                         return 1;
948                 }
949                 if ((msg = ldap_first_entry(conn->ld, result)) == NULL) {
950                         DEBUG("rlm_ldap::ldap_groupcmp: ldap_first_entry() failed");
951                         ldap_release_conn(conn_id,inst->conns);
952                         ldap_msgfree(result);
953                         return 1;
954                 }
955                 if ((user_dn = ldap_get_dn(conn->ld, msg)) == NULL) {
956                         DEBUG("rlm_ldap:ldap_groupcmp:: ldap_get_dn() failed");
957                         ldap_release_conn(conn_id,inst->conns);
958                         ldap_msgfree(result);
959                         return 1;
960                 }
961                 ldap_release_conn(conn_id,inst->conns);
962                 /*
963                 * Adding new attribute containing DN for LDAP object associated with
964                 * given username
965                 */
966                 pairadd(request_pairs, pairmake("Ldap-UserDn", user_dn, T_OP_EQ));
967                 ldap_memfree(user_dn);
968                 ldap_msgfree(result);
969         }
970
971         if(!radius_xlat(gr_filter, sizeof(gr_filter), inst->groupmemb_filt, req, ldap_escape_func)){
972                 DEBUG("rlm_ldap::ldap_groupcmp: unable to create filter.");
973                 return 1;
974         }
975
976         if (strchr((char *)check->strvalue,',') != NULL) {
977                 /* This looks like a DN */
978                 snprintf(filter,sizeof(filter), "%s",gr_filter);
979                 snprintf(basedn,sizeof(basedn), "%s",(char *)check->strvalue);
980         } else
981                 snprintf(filter,sizeof(filter), "(&(%s=%s)%s)",inst->groupname_attr,(char *)check->strvalue,gr_filter);
982
983         if ((conn_id = ldap_get_conn(inst->conns,&conn,inst)) == -1){
984                 radlog(L_ERR, "rlm_ldap: All ldap connections are in use");
985                 return 1;
986         }
987
988         if ((res = perform_search(inst, conn, basedn, LDAP_SCOPE_SUBTREE,
989                                 filter, attrs, &result)) == RLM_MODULE_OK){
990                 DEBUG("rlm_ldap::ldap_groupcmp: User found in group %s",
991                                 (char *)check->strvalue);
992                 ldap_msgfree(result);
993                 ldap_release_conn(conn_id,inst->conns);
994                 return 0;
995         }
996
997         ldap_release_conn(conn_id,inst->conns);
998
999         if (res != RLM_MODULE_NOTFOUND ) {
1000                 DEBUG("rlm_ldap::ldap_groupcmp: Search returned error");
1001                 return 1;
1002         }
1003
1004         if (inst->groupmemb_attr == NULL){
1005                 /* search returned NOTFOUND and searching for membership
1006                  * using user object attributes is not specified in config
1007                  * file
1008                  */
1009                 DEBUG("rlm_ldap::ldap_groupcmp: Group %s not found or user is not a member.",(char *)check->strvalue);
1010                 return 1;
1011         }
1012
1013         snprintf(filter,sizeof(filter), "(objectclass=*)");
1014         if ((conn_id = ldap_get_conn(inst->conns,&conn,inst)) == -1){
1015                 radlog(L_ERR, "rlm_ldap: Add ldap connections are in use");
1016                 return 1;
1017         }
1018         if ((res = perform_search(inst, conn, vp_user_dn->strvalue, LDAP_SCOPE_BASE,
1019                                         filter, group_attrs,&result)) != RLM_MODULE_OK){
1020                 DEBUG("rlm_ldap::ldap_groupcmp: Search returned error");
1021                 ldap_release_conn(conn_id, inst->conns);
1022                 return 1;
1023         }
1024
1025         if ((msg = ldap_first_entry(conn->ld, result)) == NULL) {
1026                 DEBUG("rlm_ldap::ldap_groupcmp: ldap_first_entry() failed");
1027                 ldap_release_conn(conn_id,inst->conns);
1028                 ldap_msgfree(result);
1029                 return 1;
1030         }
1031         if ((vals = ldap_get_values(conn->ld, msg, inst->groupmemb_attr)) != NULL) {
1032                 unsigned int i = 0;
1033                 char found = 0;
1034                 for (;i < ldap_count_values(vals);i++){
1035                         if (strchr(vals[i],',') != NULL){
1036                                 /* This looks like a DN */
1037                                 LDAPMessage *gr_result = NULL;
1038                                 snprintf(filter,sizeof(filter), "(%s=%s)",
1039                                         inst->groupname_attr,
1040                                         (char *)check->strvalue);
1041                                 if ((res = perform_search(inst, conn, vals[i],
1042                                                 LDAP_SCOPE_BASE, filter,
1043                                                 attrs, &gr_result)) != RLM_MODULE_OK){
1044                                         if (res != RLM_MODULE_NOTFOUND){
1045                                                 DEBUG("rlm_ldap::ldap_groupcmp: \
1046                                                         Search returned error");
1047                                                 ldap_value_free(vals);
1048                                                 ldap_msgfree(result);
1049                                                 ldap_release_conn(conn_id,inst->conns);
1050                                                 return 1;
1051                                         }
1052                                 } else {
1053                                         ldap_msgfree(gr_result);
1054                                         found = 1;
1055                                         break;
1056                                 }
1057                         } else {
1058                                 if (strcmp(vals[i],(char *)check->strvalue) == 0){
1059                                         found = 1;
1060                                         break;
1061                                 }
1062                         }
1063                 }
1064                 ldap_value_free(vals);
1065                 ldap_msgfree(result);
1066                 if (found == 0){
1067                         DEBUG("rlm_ldap::groupcmp: Group %s not found \
1068                                 or user not a member",
1069                                 (char *)check->strvalue);
1070                         ldap_release_conn(conn_id,inst->conns);
1071                         return 1;
1072                 }
1073         } else {
1074                         DEBUG("rlm_ldap::ldap_groupcmp: ldap_get_values() failed");
1075                         ldap_msgfree(result);
1076                         ldap_release_conn(conn_id,inst->conns);
1077                         return 1;
1078         }
1079
1080         DEBUG("rlm_ldap::ldap_groupcmp: User found in group %s",(char *)check->strvalue);
1081         ldap_release_conn(conn_id,inst->conns);
1082
1083         return 0;
1084 }
1085
1086 /*
1087  * ldap_xlat()
1088  * Do an xlat on an LDAP URL
1089  */
1090
1091 static int ldap_xlat(void *instance, REQUEST *request, char *fmt, char *out,
1092                      size_t freespace, RADIUS_ESCAPE_STRING func)
1093 {
1094         char url[MAX_FILTER_STR_LEN];
1095         int res;
1096         int ret = 0;
1097         ldap_instance *inst = instance;
1098         LDAPURLDesc *ldap_url;
1099         LDAPMessage *result = NULL;
1100         LDAPMessage *msg = NULL;
1101         char **vals;
1102         int conn_id = -1;
1103         LDAP_CONN *conn;
1104
1105         DEBUG("rlm_ldap: - ldap_xlat");
1106         if (!radius_xlat(url, sizeof(url), fmt, request, func)) {
1107                 radlog (L_ERR, "rlm_ldap: Unable to create LDAP URL.\n");
1108                 return 0;
1109         }
1110         if (!ldap_is_ldap_url(url)){
1111                 radlog (L_ERR, "rlm_ldap: String passed does not look like an LDAP URL.\n");
1112                 return 0;
1113         }
1114         if (ldap_url_parse(url,&ldap_url)){
1115                 radlog (L_ERR, "rlm_ldap: LDAP URL parse failed.\n");
1116                 return 0;
1117         }
1118         if (ldap_url->lud_attrs == NULL || ldap_url->lud_attrs[0] == NULL || \
1119                 ( ldap_url->lud_attrs[1] != NULL || ( ! strlen(ldap_url->lud_attrs[0]) || \
1120                 ! strcmp(ldap_url->lud_attrs[0],"*") ) ) ){
1121                 radlog (L_ERR, "rlm_ldap: Invalid Attribute(s) request.\n");
1122                 ldap_free_urldesc(ldap_url);
1123                 return 0;
1124         }
1125         if (ldap_url->lud_host){
1126                 if (strncmp(inst->server,ldap_url->lud_host,strlen(inst->server)) != 0 || \
1127                                 ldap_url->lud_port != inst->port){
1128                         DEBUG("rlm_ldap: Requested server/port is not known to this module instance.");
1129                         ldap_free_urldesc(ldap_url);
1130                         return 0;
1131                 }
1132         }
1133         if ((conn_id = ldap_get_conn(inst->conns,&conn,inst)) == -1){
1134                 radlog(L_ERR, "rlm_ldap: All ldap connections are in use");
1135                 ldap_free_urldesc(ldap_url);
1136                 return 0;
1137         }
1138         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){
1139                 if (res == RLM_MODULE_NOTFOUND){
1140                         DEBUG("rlm_ldap: Search returned not found");
1141                         ldap_free_urldesc(ldap_url);
1142                         ldap_release_conn(conn_id,inst->conns);
1143                         return 0;
1144                 }
1145                 DEBUG("rlm_ldap: Search returned error");
1146                 ldap_free_urldesc(ldap_url);
1147                 ldap_release_conn(conn_id,inst->conns);
1148                 return 0;
1149         }
1150         if ((msg = ldap_first_entry(conn->ld, result)) == NULL){
1151                 DEBUG("rlm_ldap: ldap_first_entry() failed");
1152                 ldap_msgfree(result);
1153                 ldap_free_urldesc(ldap_url);
1154                 ldap_release_conn(conn_id,inst->conns);
1155                 return 0;
1156         }
1157         if ((vals = ldap_get_values(conn->ld, msg, ldap_url->lud_attrs[0])) != NULL) {
1158                 ret = strlen(vals[0]);
1159                 if (ret > freespace){
1160                         DEBUG("rlm_ldap: Insufficient string space");
1161                         ldap_free_urldesc(ldap_url);
1162                         ldap_value_free(vals);
1163                         ldap_msgfree(result);
1164                         ldap_release_conn(conn_id,inst->conns);
1165                         return 0;
1166                 }
1167                 DEBUG("rlm_ldap: Adding attribute %s, value: %s",ldap_url->lud_attrs[0],vals[0]);
1168                 strncpy(out,vals[0],ret);
1169                 ldap_value_free(vals);
1170         }
1171         else
1172                 ret = 0;
1173
1174         ldap_msgfree(result);
1175         ldap_free_urldesc(ldap_url);
1176         ldap_release_conn(conn_id,inst->conns);
1177
1178         DEBUG("rlm_ldap: - ldap_xlat end");
1179
1180         return ret;
1181 }
1182
1183
1184 /******************************************************************************
1185  *
1186  *      Function: rlm_ldap_authorize
1187  *
1188  *      Purpose: Check if user is authorized for remote access
1189  *
1190  ******************************************************************************/
1191 static int
1192 ldap_authorize(void *instance, REQUEST * request)
1193 {
1194         LDAPMessage     *result = NULL;
1195         LDAPMessage     *msg = NULL;
1196         LDAPMessage     *def_msg = NULL;
1197         LDAPMessage     *def_attr_msg = NULL;
1198         LDAPMessage     *def_result = NULL;
1199         LDAPMessage     *def_attr_result = NULL;
1200         ldap_instance   *inst = instance;
1201         char            *user_dn = NULL;
1202         char            filter[MAX_FILTER_STR_LEN];
1203         char            basedn[MAX_FILTER_STR_LEN];
1204         VALUE_PAIR      *check_tmp;
1205         VALUE_PAIR      *reply_tmp;
1206         int             res;
1207         VALUE_PAIR      **check_pairs, **reply_pairs;
1208         char            **vals;
1209         VALUE_PAIR      *module_fmsg_vp;
1210         VALUE_PAIR      *user_profile;
1211         char            module_fmsg[MAX_STRING_LEN];
1212         LDAP_CONN       *conn;
1213         int             conn_id = -1;
1214
1215         DEBUG("rlm_ldap: - authorize");
1216
1217         if (!request->username){
1218                 radlog(L_AUTH, "rlm_ldap: Attribute \"User-Name\" is required for authentication.\n");
1219                 return RLM_MODULE_INVALID;
1220         }
1221
1222         check_pairs = &request->config_items;
1223         reply_pairs = &request->reply->vps;
1224
1225         /*
1226          * Check for valid input, zero length names not permitted
1227          */
1228         if (request->username->strvalue == 0) {
1229                 radlog(L_ERR, "rlm_ldap: zero length username not permitted\n");
1230                 return RLM_MODULE_INVALID;
1231         }
1232         DEBUG("rlm_ldap: performing user authorization for %s",
1233                request->username->strvalue);
1234
1235         if (!radius_xlat(filter, sizeof(filter), inst->filter,
1236                          request, ldap_escape_func)) {
1237                 radlog (L_ERR, "rlm_ldap: unable to create filter.\n");
1238                 return RLM_MODULE_INVALID;
1239         }
1240
1241         if (!radius_xlat(basedn, sizeof(basedn), inst->basedn,
1242                          request, ldap_escape_func)) {
1243                 radlog (L_ERR, "rlm_ldap: unable to create basedn.\n");
1244                 return RLM_MODULE_INVALID;
1245         }
1246
1247         if ((conn_id = ldap_get_conn(inst->conns,&conn,inst)) == -1){
1248                 radlog(L_ERR, "rlm_ldap: All ldap connections are in use");
1249                 return RLM_MODULE_FAIL;
1250         }
1251         if ((res = perform_search(instance, conn, basedn, LDAP_SCOPE_SUBTREE, filter, inst->atts, &result)) != RLM_MODULE_OK) {
1252                 DEBUG("rlm_ldap: search failed");
1253                 if (res == RLM_MODULE_NOTFOUND){
1254                         snprintf(module_fmsg,sizeof(module_fmsg),"rlm_ldap: User not found");
1255                         module_fmsg_vp = pairmake("Module-Failure-Message", module_fmsg, T_OP_EQ);
1256                         pairadd(&request->packet->vps, module_fmsg_vp);
1257                 }
1258                 ldap_release_conn(conn_id,inst->conns);
1259                 return (res);
1260         }
1261         if ((msg = ldap_first_entry(conn->ld, result)) == NULL) {
1262                 DEBUG("rlm_ldap: ldap_first_entry() failed");
1263                 ldap_msgfree(result);
1264                 ldap_release_conn(conn_id,inst->conns);
1265                 return RLM_MODULE_FAIL;
1266         }
1267         if ((user_dn = ldap_get_dn(conn->ld, msg)) == NULL) {
1268                 DEBUG("rlm_ldap: ldap_get_dn() failed");
1269                 ldap_msgfree(result);
1270                 ldap_release_conn(conn_id,inst->conns);
1271                 return RLM_MODULE_FAIL;
1272         }
1273         /*
1274          * Adding new attribute containing DN for LDAP object associated with
1275          * given username
1276          */
1277         pairadd(&request->packet->vps, pairmake("Ldap-UserDn", user_dn, T_OP_EQ));
1278         ldap_memfree(user_dn);
1279
1280
1281         /* Remote access is controled by attribute of the user object */
1282         if (inst->access_attr) {
1283                 if ((vals = ldap_get_values(conn->ld, msg, inst->access_attr)) != NULL) {
1284                         if (inst->default_allow){
1285                                 DEBUG("rlm_ldap: checking if remote access for %s is allowed by %s", request->username->strvalue, inst->access_attr);
1286                                 if (!strncmp(vals[0], "FALSE", 5)) {
1287                                         DEBUG("rlm_ldap: dialup access disabled");
1288                                         snprintf(module_fmsg,sizeof(module_fmsg),"rlm_ldap: Access Attribute denies access");
1289                                         module_fmsg_vp = pairmake("Module-Failure-Message", module_fmsg, T_OP_EQ);
1290                                         pairadd(&request->packet->vps, module_fmsg_vp);
1291                                         ldap_msgfree(result);
1292                                         ldap_value_free(vals);
1293                                         ldap_release_conn(conn_id,inst->conns);
1294                                         return RLM_MODULE_USERLOCK;
1295                                 }
1296                                 ldap_value_free(vals);
1297                         }
1298                         else{
1299                                 DEBUG("rlm_ldap: %s attribute exists - access denied by default", inst->access_attr);
1300                                 snprintf(module_fmsg,sizeof(module_fmsg),"rlm_ldap: Access Attribute denies access");
1301                                 module_fmsg_vp = pairmake("Module-Failure-Message", module_fmsg, T_OP_EQ);
1302                                 pairadd(&request->packet->vps, module_fmsg_vp);
1303                                 ldap_msgfree(result);
1304                                 ldap_value_free(vals);
1305                                 ldap_release_conn(conn_id,inst->conns);
1306                                 return RLM_MODULE_USERLOCK;
1307                         }
1308                 } else {
1309                         if (inst->default_allow){
1310                                 DEBUG("rlm_ldap: no %s attribute - access denied by default", inst->access_attr);
1311                                 snprintf(module_fmsg,sizeof(module_fmsg),"rlm_ldap: Access Attribute denies access");
1312                                 module_fmsg_vp = pairmake("Module-Failure-Message", module_fmsg, T_OP_EQ);
1313                                 pairadd(&request->packet->vps, module_fmsg_vp);
1314                                 ldap_msgfree(result);
1315                                 ldap_release_conn(conn_id,inst->conns);
1316                                 return RLM_MODULE_USERLOCK;
1317                         }
1318                 }
1319         }
1320
1321         /*
1322          * Check for the default profile entry. If it exists then add the
1323          * attributes it contains in the check and reply pairs
1324          */
1325
1326         user_profile = pairfind(request->config_items, PW_USER_PROFILE);
1327         if (inst->default_profile || user_profile){
1328                 char *profile = inst->default_profile;
1329
1330                 strNcpy(filter,inst->base_filter,sizeof(filter));
1331                 if (user_profile)
1332                         profile = user_profile->strvalue;
1333                 if (profile && strlen(profile)){
1334                         if ((res = perform_search(instance, conn,
1335                                 profile, LDAP_SCOPE_BASE,
1336                                 filter, inst->atts, &def_result)) == RLM_MODULE_OK){
1337                                 if ((def_msg = ldap_first_entry(conn->ld,def_result))){
1338                                         if ((check_tmp = ldap_pairget(conn->ld,def_msg,inst->check_item_map,check_pairs,1))) {
1339                                                 if (inst->do_xlat){
1340                                                         pairxlatmove(request, check_pairs, &check_tmp);
1341                                                         pairfree(&check_tmp);
1342                                                 }
1343                                                 else
1344                                                         pairadd(check_pairs,check_tmp);
1345                                         }
1346                                         if ((reply_tmp = ldap_pairget(conn->ld,def_msg,inst->reply_item_map,reply_pairs,0))) {
1347                                                 if (inst->do_xlat){
1348                                                         pairxlatmove(request, reply_pairs, &reply_tmp);
1349                                                         pairfree(&reply_tmp);
1350                                                 }
1351                                                 else
1352                                                         pairadd(reply_pairs,reply_tmp);
1353                                         }
1354                                 }
1355                                 ldap_msgfree(def_result);
1356                         } else
1357                                 DEBUG("rlm_ldap: default_profile/user-profile search failed");
1358                 }
1359         }
1360
1361         /*
1362          * Check for the profile attribute. If it exists, we assume that it
1363          * contains the DN of an entry containg a profile for the user. That
1364          * way we can have different general profiles for various user groups
1365          * (students,faculty,staff etc)
1366          */
1367
1368         if (inst->profile_attr){
1369                 if ((vals = ldap_get_values(conn->ld, msg, inst->profile_attr)) != NULL) {
1370                         unsigned int i=0;
1371                         strNcpy(filter,inst->base_filter,sizeof(filter));
1372                         while(vals[i] != NULL && strlen(vals[i])){
1373                                 if ((res = perform_search(instance, conn,
1374                                         vals[i], LDAP_SCOPE_BASE,
1375                                         filter, inst->atts, &def_attr_result)) == RLM_MODULE_OK){
1376                                         if ((def_attr_msg = ldap_first_entry(conn->ld,def_attr_result))){
1377                                                 if ((check_tmp = ldap_pairget(conn->ld,def_attr_msg,inst->check_item_map,check_pairs,1))) {
1378                                                         if (inst->do_xlat){
1379                                                                 pairxlatmove(request, check_pairs, &check_tmp);
1380                                                                 pairfree(&check_tmp);
1381                                                         }
1382                                                         else
1383                                                                 pairadd(check_pairs,check_tmp);
1384                                                 }
1385                                                 if ((reply_tmp = ldap_pairget(conn->ld,def_attr_msg,inst->reply_item_map,reply_pairs,0))) {
1386                                                         if (inst->do_xlat){
1387                                                                 pairxlatmove(request, reply_pairs, &reply_tmp);
1388                                                                 pairfree(&reply_tmp);
1389                                                         }
1390                                                         else
1391                                                                 pairadd(reply_pairs,reply_tmp);
1392                                                 }
1393                                         }
1394                                         ldap_msgfree(def_attr_result);
1395                                 } else
1396                                         DEBUG("rlm_ldap: profile_attribute search failed");
1397                                 i++;
1398                         }
1399                         ldap_value_free(vals);
1400                 }
1401         }
1402         if (inst->passwd_attr && strlen(inst->passwd_attr)){
1403 #ifdef NOVELL_UNIVERSAL_PASSWORD
1404                 if(strcasecmp(inst->passwd_attr,"nspmPassword")!= 0){
1405 #endif
1406                 VALUE_PAIR *passwd_item;
1407
1408                 if ((passwd_item = pairfind(request->config_items, PW_PASSWORD)) == NULL){
1409                         char **passwd_vals;
1410                         char *passwd_val = NULL;
1411                         int passwd_len;
1412
1413                         if ((passwd_vals = ldap_get_values(conn->ld,msg,inst->passwd_attr)) != NULL){
1414                                 unsigned int i=0;
1415                                 while(passwd_vals[i] != NULL){
1416                                         if (strlen(passwd_vals[i])){
1417                                                 passwd_val = passwd_vals[i];
1418
1419                                                 if (inst->passwd_hdr && strlen(inst->passwd_hdr)){
1420                                                         passwd_val = strstr(passwd_val,inst->passwd_hdr);
1421                                                         if (passwd_val != NULL)
1422                                                                 passwd_val += strlen(inst->passwd_hdr);
1423                                                         else
1424                                                                 DEBUG("rlm_ldap: Password header not found in password %s for user %s", passwd_vals[0],request->username->strvalue);
1425                                                 }
1426                                                 if (passwd_val){
1427                                                         if ((passwd_item = paircreate(PW_PASSWORD,PW_TYPE_STRING)) == NULL){
1428                                                                 radlog(L_ERR|L_CONS, "no memory");
1429                                                                 ldap_value_free(passwd_vals);
1430                                                                 ldap_msgfree(result);
1431                                                                 ldap_release_conn(conn_id,inst->conns);
1432                                                                 return RLM_MODULE_FAIL;
1433                                                         }
1434                                                         passwd_len = strlen(passwd_val);
1435                                                         strncpy(passwd_item->strvalue,passwd_val,MAX_STRING_LEN - 1);
1436                                                         passwd_item->length = (passwd_len > (MAX_STRING_LEN - 1)) ? (MAX_STRING_LEN - 1) : passwd_len;
1437                                                         pairadd(&request->config_items,passwd_item);
1438                                                         DEBUG("rlm_ldap: Added password %s in check items",passwd_item->strvalue);
1439                                                 }
1440                                         }
1441                                         i++;
1442                                 }
1443                                 ldap_value_free(passwd_vals);
1444                         }
1445                 }
1446 #ifdef NOVELL_UNIVERSAL_PASSWORD
1447                 }
1448                 else{
1449                 /*
1450                 * Read Universal Password from eDirectory
1451                 */
1452                         VALUE_PAIR      *passwd_item;
1453                         VALUE_PAIR      *vp_user_dn;
1454                         int             passwd_len;
1455                         char            *universal_password = NULL;
1456                         int             universal_password_len = UNIVERSAL_PASS_LEN;
1457                         char            *passwd_val = NULL;
1458
1459                         res = 0;
1460
1461                         if ((passwd_item = pairfind(request->config_items, PW_PASSWORD)) == NULL){
1462                         
1463                                 universal_password = rad_malloc(universal_password_len);
1464                                 memset(universal_password, 0, universal_password_len);
1465
1466                                 vp_user_dn = pairfind(request->packet->vps,PW_LDAP_USERDN);
1467                                 res = nmasldap_get_password(conn->ld,vp_user_dn->strvalue,&universal_password_len,universal_password);
1468
1469                                 if (res == 0){
1470                                         passwd_val = universal_password;
1471
1472                                         if (inst->passwd_hdr && strlen(inst->passwd_hdr)){
1473                                                 passwd_val = strstr(passwd_val,inst->passwd_hdr);
1474
1475                                                 if (passwd_val != NULL)
1476                                                         passwd_val += strlen((char*)inst->passwd_hdr);
1477                                                 else
1478                                                         DEBUG("rlm_ldap: Password header not found in password %s for user %s ",passwd_val,request->username->strvalue);
1479                                         }
1480
1481                                         if (passwd_val){
1482                                                 if ((passwd_item = paircreate(PW_PASSWORD,PW_TYPE_STRING)) == NULL){
1483                                                         radlog(L_ERR, "rlm_ldap: Could not allocate memory. Aborting.");
1484                                                         ldap_msgfree(result);
1485                                                         ldap_release_conn(conn_id,inst->conns);
1486                                                         memset(universal_password, 0, universal_password_len);
1487                                                         free(universal_password);
1488                                                         return RLM_MODULE_FAIL;
1489                                                 }
1490
1491                                                 passwd_len = strlen(passwd_val);
1492                                                 strncpy(passwd_item->strvalue,passwd_val,MAX_STRING_LEN - 1);
1493                                                 passwd_item->length = (passwd_len > (MAX_STRING_LEN - 1)) ? (MAX_STRING_LEN - 1) : passwd_len;
1494                                                 pairadd(&request->config_items,passwd_item);
1495
1496 #ifdef NOVELL
1497                                                 {
1498                                                         DICT_ATTR *dattr;
1499                                                         VALUE_PAIR      *vp_inst, *vp_apc;
1500                                                         int inst_attr, apc_attr;
1501
1502                                                         dattr = dict_attrbyname("LDAP-Instance");
1503                                                         inst_attr = dattr->attr;
1504                                                         dattr = dict_attrbyname("eDir-APC");
1505                                                         apc_attr = dattr->attr;
1506
1507                                                         vp_inst = pairfind(request->config_items, inst_attr);
1508                                                         if(vp_inst == NULL){
1509                                                                 /*
1510                                                                  * The authorize method of no other LDAP module instance has
1511                                                                  * processed this request.
1512                                                                  */
1513                                                                 if ((vp_inst = paircreate(inst_attr, PW_TYPE_STRING)) == NULL){
1514                                                                         radlog(L_ERR, "rlm_ldap: Could not allocate memory. Aborting.");
1515                                                                         ldap_msgfree(result);
1516                                                                         ldap_release_conn(conn_id, inst->conns);
1517                                                                         memset(universal_password, 0, universal_password_len);
1518                                                                         free(universal_password);
1519                                                                         return RLM_MODULE_FAIL;
1520                                                                 }
1521                                                                 strcpy(vp_inst->strvalue, inst->xlat_name);
1522                                                                 vp_inst->length = strlen(vp_inst->strvalue);
1523                                                                 pairadd(&request->config_items, vp_inst);
1524
1525                                                                 /*
1526                                                                  * Inform the authenticate / post-auth method about the presence
1527                                                                  * of UP in the config items list and whether eDirectory account
1528                                                                  * policy check is to be performed or not.
1529                                                                  */
1530                                                                 if ((vp_apc = paircreate(apc_attr, PW_TYPE_INTEGER)) == NULL){
1531                                                                         radlog(L_ERR, "rlm_ldap: Could not allocate memory. Aborting.");
1532                                                                         ldap_msgfree(result);
1533                                                                         ldap_release_conn(conn_id, inst->conns);
1534                                                                         memset(universal_password, 0, universal_password_len);
1535                                                                         free(universal_password);
1536                                                                         return RLM_MODULE_FAIL;
1537                                                                 }
1538
1539                                                                 if(!inst->edir_account_policy_check){
1540                                                                         /* Do nothing */
1541                                                                         strcpy(vp_apc->strvalue, "1");
1542                                                                 }else{
1543                                                                         /* Perform eDirectory account-policy check */
1544                                                                         strcpy(vp_apc->strvalue, "2");
1545                                                                 }
1546                                                                 vp_apc->length = 1;
1547                                                                 pairadd(&request->config_items, vp_apc);
1548                                                         }
1549                                                 }
1550 #endif
1551
1552                                                 DEBUG("rlm_ldap: Added the eDirectory password in check items");
1553                                         }
1554                                 }
1555                                 else {
1556                                         DEBUG("rlm_ldap: Error reading Universal Password.Return Code = %d",res);
1557                                 }
1558
1559                                 memset(universal_password, 0, universal_password_len);
1560                                 free(universal_password);
1561                         }
1562                 }                       
1563 #endif
1564
1565         }
1566
1567
1568
1569         DEBUG("rlm_ldap: looking for check items in directory...");
1570
1571         if ((check_tmp = ldap_pairget(conn->ld, msg, inst->check_item_map,check_pairs,1)) != NULL) {
1572                 if (inst->do_xlat){
1573                         pairxlatmove(request, check_pairs, &check_tmp);
1574                         pairfree(&check_tmp);
1575                 }
1576                 else
1577                         pairadd(check_pairs,check_tmp);
1578         }
1579
1580
1581         DEBUG("rlm_ldap: looking for reply items in directory...");
1582
1583
1584         if ((reply_tmp = ldap_pairget(conn->ld, msg, inst->reply_item_map,reply_pairs,0)) != NULL) {
1585                 if (inst->do_xlat){
1586                         pairxlatmove(request, reply_pairs, &reply_tmp);
1587                         pairfree(&reply_tmp);
1588                 }
1589                 else
1590                         pairadd(reply_pairs,reply_tmp);
1591         }
1592
1593        if (inst->do_comp && paircmp(request,request->packet->vps,*check_pairs,reply_pairs) != 0){
1594 #ifdef NOVELL
1595                 /* Don't perform eDirectory APC if RADIUS authorize fails */
1596                 int apc_attr;
1597                 VALUE_PAIR *vp_apc;
1598                 DICT_ATTR *dattr;
1599
1600                 dattr = dict_attrbyname("eDir-APC");
1601                 apc_attr = dattr->attr;
1602
1603                 vp_apc = pairfind(request->config_items, apc_attr);
1604                 if(vp_apc)
1605                         vp_apc->strvalue[0] = '1';
1606 #endif
1607
1608                 DEBUG("rlm_ldap: Pairs do not match. Rejecting user.");
1609                 snprintf(module_fmsg,sizeof(module_fmsg),"rlm_ldap: Pairs do not match");
1610                 module_fmsg_vp = pairmake("Module-Failure-Message", module_fmsg, T_OP_EQ);
1611                 pairadd(&request->packet->vps, module_fmsg_vp);
1612                 ldap_msgfree(result);
1613                 ldap_release_conn(conn_id,inst->conns);
1614
1615                 return RLM_MODULE_REJECT;
1616         }
1617
1618         /*
1619          * Module should default to LDAP authentication if no Auth-Type
1620          * specified.  Note that we do this ONLY if configured, AND we
1621          * set the Auth-Type to our module name, which allows multiple
1622          * ldap instances to work.
1623          */
1624         if (inst->set_auth_type &&
1625             (pairfind(*check_pairs, PW_AUTH_TYPE) == NULL) &&
1626             request->password &&
1627             (request->password->attribute == PW_USER_PASSWORD)) {
1628                 pairadd(check_pairs, pairmake("Auth-Type", inst->xlat_name, T_OP_EQ));
1629                 DEBUG("rlm_ldap: Setting Auth-Type = %s", inst->xlat_name);
1630         }
1631
1632         DEBUG("rlm_ldap: user %s authorized to use remote access",
1633               request->username->strvalue);
1634         ldap_msgfree(result);
1635         ldap_release_conn(conn_id,inst->conns);
1636
1637         return RLM_MODULE_OK;
1638 }
1639
1640 /*****************************************************************************
1641  *
1642  *      Function: rlm_ldap_authenticate
1643  *
1644  *      Purpose: Check the user's password against ldap database
1645  *
1646  *****************************************************************************/
1647 static int
1648 ldap_authenticate(void *instance, REQUEST * request)
1649 {
1650         LDAP           *ld_user;
1651         LDAPMessage    *result, *msg;
1652         ldap_instance  *inst = instance;
1653         char           *user_dn, *attrs[] = {"uid", NULL};
1654         char            filter[MAX_FILTER_STR_LEN];
1655         char            basedn[MAX_FILTER_STR_LEN];
1656         int             res;
1657         VALUE_PAIR     *vp_user_dn;
1658         VALUE_PAIR      *module_fmsg_vp;
1659         char            module_fmsg[MAX_STRING_LEN];
1660         LDAP_CONN       *conn;
1661         int             conn_id = -1;
1662 #ifdef NOVELL
1663         char            *err = NULL;
1664 #endif
1665
1666         DEBUG("rlm_ldap: - authenticate");
1667
1668         /*
1669          * Ensure that we're being passed a plain-text password, and not
1670          * anything else.
1671          */
1672
1673         if (!request->username) {
1674                 radlog(L_AUTH, "rlm_ldap: Attribute \"User-Name\" is required for authentication.\n");
1675                 return RLM_MODULE_INVALID;
1676         }
1677
1678         if (!request->password){
1679                 radlog(L_AUTH, "rlm_ldap: Attribute \"User-Password\" is required for authentication.");
1680                 return RLM_MODULE_INVALID;
1681         }
1682
1683         if(request->password->attribute != PW_PASSWORD) {
1684                 radlog(L_AUTH, "rlm_ldap: Attribute \"User-Password\" is required for authentication. Cannot use \"%s\".", request->password->name);
1685                 return RLM_MODULE_INVALID;
1686         }
1687
1688         if (request->password->length == 0) {
1689                 snprintf(module_fmsg,sizeof(module_fmsg),"rlm_ldap: empty password supplied");
1690                 module_fmsg_vp = pairmake("Module-Failure-Message", module_fmsg, T_OP_EQ);
1691                 pairadd(&request->packet->vps, module_fmsg_vp);
1692                 return RLM_MODULE_INVALID;
1693         }
1694
1695         /*
1696          * Check that we don't have any failed connections. If we do there's no real need
1697          * of runing. Also give it another chance if we have a lot of failed connections.
1698          */
1699         if (inst->failed_conns > MAX_FAILED_CONNS_END)
1700                 inst->failed_conns = 0;
1701         if (inst->failed_conns > MAX_FAILED_CONNS_START){
1702                 inst->failed_conns++;
1703                 return RLM_MODULE_FAIL;
1704         }
1705
1706
1707         DEBUG("rlm_ldap: login attempt by \"%s\" with password \"%s\"",
1708                request->username->strvalue, request->password->strvalue);
1709
1710         while((vp_user_dn = pairfind(request->packet->vps, PW_LDAP_USERDN)) == NULL) {
1711                 if (!radius_xlat(filter, sizeof(filter), inst->filter,
1712                                 request, ldap_escape_func)) {
1713                         radlog (L_ERR, "rlm_ldap: unable to create filter.\n");
1714                         return RLM_MODULE_INVALID;
1715                 }
1716
1717                 if (!radius_xlat(basedn, sizeof(basedn), inst->basedn,
1718                                 request, ldap_escape_func)) {
1719                         radlog (L_ERR, "rlm_ldap: unable to create basedn.\n");
1720                         return RLM_MODULE_INVALID;
1721                 }
1722
1723                 if ((conn_id = ldap_get_conn(inst->conns,&conn,inst)) == -1){
1724                         radlog(L_ERR, "rlm_ldap: All ldap connections are in use");
1725                         return RLM_MODULE_FAIL;
1726                 }
1727                 if ((res = perform_search(instance, conn, basedn, LDAP_SCOPE_SUBTREE, filter, attrs, &result)) != RLM_MODULE_OK) {
1728                         if (res == RLM_MODULE_NOTFOUND){
1729                                 snprintf(module_fmsg,sizeof(module_fmsg),"rlm_ldap: User not found");
1730                                 module_fmsg_vp = pairmake("Module-Failure-Message", module_fmsg, T_OP_EQ);
1731                                 pairadd(&request->packet->vps, module_fmsg_vp);
1732                         }
1733                         ldap_release_conn(conn_id,inst->conns);
1734                         return (res);
1735                 }
1736                 if ((msg = ldap_first_entry(conn->ld, result)) == NULL) {
1737                         ldap_msgfree(result);
1738                         ldap_release_conn(conn_id,inst->conns);
1739                         return RLM_MODULE_FAIL;
1740                 }
1741                 if ((user_dn = ldap_get_dn(conn->ld, msg)) == NULL) {
1742                         DEBUG("rlm_ldap: ldap_get_dn() failed");
1743                         ldap_msgfree(result);
1744                         ldap_release_conn(conn_id,inst->conns);
1745                         return RLM_MODULE_FAIL;
1746                 }
1747                 ldap_release_conn(conn_id,inst->conns);
1748                 pairadd(&request->packet->vps, pairmake("Ldap-UserDn", user_dn, T_OP_EQ));
1749                 ldap_memfree(user_dn);
1750                 ldap_msgfree(result);
1751         }
1752
1753         user_dn = vp_user_dn->strvalue;
1754
1755         DEBUG("rlm_ldap: user DN: %s", user_dn);
1756
1757 #ifndef NOVELL
1758         ld_user = ldap_connect(instance, user_dn, request->password->strvalue,
1759                                1, &res, NULL);
1760 #else
1761
1762         ld_user = ldap_connect(instance, user_dn, request->password->strvalue,
1763                         1, &res, &err);
1764
1765         if(err != NULL){
1766                 /* 'err' contains the LDAP connection error description */
1767                 DEBUG("rlm_ldap: %s", err);
1768                 pairadd(&request->reply->vps, pairmake("Reply-Message", err, T_OP_EQ));
1769                 ldap_memfree((void *)err);
1770         }
1771
1772         /* Don't perform eDirectory APC again after attempting to bind here. */
1773         {
1774                 int apc_attr;
1775                 DICT_ATTR *dattr;
1776                 VALUE_PAIR *vp_apc;
1777
1778                 dattr = dict_attrbyname("eDir-APC");
1779                 apc_attr = dattr->attr;
1780                 vp_apc = pairfind(request->config_items, apc_attr);
1781                 if(vp_apc && vp_apc->strvalue[0] == '2')
1782                         vp_apc->strvalue[0] = '3';
1783         }
1784 #endif
1785
1786         if (ld_user == NULL){
1787                 if (res == RLM_MODULE_REJECT){
1788                         inst->failed_conns = 0;
1789                         snprintf(module_fmsg,sizeof(module_fmsg),"rlm_ldap: Bind as user failed");
1790                         module_fmsg_vp = pairmake("Module-Failure-Message", module_fmsg, T_OP_EQ);
1791                         pairadd(&request->packet->vps, module_fmsg_vp);
1792                 }
1793                 if (res == RLM_MODULE_FAIL){
1794                         DEBUG("rlm_ldap: ldap_connect() failed");
1795                         inst->failed_conns++;
1796                 }
1797                 return (res);
1798         }
1799
1800         DEBUG("rlm_ldap: user %s authenticated succesfully",
1801               request->username->strvalue);
1802         ldap_unbind_s(ld_user);
1803         inst->failed_conns = 0;
1804
1805         return RLM_MODULE_OK;
1806 }
1807
1808 #ifdef NOVELL
1809 /*****************************************************************************
1810  *
1811  *      Function: rlm_ldap_postauth
1812  *
1813  *      Purpose: Perform eDirectory account policy check and failed-login reporting
1814  *      to eDirectory.
1815  *
1816  *****************************************************************************/
1817 static int
1818 ldap_postauth(void *instance, REQUEST * request)
1819 {
1820         int res = RLM_MODULE_FAIL;
1821         int inst_attr, apc_attr;
1822         char password[UNIVERSAL_PASS_LEN];
1823         ldap_instance  *inst = instance;
1824         LDAP_CONN       *conn;
1825         VALUE_PAIR *vp_inst, *vp_apc;
1826         DICT_ATTR *dattr;
1827
1828         dattr = dict_attrbyname("LDAP-Instance");
1829         inst_attr = dattr->attr;
1830         dattr = dict_attrbyname("eDir-APC");
1831         apc_attr = dattr->attr;
1832
1833         vp_inst = pairfind(request->config_items, inst_attr);
1834
1835         /*
1836          * Check if the password in the config items list is the user's UP which has
1837          * been read in the authorize method of this instance of the LDAP module.
1838          */
1839         if((vp_inst == NULL) || strcmp(vp_inst->strvalue, inst->xlat_name))
1840                 return RLM_MODULE_NOOP;
1841
1842         vp_apc = pairfind(request->config_items, apc_attr);
1843
1844         switch(vp_apc->strvalue[0]){
1845                 case '1':
1846                         /* Account policy check not enabled */
1847                 case '3':
1848                         /* Account policy check has been completed */
1849                         res = RLM_MODULE_NOOP;
1850                         break;
1851                 case '2':
1852                         {
1853                                 int err, conn_id = -1;
1854                                 char *error_msg = NULL;
1855                                 VALUE_PAIR *vp_fdn, *vp_pwd;
1856                                 DICT_ATTR *da;
1857
1858                                 if(request->reply->code == PW_AUTHENTICATION_REJECT){
1859                                         /* Bind to eDirectory as the RADIUS user with a wrong password. */
1860                                         vp_pwd = pairfind(request->config_items, PW_PASSWORD);
1861                                         strcpy(password, vp_pwd->strvalue);
1862                                         if(strlen(password) > 0){
1863                                                 if(password[0] != 'a'){
1864                                                         password[0] = 'a';
1865                                                 }else{
1866                                                         password[0] = 'b';
1867                                                 }
1868                                         }else{
1869                                                 strcpy(password, "dummy_password");
1870                                         }
1871                                         res = RLM_MODULE_REJECT;
1872                                 }else{
1873                                         /* Bind to eDirectory as the RADIUS user using the user's UP */
1874                                         vp_pwd = pairfind(request->config_items, PW_PASSWORD);
1875                                         if(vp_pwd == NULL){
1876                                                 DEBUG("rlm_ldap: User's Universal Password not in config items list.");
1877                                                 return RLM_MODULE_FAIL;
1878                                         }
1879                                         strcpy(password, vp_pwd->strvalue);
1880                                 }
1881
1882                                 if ((da = dict_attrbyname("Ldap-UserDn")) == NULL) {
1883                                         DEBUG("rlm_ldap: Attribute for user FDN not found in dictionary. Unable to proceed");
1884                                         return RLM_MODULE_FAIL;
1885                                 }
1886
1887                                 vp_fdn = pairfind(request->packet->vps, da->attr);
1888                                 if(vp_fdn == NULL){
1889                                         DEBUG("rlm_ldap: User's FQDN not in config items list.");
1890                                         return RLM_MODULE_FAIL;
1891                                 }
1892
1893                                 if ((conn_id = ldap_get_conn(inst->apc_conns, &conn, inst)) == -1){
1894                                         radlog(L_ERR, "rlm_ldap: All ldap connections are in use");
1895                                         return RLM_MODULE_FAIL;
1896                                 }
1897
1898                                 /*
1899                                  * If there is an existing LDAP connection to the directory, bind over
1900                                  * it. Otherwise, establish a new connection.
1901                                  */
1902 postauth_reconnect:
1903                                 if (!conn->bound || conn->ld == NULL) {
1904                                         DEBUG2("rlm_ldap: attempting LDAP reconnection");
1905                                         if (conn->ld){
1906                                                 DEBUG2("rlm_ldap: closing existing LDAP connection");
1907                                                 ldap_unbind_s(conn->ld);
1908                                         }
1909                                         if ((conn->ld = ldap_connect(instance, (char *)vp_fdn->strvalue, password, 0, &res, &error_msg)) == NULL) {
1910                                                 radlog(L_ERR, "rlm_ldap: eDirectory account policy check failed.");
1911
1912                                                 if(error_msg != NULL){
1913                                                         DEBUG("rlm_ldap: %s", error_msg);
1914                                                         pairadd(&request->reply->vps, pairmake("Reply-Message", error_msg, T_OP_EQ));
1915                                                         ldap_memfree((void *)error_msg);
1916                                                 }
1917
1918                                                 vp_apc->strvalue[0] = '3';
1919                                                 ldap_release_conn(conn_id, inst->apc_conns);
1920                                                 return RLM_MODULE_REJECT;
1921                                         }
1922                                         conn->bound = 1;
1923                                 }else if((err = ldap_simple_bind_s(conn->ld, (char *)vp_fdn->strvalue, password)) != LDAP_SUCCESS){
1924                                         if(err == LDAP_SERVER_DOWN){
1925                                                 conn->bound = 0;
1926                                                 goto postauth_reconnect;
1927                                         }
1928                                         DEBUG("rlm_ldap: eDirectory account policy check failed.");
1929                                         ldap_get_option(conn->ld, LDAP_OPT_ERROR_STRING, &error_msg);
1930                                         if(error_msg != NULL){
1931                                                 DEBUG("rlm_ldap: %s", error_msg);
1932                                                 pairadd(&request->reply->vps, pairmake("Reply-Message", error_msg, T_OP_EQ));
1933                                                 ldap_memfree((void *)error_msg);
1934                                         }
1935                                         vp_apc->strvalue[0] = '3';
1936                                         ldap_release_conn(conn_id, inst->apc_conns);
1937                                         return RLM_MODULE_REJECT;
1938                                 }
1939                                 vp_apc->strvalue[0] = '3';
1940                                 ldap_release_conn(conn_id, inst->apc_conns);
1941                                 return RLM_MODULE_OK;
1942                         }
1943         }
1944         return res;
1945 }
1946 #endif
1947
1948 static LDAP    *
1949 ldap_connect(void *instance, const char *dn, const char *password, int auth, int *result, char **err)
1950 {
1951         ldap_instance  *inst = instance;
1952         LDAP           *ld = NULL;
1953         int             msgid, rc, ldap_version;
1954         int             ldap_errno = 0;
1955         LDAPMessage    *res;
1956
1957         if (inst->is_url){
1958 #ifdef HAVE_LDAP_INITIALIZE
1959                 DEBUG("rlm_ldap: (re)connect to %s, authentication %d", inst->server, auth);
1960                 if (ldap_initialize(&ld, inst->server) != LDAP_SUCCESS) {
1961                         radlog(L_ERR, "rlm_ldap: ldap_initialize() failed");
1962                         *result = RLM_MODULE_FAIL;
1963                         return (NULL);
1964                 }
1965 #endif
1966         }
1967         else{
1968                 DEBUG("rlm_ldap: (re)connect to %s:%d, authentication %d", inst->server, inst->port, auth);
1969                 if ((ld = ldap_init(inst->server, inst->port)) == NULL) {
1970                         radlog(L_ERR, "rlm_ldap: ldap_init() failed");
1971                         *result = RLM_MODULE_FAIL;
1972                         return (NULL);
1973                 }
1974         }
1975         if (ldap_set_option(ld, LDAP_OPT_NETWORK_TIMEOUT, (void *) &(inst->net_timeout)) != LDAP_OPT_SUCCESS) {
1976                 radlog(L_ERR, "rlm_ldap: Could not set LDAP_OPT_NETWORK_TIMEOUT %ld.%ld", inst->net_timeout.tv_sec, inst->net_timeout.tv_usec);
1977         }
1978         if (ldap_set_option(ld, LDAP_OPT_TIMELIMIT, (void *) &(inst->timelimit)) != LDAP_OPT_SUCCESS) {
1979                 radlog(L_ERR, "rlm_ldap: Could not set LDAP_OPT_TIMELIMIT %d", inst->timelimit);
1980         }
1981         if (inst->ldap_debug && ldap_set_option(NULL, LDAP_OPT_DEBUG_LEVEL, &(inst->ldap_debug)) != LDAP_OPT_SUCCESS) {
1982                 radlog(L_ERR, "rlm_ldap: Could not set LDAP_OPT_DEBUG_LEVEL %d", inst->ldap_debug);
1983         }
1984         ldap_version = LDAP_VERSION3;
1985         if (ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, &ldap_version) != LDAP_OPT_SUCCESS) {
1986                 radlog(L_ERR, "rlm_ldap: Could not set LDAP version to V3");
1987         }
1988 #ifdef HAVE_LDAP_START_TLS
1989         if(inst->tls_mode) {
1990                 DEBUG("rlm_ldap: setting TLS mode to %d", inst->tls_mode);
1991                 if(ldap_set_option(ld, LDAP_OPT_X_TLS,
1992                            (void *) &(inst->tls_mode)) != LDAP_OPT_SUCCESS) {
1993                         ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &ldap_errno);
1994                         radlog(L_ERR, "rlm_ldap: could not set LDAP_OPT_X_TLS option %s", ldap_err2string(ldap_errno));
1995                 }
1996         }
1997
1998         if(inst->tls_cacertfile != NULL) {
1999                 DEBUG("rlm_ldap: setting TLS CACert File to %s", inst->tls_cacertfile);
2000
2001                 if ( ldap_set_option( NULL, LDAP_OPT_X_TLS_CACERTFILE,
2002                                                           (void *) inst->tls_cacertfile )
2003                          != LDAP_OPT_SUCCESS) {
2004                         radlog(L_ERR, "rlm_ldap: could not set "
2005                                    "LDAP_OPT_X_TLS_CACERTFILE option to %s", inst->tls_cacertfile);
2006                 }
2007         }
2008
2009         if(inst->tls_cacertdir != NULL) {
2010                 DEBUG("rlm_ldap: setting TLS CACert Directory to %s", inst->tls_cacertdir);
2011
2012                 if ( ldap_set_option( NULL, LDAP_OPT_X_TLS_CACERTDIR,
2013                                                           (void *) inst->tls_cacertdir )
2014                          != LDAP_OPT_SUCCESS) {
2015                         radlog(L_ERR, "rlm_ldap: could not set "
2016                                    "LDAP_OPT_X_TLS_CACERTDIR option to %s", inst->tls_cacertdir);
2017                 }
2018         }
2019
2020         if( strcmp( TLS_DEFAULT_VERIFY, inst->tls_require_cert ) != 0 ) {
2021                 DEBUG("rlm_ldap: setting TLS Require Cert to %s",
2022                           inst->tls_require_cert);
2023         }
2024
2025
2026 #ifdef HAVE_LDAP_INT_TLS_CONFIG
2027
2028         if ( ldap_int_tls_config( NULL, LDAP_OPT_X_TLS_REQUIRE_CERT,
2029                                                           (inst->tls_require_cert) )
2030                  != LDAP_OPT_SUCCESS) {
2031                 radlog(L_ERR, "rlm_ldap: could not set "
2032                            "LDAP_OPT_X_TLS_REQUIRE_CERT option to %s",
2033                            inst->tls_require_cert);
2034         }
2035
2036 #endif
2037
2038         if(inst->tls_certfile != NULL) {
2039                 DEBUG("rlm_ldap: setting TLS Cert File to %s", inst->tls_certfile);
2040
2041                 if ( ldap_set_option( NULL, LDAP_OPT_X_TLS_CERTFILE,
2042                                                           (void *) inst->tls_certfile )
2043                          != LDAP_OPT_SUCCESS) {
2044                         radlog(L_ERR, "rlm_ldap: could not set "
2045                                    "LDAP_OPT_X_TLS_CERTFILE option to %s",
2046                                    inst->tls_certfile);
2047                 }
2048         }
2049
2050         if(inst->tls_keyfile != NULL) {
2051                 DEBUG("rlm_ldap: setting TLS Key File to %s", inst->tls_keyfile);
2052
2053                 if ( ldap_set_option( NULL, LDAP_OPT_X_TLS_KEYFILE,
2054                                                           (void *) inst->tls_keyfile )
2055                          != LDAP_OPT_SUCCESS) {
2056                         radlog(L_ERR, "rlm_ldap: could not set "
2057                                    "LDAP_OPT_X_TLS_KEYFILE option to %s",
2058                                    inst->tls_keyfile);
2059                 }
2060         }
2061
2062         if(inst->tls_randfile != NULL) {
2063                 DEBUG("rlm_ldap: setting TLS Key File to %s", inst->tls_randfile);
2064
2065                 if ( ldap_set_option( NULL, LDAP_OPT_X_TLS_RANDOM_FILE,
2066                                                           (void *) inst->tls_randfile )
2067                          != LDAP_OPT_SUCCESS) {
2068                         radlog(L_ERR, "rlm_ldap: could not set "
2069                                    "LDAP_OPT_X_TLS_RANDOM_FILE option to %s",
2070                                    inst->tls_randfile);
2071                 }
2072         }
2073         if (inst->start_tls) {
2074                 DEBUG("rlm_ldap: starting TLS");
2075                 rc = ldap_start_tls_s(ld, NULL, NULL);
2076                 if (rc != LDAP_SUCCESS) {
2077                         DEBUG("rlm_ldap: ldap_start_tls_s()");
2078                         ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &ldap_errno);
2079                         radlog(L_ERR, "rlm_ldap: could not start TLS %s", ldap_err2string(ldap_errno));
2080                         *result = RLM_MODULE_FAIL;
2081                         ldap_unbind_s(ld);
2082                         return (NULL);
2083                 }
2084         }
2085 #endif /* HAVE_LDAP_START_TLS */
2086
2087         if (inst->is_url){
2088                 DEBUG("rlm_ldap: bind as %s/%s to %s", dn, password, inst->server);
2089         }
2090         else{
2091                 DEBUG("rlm_ldap: bind as %s/%s to %s:%d", dn, password, inst->server, inst->port);
2092         }
2093         msgid = ldap_bind(ld, dn, password,LDAP_AUTH_SIMPLE);
2094         if (msgid == -1) {
2095                 ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &ldap_errno);
2096                 if(err != NULL){
2097                         ldap_get_option(ld, LDAP_OPT_ERROR_STRING, err);
2098                 }
2099                 if (inst->is_url) {
2100                         radlog(L_ERR, "rlm_ldap: %s bind to %s failed: %s",
2101                                 dn, inst->server, ldap_err2string(ldap_errno));
2102                 } else {
2103                         radlog(L_ERR, "rlm_ldap: %s bind to %s:%d failed: %s",
2104                                 dn, inst->server, inst->port,
2105                                 ldap_err2string(ldap_errno));
2106                 }
2107                 *result = RLM_MODULE_FAIL;
2108                 ldap_unbind_s(ld);
2109                 return (NULL);
2110         }
2111         DEBUG("rlm_ldap: waiting for bind result ...");
2112
2113         rc = ldap_result(ld, msgid, 1, &(inst->timeout), &res);
2114
2115         if(rc < 1) {
2116                 DEBUG("rlm_ldap: ldap_result()");
2117                 ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &ldap_errno);
2118                 if(err != NULL){
2119                         ldap_get_option(ld, LDAP_OPT_ERROR_STRING, err);
2120                 }
2121                 if (inst->is_url) {
2122                         radlog(L_ERR, "rlm_ldap: %s bind to %s failed: %s",
2123                                 dn, inst->server, (rc == 0) ? "timeout" : ldap_err2string(ldap_errno));
2124                 } else {
2125                         radlog(L_ERR, "rlm_ldap: %s bind to %s:%d failed: %s",
2126                                 dn, inst->server, inst->port,
2127                                 (rc == 0) ? "timeout" : ldap_err2string(ldap_errno));
2128                 }
2129                 *result = RLM_MODULE_FAIL;
2130                 ldap_unbind_s(ld);
2131                 return (NULL);
2132         }
2133         ldap_errno = ldap_result2error(ld, res, 1);
2134         switch (ldap_errno) {
2135         case LDAP_SUCCESS:
2136                 DEBUG("rlm_ldap: Bind was successful");
2137                 *result = RLM_MODULE_OK;
2138                 break;
2139
2140         case LDAP_INVALID_CREDENTIALS:
2141                 if (auth){
2142                         DEBUG("rlm_ldap: Bind failed with invalid credentials");
2143                         *result = RLM_MODULE_REJECT;
2144                 }
2145                 else {
2146                         radlog(L_ERR, "rlm_ldap: LDAP login failed: check identity, password settings in ldap section of radiusd.conf");
2147                         *result = RLM_MODULE_FAIL;
2148                 }
2149                 if(err != NULL){
2150                         ldap_get_option(ld, LDAP_OPT_ERROR_STRING, err);
2151                 }
2152                 break;
2153
2154         default:
2155                 if (inst->is_url)
2156                         radlog(L_ERR,"rlm_ldap: %s bind to %s failed %s",
2157                                 dn, inst->server, ldap_err2string(ldap_errno));
2158                 else
2159                         radlog(L_ERR,"rlm_ldap: %s bind to %s:%d failed %s",
2160                                 dn, inst->server, inst->port,
2161                                 ldap_err2string(ldap_errno));
2162                 *result = RLM_MODULE_FAIL;
2163                 if(err != NULL){
2164                         ldap_get_option(ld, LDAP_OPT_ERROR_STRING, err);
2165                 }
2166         }
2167
2168         if (*result != RLM_MODULE_OK) {
2169                 ldap_unbind_s(ld);
2170                 ld = NULL;
2171         }
2172         return ld;
2173 }
2174
2175 /*****************************************************************************
2176  *
2177  *      Detach from the LDAP server and cleanup internal state.
2178  *
2179  *****************************************************************************/
2180 static int
2181 ldap_detach(void *instance)
2182 {
2183         ldap_instance  *inst = instance;
2184         TLDAP_RADIUS *pair, *nextpair;
2185
2186         if (inst->server)
2187                 free((char *) inst->server);
2188         if (inst->login)
2189                 free((char *) inst->login);
2190         if (inst->password)
2191                 free((char *) inst->password);
2192         if (inst->basedn)
2193                 free((char *) inst->basedn);
2194         if (inst->dictionary_mapping)
2195                 free(inst->dictionary_mapping);
2196         if (inst->filter)
2197                 free((char *) inst->filter);
2198         if (inst->base_filter)
2199                 free((char *) inst->base_filter);
2200         if (inst->passwd_hdr)
2201                 free((char *) inst->passwd_hdr);
2202         if (inst->passwd_attr)
2203                 free((char *) inst->passwd_attr);
2204         if (inst->groupname_attr)
2205                 free((char *) inst->groupname_attr);
2206         if (inst->groupmemb_filt)
2207                 free((char *) inst->groupmemb_filt);
2208         if (inst->groupmemb_attr)
2209                 free((char *) inst->groupmemb_attr);
2210         if (inst->access_attr)
2211                 free((char *) inst->access_attr);
2212         if (inst->profile_attr)
2213                 free((char *) inst->profile_attr);
2214         if (inst->conns){
2215                 int i=0;
2216
2217                 for(;i<inst->num_conns;i++){
2218                         if (inst->conns[i].ld){
2219                                 ldap_unbind_s(inst->conns[i].ld);
2220                         }
2221                         pthread_mutex_destroy(&inst->conns[i].mutex);
2222                 }
2223                 free(inst->conns);
2224         }
2225
2226 #ifdef NOVELL
2227         if (inst->apc_conns){ 
2228                 int i;
2229
2230                 for(i = 0; i < inst->num_conns; i++){
2231                         if (inst->apc_conns[i].ld){
2232                                 ldap_unbind_s(inst->apc_conns[i].ld);
2233                         }
2234                         pthread_mutex_destroy(&inst->apc_conns[i].mutex);
2235                 }
2236                 free(inst->apc_conns);
2237         }
2238 #endif
2239
2240         pair = inst->check_item_map;
2241
2242         while (pair != NULL) {
2243                 nextpair = pair->next;
2244                 free(pair->attr);
2245                 free(pair->radius_attr);
2246                 free(pair);
2247                 pair = nextpair;
2248         }
2249
2250         pair = inst->reply_item_map;
2251
2252         while (pair != NULL) {
2253                 nextpair = pair->next;
2254                 free(pair->attr);
2255                 free(pair->radius_attr);
2256                 free(pair);
2257                 pair = nextpair;
2258         }
2259
2260         if (inst->atts)
2261                 free(inst->atts);
2262
2263         paircompare_unregister(PW_LDAP_GROUP, ldap_groupcmp);
2264         xlat_unregister(inst->xlat_name,ldap_xlat);
2265         free(inst->xlat_name);
2266
2267         free(inst);
2268
2269         return 0;
2270 }
2271
2272 #ifdef FIELDCPY
2273 static void
2274 fieldcpy(char *string, char **uptr)
2275 {
2276         char           *ptr;
2277
2278         ptr = *uptr;
2279         while (*ptr == ' ' || *ptr == '\t') {
2280                 ptr++;
2281         }
2282         if (*ptr == '"') {
2283                 ptr++;
2284                 while (*ptr != '"' && *ptr != '\0' && *ptr != '\n') {
2285                         *string++ = *ptr++;
2286                 }
2287                 *string = '\0';
2288                 if (*ptr == '"') {
2289                         ptr++;
2290                 }
2291                 *uptr = ptr;
2292                 return;
2293         }
2294         while (*ptr != ' ' && *ptr != '\t' && *ptr != '\0' && *ptr != '\n' &&
2295                *ptr != '=' && *ptr != ',') {
2296                 *string++ = *ptr++;
2297         }
2298         *string = '\0';
2299         *uptr = ptr;
2300         return;
2301 }
2302 #endif
2303 /*****************************************************************************
2304  *      Get RADIUS attributes from LDAP object
2305  *      ( according to draft-adoba-radius-05.txt
2306  *        <http://www.ietf.org/internet-drafts/draft-adoba-radius-05.txt> )
2307  *
2308  *****************************************************************************/
2309
2310 static VALUE_PAIR *
2311 ldap_pairget(LDAP * ld, LDAPMessage * entry,
2312              TLDAP_RADIUS * item_map, VALUE_PAIR **pairs,char is_check)
2313 {
2314         char          **vals;
2315         int             vals_count;
2316         int             vals_idx;
2317         char           *ptr;
2318         char           *value;
2319         TLDAP_RADIUS   *element;
2320         LRAD_TOKEN      token, operator;
2321         int             is_generic_attribute;
2322         char            buf[MAX_STRING_LEN];
2323         VALUE_PAIR     *pairlist = NULL;
2324         VALUE_PAIR     *newpair = NULL;
2325         char            do_xlat = FALSE;
2326
2327         /*
2328          *      check if there is a mapping from this LDAP attribute
2329          *      to a RADIUS attribute
2330          */
2331         for (element = item_map; element != NULL; element = element->next) {
2332                 /*
2333                  *      No mapping, skip it.
2334                  */
2335                 if ((vals = ldap_get_values(ld,entry,element->attr)) == NULL)
2336                         continue;
2337
2338                 /*
2339                  *      Check whether this is a one-to-one-mapped ldap
2340                  *      attribute or a generic attribute and set flag
2341                  *      accordingly.
2342                  */
2343                 if (strcasecmp(element->radius_attr, GENERIC_ATTRIBUTE_ID)==0)
2344                         is_generic_attribute = 1;
2345                 else
2346                         is_generic_attribute = 0;
2347
2348                 /*
2349                  *      Find out how many values there are for the
2350                  *      attribute and extract all of them.
2351                  */
2352                 vals_count = ldap_count_values(vals);
2353
2354                 for (vals_idx = 0; vals_idx < vals_count; vals_idx++) {
2355                         value = vals[vals_idx];
2356
2357                         if (is_generic_attribute) {
2358                                 /*
2359                                  *      This is a generic attribute.
2360                                  */
2361                                 LRAD_TOKEN dummy; /* makes pairread happy */
2362
2363                                 /* not sure if using pairread here is ok ... */
2364                                 if ( (newpair = pairread(&value, &dummy)) != NULL) {
2365                                         DEBUG("rlm_ldap: extracted attribute %s from generic item %s",
2366                                               newpair->name, vals[vals_idx]);
2367                                         pairadd(&pairlist, newpair);
2368                                 } else {
2369                                         radlog(L_ERR, "rlm_ldap: parsing %s failed: %s",
2370                                                element->attr, vals[vals_idx]);
2371                                 }
2372                         } else {
2373                                 /*
2374                                  *      This is a one-to-one-mapped attribute
2375                                  */
2376                                 ptr = value;
2377                                 operator = gettoken(&ptr, buf, sizeof(buf));
2378                                 if (operator < T_EQSTART || operator > T_EQEND) {
2379                                         /* no leading operator found */
2380                                         if (is_check)
2381                                                 operator = T_OP_CMP_EQ;
2382                                         else
2383                                                 operator = T_OP_EQ;
2384                                 } else {
2385                                         /* the value is after the operator */
2386                                         value = ptr;
2387                                 }
2388
2389                                 /*
2390                                  *      Do xlat if the *entire* string
2391                                  *      is quoted.
2392                                  */
2393                                 if ((value[0] == '\'' || value[0] == '"' ||
2394                                      value[0] == '`') &&
2395                                     (value[0] == value[strlen(value)-1])) {
2396                                         ptr = value;
2397                                         token = gettoken(&ptr, buf, sizeof(buf));
2398                                         switch (token) {
2399                                         /* take the unquoted string */
2400                                         case T_SINGLE_QUOTED_STRING:
2401                                         case T_DOUBLE_QUOTED_STRING:
2402                                                 value = buf;
2403                                                 break;
2404
2405                                         /* the value will be xlat'ed later */
2406                                         case T_BACK_QUOTED_STRING:
2407                                                 value = buf;
2408                                                 do_xlat = TRUE;
2409                                                 break;
2410
2411                                         /* keep the original string */
2412                                         default:
2413                                                 break;
2414                                         }
2415                                 }
2416                                 if (value[0] == '\0') {
2417                                         DEBUG("rlm_ldap: Attribute %s has no value", element->attr);
2418                                         continue;
2419                                 }
2420
2421                                 DEBUG("rlm_ldap: Adding %s as %s, value %s & op=%d", element->attr, element->radius_attr, value, operator);
2422
2423                                 /*
2424                                  *      Create the pair.
2425                                  */
2426                                 newpair = pairmake(element->radius_attr,
2427                                                    do_xlat ? NULL : value,
2428                                                    operator);
2429                                 if (newpair == NULL) {
2430                                         radlog(L_ERR, "rlm_ldap: Failed to create the pair: %s", librad_errstr);
2431                                         continue;
2432                                 }
2433                                 if (do_xlat) {
2434                                         newpair->flags.do_xlat = 1;
2435                                         strNcpy(newpair->strvalue, buf,
2436                                                 sizeof(newpair->strvalue));
2437                                         newpair->length = 0;
2438                                 }
2439
2440                                 /*
2441                                  *      Add the pair into the packet.
2442                                  */
2443                                 if (!vals_idx){
2444                                         pairdelete(pairs, newpair->attribute);
2445                                 }
2446                                 pairadd(&pairlist, newpair);
2447                         }
2448                 }
2449                 ldap_value_free(vals);
2450         }
2451
2452         return (pairlist);
2453 }
2454
2455 /* globally exported name */
2456 module_t        rlm_ldap = {
2457         "LDAP",
2458         RLM_TYPE_THREAD_SAFE,   /* type: reserved        */
2459         NULL,                   /* initialization        */
2460         ldap_instantiate,       /* instantiation         */
2461         {
2462                 ldap_authenticate,      /* authentication        */
2463                 ldap_authorize,         /* authorization         */
2464                 NULL,                   /* preaccounting         */
2465                 NULL,                   /* accounting            */
2466                 NULL,                   /* checksimul            */
2467                 NULL,                   /* pre-proxy             */
2468                 NULL,                   /* post-proxy            */
2469 #ifdef NOVELL
2470                 ldap_postauth                   /* post-auth             */
2471 #else
2472                 NULL
2473 #endif
2474         },
2475         ldap_detach,            /* detach                */
2476         NULL,                   /* destroy               */
2477 };