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