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