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