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