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         int             set_auth_type;
313 }               ldap_instance;
314
315 /* The default setting for TLS Certificate Verification */
316 #define TLS_DEFAULT_VERIFY "allow"
317
318 static CONF_PARSER module_config[] = {
319         {"server", PW_TYPE_STRING_PTR, offsetof(ldap_instance,server), NULL, "localhost"},
320         {"port", PW_TYPE_INTEGER, offsetof(ldap_instance,port), NULL, "389"},
321         /* wait forever on network activity */
322         {"net_timeout", PW_TYPE_INTEGER, offsetof(ldap_instance,net_timeout.tv_sec), NULL, "10"},
323         /* wait forever for search results */
324         {"timeout", PW_TYPE_INTEGER, offsetof(ldap_instance,timeout.tv_sec), NULL, "20"},
325         /* allow server unlimited time for search (server-side limit) */
326         {"timelimit", PW_TYPE_INTEGER, offsetof(ldap_instance,timelimit), NULL, "20"},
327         {"identity", PW_TYPE_STRING_PTR, offsetof(ldap_instance,login), NULL, ""},
328         {"tls_mode", PW_TYPE_BOOLEAN, offsetof(ldap_instance,tls_mode), NULL, "no"},
329         {"start_tls", PW_TYPE_BOOLEAN, offsetof(ldap_instance,start_tls), NULL, "no"},
330         {"tls_cacertfile", PW_TYPE_STRING_PTR, offsetof(ldap_instance,tls_cacertfile), NULL, NULL},
331         {"tls_cacertdir", PW_TYPE_STRING_PTR, offsetof(ldap_instance,tls_cacertdir), NULL, NULL},
332         {"tls_certfile", PW_TYPE_STRING_PTR, offsetof(ldap_instance,tls_certfile), NULL, NULL},
333         {"tls_keyfile", PW_TYPE_STRING_PTR, offsetof(ldap_instance,tls_keyfile), NULL, NULL},
334         {"tls_randfile", PW_TYPE_STRING_PTR, offsetof(ldap_instance,tls_randfile), NULL, NULL},
335         {"tls_require_cert", PW_TYPE_STRING_PTR, offsetof(ldap_instance,tls_require_cert), NULL, TLS_DEFAULT_VERIFY},
336         {"password", PW_TYPE_STRING_PTR, offsetof(ldap_instance,password), NULL, ""},
337         {"basedn", PW_TYPE_STRING_PTR, offsetof(ldap_instance,basedn), NULL, "o=notexist"},
338         {"filter", PW_TYPE_STRING_PTR, offsetof(ldap_instance,filter), NULL, "(uid=%u)"},
339         {"base_filter", PW_TYPE_STRING_PTR, offsetof(ldap_instance,base_filter), NULL, "(objectclass=radiusprofile)"},
340         {"default_profile", PW_TYPE_STRING_PTR, offsetof(ldap_instance,default_profile), NULL, NULL},
341         {"profile_attribute", PW_TYPE_STRING_PTR, offsetof(ldap_instance,profile_attr), NULL, NULL},
342         {"password_header", PW_TYPE_STRING_PTR, offsetof(ldap_instance,passwd_hdr), NULL, NULL},
343         {"password_attribute", PW_TYPE_STRING_PTR, offsetof(ldap_instance,passwd_attr), NULL, NULL},
344         /* LDAP attribute name that controls remote access */
345         {"access_attr", PW_TYPE_STRING_PTR, offsetof(ldap_instance,access_attr), NULL, NULL},
346         /* file with mapping between LDAP and RADIUS attributes */
347         {"groupname_attribute", PW_TYPE_STRING_PTR, offsetof(ldap_instance,groupname_attr), NULL, "cn"},
348         {"groupmembership_filter", PW_TYPE_STRING_PTR, offsetof(ldap_instance,groupmemb_filt), NULL, "(|(&(objectClass=GroupOfNames)(member=%{Ldap-UserDn}))(&(objectClass=GroupOfUniqueNames)(uniquemember=%{Ldap-UserDn})))"},
349         {"groupmembership_attribute", PW_TYPE_STRING_PTR, offsetof(ldap_instance,groupmemb_attr), NULL, NULL},
350         {"dictionary_mapping", PW_TYPE_STRING_PTR, offsetof(ldap_instance,dictionary_mapping), NULL, "${confdir}/ldap.attrmap"},
351         {"ldap_debug", PW_TYPE_INTEGER, offsetof(ldap_instance,ldap_debug), NULL, "0x0000"},
352         {"ldap_connections_number", PW_TYPE_INTEGER, offsetof(ldap_instance,num_conns), NULL, "5"},
353         {"compare_check_items", PW_TYPE_BOOLEAN, offsetof(ldap_instance,do_comp), NULL, "no"},
354         {"access_attr_used_for_allow", PW_TYPE_BOOLEAN, offsetof(ldap_instance,default_allow), NULL, "yes"},
355         {"do_xlat", PW_TYPE_BOOLEAN, offsetof(ldap_instance,do_xlat), NULL, "yes"},
356 #ifdef NOVELL
357         {"edir_account_policy_check", PW_TYPE_BOOLEAN, offsetof(ldap_instance,edir_account_policy_check), NULL, "yes"},
358 #endif
359
360         {"set_auth_type", PW_TYPE_BOOLEAN, offsetof(ldap_instance,set_auth_type), NULL, "yes"},
361         {NULL, -1, 0, NULL, NULL}
362 };
363
364 #define ld_valid                ld_options.ldo_valid
365 #define LDAP_VALID_SESSION      0x2
366 #define LDAP_VALID(ld)  ( (ld)->ld_valid == LDAP_VALID_SESSION )
367
368 #ifdef FIELDCPY
369 static void     fieldcpy(char *, char **);
370 #endif
371 static VALUE_PAIR *ldap_pairget(LDAP *, LDAPMessage *, TLDAP_RADIUS *,VALUE_PAIR **,char);
372 static int ldap_groupcmp(void *, REQUEST *, VALUE_PAIR *, VALUE_PAIR *, VALUE_PAIR *, VALUE_PAIR **);
373 static int ldap_xlat(void *, REQUEST *, char *, char *, size_t, RADIUS_ESCAPE_STRING);
374 static LDAP    *ldap_connect(void *instance, const char *, const char *, int, int *, char **);
375 static int     read_mappings(ldap_instance* inst);
376
377 static inline int ldap_get_conn(LDAP_CONN *conns,LDAP_CONN **ret,void *instance)
378 {
379         ldap_instance *inst = instance;
380         register int i = 0;
381
382         for(i=0;i<inst->num_conns;i++){
383                 DEBUG("rlm_ldap: ldap_get_conn: Checking Id: %d",i);
384                 if (conns[i].locked == 0 && pthread_mutex_trylock(&(conns[i].mutex)) == 0){
385                         *ret = &conns[i];
386                         conns[i].locked = 1;
387                         DEBUG("rlm_ldap: ldap_get_conn: Got Id: %d",i);
388                         return i;
389                 }
390         }
391
392         return -1;
393 }
394
395 static inline void ldap_release_conn(int i, LDAP_CONN *conns)
396 {
397         DEBUG("rlm_ldap: ldap_release_conn: Release Id: %d",i);
398         conns[i].locked = 0;
399         pthread_mutex_unlock(&(conns[i].mutex));
400 }
401
402 /*************************************************************************
403  *
404  *      Function: rlm_ldap_instantiate
405  *
406  *      Purpose: Uses section of radiusd config file passed as parameter
407  *               to create an instance of the module.
408  *
409  *************************************************************************/
410 static int
411 ldap_instantiate(CONF_SECTION * conf, void **instance)
412 {
413         ldap_instance  *inst;
414         int i = 0;
415         int atts_num = 0;
416         int reply_map_num = 0;
417         int check_map_num = 0;
418         int att_map[3] = {0,0,0};
419         TLDAP_RADIUS *pair;
420         ATTR_FLAGS flags;
421         char *xlat_name;
422         DICT_VALUE *dv;
423
424         inst = rad_malloc(sizeof *inst);
425         if (!inst) {
426                 return -1;
427         }
428         memset(inst, 0, sizeof(*inst));
429
430         if (cf_section_parse(conf, inst, module_config) < 0) {
431                 free(inst);
432                 return -1;
433         }
434
435         if (inst->server == NULL) {
436                 radlog(L_ERR, "rlm_ldap: missing 'server' directive.");
437                 free(inst);
438                 return -1;
439         }
440         inst->is_url = 0;
441         if (ldap_is_ldap_url(inst->server)){
442 #ifdef HAVE_LDAP_INITIALIZE
443                 inst->is_url = 1;
444                 inst->port = 0;
445 #else
446                 radlog(L_ERR, "rlm_ldap: 'server' directive is in URL form but ldap_initialize() is not available.");
447                 free(inst);
448                 return -1;
449 #endif
450         }
451
452         inst->timeout.tv_usec = 0;
453         inst->net_timeout.tv_usec = 0;
454         /* workaround for servers which support LDAPS but not START TLS */
455         if(inst->port == LDAPS_PORT || inst->tls_mode)
456                 inst->tls_mode = LDAP_OPT_X_TLS_HARD;
457         else
458                 inst->tls_mode = 0;
459         inst->reply_item_map = NULL;
460         inst->check_item_map = NULL;
461         inst->conns = NULL;
462         inst->failed_conns = 0;
463
464         DEBUG("rlm_ldap: Registering ldap_groupcmp for Ldap-Group");
465         paircompare_register(PW_LDAP_GROUP, PW_USER_NAME, ldap_groupcmp, inst);
466
467         xlat_name = cf_section_name2(conf);
468         if (xlat_name != NULL){
469                 char *group_name;
470                 DICT_ATTR *dattr;
471
472                 /*
473                  * Allocate room for <instance>-Ldap-Group
474                  */
475                 group_name = malloc((strlen(xlat_name) + 1 + 11) * sizeof(char));
476                 rad_assert(group_name != NULL);
477                 sprintf(group_name,"%s-Ldap-Group",xlat_name);
478                 DEBUG("rlm_ldap: Creating new attribute %s",group_name);
479                 dict_addattr(group_name, 0, PW_TYPE_STRING, -1, flags);
480                 dattr = dict_attrbyname(group_name);
481                 if (dattr == NULL){
482                         radlog(L_ERR, "rlm_ldap: Failed to create attribute %s",group_name);
483                         free(inst);
484                         return -1;
485                 }
486                 DEBUG("rlm_ldap: Registering ldap_groupcmp for %s",group_name);
487                 paircompare_register(dattr->attr, PW_USER_NAME, ldap_groupcmp, inst);
488         }
489         else {
490                 xlat_name = cf_section_name1(conf);
491                 rad_assert(xlat_name != NULL); /* or all hell breaks loose */
492         }
493         inst->xlat_name = strdup(xlat_name);
494         DEBUG("rlm_ldap: Registering ldap_xlat with xlat_name %s",xlat_name);
495         xlat_register(xlat_name,ldap_xlat,inst);
496
497         /*
498          *      Over-ride set_auth_type if there's no Auth-Type of our name.
499          *      This automagically catches the case where LDAP is listed
500          *      in "authorize", but not "authenticate".
501          */
502         dv = dict_valbyname(PW_AUTH_TYPE, xlat_name);
503         if (!dv) {
504                 if (inst->set_auth_type) {
505                         DEBUG2("rlm_ldap: Over-riding set_auth_type, as we're not listed in the \"authenticate\" section.");
506                 }
507           inst->set_auth_type = 0;
508         }
509
510 #ifdef NOVELL
511         /*
512          * (LDAP_Instance, V1) attribute-value pair in the config items list means
513          * that the 'authorize' method of the instance 'V1' of the LDAP module has
514          * processed this request.
515          */
516         dict_addattr("LDAP-Instance", 0, PW_TYPE_STRING, -1, flags);
517         /*
518          * ('eDir-APC', '1') in config items list => Do not perform eDirectory account
519          *                                           policy check (APC)
520          * ('eDir-APC', '2') in config items list => Perform eDirectory APC
521          * ('eDir-APC', '3') in config items list => eDirectory APC has been completed
522          */
523         dict_addattr("eDir-APC", 0, PW_TYPE_INTEGER, -1, flags);
524 #endif
525
526         if (inst->num_conns <= 0){
527                 radlog(L_ERR, "rlm_ldap: Invalid ldap connections number passed.");
528                 free(inst);
529                 return -1;
530         }
531         inst->conns = (LDAP_CONN *)malloc(sizeof(LDAP_CONN)*inst->num_conns);
532         if (inst->conns == NULL){
533                 radlog(L_ERR, "rlm_ldap: Could not allocate memory. Aborting.");
534                 free(inst);
535                 return -1;
536         }
537         for(;i<inst->num_conns;i++){
538                 inst->conns[i].bound = 0;
539                 inst->conns[i].locked = 0;
540                 inst->conns[i].failed_conns = 0;
541                 inst->conns[i].ld = NULL;
542                 pthread_mutex_init(&inst->conns[i].mutex, NULL);
543         }
544
545 #ifdef NOVELL
546         /*
547          * 'inst->apc_conns' is a separate connection pool to be used for performing
548          * eDirectory account policy check in the 'postauth' method. This avoids
549          * changing the (RADIUS server) credentials associated with the 'inst->conns'
550          * connection pool.
551          */
552         inst->apc_conns = (LDAP_CONN *)malloc(sizeof(LDAP_CONN)*inst->num_conns);
553         if (inst->apc_conns == NULL){
554                 radlog(L_ERR, "rlm_ldap: Could not allocate memory. Aborting.");
555                 free(inst);
556                 return -1;
557         }
558         for(i = 0; i < inst->num_conns; i++){
559                 inst->apc_conns[i].bound = 0;
560                 inst->apc_conns[i].locked = 0;
561                 inst->apc_conns[i].failed_conns = 0;
562                 inst->apc_conns[i].ld = NULL;
563                 pthread_mutex_init(&inst->apc_conns[i].mutex, NULL);
564         }
565 #endif
566
567         if (read_mappings(inst) != 0) {
568                 radlog(L_ERR, "rlm_ldap: Reading dictionary mappings from file %s failed",
569                        inst->dictionary_mapping);
570                 free(inst);
571                 return -1;
572         }
573         if (inst->check_item_map == NULL && inst->reply_item_map == NULL){
574                 radlog(L_ERR, "rlm_ldap: dictionary mappings file %s did not contain any mappings",
575                         inst->dictionary_mapping);
576                 free(inst);
577                 return -1;
578         }
579
580         pair = inst->check_item_map;
581         while(pair != NULL){
582                 atts_num++;
583                 pair = pair->next;
584         }
585         check_map_num = (atts_num - 1);
586         pair = inst->reply_item_map;
587         while(pair != NULL){
588                 atts_num++;
589                 pair = pair->next;
590         }
591         reply_map_num = (atts_num - 1);
592         if (inst->profile_attr)
593                 atts_num++;
594         if (inst->passwd_attr)
595                 atts_num++;
596         if (inst->access_attr)
597                 atts_num++;
598         inst->atts = (char **)malloc(sizeof(char *)*(atts_num + 1));
599         if (inst->atts == NULL){
600                 radlog(L_ERR, "rlm_ldap: Could not allocate memory. Aborting.");
601                 free(inst);
602                 return -1;
603         }
604         pair = inst->check_item_map;
605         if (pair == NULL)
606                 pair = inst->reply_item_map;
607         for(i=0;i<atts_num;i++){
608                 if (i <= check_map_num ){
609                         inst->atts[i] = pair->attr;
610                         if (i == check_map_num)
611                                 pair = inst->reply_item_map;
612                         else
613                                 pair = pair->next;
614                 }
615                 else if (i <= reply_map_num){
616                         inst->atts[i] = pair->attr;
617                         pair = pair->next;
618                 }
619                 else{
620                         if (inst->profile_attr && !att_map[0]){
621                                 inst->atts[i] = inst->profile_attr;
622                                 att_map[0] = 1;
623                         }
624                         else if (inst->passwd_attr && !att_map[1]){
625                                 inst->atts[i] = inst->passwd_attr;
626                                 att_map[1] = 1;
627                         }
628                         else if (inst->access_attr && !att_map[2]){
629                                 inst->atts[i] = inst->access_attr;
630                                 att_map[2] = 1;
631                         }
632                 }
633         }
634         inst->atts[atts_num] = NULL;
635
636         DEBUG("conns: %p",inst->conns);
637
638         *instance = inst;
639
640
641         return 0;
642 }
643
644
645 /*
646  * read_mappings(...) reads a ldap<->radius mappings file to inst->reply_item_map and inst->check_item_map
647  */
648
649 #define MAX_LINE_LEN 160
650 #define GENERIC_ATTRIBUTE_ID "$GENERIC$"
651
652 static int
653 read_mappings(ldap_instance* inst)
654 {
655         FILE* mapfile;
656         char *filename;
657         /* all buffers are of MAX_LINE_LEN so we can use sscanf without being afraid of buffer overflows */
658         char buf[MAX_LINE_LEN], itemType[MAX_LINE_LEN], radiusAttribute[MAX_LINE_LEN], ldapAttribute[MAX_LINE_LEN];
659         int linenumber;
660
661         /* open the mappings file for reading */
662
663         filename = inst->dictionary_mapping;
664         DEBUG("rlm_ldap: reading ldap<->radius mappings from file %s", filename);
665         mapfile = fopen(filename, "r");
666
667         if (mapfile == NULL) {
668                 radlog(L_ERR, "rlm_ldap: Opening file %s failed", filename);
669                 return -1; /* error */
670         }
671
672         /* read file line by line. Note that if line length exceed MAX_LINE_LEN, line numbers will be mixed up */
673
674         linenumber = 0;
675
676         while (fgets(buf, sizeof buf, mapfile)!=NULL) {
677                 char* ptr;
678                 int token_count;
679                 TLDAP_RADIUS* pair;
680
681                 linenumber++;
682
683                 /* strip comments */
684                 ptr = strchr(buf, '#');
685                 if (ptr) *ptr = 0;
686
687                 /* empty line */
688                 if (buf[0] == 0) continue;
689
690                 /* extract tokens from the string */
691                 token_count = sscanf(buf, "%s %s %s", itemType, radiusAttribute, ldapAttribute);
692
693                 if (token_count <= 0) /* no tokens */
694                         continue;
695
696                 if (token_count != 3) {
697                         radlog(L_ERR, "rlm_ldap: Skipping %s line %i: %s", filename, linenumber, buf);
698                         radlog(L_ERR, "rlm_ldap: Expected 3 tokens "
699                                "(Item type, RADIUS Attribute and LDAP Attribute) but found only %i", token_count);
700                         continue;
701                 }
702
703                 /* create new TLDAP_RADIUS list node */
704                 pair = rad_malloc(sizeof(TLDAP_RADIUS));
705
706                 pair->attr = strdup(ldapAttribute);
707                 pair->radius_attr = strdup(radiusAttribute);
708
709                 if ( (pair->attr == NULL) || (pair->radius_attr == NULL) ) {
710                         radlog(L_ERR, "rlm_ldap: Out of memory");
711                         if (pair->attr) free(pair->attr);
712                         if (pair->radius_attr) free(pair->radius_attr);
713                         free(pair);
714                         fclose(mapfile);
715                         return -1;
716                 }
717
718                 /* push node to correct list */
719                 if (strcasecmp(itemType, "checkItem") == 0) {
720                         pair->next = inst->check_item_map;
721                         inst->check_item_map = pair;
722                 } else if (strcasecmp(itemType, "replyItem") == 0) {
723                         pair->next = inst->reply_item_map;
724                         inst->reply_item_map = pair;
725                 } else {
726                         radlog(L_ERR, "rlm_ldap: file %s: skipping line %i: unknown itemType %s",
727                                filename, linenumber, itemType);
728                         free(pair->attr);
729                         free(pair->radius_attr);
730                         free(pair);
731                         continue;
732                 }
733
734                 DEBUG("rlm_ldap: LDAP %s mapped to RADIUS %s",
735                       pair->attr, pair->radius_attr);
736         }
737
738         fclose(mapfile);
739
740         return 0; /* success */
741 }
742
743 static int
744 perform_search(void *instance, LDAP_CONN *conn, char *search_basedn, int scope, char *filter,
745                 char **attrs, LDAPMessage ** result)
746 {
747         int             res = RLM_MODULE_OK;
748         int             ldap_errno = 0;
749         ldap_instance  *inst = instance;
750         int             search_retry = 0;
751
752         *result = NULL;
753
754         if (!conn){
755                 radlog(L_ERR, "rlm_ldap: NULL connection handle passed");
756                 return RLM_MODULE_FAIL;
757         }
758         if (conn->failed_conns > MAX_FAILED_CONNS_START){
759                 conn->failed_conns++;
760                 if (conn->failed_conns >= MAX_FAILED_CONNS_END){
761                         conn->failed_conns = MAX_FAILED_CONNS_RESTART;
762                         conn->bound = 0;
763                 }
764         }
765 retry:
766         if (!conn->bound || conn->ld == NULL) {
767                 DEBUG2("rlm_ldap: attempting LDAP reconnection");
768                 if (conn->ld){
769                         DEBUG2("rlm_ldap: closing existing LDAP connection");
770                         ldap_unbind_s(conn->ld);
771                 }
772                 if ((conn->ld = ldap_connect(instance, inst->login,
773                                              inst->password, 0, &res, NULL)) == NULL) {
774                         radlog(L_ERR, "rlm_ldap: (re)connection attempt failed");
775                         if (search_retry == 0)
776                                 conn->failed_conns++;
777                         return (RLM_MODULE_FAIL);
778                 }
779                 conn->bound = 1;
780                 conn->failed_conns = 0;
781         }
782         DEBUG2("rlm_ldap: performing search in %s, with filter %s", search_basedn ? search_basedn : "(null)" , filter);
783         switch (ldap_search_st(conn->ld, search_basedn, scope, filter, attrs, 0, &(inst->timeout), result)) {
784         case LDAP_SUCCESS:
785         case LDAP_NO_SUCH_OBJECT:
786                 break;
787         case LDAP_SERVER_DOWN:
788                 radlog(L_ERR, "rlm_ldap: ldap_search() failed: LDAP connection lost.");
789                 conn->failed_conns++;
790                 if (search_retry == 0){
791                         if (conn->failed_conns <= MAX_FAILED_CONNS_START){
792                                 radlog(L_INFO, "rlm_ldap: Attempting reconnect");
793                                 search_retry = 1;
794                                 conn->bound = 0;
795                                 ldap_msgfree(*result);
796                                 goto retry;
797                         }
798                 }
799                 ldap_msgfree(*result);
800                 return RLM_MODULE_FAIL;
801         case LDAP_INSUFFICIENT_ACCESS:
802                 radlog(L_ERR, "rlm_ldap: ldap_search() failed: Insufficient access. Check the identity and password configuration directives.");
803                 ldap_msgfree(*result);
804                 return RLM_MODULE_FAIL;
805         case LDAP_TIMEOUT:
806                 radlog(L_ERR, "rlm_ldap: ldap_search() failed: Timed out while waiting for server to respond. Please increase the timeout.");
807                 ldap_msgfree(*result);
808                 return RLM_MODULE_FAIL;
809         case LDAP_FILTER_ERROR:
810                 radlog(L_ERR, "rlm_ldap: ldap_search() failed: Bad search filter: %s",filter);
811                 ldap_msgfree(*result);
812                 return RLM_MODULE_FAIL;
813         case LDAP_TIMELIMIT_EXCEEDED:
814         case LDAP_BUSY:
815         case LDAP_UNAVAILABLE:
816                 /* We don't need to reconnect in these cases so we don't set conn->bound */
817                 ldap_get_option(conn->ld, LDAP_OPT_ERROR_NUMBER, &ldap_errno);
818                 radlog(L_ERR, "rlm_ldap: ldap_search() failed: %s", ldap_err2string(ldap_errno));
819                 ldap_msgfree(*result);
820                 return (RLM_MODULE_FAIL);
821         default:
822                 ldap_get_option(conn->ld, LDAP_OPT_ERROR_NUMBER, &ldap_errno);
823                 radlog(L_ERR, "rlm_ldap: ldap_search() failed: %s", ldap_err2string(ldap_errno));
824                 conn->bound = 0;
825                 ldap_msgfree(*result);
826                 return (RLM_MODULE_FAIL);
827         }
828
829         if ((ldap_count_entries(conn->ld, *result)) != 1) {
830                 DEBUG("rlm_ldap: object not found or got ambiguous search result");
831                 res = RLM_MODULE_NOTFOUND;
832                 ldap_msgfree(*result);
833         }
834         return res;
835 }
836
837
838 /*
839  *      Translate the LDAP queries.
840  */
841 static int ldap_escape_func(char *out, int outlen, const char *in)
842 {
843         int len = 0;
844
845         while (in[0]) {
846                 /*
847                  *      Encode unsafe characters.
848                  */
849                 if (strchr("*=\\,()", *in)) {
850                         static const char hex[] = "0123456789abcdef";
851
852                         /*
853                          *      Only 3 or less bytes available.
854                          */
855                         if (outlen <= 3) {
856                                 break;
857                         }
858
859                         *(out++) = '\\';
860                         *(out++) = hex[((*in) >> 4) & 0x0f];
861                         *(out++) = hex[(*in) & 0x0f];
862                         outlen -= 3;
863                         len += 3;
864                         in++;
865                         continue;
866                 }
867
868                 /*
869                  *      Only one byte left.
870                  */
871                 if (outlen <= 1) {
872                         break;
873                 }
874
875                 /*
876                  *      Allowed character.
877                  */
878                 *(out++) = *(in++);
879                 outlen--;
880                 len++;
881         }
882         *out = '\0';
883         return len;
884 }
885
886 /*
887  * ldap_groupcmp(). Implement the Ldap-Group == "group" filter
888  */
889
890 static int ldap_groupcmp(void *instance, REQUEST *req, VALUE_PAIR *request, VALUE_PAIR *check,
891                 VALUE_PAIR *check_pairs, VALUE_PAIR **reply_pairs)
892 {
893         char            filter[MAX_FILTER_STR_LEN];
894         char            gr_filter[MAX_FILTER_STR_LEN];
895         int             res;
896         LDAPMessage     *result = NULL;
897         LDAPMessage     *msg = NULL;
898         char            basedn[MAX_FILTER_STR_LEN];
899         char            *attrs[] = {"dn",NULL};
900         char            **vals;
901         ldap_instance   *inst = instance;
902         char            *group_attrs[] = {inst->groupmemb_attr,NULL};
903         LDAP_CONN       *conn;
904         int             conn_id = -1;
905         VALUE_PAIR      *vp_user_dn;
906         VALUE_PAIR      **request_pairs;
907
908         request_pairs = &req->packet->vps;
909
910         DEBUG("rlm_ldap: Entering ldap_groupcmp()");
911
912         if (check->strvalue == NULL || check->length == 0){
913                 DEBUG("rlm_ldap::ldap_groupcmp: Illegal group name");
914                 return 1;
915         }
916
917         if (req == NULL){
918                 DEBUG("rlm_ldap::ldap_groupcmp: NULL request");
919                 return 1;
920         }
921
922         if (!radius_xlat(basedn, sizeof(basedn), inst->basedn, req, NULL)) {
923                 DEBUG("rlm_ldap::ldap_groupcmp: unable to create basedn.");
924                 return 1;
925         }
926
927         while((vp_user_dn = pairfind(*request_pairs, PW_LDAP_USERDN)) == NULL){
928                 char            *user_dn = NULL;
929
930                 if (!radius_xlat(filter, sizeof(filter), inst->filter,
931                                         req, ldap_escape_func)){
932                         DEBUG("rlm_ldap::ldap_groupcmp: unable to create filter");
933                         return 1;
934                 }
935                 if ((conn_id = ldap_get_conn(inst->conns,&conn,inst)) == -1){
936                         radlog(L_ERR, "rlm_ldap: All ldap connections are in use");
937                         return 1;
938                 }
939                 if ((res = perform_search(inst, conn, basedn, LDAP_SCOPE_SUBTREE,
940                                         filter, attrs, &result)) != RLM_MODULE_OK){
941                         DEBUG("rlm_ldap::ldap_groupcmp: search failed");
942                         ldap_release_conn(conn_id,inst->conns);
943                         return 1;
944                 }
945                 if ((msg = ldap_first_entry(conn->ld, result)) == NULL) {
946                         DEBUG("rlm_ldap::ldap_groupcmp: ldap_first_entry() failed");
947                         ldap_release_conn(conn_id,inst->conns);
948                         ldap_msgfree(result);
949                         return 1;
950                 }
951                 if ((user_dn = ldap_get_dn(conn->ld, msg)) == NULL) {
952                         DEBUG("rlm_ldap:ldap_groupcmp:: ldap_get_dn() failed");
953                         ldap_release_conn(conn_id,inst->conns);
954                         ldap_msgfree(result);
955                         return 1;
956                 }
957                 ldap_release_conn(conn_id,inst->conns);
958                 /*
959                 * Adding new attribute containing DN for LDAP object associated with
960                 * given username
961                 */
962                 pairadd(request_pairs, pairmake("Ldap-UserDn", user_dn, T_OP_EQ));
963                 ldap_memfree(user_dn);
964                 ldap_msgfree(result);
965         }
966
967         if(!radius_xlat(gr_filter, sizeof(gr_filter), inst->groupmemb_filt, req, NULL)){
968                 DEBUG("rlm_ldap::ldap_groupcmp: unable to create filter.");
969                 return 1;
970         }
971
972         if (strchr((char *)check->strvalue,',') != NULL) {
973                 /* This looks like a DN */
974                 snprintf(filter,sizeof(filter), "%s",gr_filter);
975                 snprintf(basedn,sizeof(basedn), "%s",(char *)check->strvalue);
976         } else
977                 snprintf(filter,sizeof(filter), "(&(%s=%s)%s)",inst->groupname_attr,(char *)check->strvalue,gr_filter);
978
979         if ((conn_id = ldap_get_conn(inst->conns,&conn,inst)) == -1){
980                 radlog(L_ERR, "rlm_ldap: All ldap connections are in use");
981                 return 1;
982         }
983
984         if ((res = perform_search(inst, conn, basedn, LDAP_SCOPE_SUBTREE,
985                                 filter, attrs, &result)) == RLM_MODULE_OK){
986                 DEBUG("rlm_ldap::ldap_groupcmp: User found in group %s",
987                                 (char *)check->strvalue);
988                 ldap_msgfree(result);
989                 ldap_release_conn(conn_id,inst->conns);
990                 return 0;
991         }
992
993         ldap_release_conn(conn_id,inst->conns);
994
995         if (res != RLM_MODULE_NOTFOUND ) {
996                 DEBUG("rlm_ldap::ldap_groupcmp: Search returned error");
997                 return 1;
998         }
999
1000         if (inst->groupmemb_attr == NULL){
1001                 /* search returned NOTFOUND and searching for membership
1002                  * using user object attributes is not specified in config
1003                  * file
1004                  */
1005                 DEBUG("rlm_ldap::ldap_groupcmp: Group %s not found or user is not a member.",(char *)check->strvalue);
1006                 return 1;
1007         }
1008
1009         snprintf(filter,sizeof(filter), "(objectclass=*)");
1010         if ((conn_id = ldap_get_conn(inst->conns,&conn,inst)) == -1){
1011                 radlog(L_ERR, "rlm_ldap: Add ldap connections are in use");
1012                 return 1;
1013         }
1014         if ((res = perform_search(inst, conn, vp_user_dn->strvalue, LDAP_SCOPE_BASE,
1015                                         filter, group_attrs,&result)) != RLM_MODULE_OK){
1016                 DEBUG("rlm_ldap::ldap_groupcmp: Search returned error");
1017                 ldap_release_conn(conn_id, inst->conns);
1018                 return 1;
1019         }
1020
1021         if ((msg = ldap_first_entry(conn->ld, result)) == NULL) {
1022                 DEBUG("rlm_ldap::ldap_groupcmp: ldap_first_entry() failed");
1023                 ldap_release_conn(conn_id,inst->conns);
1024                 ldap_msgfree(result);
1025                 return 1;
1026         }
1027         if ((vals = ldap_get_values(conn->ld, msg, inst->groupmemb_attr)) != NULL) {
1028                 unsigned int i = 0;
1029                 char found = 0;
1030                 for (;i < ldap_count_values(vals);i++){
1031                         if (strchr(vals[i],',') != NULL){
1032                                 /* This looks like a DN */
1033                                 LDAPMessage *gr_result = NULL;
1034                                 snprintf(filter,sizeof(filter), "(%s=%s)",
1035                                         inst->groupname_attr,
1036                                         (char *)check->strvalue);
1037                                 if ((res = perform_search(inst, conn, vals[i],
1038                                                 LDAP_SCOPE_BASE, filter,
1039                                                 attrs, &gr_result)) != RLM_MODULE_OK){
1040                                         if (res != RLM_MODULE_NOTFOUND){
1041                                                 DEBUG("rlm_ldap::ldap_groupcmp: \
1042                                                         Search returned error");
1043                                                 ldap_value_free(vals);
1044                                                 ldap_msgfree(result);
1045                                                 ldap_release_conn(conn_id,inst->conns);
1046                                                 return 1;
1047                                         }
1048                                 } else {
1049                                         ldap_msgfree(gr_result);
1050                                         found = 1;
1051                                         break;
1052                                 }
1053                         } else {
1054                                 if (strcmp(vals[i],(char *)check->strvalue) == 0){
1055                                         found = 1;
1056                                         break;
1057                                 }
1058                         }
1059                 }
1060                 ldap_value_free(vals);
1061                 ldap_msgfree(result);
1062                 if (found == 0){
1063                         DEBUG("rlm_ldap::groupcmp: Group %s not found \
1064                                 or user not a member",
1065                                 (char *)check->strvalue);
1066                         ldap_release_conn(conn_id,inst->conns);
1067                         return 1;
1068                 }
1069         } else {
1070                         DEBUG("rlm_ldap::ldap_groupcmp: ldap_get_values() failed");
1071                         ldap_msgfree(result);
1072                         ldap_release_conn(conn_id,inst->conns);
1073                         return 1;
1074         }
1075
1076         DEBUG("rlm_ldap::ldap_groupcmp: User found in group %s",(char *)check->strvalue);
1077         ldap_release_conn(conn_id,inst->conns);
1078
1079         return 0;
1080 }
1081
1082 /*
1083  * ldap_xlat()
1084  * Do an xlat on an LDAP URL
1085  */
1086
1087 static int ldap_xlat(void *instance, REQUEST *request, char *fmt, char *out,
1088                      size_t freespace, RADIUS_ESCAPE_STRING func)
1089 {
1090         char url[MAX_FILTER_STR_LEN];
1091         int res;
1092         int ret = 0;
1093         ldap_instance *inst = instance;
1094         LDAPURLDesc *ldap_url;
1095         LDAPMessage *result = NULL;
1096         LDAPMessage *msg = NULL;
1097         char **vals;
1098         int conn_id = -1;
1099         LDAP_CONN *conn;
1100
1101         DEBUG("rlm_ldap: - ldap_xlat");
1102         if (!radius_xlat(url, sizeof(url), fmt, request, func)) {
1103                 radlog (L_ERR, "rlm_ldap: Unable to create LDAP URL.\n");
1104                 return 0;
1105         }
1106         if (!ldap_is_ldap_url(url)){
1107                 radlog (L_ERR, "rlm_ldap: String passed does not look like an LDAP URL.\n");
1108                 return 0;
1109         }
1110         if (ldap_url_parse(url,&ldap_url)){
1111                 radlog (L_ERR, "rlm_ldap: LDAP URL parse failed.\n");
1112                 return 0;
1113         }
1114         if (ldap_url->lud_attrs == NULL || ldap_url->lud_attrs[0] == NULL || \
1115                 ( ldap_url->lud_attrs[1] != NULL || ( ! strlen(ldap_url->lud_attrs[0]) || \
1116                 ! strcmp(ldap_url->lud_attrs[0],"*") ) ) ){
1117                 radlog (L_ERR, "rlm_ldap: Invalid Attribute(s) request.\n");
1118                 ldap_free_urldesc(ldap_url);
1119                 return 0;
1120         }
1121         if (ldap_url->lud_host){
1122                 if (strncmp(inst->server,ldap_url->lud_host,strlen(inst->server)) != 0 || \
1123                                 ldap_url->lud_port != inst->port){
1124                         DEBUG("rlm_ldap: Requested server/port is not known to this module instance.");
1125                         ldap_free_urldesc(ldap_url);
1126                         return 0;
1127                 }
1128         }
1129         if ((conn_id = ldap_get_conn(inst->conns,&conn,inst)) == -1){
1130                 radlog(L_ERR, "rlm_ldap: All ldap connections are in use");
1131                 ldap_free_urldesc(ldap_url);
1132                 return 0;
1133         }
1134         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){
1135                 if (res == RLM_MODULE_NOTFOUND){
1136                         DEBUG("rlm_ldap: Search returned not found");
1137                         ldap_free_urldesc(ldap_url);
1138                         ldap_release_conn(conn_id,inst->conns);
1139                         return 0;
1140                 }
1141                 DEBUG("rlm_ldap: Search returned error");
1142                 ldap_free_urldesc(ldap_url);
1143                 ldap_release_conn(conn_id,inst->conns);
1144                 return 0;
1145         }
1146         if ((msg = ldap_first_entry(conn->ld, result)) == NULL){
1147                 DEBUG("rlm_ldap: ldap_first_entry() failed");
1148                 ldap_msgfree(result);
1149                 ldap_free_urldesc(ldap_url);
1150                 ldap_release_conn(conn_id,inst->conns);
1151                 return 0;
1152         }
1153         if ((vals = ldap_get_values(conn->ld, msg, ldap_url->lud_attrs[0])) != NULL) {
1154                 ret = strlen(vals[0]);
1155                 if (ret > freespace){
1156                         DEBUG("rlm_ldap: Insufficient string space");
1157                         ldap_free_urldesc(ldap_url);
1158                         ldap_value_free(vals);
1159                         ldap_msgfree(result);
1160                         ldap_release_conn(conn_id,inst->conns);
1161                         return 0;
1162                 }
1163                 DEBUG("rlm_ldap: Adding attribute %s, value: %s",ldap_url->lud_attrs[0],vals[0]);
1164                 strncpy(out,vals[0],ret);
1165                 ldap_value_free(vals);
1166         }
1167         else
1168                 ret = 0;
1169
1170         ldap_msgfree(result);
1171         ldap_free_urldesc(ldap_url);
1172         ldap_release_conn(conn_id,inst->conns);
1173
1174         DEBUG("rlm_ldap: - ldap_xlat end");
1175
1176         return ret;
1177 }
1178
1179
1180 /******************************************************************************
1181  *
1182  *      Function: rlm_ldap_authorize
1183  *
1184  *      Purpose: Check if user is authorized for remote access
1185  *
1186  ******************************************************************************/
1187 static int
1188 ldap_authorize(void *instance, REQUEST * request)
1189 {
1190         LDAPMessage     *result = NULL;
1191         LDAPMessage     *msg = NULL;
1192         LDAPMessage     *def_msg = NULL;
1193         LDAPMessage     *def_attr_msg = NULL;
1194         LDAPMessage     *def_result = NULL;
1195         LDAPMessage     *def_attr_result = NULL;
1196         ldap_instance   *inst = instance;
1197         char            *user_dn = NULL;
1198         char            filter[MAX_FILTER_STR_LEN];
1199         char            basedn[MAX_FILTER_STR_LEN];
1200         VALUE_PAIR      *check_tmp;
1201         VALUE_PAIR      *reply_tmp;
1202         int             res;
1203         VALUE_PAIR      **check_pairs, **reply_pairs;
1204         char            **vals;
1205         VALUE_PAIR      *module_fmsg_vp;
1206         VALUE_PAIR      *user_profile;
1207         char            module_fmsg[MAX_STRING_LEN];
1208         LDAP_CONN       *conn;
1209         int             conn_id = -1;
1210
1211         DEBUG("rlm_ldap: - authorize");
1212
1213         if (!request->username){
1214                 radlog(L_AUTH, "rlm_ldap: Attribute \"User-Name\" is required for authentication.\n");
1215                 return RLM_MODULE_INVALID;
1216         }
1217
1218         check_pairs = &request->config_items;
1219         reply_pairs = &request->reply->vps;
1220
1221         /*
1222          * Check for valid input, zero length names not permitted
1223          */
1224         if (request->username->strvalue == 0) {
1225                 radlog(L_ERR, "rlm_ldap: zero length username not permitted\n");
1226                 return RLM_MODULE_INVALID;
1227         }
1228         DEBUG("rlm_ldap: performing user authorization for %s",
1229                request->username->strvalue);
1230
1231         if (!radius_xlat(filter, sizeof(filter), inst->filter,
1232                          request, ldap_escape_func)) {
1233                 radlog (L_ERR, "rlm_ldap: unable to create filter.\n");
1234                 return RLM_MODULE_INVALID;
1235         }
1236
1237         if (!radius_xlat(basedn, sizeof(basedn), inst->basedn,
1238                          request, NULL)) {
1239                 radlog (L_ERR, "rlm_ldap: unable to create basedn.\n");
1240                 return RLM_MODULE_INVALID;
1241         }
1242
1243         if ((conn_id = ldap_get_conn(inst->conns,&conn,inst)) == -1){
1244                 radlog(L_ERR, "rlm_ldap: All ldap connections are in use");
1245                 return RLM_MODULE_FAIL;
1246         }
1247         if ((res = perform_search(instance, conn, basedn, LDAP_SCOPE_SUBTREE, filter, inst->atts, &result)) != RLM_MODULE_OK) {
1248                 DEBUG("rlm_ldap: search failed");
1249                 if (res == RLM_MODULE_NOTFOUND){
1250                         snprintf(module_fmsg,sizeof(module_fmsg),"rlm_ldap: User not found");
1251                         module_fmsg_vp = pairmake("Module-Failure-Message", module_fmsg, T_OP_EQ);
1252                         pairadd(&request->packet->vps, module_fmsg_vp);
1253                 }
1254                 ldap_release_conn(conn_id,inst->conns);
1255                 return (res);
1256         }
1257         if ((msg = ldap_first_entry(conn->ld, result)) == NULL) {
1258                 DEBUG("rlm_ldap: ldap_first_entry() failed");
1259                 ldap_msgfree(result);
1260                 ldap_release_conn(conn_id,inst->conns);
1261                 return RLM_MODULE_FAIL;
1262         }
1263         if ((user_dn = ldap_get_dn(conn->ld, msg)) == NULL) {
1264                 DEBUG("rlm_ldap: ldap_get_dn() failed");
1265                 ldap_msgfree(result);
1266                 ldap_release_conn(conn_id,inst->conns);
1267                 return RLM_MODULE_FAIL;
1268         }
1269         /*
1270          * Adding new attribute containing DN for LDAP object associated with
1271          * given username
1272          */
1273         pairadd(&request->packet->vps, pairmake("Ldap-UserDn", user_dn, T_OP_EQ));
1274         ldap_memfree(user_dn);
1275
1276
1277         /* Remote access is controled by attribute of the user object */
1278         if (inst->access_attr) {
1279                 if ((vals = ldap_get_values(conn->ld, msg, inst->access_attr)) != NULL) {
1280                         if (inst->default_allow){
1281                                 DEBUG("rlm_ldap: checking if remote access for %s is allowed by %s", request->username->strvalue, inst->access_attr);
1282                                 if (!strncmp(vals[0], "FALSE", 5)) {
1283                                         DEBUG("rlm_ldap: dialup access disabled");
1284                                         snprintf(module_fmsg,sizeof(module_fmsg),"rlm_ldap: Access Attribute denies access");
1285                                         module_fmsg_vp = pairmake("Module-Failure-Message", module_fmsg, T_OP_EQ);
1286                                         pairadd(&request->packet->vps, module_fmsg_vp);
1287                                         ldap_msgfree(result);
1288                                         ldap_value_free(vals);
1289                                         ldap_release_conn(conn_id,inst->conns);
1290                                         return RLM_MODULE_USERLOCK;
1291                                 }
1292                                 ldap_value_free(vals);
1293                         }
1294                         else{
1295                                 DEBUG("rlm_ldap: %s attribute exists - access denied by default", inst->access_attr);
1296                                 snprintf(module_fmsg,sizeof(module_fmsg),"rlm_ldap: Access Attribute denies access");
1297                                 module_fmsg_vp = pairmake("Module-Failure-Message", module_fmsg, T_OP_EQ);
1298                                 pairadd(&request->packet->vps, module_fmsg_vp);
1299                                 ldap_msgfree(result);
1300                                 ldap_value_free(vals);
1301                                 ldap_release_conn(conn_id,inst->conns);
1302                                 return RLM_MODULE_USERLOCK;
1303                         }
1304                 } else {
1305                         if (inst->default_allow){
1306                                 DEBUG("rlm_ldap: no %s attribute - access denied by default", inst->access_attr);
1307                                 snprintf(module_fmsg,sizeof(module_fmsg),"rlm_ldap: Access Attribute denies access");
1308                                 module_fmsg_vp = pairmake("Module-Failure-Message", module_fmsg, T_OP_EQ);
1309                                 pairadd(&request->packet->vps, module_fmsg_vp);
1310                                 ldap_msgfree(result);
1311                                 ldap_release_conn(conn_id,inst->conns);
1312                                 return RLM_MODULE_USERLOCK;
1313                         }
1314                 }
1315         }
1316
1317         /*
1318          * Check for the default profile entry. If it exists then add the
1319          * attributes it contains in the check and reply pairs
1320          */
1321
1322         user_profile = pairfind(request->config_items, PW_USER_PROFILE);
1323         if (inst->default_profile || user_profile){
1324                 char *profile = inst->default_profile;
1325
1326                 strNcpy(filter,inst->base_filter,sizeof(filter));
1327                 if (user_profile)
1328                         profile = user_profile->strvalue;
1329                 if (profile && strlen(profile)){
1330                         if ((res = perform_search(instance, conn,
1331                                 profile, LDAP_SCOPE_BASE,
1332                                 filter, inst->atts, &def_result)) == RLM_MODULE_OK){
1333                                 if ((def_msg = ldap_first_entry(conn->ld,def_result))){
1334                                         if ((check_tmp = ldap_pairget(conn->ld,def_msg,inst->check_item_map,check_pairs,1))) {
1335                                                 if (inst->do_xlat){
1336                                                         pairxlatmove(request, check_pairs, &check_tmp);
1337                                                         pairfree(&check_tmp);
1338                                                 }
1339                                                 else
1340                                                         pairadd(check_pairs,check_tmp);
1341                                         }
1342                                         if ((reply_tmp = ldap_pairget(conn->ld,def_msg,inst->reply_item_map,reply_pairs,0))) {
1343                                                 if (inst->do_xlat){
1344                                                         pairxlatmove(request, reply_pairs, &reply_tmp);
1345                                                         pairfree(&reply_tmp);
1346                                                 }
1347                                                 else
1348                                                         pairadd(reply_pairs,reply_tmp);
1349                                         }
1350                                 }
1351                                 ldap_msgfree(def_result);
1352                         } else
1353                                 DEBUG("rlm_ldap: default_profile/user-profile search failed");
1354                 }
1355         }
1356
1357         /*
1358          * Check for the profile attribute. If it exists, we assume that it
1359          * contains the DN of an entry containg a profile for the user. That
1360          * way we can have different general profiles for various user groups
1361          * (students,faculty,staff etc)
1362          */
1363
1364         if (inst->profile_attr){
1365                 if ((vals = ldap_get_values(conn->ld, msg, inst->profile_attr)) != NULL) {
1366                         unsigned int i=0;
1367                         strNcpy(filter,inst->base_filter,sizeof(filter));
1368                         while(vals[i] != NULL && strlen(vals[i])){
1369                                 if ((res = perform_search(instance, conn,
1370                                         vals[i], LDAP_SCOPE_BASE,
1371                                         filter, inst->atts, &def_attr_result)) == RLM_MODULE_OK){
1372                                         if ((def_attr_msg = ldap_first_entry(conn->ld,def_attr_result))){
1373                                                 if ((check_tmp = ldap_pairget(conn->ld,def_attr_msg,inst->check_item_map,check_pairs,1))) {
1374                                                         if (inst->do_xlat){
1375                                                                 pairxlatmove(request, check_pairs, &check_tmp);
1376                                                                 pairfree(&check_tmp);
1377                                                         }
1378                                                         else
1379                                                                 pairadd(check_pairs,check_tmp);
1380                                                 }
1381                                                 if ((reply_tmp = ldap_pairget(conn->ld,def_attr_msg,inst->reply_item_map,reply_pairs,0))) {
1382                                                         if (inst->do_xlat){
1383                                                                 pairxlatmove(request, reply_pairs, &reply_tmp);
1384                                                                 pairfree(&reply_tmp);
1385                                                         }
1386                                                         else
1387                                                                 pairadd(reply_pairs,reply_tmp);
1388                                                 }
1389                                         }
1390                                         ldap_msgfree(def_attr_result);
1391                                 } else
1392                                         DEBUG("rlm_ldap: profile_attribute search failed");
1393                                 i++;
1394                         }
1395                         ldap_value_free(vals);
1396                 }
1397         }
1398         if (inst->passwd_attr && strlen(inst->passwd_attr)){
1399 #ifdef NOVELL_UNIVERSAL_PASSWORD
1400                 if(strcasecmp(inst->passwd_attr,"nspmPassword")!= 0){
1401 #endif
1402                 VALUE_PAIR *passwd_item;
1403
1404                 if ((passwd_item = pairfind(request->config_items, PW_PASSWORD)) == NULL){
1405                         char **passwd_vals;
1406                         char *passwd_val = NULL;
1407                         int passwd_len;
1408
1409                         if ((passwd_vals = ldap_get_values(conn->ld,msg,inst->passwd_attr)) != NULL){
1410                                 unsigned int i=0;
1411                                 while(passwd_vals[i] != NULL){
1412                                         if (strlen(passwd_vals[i])){
1413                                                 passwd_val = passwd_vals[i];
1414
1415                                                 if (inst->passwd_hdr && strlen(inst->passwd_hdr)){
1416                                                         passwd_val = strstr(passwd_val,inst->passwd_hdr);
1417                                                         if (passwd_val != NULL)
1418                                                                 passwd_val += strlen(inst->passwd_hdr);
1419                                                         else
1420                                                                 DEBUG("rlm_ldap: Password header not found in password %s for user %s", passwd_vals[0],request->username->strvalue);
1421                                                 }
1422                                                 if (passwd_val){
1423                                                         if ((passwd_item = paircreate(PW_PASSWORD,PW_TYPE_STRING)) == NULL){
1424                                                                 radlog(L_ERR|L_CONS, "no memory");
1425                                                                 ldap_value_free(passwd_vals);
1426                                                                 ldap_msgfree(result);
1427                                                                 ldap_release_conn(conn_id,inst->conns);
1428                                                                 return RLM_MODULE_FAIL;
1429                                                         }
1430                                                         passwd_len = strlen(passwd_val);
1431                                                         strncpy(passwd_item->strvalue,passwd_val,MAX_STRING_LEN - 1);
1432                                                         passwd_item->length = (passwd_len > (MAX_STRING_LEN - 1)) ? (MAX_STRING_LEN - 1) : passwd_len;
1433                                                         pairadd(&request->config_items,passwd_item);
1434                                                         DEBUG("rlm_ldap: Added password %s in check items",passwd_item->strvalue);
1435                                                 }
1436                                         }
1437                                         i++;
1438                                 }
1439                                 ldap_value_free(passwd_vals);
1440                         }
1441                 }
1442 #ifdef NOVELL_UNIVERSAL_PASSWORD
1443                 }
1444                 else{
1445                 /*
1446                 * Read Universal Password from eDirectory
1447                 */
1448                         VALUE_PAIR      *passwd_item;
1449                         VALUE_PAIR      *vp_user_dn;
1450                         int             passwd_len;
1451                         char            *universal_password = NULL;
1452                         int             universal_password_len = UNIVERSAL_PASS_LEN;
1453                         char            *passwd_val = NULL;
1454
1455                         res = 0;
1456
1457                         if ((passwd_item = pairfind(request->config_items, PW_PASSWORD)) == NULL){
1458                         
1459                                 universal_password = rad_malloc(universal_password_len);
1460                                 memset(universal_password, 0, universal_password_len);
1461
1462                                 vp_user_dn = pairfind(request->packet->vps,PW_LDAP_USERDN);
1463                                 res = nmasldap_get_password(conn->ld,vp_user_dn->strvalue,&universal_password_len,universal_password);
1464
1465                                 if (res == 0){
1466                                         passwd_val = universal_password;
1467
1468                                         if (inst->passwd_hdr && strlen(inst->passwd_hdr)){
1469                                                 passwd_val = strstr(passwd_val,inst->passwd_hdr);
1470
1471                                                 if (passwd_val != NULL)
1472                                                         passwd_val += strlen((char*)inst->passwd_hdr);
1473                                                 else
1474                                                         DEBUG("rlm_ldap: Password header not found in password %s for user %s ",passwd_val,request->username->strvalue);
1475                                         }
1476
1477                                         if (passwd_val){
1478                                                 if ((passwd_item = paircreate(PW_PASSWORD,PW_TYPE_STRING)) == NULL){
1479                                                         radlog(L_ERR, "rlm_ldap: Could not allocate memory. Aborting.");
1480                                                         ldap_msgfree(result);
1481                                                         ldap_release_conn(conn_id,inst->conns);
1482                                                         memset(universal_password, 0, universal_password_len);
1483                                                         free(universal_password);
1484                                                         return RLM_MODULE_FAIL;
1485                                                 }
1486
1487                                                 passwd_len = strlen(passwd_val);
1488                                                 strncpy(passwd_item->strvalue,passwd_val,MAX_STRING_LEN - 1);
1489                                                 passwd_item->length = (passwd_len > (MAX_STRING_LEN - 1)) ? (MAX_STRING_LEN - 1) : passwd_len;
1490                                                 pairadd(&request->config_items,passwd_item);
1491
1492 #ifdef NOVELL
1493                                                 {
1494                                                         DICT_ATTR *dattr;
1495                                                         VALUE_PAIR      *vp_inst, *vp_apc;
1496                                                         int inst_attr, apc_attr;
1497
1498                                                         dattr = dict_attrbyname("LDAP-Instance");
1499                                                         inst_attr = dattr->attr;
1500                                                         dattr = dict_attrbyname("eDir-APC");
1501                                                         apc_attr = dattr->attr;
1502
1503                                                         vp_inst = pairfind(request->config_items, inst_attr);
1504                                                         if(vp_inst == NULL){
1505                                                                 /*
1506                                                                  * The authorize method of no other LDAP module instance has
1507                                                                  * processed this request.
1508                                                                  */
1509                                                                 if ((vp_inst = paircreate(inst_attr, PW_TYPE_STRING)) == NULL){
1510                                                                         radlog(L_ERR, "rlm_ldap: Could not allocate memory. Aborting.");
1511                                                                         ldap_msgfree(result);
1512                                                                         ldap_release_conn(conn_id, inst->conns);
1513                                                                         memset(universal_password, 0, universal_password_len);
1514                                                                         free(universal_password);
1515                                                                         return RLM_MODULE_FAIL;
1516                                                                 }
1517                                                                 strcpy(vp_inst->strvalue, inst->xlat_name);
1518                                                                 vp_inst->length = strlen(vp_inst->strvalue);
1519                                                                 pairadd(&request->config_items, vp_inst);
1520
1521                                                                 /*
1522                                                                  * Inform the authenticate / post-auth method about the presence
1523                                                                  * of UP in the config items list and whether eDirectory account
1524                                                                  * policy check is to be performed or not.
1525                                                                  */
1526                                                                 if ((vp_apc = paircreate(apc_attr, PW_TYPE_INTEGER)) == NULL){
1527                                                                         radlog(L_ERR, "rlm_ldap: Could not allocate memory. Aborting.");
1528                                                                         ldap_msgfree(result);
1529                                                                         ldap_release_conn(conn_id, inst->conns);
1530                                                                         memset(universal_password, 0, universal_password_len);
1531                                                                         free(universal_password);
1532                                                                         return RLM_MODULE_FAIL;
1533                                                                 }
1534
1535                                                                 if(!inst->edir_account_policy_check){
1536                                                                         /* Do nothing */
1537                                                                         strcpy(vp_apc->strvalue, "1");
1538                                                                 }else{
1539                                                                         /* Perform eDirectory account-policy check */
1540                                                                         strcpy(vp_apc->strvalue, "2");
1541                                                                 }
1542                                                                 vp_apc->length = 1;
1543                                                                 pairadd(&request->config_items, vp_apc);
1544                                                         }
1545                                                 }
1546 #endif
1547
1548                                                 DEBUG("rlm_ldap: Added the eDirectory password in check items");
1549                                         }
1550                                 }
1551                                 else {
1552                                         DEBUG("rlm_ldap: Error reading Universal Password.Return Code = %d",res);
1553                                 }
1554
1555                                 memset(universal_password, 0, universal_password_len);
1556                                 free(universal_password);
1557                         }
1558                 }                       
1559 #endif
1560
1561         }
1562
1563
1564
1565         DEBUG("rlm_ldap: looking for check items in directory...");
1566
1567         if ((check_tmp = ldap_pairget(conn->ld, msg, inst->check_item_map,check_pairs,1)) != NULL) {
1568                 if (inst->do_xlat){
1569                         pairxlatmove(request, check_pairs, &check_tmp);
1570                         pairfree(&check_tmp);
1571                 }
1572                 else
1573                         pairadd(check_pairs,check_tmp);
1574         }
1575
1576
1577         DEBUG("rlm_ldap: looking for reply items in directory...");
1578
1579
1580         if ((reply_tmp = ldap_pairget(conn->ld, msg, inst->reply_item_map,reply_pairs,0)) != NULL) {
1581                 if (inst->do_xlat){
1582                         pairxlatmove(request, reply_pairs, &reply_tmp);
1583                         pairfree(&reply_tmp);
1584                 }
1585                 else
1586                         pairadd(reply_pairs,reply_tmp);
1587         }
1588
1589        if (inst->do_comp && paircmp(request,request->packet->vps,*check_pairs,reply_pairs) != 0){
1590 #ifdef NOVELL
1591                 /* Don't perform eDirectory APC if RADIUS authorize fails */
1592                 int apc_attr;
1593                 VALUE_PAIR *vp_apc;
1594                 DICT_ATTR *dattr;
1595
1596                 dattr = dict_attrbyname("eDir-APC");
1597                 apc_attr = dattr->attr;
1598
1599                 vp_apc = pairfind(request->config_items, apc_attr);
1600                 if(vp_apc)
1601                         vp_apc->strvalue[0] = '1';
1602 #endif
1603
1604                 DEBUG("rlm_ldap: Pairs do not match. Rejecting user.");
1605                 snprintf(module_fmsg,sizeof(module_fmsg),"rlm_ldap: Pairs do not match");
1606                 module_fmsg_vp = pairmake("Module-Failure-Message", module_fmsg, T_OP_EQ);
1607                 pairadd(&request->packet->vps, module_fmsg_vp);
1608                 ldap_msgfree(result);
1609                 ldap_release_conn(conn_id,inst->conns);
1610
1611                 return RLM_MODULE_REJECT;
1612         }
1613
1614         /*
1615          * Module should default to LDAP authentication if no Auth-Type
1616          * specified.  Note that we do this ONLY if configured, AND we
1617          * set the Auth-Type to our module name, which allows multiple
1618          * ldap instances to work.
1619          */
1620         if (inst->set_auth_type &&
1621             (pairfind(*check_pairs, PW_AUTH_TYPE) == NULL) &&
1622             request->password &&
1623             (request->password->attribute == PW_USER_PASSWORD))
1624                 pairadd(check_pairs, pairmake("Auth-Type", inst->xlat_name, T_OP_EQ));
1625
1626         DEBUG("rlm_ldap: user %s authorized to use remote access",
1627               request->username->strvalue);
1628         ldap_msgfree(result);
1629         ldap_release_conn(conn_id,inst->conns);
1630
1631         return RLM_MODULE_OK;
1632 }
1633
1634 /*****************************************************************************
1635  *
1636  *      Function: rlm_ldap_authenticate
1637  *
1638  *      Purpose: Check the user's password against ldap database
1639  *
1640  *****************************************************************************/
1641 static int
1642 ldap_authenticate(void *instance, REQUEST * request)
1643 {
1644         LDAP           *ld_user;
1645         LDAPMessage    *result, *msg;
1646         ldap_instance  *inst = instance;
1647         char           *user_dn, *attrs[] = {"uid", NULL};
1648         char            filter[MAX_FILTER_STR_LEN];
1649         char            basedn[MAX_FILTER_STR_LEN];
1650         int             res;
1651         VALUE_PAIR     *vp_user_dn;
1652         VALUE_PAIR      *module_fmsg_vp;
1653         char            module_fmsg[MAX_STRING_LEN];
1654         LDAP_CONN       *conn;
1655         int             conn_id = -1;
1656 #ifdef NOVELL
1657         char            *err = NULL;
1658 #endif
1659
1660         DEBUG("rlm_ldap: - authenticate");
1661
1662         /*
1663          * Ensure that we're being passed a plain-text password, and not
1664          * anything else.
1665          */
1666
1667         if (!request->username) {
1668                 radlog(L_AUTH, "rlm_ldap: Attribute \"User-Name\" is required for authentication.\n");
1669                 return RLM_MODULE_INVALID;
1670         }
1671
1672         if (!request->password){
1673                 radlog(L_AUTH, "rlm_ldap: Attribute \"User-Password\" is required for authentication.");
1674                 return RLM_MODULE_INVALID;
1675         }
1676
1677         if(request->password->attribute != PW_PASSWORD) {
1678                 radlog(L_AUTH, "rlm_ldap: Attribute \"User-Password\" is required for authentication. Cannot use \"%s\".", request->password->name);
1679                 return RLM_MODULE_INVALID;
1680         }
1681
1682         if (request->password->length == 0) {
1683                 snprintf(module_fmsg,sizeof(module_fmsg),"rlm_ldap: empty password supplied");
1684                 module_fmsg_vp = pairmake("Module-Failure-Message", module_fmsg, T_OP_EQ);
1685                 pairadd(&request->packet->vps, module_fmsg_vp);
1686                 return RLM_MODULE_INVALID;
1687         }
1688
1689         /*
1690          * Check that we don't have any failed connections. If we do there's no real need
1691          * of runing. Also give it another chance if we have a lot of failed connections.
1692          */
1693         if (inst->failed_conns > MAX_FAILED_CONNS_END)
1694                 inst->failed_conns = 0;
1695         if (inst->failed_conns > MAX_FAILED_CONNS_START){
1696                 inst->failed_conns++;
1697                 return RLM_MODULE_FAIL;
1698         }
1699
1700
1701         DEBUG("rlm_ldap: login attempt by \"%s\" with password \"%s\"",
1702                request->username->strvalue, request->password->strvalue);
1703
1704         while((vp_user_dn = pairfind(request->packet->vps, PW_LDAP_USERDN)) == NULL) {
1705                 if (!radius_xlat(filter, sizeof(filter), inst->filter,
1706                                 request, NULL)) {
1707                         radlog (L_ERR, "rlm_ldap: unable to create filter.\n");
1708                         return RLM_MODULE_INVALID;
1709                 }
1710
1711                 if (!radius_xlat(basedn, sizeof(basedn), inst->basedn,
1712                                 request, NULL)) {
1713                         radlog (L_ERR, "rlm_ldap: unable to create basedn.\n");
1714                         return RLM_MODULE_INVALID;
1715                 }
1716
1717                 if ((conn_id = ldap_get_conn(inst->conns,&conn,inst)) == -1){
1718                         radlog(L_ERR, "rlm_ldap: All ldap connections are in use");
1719                         return RLM_MODULE_FAIL;
1720                 }
1721                 if ((res = perform_search(instance, conn, basedn, LDAP_SCOPE_SUBTREE, filter, attrs, &result)) != RLM_MODULE_OK) {
1722                         if (res == RLM_MODULE_NOTFOUND){
1723                                 snprintf(module_fmsg,sizeof(module_fmsg),"rlm_ldap: User not found");
1724                                 module_fmsg_vp = pairmake("Module-Failure-Message", module_fmsg, T_OP_EQ);
1725                                 pairadd(&request->packet->vps, module_fmsg_vp);
1726                         }
1727                         ldap_release_conn(conn_id,inst->conns);
1728                         return (res);
1729                 }
1730                 if ((msg = ldap_first_entry(conn->ld, result)) == NULL) {
1731                         ldap_msgfree(result);
1732                         ldap_release_conn(conn_id,inst->conns);
1733                         return RLM_MODULE_FAIL;
1734                 }
1735                 if ((user_dn = ldap_get_dn(conn->ld, msg)) == NULL) {
1736                         DEBUG("rlm_ldap: ldap_get_dn() failed");
1737                         ldap_msgfree(result);
1738                         ldap_release_conn(conn_id,inst->conns);
1739                         return RLM_MODULE_FAIL;
1740                 }
1741                 ldap_release_conn(conn_id,inst->conns);
1742                 pairadd(&request->packet->vps, pairmake("Ldap-UserDn", user_dn, T_OP_EQ));
1743                 ldap_memfree(user_dn);
1744                 ldap_msgfree(result);
1745         }
1746
1747         user_dn = vp_user_dn->strvalue;
1748
1749         DEBUG("rlm_ldap: user DN: %s", user_dn);
1750
1751 #ifndef NOVELL
1752         ld_user = ldap_connect(instance, user_dn, request->password->strvalue,
1753                                1, &res, NULL);
1754 #else
1755
1756         ld_user = ldap_connect(instance, user_dn, request->password->strvalue,
1757                         1, &res, &err);
1758
1759         if(err != NULL){
1760                 /* 'err' contains the LDAP connection error description */
1761                 DEBUG("rlm_ldap: %s", err);
1762                 pairadd(&request->reply->vps, pairmake("Reply-Message", err, T_OP_EQ));
1763                 ldap_memfree((void *)err);
1764         }
1765
1766         /* Don't perform eDirectory APC again after attempting to bind here. */
1767         {
1768                 int apc_attr;
1769                 DICT_ATTR *dattr;
1770                 VALUE_PAIR *vp_apc;
1771
1772                 dattr = dict_attrbyname("eDir-APC");
1773                 apc_attr = dattr->attr;
1774                 vp_apc = pairfind(request->config_items, apc_attr);
1775                 if(vp_apc && vp_apc->strvalue[0] == '2')
1776                         vp_apc->strvalue[0] = '3';
1777         }
1778 #endif
1779
1780         if (ld_user == NULL){
1781                 if (res == RLM_MODULE_REJECT){
1782                         inst->failed_conns = 0;
1783                         snprintf(module_fmsg,sizeof(module_fmsg),"rlm_ldap: Bind as user failed");
1784                         module_fmsg_vp = pairmake("Module-Failure-Message", module_fmsg, T_OP_EQ);
1785                         pairadd(&request->packet->vps, module_fmsg_vp);
1786                 }
1787                 if (res == RLM_MODULE_FAIL){
1788                         DEBUG("rlm_ldap: ldap_connect() failed");
1789                         inst->failed_conns++;
1790                 }
1791                 return (res);
1792         }
1793
1794         DEBUG("rlm_ldap: user %s authenticated succesfully",
1795               request->username->strvalue);
1796         ldap_unbind_s(ld_user);
1797         inst->failed_conns = 0;
1798
1799         return RLM_MODULE_OK;
1800 }
1801
1802 #ifdef NOVELL
1803 /*****************************************************************************
1804  *
1805  *      Function: rlm_ldap_postauth
1806  *
1807  *      Purpose: Perform eDirectory account policy check and failed-login reporting
1808  *      to eDirectory.
1809  *
1810  *****************************************************************************/
1811 static int
1812 ldap_postauth(void *instance, REQUEST * request)
1813 {
1814         int res = RLM_MODULE_FAIL;
1815         int inst_attr, apc_attr;
1816         char password[UNIVERSAL_PASS_LEN];
1817         ldap_instance  *inst = instance;
1818         LDAP_CONN       *conn;
1819         VALUE_PAIR *vp_inst, *vp_apc;
1820         DICT_ATTR *dattr;
1821
1822         dattr = dict_attrbyname("LDAP-Instance");
1823         inst_attr = dattr->attr;
1824         dattr = dict_attrbyname("eDir-APC");
1825         apc_attr = dattr->attr;
1826
1827         vp_inst = pairfind(request->config_items, inst_attr);
1828
1829         /*
1830          * Check if the password in the config items list is the user's UP which has
1831          * been read in the authorize method of this instance of the LDAP module.
1832          */
1833         if((vp_inst == NULL) || strcmp(vp_inst->strvalue, inst->xlat_name))
1834                 return RLM_MODULE_NOOP;
1835
1836         vp_apc = pairfind(request->config_items, apc_attr);
1837
1838         switch(vp_apc->strvalue[0]){
1839                 case '1':
1840                         /* Account policy check not enabled */
1841                 case '3':
1842                         /* Account policy check has been completed */
1843                         res = RLM_MODULE_NOOP;
1844                         break;
1845                 case '2':
1846                         {
1847                                 int err, conn_id = -1;
1848                                 char *error_msg = NULL;
1849                                 VALUE_PAIR *vp_fdn, *vp_pwd;
1850                                 DICT_ATTR *da;
1851
1852                                 if(request->reply->code == PW_AUTHENTICATION_REJECT){
1853                                         /* Bind to eDirectory as the RADIUS user with a wrong password. */
1854                                         vp_pwd = pairfind(request->config_items, PW_PASSWORD);
1855                                         strcpy(password, vp_pwd->strvalue);
1856                                         if(strlen(password) > 0){
1857                                                 if(password[0] != 'a'){
1858                                                         password[0] = 'a';
1859                                                 }else{
1860                                                         password[0] = 'b';
1861                                                 }
1862                                         }else{
1863                                                 strcpy(password, "dummy_password");
1864                                         }
1865                                         res = RLM_MODULE_REJECT;
1866                                 }else{
1867                                         /* Bind to eDirectory as the RADIUS user using the user's UP */
1868                                         vp_pwd = pairfind(request->config_items, PW_PASSWORD);
1869                                         if(vp_pwd == NULL){
1870                                                 DEBUG("rlm_ldap: User's Universal Password not in config items list.");
1871                                                 return RLM_MODULE_FAIL;
1872                                         }
1873                                         strcpy(password, vp_pwd->strvalue);
1874                                 }
1875
1876                                 if ((da = dict_attrbyname("Ldap-UserDn")) == NULL) {
1877                                         DEBUG("rlm_ldap: Attribute for user FDN not found in dictionary. Unable to proceed");
1878                                         return RLM_MODULE_FAIL;
1879                                 }
1880
1881                                 vp_fdn = pairfind(request->packet->vps, da->attr);
1882                                 if(vp_fdn == NULL){
1883                                         DEBUG("rlm_ldap: User's FQDN not in config items list.");
1884                                         return RLM_MODULE_FAIL;
1885                                 }
1886
1887                                 if ((conn_id = ldap_get_conn(inst->apc_conns, &conn, inst)) == -1){
1888                                         radlog(L_ERR, "rlm_ldap: All ldap connections are in use");
1889                                         return RLM_MODULE_FAIL;
1890                                 }
1891
1892                                 /*
1893                                  * If there is an existing LDAP connection to the directory, bind over
1894                                  * it. Otherwise, establish a new connection.
1895                                  */
1896 postauth_reconnect:
1897                                 if (!conn->bound || conn->ld == NULL) {
1898                                         DEBUG2("rlm_ldap: attempting LDAP reconnection");
1899                                         if (conn->ld){
1900                                                 DEBUG2("rlm_ldap: closing existing LDAP connection");
1901                                                 ldap_unbind_s(conn->ld);
1902                                         }
1903                                         if ((conn->ld = ldap_connect(instance, (char *)vp_fdn->strvalue, password, 0, &res, &error_msg)) == NULL) {
1904                                                 radlog(L_ERR, "rlm_ldap: eDirectory account policy check failed.");
1905
1906                                                 if(error_msg != NULL){
1907                                                         DEBUG("rlm_ldap: %s", error_msg);
1908                                                         pairadd(&request->reply->vps, pairmake("Reply-Message", error_msg, T_OP_EQ));
1909                                                         ldap_memfree((void *)error_msg);
1910                                                 }
1911
1912                                                 vp_apc->strvalue[0] = '3';
1913                                                 ldap_release_conn(conn_id, inst->apc_conns);
1914                                                 return RLM_MODULE_REJECT;
1915                                         }
1916                                         conn->bound = 1;
1917                                 }else if((err = ldap_simple_bind_s(conn->ld, (char *)vp_fdn->strvalue, password)) != LDAP_SUCCESS){
1918                                         if(err == LDAP_SERVER_DOWN){
1919                                                 conn->bound = 0;
1920                                                 goto postauth_reconnect;
1921                                         }
1922                                         DEBUG("rlm_ldap: eDirectory account policy check failed.");
1923                                         ldap_get_option(conn->ld, LDAP_OPT_ERROR_STRING, &error_msg);
1924                                         if(error_msg != NULL){
1925                                                 DEBUG("rlm_ldap: %s", error_msg);
1926                                                 pairadd(&request->reply->vps, pairmake("Reply-Message", error_msg, T_OP_EQ));
1927                                                 ldap_memfree((void *)error_msg);
1928                                         }
1929                                         vp_apc->strvalue[0] = '3';
1930                                         ldap_release_conn(conn_id, inst->apc_conns);
1931                                         return RLM_MODULE_REJECT;
1932                                 }
1933                                 vp_apc->strvalue[0] = '3';
1934                                 ldap_release_conn(conn_id, inst->apc_conns);
1935                                 return RLM_MODULE_OK;
1936                         }
1937         }
1938         return res;
1939 }
1940 #endif
1941
1942 static LDAP    *
1943 ldap_connect(void *instance, const char *dn, const char *password, int auth, int *result, char **err)
1944 {
1945         ldap_instance  *inst = instance;
1946         LDAP           *ld = NULL;
1947         int             msgid, rc, ldap_version;
1948         int             ldap_errno = 0;
1949         LDAPMessage    *res;
1950
1951         if (inst->is_url){
1952 #ifdef HAVE_LDAP_INITIALIZE
1953                 DEBUG("rlm_ldap: (re)connect to %s, authentication %d", inst->server, auth);
1954                 if (ldap_initialize(&ld, inst->server) != LDAP_SUCCESS) {
1955                         radlog(L_ERR, "rlm_ldap: ldap_initialize() failed");
1956                         *result = RLM_MODULE_FAIL;
1957                         return (NULL);
1958                 }
1959 #endif
1960         }
1961         else{
1962                 DEBUG("rlm_ldap: (re)connect to %s:%d, authentication %d", inst->server, inst->port, auth);
1963                 if ((ld = ldap_init(inst->server, inst->port)) == NULL) {
1964                         radlog(L_ERR, "rlm_ldap: ldap_init() failed");
1965                         *result = RLM_MODULE_FAIL;
1966                         return (NULL);
1967                 }
1968         }
1969         if (ldap_set_option(ld, LDAP_OPT_NETWORK_TIMEOUT, (void *) &(inst->net_timeout)) != LDAP_OPT_SUCCESS) {
1970                 radlog(L_ERR, "rlm_ldap: Could not set LDAP_OPT_NETWORK_TIMEOUT %ld.%ld", inst->net_timeout.tv_sec, inst->net_timeout.tv_usec);
1971         }
1972         if (ldap_set_option(ld, LDAP_OPT_TIMELIMIT, (void *) &(inst->timelimit)) != LDAP_OPT_SUCCESS) {
1973                 radlog(L_ERR, "rlm_ldap: Could not set LDAP_OPT_TIMELIMIT %d", inst->timelimit);
1974         }
1975         if (inst->ldap_debug && ldap_set_option(NULL, LDAP_OPT_DEBUG_LEVEL, &(inst->ldap_debug)) != LDAP_OPT_SUCCESS) {
1976                 radlog(L_ERR, "rlm_ldap: Could not set LDAP_OPT_DEBUG_LEVEL %d", inst->ldap_debug);
1977         }
1978         ldap_version = LDAP_VERSION3;
1979         if (ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, &ldap_version) != LDAP_OPT_SUCCESS) {
1980                 radlog(L_ERR, "rlm_ldap: Could not set LDAP version to V3");
1981         }
1982 #ifdef HAVE_LDAP_START_TLS
1983         if(inst->tls_mode) {
1984                 DEBUG("rlm_ldap: setting TLS mode to %d", inst->tls_mode);
1985                 if(ldap_set_option(ld, LDAP_OPT_X_TLS,
1986                            (void *) &(inst->tls_mode)) != LDAP_OPT_SUCCESS) {
1987                         ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &ldap_errno);
1988                         radlog(L_ERR, "rlm_ldap: could not set LDAP_OPT_X_TLS option %s", ldap_err2string(ldap_errno));
1989                 }
1990         }
1991
1992         if(inst->tls_cacertfile != NULL) {
1993                 DEBUG("rlm_ldap: setting TLS CACert File to %s", inst->tls_cacertfile);
1994
1995                 if ( ldap_set_option( NULL, LDAP_OPT_X_TLS_CACERTFILE,
1996                                                           (void *) inst->tls_cacertfile )
1997                          != LDAP_OPT_SUCCESS) {
1998                         radlog(L_ERR, "rlm_ldap: could not set "
1999                                    "LDAP_OPT_X_TLS_CACERTFILE option to %s", inst->tls_cacertfile);
2000                 }
2001         }
2002
2003         if(inst->tls_cacertdir != NULL) {
2004                 DEBUG("rlm_ldap: setting TLS CACert Directory to %s", inst->tls_cacertdir);
2005
2006                 if ( ldap_set_option( NULL, LDAP_OPT_X_TLS_CACERTDIR,
2007                                                           (void *) inst->tls_cacertdir )
2008                          != LDAP_OPT_SUCCESS) {
2009                         radlog(L_ERR, "rlm_ldap: could not set "
2010                                    "LDAP_OPT_X_TLS_CACERTDIR option to %s", inst->tls_cacertdir);
2011                 }
2012         }
2013
2014         if( strcmp( TLS_DEFAULT_VERIFY, inst->tls_require_cert ) != 0 ) {
2015                 DEBUG("rlm_ldap: setting TLS Require Cert to %s",
2016                           inst->tls_require_cert);
2017         }
2018
2019
2020 #ifdef HAVE_LDAP_INT_TLS_CONFIG
2021
2022         if ( ldap_int_tls_config( NULL, LDAP_OPT_X_TLS_REQUIRE_CERT,
2023                                                           (inst->tls_require_cert) )
2024                  != LDAP_OPT_SUCCESS) {
2025                 radlog(L_ERR, "rlm_ldap: could not set "
2026                            "LDAP_OPT_X_TLS_REQUIRE_CERT option to %s",
2027                            inst->tls_require_cert);
2028         }
2029
2030 #endif
2031
2032         if(inst->tls_certfile != NULL) {
2033                 DEBUG("rlm_ldap: setting TLS Cert File to %s", inst->tls_certfile);
2034
2035                 if ( ldap_set_option( NULL, LDAP_OPT_X_TLS_CERTFILE,
2036                                                           (void *) inst->tls_certfile )
2037                          != LDAP_OPT_SUCCESS) {
2038                         radlog(L_ERR, "rlm_ldap: could not set "
2039                                    "LDAP_OPT_X_TLS_CERTFILE option to %s",
2040                                    inst->tls_certfile);
2041                 }
2042         }
2043
2044         if(inst->tls_keyfile != NULL) {
2045                 DEBUG("rlm_ldap: setting TLS Key File to %s", inst->tls_keyfile);
2046
2047                 if ( ldap_set_option( NULL, LDAP_OPT_X_TLS_KEYFILE,
2048                                                           (void *) inst->tls_keyfile )
2049                          != LDAP_OPT_SUCCESS) {
2050                         radlog(L_ERR, "rlm_ldap: could not set "
2051                                    "LDAP_OPT_X_TLS_KEYFILE option to %s",
2052                                    inst->tls_keyfile);
2053                 }
2054         }
2055
2056         if(inst->tls_randfile != NULL) {
2057                 DEBUG("rlm_ldap: setting TLS Key File to %s", inst->tls_randfile);
2058
2059                 if ( ldap_set_option( NULL, LDAP_OPT_X_TLS_RANDOM_FILE,
2060                                                           (void *) inst->tls_randfile )
2061                          != LDAP_OPT_SUCCESS) {
2062                         radlog(L_ERR, "rlm_ldap: could not set "
2063                                    "LDAP_OPT_X_TLS_RANDOM_FILE option to %s",
2064                                    inst->tls_randfile);
2065                 }
2066         }
2067         if (inst->start_tls) {
2068                 DEBUG("rlm_ldap: starting TLS");
2069                 rc = ldap_start_tls_s(ld, NULL, NULL);
2070                 if (rc != LDAP_SUCCESS) {
2071                         DEBUG("rlm_ldap: ldap_start_tls_s()");
2072                         ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &ldap_errno);
2073                         radlog(L_ERR, "rlm_ldap: could not start TLS %s", ldap_err2string(ldap_errno));
2074                         *result = RLM_MODULE_FAIL;
2075                         ldap_unbind_s(ld);
2076                         return (NULL);
2077                 }
2078         }
2079 #endif /* HAVE_LDAP_START_TLS */
2080
2081         if (inst->is_url){
2082                 DEBUG("rlm_ldap: bind as %s/%s to %s", dn, password, inst->server);
2083         }
2084         else{
2085                 DEBUG("rlm_ldap: bind as %s/%s to %s:%d", dn, password, inst->server, inst->port);
2086         }
2087         msgid = ldap_bind(ld, dn, password,LDAP_AUTH_SIMPLE);
2088         if (msgid == -1) {
2089                 ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &ldap_errno);
2090                 if(err != NULL){
2091                         ldap_get_option(ld, LDAP_OPT_ERROR_STRING, err);
2092                 }
2093                 if (inst->is_url) {
2094                         radlog(L_ERR, "rlm_ldap: %s bind to %s failed: %s",
2095                                 dn, inst->server, ldap_err2string(ldap_errno));
2096                 } else {
2097                         radlog(L_ERR, "rlm_ldap: %s bind to %s:%d failed: %s",
2098                                 dn, inst->server, inst->port,
2099                                 ldap_err2string(ldap_errno));
2100                 }
2101                 *result = RLM_MODULE_FAIL;
2102                 ldap_unbind_s(ld);
2103                 return (NULL);
2104         }
2105         DEBUG("rlm_ldap: waiting for bind result ...");
2106
2107         rc = ldap_result(ld, msgid, 1, &(inst->timeout), &res);
2108
2109         if(rc < 1) {
2110                 DEBUG("rlm_ldap: ldap_result()");
2111                 ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &ldap_errno);
2112                 if(err != NULL){
2113                         ldap_get_option(ld, LDAP_OPT_ERROR_STRING, err);
2114                 }
2115                 if (inst->is_url) {
2116                         radlog(L_ERR, "rlm_ldap: %s bind to %s failed: %s",
2117                                 dn, inst->server, (rc == 0) ? "timeout" : ldap_err2string(ldap_errno));
2118                 } else {
2119                         radlog(L_ERR, "rlm_ldap: %s bind to %s:%d failed: %s",
2120                                 dn, inst->server, inst->port,
2121                                 (rc == 0) ? "timeout" : ldap_err2string(ldap_errno));
2122                 }
2123                 *result = RLM_MODULE_FAIL;
2124                 ldap_unbind_s(ld);
2125                 return (NULL);
2126         }
2127         ldap_errno = ldap_result2error(ld, res, 1);
2128         switch (ldap_errno) {
2129         case LDAP_SUCCESS:
2130                 DEBUG("rlm_ldap: Bind was successful");
2131                 *result = RLM_MODULE_OK;
2132                 break;
2133
2134         case LDAP_INVALID_CREDENTIALS:
2135                 if (auth){
2136                         DEBUG("rlm_ldap: Bind failed with invalid credentials");
2137                         *result = RLM_MODULE_REJECT;
2138                 }
2139                 else {
2140                         radlog(L_ERR, "rlm_ldap: LDAP login failed: check identity, password settings in ldap section of radiusd.conf");
2141                         *result = RLM_MODULE_FAIL;
2142                 }
2143                 if(err != NULL){
2144                         ldap_get_option(ld, LDAP_OPT_ERROR_STRING, err);
2145                 }
2146                 break;
2147
2148         default:
2149                 if (inst->is_url)
2150                         radlog(L_ERR,"rlm_ldap: %s bind to %s failed %s",
2151                                 dn, inst->server, ldap_err2string(ldap_errno));
2152                 else
2153                         radlog(L_ERR,"rlm_ldap: %s bind to %s:%d failed %s",
2154                                 dn, inst->server, inst->port,
2155                                 ldap_err2string(ldap_errno));
2156                 *result = RLM_MODULE_FAIL;
2157                 if(err != NULL){
2158                         ldap_get_option(ld, LDAP_OPT_ERROR_STRING, err);
2159                 }
2160         }
2161
2162         if (*result != RLM_MODULE_OK) {
2163                 ldap_unbind_s(ld);
2164                 ld = NULL;
2165         }
2166         return ld;
2167 }
2168
2169 /*****************************************************************************
2170  *
2171  *      Detach from the LDAP server and cleanup internal state.
2172  *
2173  *****************************************************************************/
2174 static int
2175 ldap_detach(void *instance)
2176 {
2177         ldap_instance  *inst = instance;
2178         TLDAP_RADIUS *pair, *nextpair;
2179
2180         if (inst->server)
2181                 free((char *) inst->server);
2182         if (inst->login)
2183                 free((char *) inst->login);
2184         if (inst->password)
2185                 free((char *) inst->password);
2186         if (inst->basedn)
2187                 free((char *) inst->basedn);
2188         if (inst->dictionary_mapping)
2189                 free(inst->dictionary_mapping);
2190         if (inst->filter)
2191                 free((char *) inst->filter);
2192         if (inst->base_filter)
2193                 free((char *) inst->base_filter);
2194         if (inst->passwd_hdr)
2195                 free((char *) inst->passwd_hdr);
2196         if (inst->passwd_attr)
2197                 free((char *) inst->passwd_attr);
2198         if (inst->groupname_attr)
2199                 free((char *) inst->groupname_attr);
2200         if (inst->groupmemb_filt)
2201                 free((char *) inst->groupmemb_filt);
2202         if (inst->groupmemb_attr)
2203                 free((char *) inst->groupmemb_attr);
2204         if (inst->access_attr)
2205                 free((char *) inst->access_attr);
2206         if (inst->profile_attr)
2207                 free((char *) inst->profile_attr);
2208         if (inst->conns){
2209                 int i=0;
2210
2211                 for(;i<inst->num_conns;i++){
2212                         if (inst->conns[i].ld){
2213                                 ldap_unbind_s(inst->conns[i].ld);
2214                         }
2215                         pthread_mutex_destroy(&inst->conns[i].mutex);
2216                 }
2217                 free(inst->conns);
2218         }
2219
2220 #ifdef NOVELL
2221         if (inst->apc_conns){ 
2222                 int i;
2223
2224                 for(i = 0; i < inst->num_conns; i++){
2225                         if (inst->apc_conns[i].ld){
2226                                 ldap_unbind_s(inst->apc_conns[i].ld);
2227                         }
2228                         pthread_mutex_destroy(&inst->apc_conns[i].mutex);
2229                 }
2230                 free(inst->apc_conns);
2231         }
2232 #endif
2233
2234         pair = inst->check_item_map;
2235
2236         while (pair != NULL) {
2237                 nextpair = pair->next;
2238                 free(pair->attr);
2239                 free(pair->radius_attr);
2240                 free(pair);
2241                 pair = nextpair;
2242         }
2243
2244         pair = inst->reply_item_map;
2245
2246         while (pair != NULL) {
2247                 nextpair = pair->next;
2248                 free(pair->attr);
2249                 free(pair->radius_attr);
2250                 free(pair);
2251                 pair = nextpair;
2252         }
2253
2254         if (inst->atts)
2255                 free(inst->atts);
2256
2257         paircompare_unregister(PW_LDAP_GROUP, ldap_groupcmp);
2258         xlat_unregister(inst->xlat_name,ldap_xlat);
2259         free(inst->xlat_name);
2260
2261         free(inst);
2262
2263         return 0;
2264 }
2265
2266 #ifdef FIELDCPY
2267 static void
2268 fieldcpy(char *string, char **uptr)
2269 {
2270         char           *ptr;
2271
2272         ptr = *uptr;
2273         while (*ptr == ' ' || *ptr == '\t') {
2274                 ptr++;
2275         }
2276         if (*ptr == '"') {
2277                 ptr++;
2278                 while (*ptr != '"' && *ptr != '\0' && *ptr != '\n') {
2279                         *string++ = *ptr++;
2280                 }
2281                 *string = '\0';
2282                 if (*ptr == '"') {
2283                         ptr++;
2284                 }
2285                 *uptr = ptr;
2286                 return;
2287         }
2288         while (*ptr != ' ' && *ptr != '\t' && *ptr != '\0' && *ptr != '\n' &&
2289                *ptr != '=' && *ptr != ',') {
2290                 *string++ = *ptr++;
2291         }
2292         *string = '\0';
2293         *uptr = ptr;
2294         return;
2295 }
2296 #endif
2297 /*****************************************************************************
2298  *      Get RADIUS attributes from LDAP object
2299  *      ( according to draft-adoba-radius-05.txt
2300  *        <http://www.ietf.org/internet-drafts/draft-adoba-radius-05.txt> )
2301  *
2302  *****************************************************************************/
2303
2304 static VALUE_PAIR *
2305 ldap_pairget(LDAP * ld, LDAPMessage * entry,
2306              TLDAP_RADIUS * item_map, VALUE_PAIR **pairs,char is_check)
2307 {
2308         char          **vals;
2309         int             vals_count;
2310         int             vals_idx;
2311         char           *ptr;
2312         char           *value;
2313         TLDAP_RADIUS   *element;
2314         LRAD_TOKEN      token, operator;
2315         int             is_generic_attribute;
2316         char            buf[MAX_STRING_LEN];
2317         VALUE_PAIR     *pairlist = NULL;
2318         VALUE_PAIR     *newpair = NULL;
2319         char            do_xlat = FALSE;
2320
2321         /*
2322          *      check if there is a mapping from this LDAP attribute
2323          *      to a RADIUS attribute
2324          */
2325         for (element = item_map; element != NULL; element = element->next) {
2326                 /*
2327                  *      No mapping, skip it.
2328                  */
2329                 if ((vals = ldap_get_values(ld,entry,element->attr)) == NULL)
2330                         continue;
2331
2332                 /*
2333                  *      Check whether this is a one-to-one-mapped ldap
2334                  *      attribute or a generic attribute and set flag
2335                  *      accordingly.
2336                  */
2337                 if (strcasecmp(element->radius_attr, GENERIC_ATTRIBUTE_ID)==0)
2338                         is_generic_attribute = 1;
2339                 else
2340                         is_generic_attribute = 0;
2341
2342                 /*
2343                  *      Find out how many values there are for the
2344                  *      attribute and extract all of them.
2345                  */
2346                 vals_count = ldap_count_values(vals);
2347
2348                 for (vals_idx = 0; vals_idx < vals_count; vals_idx++) {
2349                         value = vals[vals_idx];
2350
2351                         if (is_generic_attribute) {
2352                                 /*
2353                                  *      This is a generic attribute.
2354                                  */
2355                                 LRAD_TOKEN dummy; /* makes pairread happy */
2356
2357                                 /* not sure if using pairread here is ok ... */
2358                                 if ( (newpair = pairread(&value, &dummy)) != NULL) {
2359                                         DEBUG("rlm_ldap: extracted attribute %s from generic item %s",
2360                                               newpair->name, vals[vals_idx]);
2361                                         pairadd(&pairlist, newpair);
2362                                 } else {
2363                                         radlog(L_ERR, "rlm_ldap: parsing %s failed: %s",
2364                                                element->attr, vals[vals_idx]);
2365                                 }
2366                         } else {
2367                                 /*
2368                                  *      This is a one-to-one-mapped attribute
2369                                  */
2370                                 ptr = value;
2371                                 operator = gettoken(&ptr, buf, sizeof(buf));
2372                                 if (operator < T_EQSTART || operator > T_EQEND) {
2373                                         /* no leading operator found */
2374                                         if (is_check)
2375                                                 operator = T_OP_CMP_EQ;
2376                                         else
2377                                                 operator = T_OP_EQ;
2378                                 } else {
2379                                         /* the value is after the operator */
2380                                         value = ptr;
2381                                 }
2382
2383                                 /*
2384                                  *      Do xlat if the *entire* string
2385                                  *      is quoted.
2386                                  */
2387                                 if ((value[0] == '\'' || value[0] == '"' ||
2388                                      value[0] == '`') &&
2389                                     (value[0] == value[strlen(value)-1])) {
2390                                         ptr = value;
2391                                         token = gettoken(&ptr, buf, sizeof(buf));
2392                                         switch (token) {
2393                                         /* take the unquoted string */
2394                                         case T_SINGLE_QUOTED_STRING:
2395                                         case T_DOUBLE_QUOTED_STRING:
2396                                                 value = buf;
2397                                                 break;
2398
2399                                         /* the value will be xlat'ed later */
2400                                         case T_BACK_QUOTED_STRING:
2401                                                 value = buf;
2402                                                 do_xlat = TRUE;
2403                                                 break;
2404
2405                                         /* keep the original string */
2406                                         default:
2407                                                 break;
2408                                         }
2409                                 }
2410                                 if (value[0] == '\0') {
2411                                         DEBUG("rlm_ldap: Attribute %s has no value", element->attr);
2412                                         continue;
2413                                 }
2414
2415                                 DEBUG("rlm_ldap: Adding %s as %s, value %s & op=%d", element->attr, element->radius_attr, value, operator);
2416
2417                                 /*
2418                                  *      Create the pair.
2419                                  */
2420                                 newpair = pairmake(element->radius_attr,
2421                                                    do_xlat ? NULL : value,
2422                                                    operator);
2423                                 if (newpair == NULL) {
2424                                         radlog(L_ERR, "rlm_ldap: Failed to create the pair: %s", librad_errstr);
2425                                         continue;
2426                                 }
2427                                 if (do_xlat) {
2428                                         newpair->flags.do_xlat = 1;
2429                                         strNcpy(newpair->strvalue, buf,
2430                                                 sizeof(newpair->strvalue));
2431                                         newpair->length = 0;
2432                                 }
2433
2434                                 /*
2435                                  *      Add the pair into the packet.
2436                                  */
2437                                 if (!vals_idx){
2438                                         pairdelete(pairs, newpair->attribute);
2439                                 }
2440                                 pairadd(&pairlist, newpair);
2441                         }
2442                 }
2443                 ldap_value_free(vals);
2444         }
2445
2446         return (pairlist);
2447 }
2448
2449 /* globally exported name */
2450 module_t        rlm_ldap = {
2451         "LDAP",
2452         RLM_TYPE_THREAD_SAFE,   /* type: reserved        */
2453         NULL,                   /* initialization        */
2454         ldap_instantiate,       /* instantiation         */
2455         {
2456                 ldap_authenticate,      /* authentication        */
2457                 ldap_authorize,         /* authorization         */
2458                 NULL,                   /* preaccounting         */
2459                 NULL,                   /* accounting            */
2460                 NULL,                   /* checksimul            */
2461                 NULL,                   /* pre-proxy             */
2462                 NULL,                   /* post-proxy            */
2463 #ifdef NOVELL
2464                 ldap_postauth                   /* post-auth             */
2465 #else
2466                 NULL
2467 #endif
2468         },
2469         ldap_detach,            /* detach                */
2470         NULL,                   /* destroy               */
2471 };