Rename cfree to rad_cfree
[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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17  *
18  *   Copyright 1999-2012 The FreeRADIUS Server Project.
19  *
20  *   Copyright 2012 Alan DeKok <aland@freeradius.org>
21  *   Copyright 2012 Arran Cudbard-Bell <a.cudbardb@freeradius.org>
22  */
23
24 #include <freeradius-devel/ident.h>
25 RCSID("$Id$")
26
27 #include        <freeradius-devel/radiusd.h>
28 #include        <freeradius-devel/modules.h>
29 #include        <freeradius-devel/rad_assert.h>
30
31 #include        <stdarg.h>
32 #include        <ctype.h>
33
34 #include        <lber.h>
35 #include        <ldap.h>
36
37 #define MAX_ATTRMAP             128
38 #define MAX_ATTR_STR_LEN        256
39 #define MAX_FILTER_STR_LEN      1024
40
41 #ifdef WITH_EDIR
42 extern int nmasldap_get_password(LDAP *ld,char *objectDN, char *pwd, size_t *pwdSize);
43
44 #endif
45
46 typedef struct ldap_acct_section {
47         CONF_SECTION    *cs;
48         
49         const char *reference;
50 } ldap_acct_section_t;
51
52
53 typedef struct {
54         CONF_SECTION    *cs;
55         fr_connection_pool_t *pool;
56
57         char            *server;
58         int             port;
59
60         char            *login;
61         char            *password;
62
63         char            *filter;
64         char            *basedn;
65
66         int             chase_referrals;
67         int             rebind;
68
69         int             ldap_debug; /* Debug flag for LDAP SDK */
70
71         const char      *xlat_name; /* name used to xlat */
72
73         int             expect_password;
74         
75         /*
76          *      RADIUS attribute to LDAP attribute maps
77          */
78         VALUE_PAIR_MAP  *user_map;      /* Applied to users and profiles */
79         
80         /*
81          *      Access related configuration
82          */
83         char            *access_attr;
84         int             positive_access_attr;
85
86         /*
87          *      Profiles
88          */
89         char            *base_filter;
90         char            *default_profile;
91         char            *profile_attr;
92
93         /*
94          *      Group checking.
95          */
96         char            *groupname_attr;
97         char            *groupmemb_filter;
98         char            *groupmemb_attr;
99         
100         /*
101          *      Accounting
102          */
103         ldap_acct_section_t *postauth;
104         ldap_acct_section_t *accounting;
105
106         /*
107          *      TLS items.  We should really normalize these with the
108          *      TLS code in 3.0.
109          */
110         int             tls_mode;
111         int             start_tls;
112         char            *tls_cacertfile;
113         char            *tls_cacertdir;
114         char            *tls_certfile;
115         char            *tls_keyfile;
116         char            *tls_randfile;
117         char            *tls_require_cert;
118
119         /*
120          *      Options
121          */
122         int             timelimit;
123         int             net_timeout;
124         int             timeout;
125         int             is_url;
126
127 #ifdef WITH_EDIR
128         /*
129          *      eDir support
130          */
131         int             edir;
132 #endif
133         /*
134          *      For keep-alives.
135          */
136 #ifdef LDAP_OPT_X_KEEPALIVE_IDLE
137         int             keepalive_idle;
138 #endif
139 #ifdef LDAP_OPT_X_KEEPALIVE_PROBES
140         int             keepalive_probes;
141 #endif
142 #ifdef LDAP_OPT_ERROR_NUMBER
143         int             keepalive_interval;
144 #endif
145
146 }  ldap_instance;
147
148 /* The default setting for TLS Certificate Verification */
149 #define TLS_DEFAULT_VERIFY "allow"
150
151 /*
152  *      TLS Configuration
153  */
154 static CONF_PARSER tls_config[] = {
155         {"start_tls", PW_TYPE_BOOLEAN,
156          offsetof(ldap_instance,start_tls), NULL, "no"},
157         {"cacertfile", PW_TYPE_FILENAME,
158          offsetof(ldap_instance,tls_cacertfile), NULL, NULL},
159         {"cacertdir", PW_TYPE_FILENAME,
160          offsetof(ldap_instance,tls_cacertdir), NULL, NULL},
161         {"certfile", PW_TYPE_FILENAME,
162          offsetof(ldap_instance,tls_certfile), NULL, NULL},
163         {"keyfile", PW_TYPE_FILENAME,
164          offsetof(ldap_instance,tls_keyfile), NULL, NULL},
165         {"randfile", PW_TYPE_STRING_PTR, /* OK if it changes on HUP */
166          offsetof(ldap_instance,tls_randfile), NULL, NULL},
167         {"require_cert", PW_TYPE_STRING_PTR,
168          offsetof(ldap_instance,tls_require_cert), NULL, TLS_DEFAULT_VERIFY},
169         { NULL, -1, 0, NULL, NULL }
170 };
171
172
173 static CONF_PARSER attr_config[] = {
174         /*
175          *      Access limitations
176          */
177         /* LDAP attribute name that controls remote access */
178         {"access_attr", PW_TYPE_STRING_PTR,
179          offsetof(ldap_instance,access_attr), NULL, NULL},
180         {"positive_access_attr", PW_TYPE_BOOLEAN,
181          offsetof(ldap_instance,positive_access_attr), NULL, "yes"},
182
183         {"base_filter", PW_TYPE_STRING_PTR,
184          offsetof(ldap_instance,base_filter), NULL,
185          "(objectclass=radiusprofile)"},
186         {"default_profile", PW_TYPE_STRING_PTR,
187          offsetof(ldap_instance,default_profile), NULL, NULL},
188         {"profile_attribute", PW_TYPE_STRING_PTR,
189          offsetof(ldap_instance,profile_attr), NULL, NULL},
190
191         { NULL, -1, 0, NULL, NULL }
192 };
193
194
195 /*
196  *      Group configuration
197  */
198 static CONF_PARSER group_config[] = {
199         /*
200          *      Group checks.  These could probably be done
201          *      via dynamic xlat's.
202          */
203         {"name_attribute", PW_TYPE_STRING_PTR,
204          offsetof(ldap_instance,groupname_attr), NULL, "cn"},
205         {"membership_filter", PW_TYPE_STRING_PTR,
206          offsetof(ldap_instance,groupmemb_filter), NULL,
207          "(|(&(objectClass=GroupOfNames)(member=%{Ldap-UserDn}))"
208          "(&(objectClass=GroupOfUniqueNames)(uniquemember=%{Ldap-UserDn})))"},
209         {"membership_attribute", PW_TYPE_STRING_PTR,
210          offsetof(ldap_instance,groupmemb_attr), NULL, NULL},
211
212
213         { NULL, -1, 0, NULL, NULL }
214 };
215
216 /*
217  *      Reference for accounting updates
218  */
219 static const CONF_PARSER acct_section_config[] = {
220         {"reference", PW_TYPE_STRING_PTR,
221           offsetof(ldap_acct_section_t, reference), NULL, "."},
222         {NULL, -1, 0, NULL, NULL}
223 };
224
225 /*
226  *      Various options that don't belong in the main configuration.
227  *
228  *      Note that these overlap a bit with the connection pool code!
229  */
230 static CONF_PARSER option_config[] = {
231         /*
232          *      Debugging flags to the server
233          */
234         {"ldap_debug", PW_TYPE_INTEGER,
235          offsetof(ldap_instance,ldap_debug), NULL, "0x0000"},
236
237         {"chase_referrals", PW_TYPE_BOOLEAN,
238          offsetof(ldap_instance,chase_referrals), NULL, NULL},
239
240         {"rebind", PW_TYPE_BOOLEAN,
241          offsetof(ldap_instance,rebind), NULL, NULL},
242
243         /* timeout on network activity */
244         {"net_timeout", PW_TYPE_INTEGER,
245          offsetof(ldap_instance,net_timeout), NULL, "10"},
246
247         /* timeout for search results */
248         {"timeout", PW_TYPE_INTEGER,
249          offsetof(ldap_instance,timeout), NULL, "20"},
250
251         /* allow server unlimited time for search (server-side limit) */
252         {"timelimit", PW_TYPE_INTEGER,
253          offsetof(ldap_instance,timelimit), NULL, "20"},
254
255 #ifdef LDAP_OPT_X_KEEPALIVE_IDLE
256         {"idle", PW_TYPE_INTEGER,
257          offsetof(ldap_instance,keepalive_idle), NULL, "60"},
258 #endif
259 #ifdef LDAP_OPT_X_KEEPALIVE_PROBES
260         {"probes", PW_TYPE_INTEGER,
261          offsetof(ldap_instance,keepalive_probes), NULL, "3"},
262 #endif
263 #ifdef LDAP_OPT_ERROR_NUMBER
264         {"interval", PW_TYPE_INTEGER, 
265          offsetof(ldap_instance,keepalive_interval), NULL, "30"},
266 #endif
267         { NULL, -1, 0, NULL, NULL }
268 };
269
270
271 static const CONF_PARSER module_config[] = {
272         {"server", PW_TYPE_STRING_PTR,
273          offsetof(ldap_instance,server), NULL, "localhost"},
274         {"port", PW_TYPE_INTEGER,
275          offsetof(ldap_instance,port), NULL, "389"},
276
277         {"password", PW_TYPE_STRING_PTR,
278          offsetof(ldap_instance,password), NULL, ""},
279         {"identity", PW_TYPE_STRING_PTR,
280          offsetof(ldap_instance,login), NULL, ""},
281
282         /*
283          *      DN's and filters.
284          */
285         {"basedn", PW_TYPE_STRING_PTR,
286          offsetof(ldap_instance,basedn), NULL, "o=notexist"},
287
288         {"filter", PW_TYPE_STRING_PTR,
289          offsetof(ldap_instance,filter), NULL, "(uid=%u)"},
290
291         /* turn off the annoying warning if we don't expect a password */
292         {"expect_password", PW_TYPE_BOOLEAN,
293          offsetof(ldap_instance,expect_password), NULL, "yes"},
294          
295 #ifdef WITH_EDIR
296         /* support for eDirectory Universal Password */
297         {"edir", PW_TYPE_BOOLEAN,
298          offsetof(ldap_instance,edir), NULL, NULL}, /* NULL defaults to "no" */
299 #endif
300
301         /*
302          *      Terrible things which should be deleted.
303          */
304         { "profiles", PW_TYPE_SUBSECTION, 0, NULL, (const void *) attr_config },
305
306         { "group", PW_TYPE_SUBSECTION, 0, NULL, (const void *) group_config },
307
308         { "options", PW_TYPE_SUBSECTION, 0, NULL,
309          (const void *) option_config },
310
311         { "tls", PW_TYPE_SUBSECTION, 0, NULL, (const void *) tls_config },
312
313         {NULL, -1, 0, NULL, NULL}
314 };
315
316 typedef struct ldap_conn {
317         LDAP    *handle;
318         int     rebound;
319         int     referred;
320         ldap_instance *inst;
321 } LDAP_CONN;
322
323 typedef struct xlat_attrs {
324         const VALUE_PAIR_MAP *maps;
325         const char *attrs[MAX_ATTRMAP];
326 } xlat_attrs_t;
327
328 typedef struct rlm_ldap_result {
329         char    **values;
330         int     count;
331 } rlm_ldap_result_t;
332
333
334 #if LDAP_SET_REBIND_PROC_ARGS == 3
335 /*
336  *      Rebind && chase referral stuff
337  */
338 static int ldap_rebind(LDAP *handle, LDAP_CONST char *url,
339                        UNUSED ber_tag_t request, UNUSED ber_int_t msgid,
340                        void *ctx )
341 {
342         LDAP_CONN *conn = ctx;
343
344         conn->referred = TRUE;
345         conn->rebound = TRUE;   /* not really, but oh well... */
346         rad_assert(handle == conn->handle);
347
348         DEBUG("rlm_ldap (%s): Rebinding to URL %s", conn->inst->xlat_name, url);
349         
350         return ldap_bind_s(handle, conn->inst->login, conn->inst->password,
351                            LDAP_AUTH_SIMPLE);
352 }
353 #endif
354
355 static int ldap_bind_wrapper(LDAP_CONN **pconn, const char *user,
356                              const char *password,
357                              const char **perror_str, int do_rebind)
358 {
359         int             rcode, ldap_errno;
360         int             module_rcode = RLM_MODULE_FAIL;
361         int             reconnect = FALSE;
362         const char      *error_string;
363         LDAP_CONN       *conn = *pconn;
364         ldap_instance   *inst = conn->inst;
365         LDAPMessage     *result = NULL;
366         struct timeval tv;
367
368 redo:
369         ldap_errno = ldap_bind(conn->handle, user, password, LDAP_AUTH_SIMPLE);
370         if (ldap_errno < 0) {
371         get_error:
372                 ldap_get_option(conn->handle, LDAP_OPT_ERROR_NUMBER,
373                                 &ldap_errno);
374                 error_string = ldap_err2string(ldap_errno);
375
376                 if (do_rebind && !reconnect) {
377                         conn = fr_connection_reconnect(inst->pool, conn);
378                         *pconn = conn;
379                         if (!conn) return RLM_MODULE_FAIL;
380                         goto redo;
381                 }
382
383         print_error:
384                 if (perror_str) *perror_str = error_string;
385
386 #ifdef HAVE_LDAP_INITIALIZE
387                 if (inst->is_url) {
388                         radlog(L_ERR, "rlm_ldap (%s): %s bind to %s failed: %s",
389                                inst->xlat_name, user,
390                                inst->server, error_string);
391                 } else
392 #endif
393                 {
394                         radlog(L_ERR, "rlm_ldap (%s): %s bind to %s:%d "
395                                       "failed: %s",
396                                inst->xlat_name, user,
397                                inst->server, inst->port,
398                                error_string);
399                 }
400
401                 return module_rcode; /* caller closes the connection */
402         }
403
404         DEBUG3("rlm_ldap (%s): Waiting for bind result...", inst->xlat_name);
405
406         tv.tv_sec = inst->timeout;
407         tv.tv_usec = 0;
408         rcode = ldap_result(conn->handle, ldap_errno, 1, &tv, &result);
409         if (rcode < 0) goto get_error;
410
411         if (rcode == 0) {
412                 error_string = "timeout";
413                 goto print_error;
414         }
415
416         ldap_errno = ldap_result2error(conn->handle, result, 1);
417         switch (ldap_errno) {
418         case LDAP_SUCCESS:
419                 break;
420
421         case LDAP_INVALID_CREDENTIALS:
422         case LDAP_CONSTRAINT_VIOLATION:
423                 rcode = RLM_MODULE_REJECT;
424                 /* FALL-THROUGH */
425
426         default:
427                 goto get_error;
428         }
429
430         return RLM_MODULE_OK;
431 }
432
433 /** Create and return a new connection
434  * This function is probably too big.
435  */
436 static void *ldap_conn_create(void *ctx)
437 {
438         int module_rcode;
439         int ldap_errno, ldap_version;
440         struct timeval tv;
441         ldap_instance *inst = ctx;
442         LDAP *handle = NULL;
443         LDAP_CONN *conn = NULL;
444         const char *error;
445
446 #ifdef HAVE_LDAP_INITIALIZE
447         if (inst->is_url) {
448                 DEBUG("rlm_ldap (%s): Connect to %s", inst->xlat_name,
449                       inst->server);
450
451                 ldap_errno = ldap_initialize(&handle, inst->server);
452
453                 if (ldap_errno != LDAP_SUCCESS) {
454                         radlog(L_ERR, "rlm_ldap (%s): ldap_initialize() "
455                                "failed: %s",
456                                inst->xlat_name, ldap_err2string(ldap_errno));
457                         goto conn_fail;
458                 }
459         } else
460 #endif
461         {
462                 DEBUG("rlm_ldap (%s): Connect to %s:%d", inst->xlat_name,
463                       inst->server, inst->port);
464
465                 handle = ldap_init(inst->server, inst->port);
466                 if (!handle) {
467                         radlog(L_ERR, "rlm_ldap (%s): ldap_init() failed",
468                                inst->xlat_name);
469                 conn_fail:
470                         if (handle) ldap_unbind_s(handle);
471                         return NULL;
472                 }
473         }
474
475         /*
476          *      We now have a connection structure, but no actual TCP connection.
477          *
478          *      Set a bunch of LDAP options, using common code.
479          */
480 #define do_ldap_option(_option, _name, _value) \
481         if (ldap_set_option(handle, _option, _value) != LDAP_OPT_SUCCESS) { \
482                 ldap_get_option(handle, LDAP_OPT_ERROR_NUMBER, &ldap_errno); \
483                 radlog(L_ERR, "rlm_ldap (%s): Could not set %s: %s", \
484                        inst->xlat_name, _name, ldap_err2string(ldap_errno)); \
485         }
486                 
487         if (inst->ldap_debug) {
488                 do_ldap_option(LDAP_OPT_DEBUG_LEVEL, "ldap_debug",
489                                &(inst->ldap_debug));
490         }
491
492         /*
493          *      Leave "chase_referrals" unset to use the OpenLDAP
494          *      default.
495          */
496         if (inst->chase_referrals != 2) {
497                 if (inst->chase_referrals) {
498                         do_ldap_option(LDAP_OPT_REFERRALS, "chase_referrals",
499                                        LDAP_OPT_ON);
500                         
501 #if LDAP_SET_REBIND_PROC_ARGS == 3
502                         if (inst->rebind == 1) {
503                                 ldap_set_rebind_proc(handle, ldap_rebind, inst);
504                         }
505 #endif
506                 } else {
507                         do_ldap_option(LDAP_OPT_REFERRALS, "chase_referrals",
508                                        LDAP_OPT_OFF);
509                 }
510         }
511
512         tv.tv_sec = inst->net_timeout;
513         tv.tv_usec = 0;
514         do_ldap_option(LDAP_OPT_NETWORK_TIMEOUT, "net_timeout", &tv);
515
516         do_ldap_option(LDAP_OPT_TIMELIMIT, "timelimit",
517                        &(inst->timelimit));
518
519         ldap_version = LDAP_VERSION3;
520         do_ldap_option(LDAP_OPT_PROTOCOL_VERSION, "ldap_version",
521                        &ldap_version);
522
523 #ifdef LDAP_OPT_X_KEEPALIVE_IDLE
524         do_ldap_option(LDAP_OPT_X_KEEPALIVE_IDLE, "keepalive idle",
525                        &(inst->keepalive_idle));
526 #endif
527
528 #ifdef LDAP_OPT_X_KEEPALIVE_PROBES
529         do_ldap_option(LDAP_OPT_X_KEEPALIVE_PROBES, "keepalive probes",
530                        &(inst->keepalive_probes));
531 #endif
532
533 #ifdef LDAP_OPT_X_KEEPALIVE_INTERVAL
534         do_ldap_option(LDAP_OPT_X_KEEPALIVE_INTERVAL, "keepalive interval",
535                        &(inst->keepalive_interval));
536 #endif
537
538 #ifdef HAVE_LDAP_START_TLS
539         /*
540          *      Set all of the TLS options
541          */
542         if (inst->tls_mode) {
543                 do_ldap_option(LDAP_OPT_X_TLS, "tls_mode", &(inst->tls_mode));
544         }
545
546 #define maybe_ldap_option(_option, _name, _value) \
547         if (_value) do_ldap_option(_option, _name, _value)
548
549         maybe_ldap_option(LDAP_OPT_X_TLS_CACERTFILE,
550                           "cacertfile", inst->tls_cacertfile);
551         maybe_ldap_option(LDAP_OPT_X_TLS_CACERTDIR,
552                           "cacertdir", inst->tls_cacertdir);
553
554 #ifdef HAVE_LDAP_INT_TLS_CONFIG
555         if (ldap_int_tls_config(NULL, LDAP_OPT_X_TLS_REQUIRE_CERT,
556                                 (inst->tls_require_cert)) != LDAP_OPT_SUCCESS) {
557                 ldap_get_option(handle, LDAP_OPT_ERROR_NUMBER, &ldap_errno);
558                 radlog(L_ERR, "rlm_ldap (%s): could not set "
559                        "LDAP_OPT_X_TLS_REQUIRE_CERT option to %s: %s",
560                        inst->xlat_name, 
561                        inst->tls_require_cert,
562                        ldap_err2string(ldap_errno));
563         }
564 #endif
565
566         maybe_ldap_option(LDAP_OPT_X_TLS_CERTFILE,
567                           "certfile", inst->tls_certfile);
568         maybe_ldap_option(LDAP_OPT_X_TLS_KEYFILE,
569                           "keyfile", inst->tls_keyfile);
570         maybe_ldap_option(LDAP_OPT_X_TLS_RANDOM_FILE,
571                           "randfile", inst->tls_randfile);
572
573         /*
574          *      And finally start the TLS code.
575          */
576         if (inst->start_tls && (inst->port != 636)) {
577                 ldap_errno = ldap_start_tls_s(handle, NULL, NULL);
578                 if (ldap_errno != LDAP_SUCCESS) {
579                         ldap_get_option(handle, LDAP_OPT_ERROR_NUMBER,
580                                         &ldap_errno);
581                         radlog(L_ERR, "rlm_ldap (%s): could not start TLS: %s",
582                                inst->xlat_name,
583                                ldap_err2string(ldap_errno));
584                         goto conn_fail;
585                 }
586         }
587 #endif /* HAVE_LDAP_START_TLS */
588
589         conn = rad_malloc(sizeof(*conn));
590         conn->inst = inst;
591         conn->handle = handle;
592         conn->rebound = FALSE;
593         conn->referred = FALSE;
594
595         module_rcode = ldap_bind_wrapper(&conn, inst->login, inst->password,
596                                          &error, FALSE);
597         if (module_rcode != RLM_MODULE_OK) {
598                 radlog(L_ERR, "rlm_ldap (%s): failed binding to LDAP "
599                        "server: %s",
600                        inst->xlat_name, error);
601
602                 /*
603                  *      FIXME: print "check config, morians!
604                  */
605                 goto conn_fail;
606         }
607
608         return conn;
609 }
610
611
612 /** Close and delete a connection
613  *
614  */
615 static int ldap_conn_delete(UNUSED void *ctx, void *connection)
616 {
617         LDAP_CONN *conn = connection;
618
619         ldap_unbind_s(conn->handle);
620         free(conn);
621
622         return 0;
623 }
624
625
626 /** Gets an LDAP socket from the connection pool
627  *
628  */
629 static LDAP_CONN *ldap_get_socket(ldap_instance *inst)
630 {
631         LDAP_CONN *conn;
632
633         conn = fr_connection_get(inst->pool);
634         if (!conn) {
635                 radlog(L_ERR, "rlm_ldap (%s): all ldap connections are in use",
636                        inst->xlat_name);
637                 return NULL;
638         }
639
640         return conn;
641 }
642
643 /** Frees an LDAP socket back to the connection pool
644  *
645  */
646 static void ldap_release_socket(ldap_instance *inst, LDAP_CONN *conn)
647 {
648         /*
649          *      Could have already been free'd due to a previous error.
650          */
651         if (!conn) return;
652
653         /*
654          *      We chased a referral to another server.
655          *
656          *      This connection is no longer part of the pool which is
657          *      connected to and bound to the configured server.
658          *      Close it.
659          *
660          *      Note that we do NOT close it if it was bound to
661          *      another user.  Instead, we let the next caller do the
662          *      rebind.
663          */
664         if (conn->referred) {
665                 fr_connection_del(inst->pool, conn);
666                 return;
667         }
668
669         fr_connection_release(inst->pool, conn);
670         return;
671 }
672
673
674 /* Converts "bad" strings into ones which are safe for LDAP
675  *
676  */
677 static size_t ldap_escape_func(UNUSED REQUEST *request, char *out,
678                                size_t outlen, const char *in, UNUSED void *arg)
679 {
680         size_t len = 0;
681
682         while (in[0]) {
683                 /*
684                  *      Encode unsafe characters.
685                  */
686                 if (((len == 0) &&
687                     ((in[0] == ' ') || (in[0] == '#'))) ||
688                     (strchr(",+\"\\<>;*=()", *in))) {
689                         static const char hex[] = "0123456789abcdef";
690
691                         /*
692                          *      Only 3 or less bytes available.
693                          */
694                         if (outlen <= 3) {
695                                 break;
696                         }
697
698                         *(out++) = '\\';
699                         *(out++) = hex[((*in) >> 4) & 0x0f];
700                         *(out++) = hex[(*in) & 0x0f];
701                         outlen -= 3;
702                         len += 3;
703                         in++;
704                         continue;
705                 }
706
707                 /*
708                  *      Only one byte left.
709                  */
710                 if (outlen <= 1) {
711                         break;
712                 }
713
714                 /*
715                  *      Allowed character.
716                  */
717                 *(out++) = *(in++);
718                 outlen--;
719                 len++;
720         }
721         *out = '\0';
722         return len;
723 }
724
725 /** Do a search and get a response
726  *
727  */
728 static int perform_search(ldap_instance *inst, REQUEST *request,
729                           LDAP_CONN **pconn, const char *search_basedn,
730                           int scope, const char *filter, 
731                           const char * const *attrs, LDAPMessage **presult)
732 {
733         int             ldap_errno;
734         int             count = 0;
735         int             reconnect = FALSE;
736         LDAP_CONN       *conn = *pconn;
737         struct timeval  tv;
738
739         /*
740          *      OpenLDAP library doesn't declare attrs array as const, but
741          *      it really should be *sigh*.
742          */
743         char **search_attrs;
744         memcpy(&search_attrs, &attrs, sizeof(attrs));
745
746         *presult = NULL;
747
748         /*
749          *      Do all searches as the default admin user.
750          */
751         if (conn->rebound) {
752                 ldap_errno = ldap_bind_wrapper(pconn,
753                                                inst->login, inst->password,
754                                                NULL, TRUE);
755                 if (ldap_errno != RLM_MODULE_OK) {
756                         return -1;
757                 }
758
759                 rad_assert(*pconn != NULL);
760                 conn = *pconn;
761                 conn->rebound = FALSE;
762         }
763
764         tv.tv_sec = inst->timeout;
765         tv.tv_usec = 0;
766         RDEBUG2("Performing search in '%s' with filter '%s'",
767                 search_basedn ? search_basedn : "(null)" ,
768                 filter);
769
770 retry:
771         ldap_errno = ldap_search_ext_s(conn->handle, search_basedn, scope,
772                                        filter, search_attrs, 0, NULL, NULL,
773                                        &tv, 0, presult);
774         switch (ldap_errno) {
775         case LDAP_SUCCESS:
776         case LDAP_NO_SUCH_OBJECT:
777                 break;
778
779         case LDAP_SERVER_DOWN:
780         do_reconnect:
781                 ldap_msgfree(*presult);
782
783                 if (reconnect) return -1;
784                 reconnect = TRUE;
785
786                 conn = fr_connection_reconnect(inst->pool, conn);
787                 *pconn = conn;  /* tell the caller we have a new connection */
788                 if (!conn) return -1;
789                 goto retry;
790
791         case LDAP_INSUFFICIENT_ACCESS:
792                 radlog(L_ERR, "rlm_ldap (%s): Search failed: "
793                        "Insufficient access. Check the identity and password "
794                        "configuration directives", inst->xlat_name);
795                 ldap_msgfree(*presult);
796                 return -1;
797
798         case LDAP_TIMEOUT:
799                 exec_trigger(NULL, inst->cs, "modules.ldap.timeout", TRUE);
800                 radlog(L_ERR, "rlm_ldap (%s): Search failed: Timed out "
801                        "while waiting for server to respond"
802                        "Please increase the timeout", inst->xlat_name);
803                 ldap_msgfree(*presult);
804                 return -1;
805
806         case LDAP_FILTER_ERROR:
807                 radlog(L_ERR, "rlm_ldap (%s): Search failed: Bad search "
808                        "filter: %s", inst->xlat_name,filter);
809                 ldap_msgfree(*presult);
810                 return -1;
811
812         case LDAP_TIMELIMIT_EXCEEDED:
813                 exec_trigger(NULL, inst->cs, "modules.ldap.timeout", TRUE);
814
815         case LDAP_BUSY:
816         case LDAP_UNAVAILABLE:
817                 /*
818                  *      Reconnect.  There's an issue with the socket
819                  *      or LDAP server.
820                  */
821                 ldap_get_option(conn->handle, LDAP_OPT_ERROR_NUMBER,
822                                 &ldap_errno);
823                 radlog(L_ERR, "rlm_ldap (%s): Search failed: %s",
824                        inst->xlat_name, ldap_err2string(ldap_errno));
825                 goto do_reconnect;
826
827         default:
828                 ldap_get_option(conn->handle, LDAP_OPT_ERROR_NUMBER,
829                                 &ldap_errno);
830                 radlog(L_ERR, "rlm_ldap (%s): Search failed: %s",
831                        inst->xlat_name, ldap_err2string(ldap_errno));
832                 ldap_msgfree(*presult);
833                 return -1;
834         }
835
836         count = ldap_count_entries(conn->handle, *presult);
837         if (count == 0) {
838                 ldap_msgfree(*presult);
839                 RDEBUG("Search returned no results");
840                 
841                 return -2;
842         }
843
844         if (count != 1) {
845                 ldap_msgfree(*presult);
846                 RDEBUG("Got ambiguous search result (%d results)", count);
847                       
848                 return -2;
849         }
850
851         return 0;
852 }
853
854 /** Expand an LDAP URL into a query, and return a string result from that query.
855  *
856  */
857 static size_t ldap_xlat(void *instance, REQUEST *request, const char *fmt,
858                         char *out, size_t freespace)
859 {
860         int rcode;
861         size_t length = 0;
862         ldap_instance *inst = instance;
863         LDAPURLDesc *ldap_url;
864         LDAPMessage *result = NULL;
865         LDAPMessage *entry = NULL;
866         char **vals;
867         LDAP_CONN *conn;
868         int ldap_errno;
869         const char *url;
870         const char **attrs;
871         char buffer[MAX_FILTER_STR_LEN];
872
873         if (strchr(fmt, '%') != NULL) {
874                 if (!radius_xlat(buffer, sizeof(buffer), fmt, request,
875                                  ldap_escape_func, NULL)) {
876                         radlog(L_ERR,
877                                "rlm_ldap (%s): Unable to create LDAP URL", 
878                                inst->xlat_name);
879                         return 0;
880                 }
881                 url = buffer;
882         } else {
883                 url = fmt;
884         }
885
886         if (!ldap_is_ldap_url(url)) {
887                 radlog(L_ERR, "rlm_ldap (%s): String passed does not look "
888                        "like an LDAP URL", inst->xlat_name);
889                 return 0;
890         }
891
892         if (ldap_url_parse(url, &ldap_url)){
893                 radlog(L_ERR, "rlm_ldap (%s): Parsing LDAP URL failed",
894                        inst->xlat_name);
895                 return 0;
896         }
897
898         /*
899          *      Nothing, empty string, "*" string, or got 2 things, die.
900          */
901         if (!ldap_url->lud_attrs || !ldap_url->lud_attrs[0] ||
902             !*ldap_url->lud_attrs[0] ||
903             (strcmp(ldap_url->lud_attrs[0], "*") == 0) ||
904             ldap_url->lud_attrs[1]) {
905                 radlog(L_ERR, "rlm_ldap (%s): Bad attributes list in LDAP "
906                        "URL. URL must specify exactly one attribute to "
907                        "retrieve",
908                        inst->xlat_name);
909                        
910                 goto free_urldesc;
911         }
912
913         if (ldap_url->lud_host &&
914             ((strncmp(inst->server, ldap_url->lud_host,
915                       strlen(inst->server)) != 0) ||
916              (ldap_url->lud_port != inst->port))) {
917                 RDEBUG("Requested server/port is \"%s:%i\"", ldap_url->lud_host,
918                        inst->port);
919                 
920                 goto free_urldesc;
921         }
922
923         conn = ldap_get_socket(inst);
924         if (!conn) goto free_urldesc;
925
926         memcpy(&attrs, &ldap_url->lud_attrs, sizeof(attrs));
927         
928         rcode = perform_search(inst, request, &conn, ldap_url->lud_dn, 
929                                ldap_url->lud_scope, ldap_url->lud_filter, attrs,
930                                &result);
931         if (rcode < 0) {
932                 if (rcode == -2) {
933                         RDEBUG("Search returned not found", inst->xlat_name);
934                         goto free_socket;
935                 }
936
937                 goto free_socket;
938         }
939
940         entry = ldap_first_entry(conn->handle, result);
941         if (!entry) {
942                 ldap_get_option(conn->handle, LDAP_OPT_RESULT_CODE,
943                                 &ldap_errno);
944                 radlog(L_ERR, "rlm_ldap (%s): Failed retrieving entry: %s", 
945                        inst->xlat_name,
946                        ldap_err2string(ldap_errno));
947                 goto free_result;
948         }
949
950         vals = ldap_get_values(conn->handle, entry, ldap_url->lud_attrs[0]);
951         if (!vals) {
952                 RDEBUG("No \"%s\" attributes found in specified object",
953                        inst->xlat_name, ldap_url->lud_attrs[0]);
954                 goto free_result;
955         }
956
957         length = strlen(vals[0]);
958         if (length >= freespace){
959
960                 goto free_vals;
961         }
962
963         strlcpy(out, vals[0], freespace);
964
965 free_vals:
966         ldap_value_free(vals);
967 free_result:
968         ldap_msgfree(result);
969 free_socket:
970         ldap_release_socket(inst, conn);
971 free_urldesc:
972         ldap_free_urldesc(ldap_url);
973
974         return length;
975 }
976
977
978 static char *get_userdn(LDAP_CONN **pconn, REQUEST *request, int *module_rcode)
979 {
980         int             rcode;
981         VALUE_PAIR      *vp;
982         ldap_instance   *inst = (*pconn)->inst;
983         LDAP            *handle = (*pconn)->handle;
984         LDAPMessage     *result, *entry;
985         int             ldap_errno;
986         static char     firstattr[] = "uid";
987         char            *user_dn;
988         const char      *attrs[] = {firstattr, NULL};
989         char            filter[MAX_FILTER_STR_LEN];     
990         char            basedn[MAX_FILTER_STR_LEN];     
991
992         *module_rcode = RLM_MODULE_FAIL;
993
994         vp = pairfind(request->config_items, PW_LDAP_USERDN, 0);
995         if (vp) return vp->vp_strvalue;
996
997         if (!radius_xlat(filter, sizeof(filter), inst->filter,
998                          request, ldap_escape_func, NULL)) {
999                 radlog(L_ERR, "rlm_ldap (%s): Unable to create filter",
1000                        inst->xlat_name);
1001                 *module_rcode = RLM_MODULE_INVALID;
1002                 return NULL;
1003         }
1004
1005         if (!radius_xlat(basedn, sizeof(basedn), inst->basedn,
1006                          request, ldap_escape_func, NULL)) {
1007                 radlog(L_ERR, "rlm_ldap (%s): Unable to create basedn",
1008                        inst->xlat_name);
1009                 *module_rcode = RLM_MODULE_INVALID;
1010                 return NULL;
1011         }
1012
1013         rcode = perform_search(inst, request, pconn, basedn, LDAP_SCOPE_SUBTREE,
1014                                filter, attrs, &result);
1015         if (rcode < 0) {
1016                 if (rcode == -2) {
1017                         *module_rcode = RLM_MODULE_NOTFOUND;
1018                 }
1019
1020                 return NULL;
1021         }
1022
1023         if ((entry = ldap_first_entry(handle, result)) == NULL) {
1024                 ldap_get_option(handle, LDAP_OPT_RESULT_CODE,
1025                                 &ldap_errno);
1026                 radlog(L_ERR, "rlm_ldap (%s): Failed retrieving entry: %s", 
1027                        inst->xlat_name,
1028                        ldap_err2string(ldap_errno));
1029                 ldap_msgfree(result);
1030                 return NULL;
1031         }
1032
1033         if ((user_dn = ldap_get_dn(handle, entry)) == NULL) {
1034                 ldap_get_option(handle, LDAP_OPT_RESULT_CODE,
1035                                 &ldap_errno);
1036                 radlog(L_ERR, "rlm_ldap (%s): ldap_get_dn() failed: %s",
1037                        inst->xlat_name,
1038                        ldap_err2string(ldap_errno));
1039                        
1040                 ldap_msgfree(result);
1041                 return NULL;
1042         }
1043
1044         vp = pairmake("LDAP-UserDn", user_dn, T_OP_EQ);
1045         if (!vp) {
1046                 ldap_memfree(user_dn);
1047                 ldap_msgfree(result);
1048                 return NULL;
1049         }
1050         
1051         pairadd(&request->config_items, vp);
1052         ldap_memfree(user_dn);
1053         ldap_msgfree(result);
1054
1055         return vp->vp_strvalue;
1056 }
1057
1058
1059 /** Perform LDAP-Group comparison checking
1060  *
1061  */
1062 static int ldap_groupcmp(void *instance, REQUEST *request,
1063                          UNUSED VALUE_PAIR *thing, VALUE_PAIR *check,
1064                          UNUSED VALUE_PAIR *check_pairs,
1065                          UNUSED VALUE_PAIR **reply_pairs)
1066 {
1067         ldap_instance   *inst = instance;
1068         int             i, rcode, found, module_rcode;
1069         LDAPMessage     *result = NULL;
1070         LDAPMessage     *entry = NULL;
1071         int             ldap_errno;
1072         int             check_is_dn = FALSE, value_is_dn = FALSE;
1073         static char     firstattr[] = "dn";
1074         const char      *attrs[] = {firstattr, NULL};
1075         char            **vals;
1076         const char      *group_attrs[] = {inst->groupmemb_attr, NULL};
1077         LDAP_CONN       *conn;
1078         char            *user_dn;
1079
1080         char            gr_filter[MAX_FILTER_STR_LEN];
1081         char            filter[MAX_FILTER_STR_LEN];
1082         char            basedn[MAX_FILTER_STR_LEN];
1083
1084         RDEBUG("Searching for user in group \"%s\"", check->vp_strvalue);
1085
1086         if (check->length == 0) {
1087                 RDEBUG("Cannot do comparison (group name is empty)");
1088                 return 1;
1089         }
1090
1091         conn = ldap_get_socket(inst);
1092         if (!conn) return 1;
1093
1094         /*
1095          *      This is used in the default membership filter.
1096          */
1097         user_dn = get_userdn(&conn, request, &module_rcode);
1098         if (!user_dn) {
1099                 ldap_release_socket(inst, conn);
1100                 return 1;
1101         }
1102
1103         if (!inst->groupmemb_filter) goto check_attr;
1104
1105         if (!radius_xlat(gr_filter, sizeof(gr_filter),
1106                          inst->groupmemb_filter, request, ldap_escape_func,
1107                          NULL)) {
1108                 radlog(L_ERR, "rlm_ldap (%s): Failed creating group filter",
1109                        inst->xlat_name);
1110                 return 1;
1111         }
1112
1113         /*
1114          *      If it's a DN, use that.
1115          */
1116         check_is_dn = strchr(check->vp_strvalue,',') == NULL ? FALSE : TRUE;
1117         
1118         if (check_is_dn) {
1119                 strlcpy(filter, gr_filter, sizeof(filter));
1120                 strlcpy(basedn, check->vp_strvalue, sizeof(basedn));    
1121         } else {
1122                 snprintf(filter, sizeof(filter), "(&(%s=%s)%s)",
1123                          inst->groupname_attr,
1124                          check->vp_strvalue, gr_filter);
1125
1126                 /*
1127                  *      get_userdn does this, too.  Oh well.
1128                  */
1129                 if (!radius_xlat(basedn, sizeof(basedn), inst->basedn,
1130                                  request, ldap_escape_func, NULL)) {
1131                         radlog(L_ERR, "rlm_ldap (%s): Failed creating basedn",
1132                                inst->xlat_name);
1133                         return 1;
1134                 }
1135         }
1136
1137         rcode = perform_search(inst, request, &conn, basedn, LDAP_SCOPE_SUBTREE,
1138                                filter, attrs, &result);
1139         if (rcode == 0) {
1140                 ldap_release_socket(inst, conn);
1141                 ldap_msgfree(result);
1142                         
1143                 RDEBUG("User found in group object");
1144                 
1145                 return 0;
1146         }
1147
1148         if (rcode == -1) {
1149                 ldap_release_socket(inst, conn);
1150                 return 1;
1151         }
1152
1153         /* else the search returned -2, for "not found" */
1154
1155         /*
1156          *      Else the search returned NOTFOUND.  See if we're
1157          *      configured to search for group membership using user
1158          *      object attribute.
1159          */
1160         if (!inst->groupmemb_attr) {
1161                 ldap_release_socket(inst, conn);
1162                 RDEBUG("Group object \"%s\" not found, or user is not a member",
1163                        check->vp_strvalue);
1164                 return 1;
1165         }
1166
1167 check_attr:
1168         RDEBUG2("Checking user object membership (%s) attributes",
1169                 inst->groupmemb_attr);
1170
1171         snprintf(filter ,sizeof(filter), "(objectclass=*)");
1172
1173         rcode = perform_search(inst, request, &conn, user_dn, LDAP_SCOPE_BASE,
1174                                filter, group_attrs, &result);
1175         if (rcode < 0) {
1176                 if (rcode == -2) {
1177                         RDEBUG("Can't check membership attributes, user object "
1178                                "not found");
1179                 }
1180                 ldap_release_socket(inst, conn);
1181                 return 1;
1182         }
1183
1184         entry = ldap_first_entry(conn->handle, result);
1185         if (!entry) {
1186                 ldap_get_option(conn->handle, LDAP_OPT_RESULT_CODE,
1187                                 &ldap_errno);
1188                 radlog(L_ERR, "rlm_ldap (%s): Failed retrieving entry: %s", 
1189                        inst->xlat_name,
1190                        ldap_err2string(ldap_errno));
1191                                
1192                 ldap_release_socket(inst, conn);
1193                 ldap_msgfree(result);
1194                 return 1;
1195         }
1196
1197         vals = ldap_get_values(conn->handle, entry, inst->groupmemb_attr);
1198         if (!vals) {
1199                 RDEBUG("No group membership attribute(s) found in user object");
1200                 ldap_release_socket(inst, conn);
1201                 ldap_msgfree(result);
1202                 return 1;
1203         }
1204
1205         /*
1206          *      Loop over the list of groups the user is a member of,
1207          *      looking for a match.
1208          */
1209         found = FALSE;
1210         for (i = 0; i < ldap_count_values(vals); i++) {
1211                 LDAPMessage *gr_result = NULL;
1212                 
1213                 value_is_dn = strchr(vals[i], ',') == NULL ? FALSE : TRUE;
1214                 
1215                 RDEBUG2("Processing group membership value \"%s\"", vals[i]);
1216
1217                 /*
1218                  *      Both literal group names, do case sensitive comparison
1219                  */
1220                 if (!check_is_dn && !value_is_dn) {
1221                         if (strcmp(vals[i], check->vp_strvalue) == 0){
1222                                 RDEBUG("User found (membership value matches "
1223                                        "check value)");
1224                                
1225                                 found = TRUE;
1226                                 break;
1227                         }
1228                         
1229                         continue;
1230                 }
1231
1232                 /*
1233                  *      Both DNs, do case insensitive comparison
1234                  */
1235                 if (check_is_dn && value_is_dn) {
1236                         if (strcasecmp(vals[i], check->vp_strvalue) == 0){
1237                                 RDEBUG("User found (membership DN matches "
1238                                        "check DN)");
1239                                
1240                                 found = TRUE;
1241                                 break;
1242                         }
1243                         
1244                         continue;
1245                 }
1246                 
1247                 /*
1248                  *      If the value is not a DN, or the check item is a DN
1249                  *      there's nothing more we can do.
1250                  */
1251                 if (!value_is_dn && check_is_dn) continue;
1252
1253                 /*
1254                  *      We have a value which is a DN, and a check item which
1255                  *      specifies the name of a group, search using the value
1256                  *      DN for the group, and see if it has a groupname_attr
1257                  *      which matches our check val.
1258                  */
1259                 RDEBUG2("Searching with membership DN and group name");
1260
1261                 snprintf(filter,sizeof(filter), "(%s=%s)",
1262                          inst->groupname_attr, check->vp_strvalue);
1263
1264                 rcode = perform_search(inst, request, &conn, vals[i],
1265                                        LDAP_SCOPE_BASE, filter, attrs,
1266                                        &gr_result);
1267                                        
1268                 ldap_msgfree(gr_result);
1269
1270                 /* Error occurred */
1271                 if (rcode == -1) {
1272                         ldap_value_free(vals);
1273                         ldap_msgfree(result);
1274                         ldap_release_socket(inst, conn);
1275                         return 1;
1276                 }
1277                 
1278                 /*
1279                  *      Either the group DN wasn't found, or it didn't have the
1280                  *      correct name. Continue looping over the attributes.
1281                  */
1282                 if (rcode == -2) {
1283                         ldap_msgfree(gr_result);
1284                         continue;
1285                 }
1286
1287                 found = TRUE;
1288
1289                 RDEBUG("User found (group name in membership DN matches check "
1290                        "value)");
1291
1292                 break;
1293         }
1294
1295         ldap_value_free(vals);
1296         ldap_msgfree(result);
1297         ldap_release_socket(inst, conn);
1298
1299         if (!found){
1300                 RDEBUG("User is not a member of specified group");
1301                 return 1;
1302         }
1303
1304         return 0;
1305 }
1306
1307 /** Parse update section
1308  *
1309  * Verify that the ldap update section makes sense, and add attribute names
1310  * to array of attributes for efficient querying later.
1311  */
1312 static int build_attrmap(CONF_SECTION *cs, VALUE_PAIR_MAP **head)
1313 {
1314         const char *cs_list, *p;
1315
1316         request_refs_t request_def = REQUEST_CURRENT;
1317         pair_lists_t list_def = PAIR_LIST_REQUEST;
1318
1319         CONF_ITEM *ci = cf_sectiontoitem(cs);
1320         CONF_PAIR *cp;
1321
1322         unsigned int total = 0;
1323         VALUE_PAIR_MAP **tail, *map;
1324         *head = NULL;
1325         tail = head;
1326         
1327         if (!cs) return 0;
1328         
1329         cs_list = p = cf_section_name2(cs);
1330         if (cs_list) {
1331                 request_def = radius_request_name(&p, REQUEST_UNKNOWN);
1332                 if (request_def == REQUEST_UNKNOWN) {
1333                         cf_log_err(ci, "rlm_ldap: Default request specified "
1334                                    "in mapping section is invalid");
1335                         return -1;
1336                 }
1337                 
1338                 list_def = fr_str2int(pair_lists, p, PAIR_LIST_UNKNOWN);
1339                 if (list_def == PAIR_LIST_UNKNOWN) {
1340                         cf_log_err(ci, "rlm_ldap: Default list specified "
1341                                    "in mapping section is invalid");
1342                         return -1;
1343                 }
1344         }
1345
1346         for (ci = cf_item_find_next(cs, NULL);
1347              ci != NULL;
1348              ci = cf_item_find_next(cs, ci)) {
1349                 if (total++ == MAX_ATTRMAP) {
1350                         cf_log_err(ci, "rlm_ldap: Attribute map size exceeded");
1351                         goto error;
1352                 }
1353                 
1354                 if (!cf_item_is_pair(ci)) {
1355                         cf_log_err(ci, "rlm_ldap: Entry is not in \"attribute ="
1356                                        " ldap-attribute\" format");
1357                         goto error;
1358                 }
1359         
1360                 cp = cf_itemtopair(ci);
1361                 map = radius_cp2map(cp, REQUEST_CURRENT, list_def);
1362                 if (!map) {
1363                         goto error;
1364                 }
1365                 
1366                 *tail = map;
1367                 tail = &(map->next);
1368         }
1369
1370         return 0;
1371         
1372         error:
1373                 radius_mapfree(head);
1374                 return -1;
1375 }
1376
1377 /** Detach from the LDAP server and cleanup internal state.
1378  *
1379  */
1380 static int ldap_detach(void *instance)
1381 {
1382         ldap_instance *inst = instance;
1383
1384         if (inst->postauth) free(inst->postauth);
1385         if (inst->accounting) free(inst->accounting);
1386         
1387         fr_connection_pool_delete(inst->pool);
1388         
1389         if (inst->user_map) {
1390                 radius_mapfree(&inst->user_map);
1391         }
1392
1393         free(inst);
1394
1395         return 0;
1396 }
1397
1398 static int parse_sub_section(CONF_SECTION *parent, 
1399                              UNUSED ldap_instance *inst,
1400                              ldap_acct_section_t **config,
1401                              rlm_components_t comp)
1402 {
1403         CONF_SECTION *cs;
1404
1405         const char *name = section_type_value[comp].section;
1406         
1407         cs = cf_section_sub_find(parent, name);
1408         if (!cs) {
1409                 radlog(L_INFO, "Couldn't find configuration for %s. "
1410                        "Will return NOOP for calls from this section.", name);
1411                 
1412                 return 0;
1413         }
1414         
1415         *config = rad_calloc(sizeof(**config));
1416         if (cf_section_parse(cs, *config, acct_section_config) < 0) {
1417                 radlog(L_ERR, "Failed parsing configuration for section %s",
1418                        name);
1419                 
1420                 free(*config);
1421                 *config = NULL;
1422                 
1423                 return -1;
1424         }
1425                 
1426         (*config)->cs = cs;
1427
1428         return 0;
1429 }
1430
1431 /** Parses config
1432  * Uses section of radiusd config file passed as parameter to create an
1433  * instance of the module.
1434  */
1435 static int ldap_instantiate(CONF_SECTION * conf, void **instance)
1436 {
1437         ldap_instance *inst;
1438         CONF_SECTION *cs;
1439
1440         inst = rad_calloc(sizeof *inst);
1441         inst->cs = conf;
1442
1443         inst->chase_referrals = 2; /* use OpenLDAP defaults */
1444         inst->rebind = 2;
1445         
1446         inst->xlat_name = cf_section_name2(conf);
1447         if (!inst->xlat_name) {
1448                 inst->xlat_name = cf_section_name1(conf);
1449         }
1450                 
1451         rad_assert(inst->xlat_name);
1452
1453         /*
1454          *      If the configuration parameters can't be parsed, then fail.
1455          */
1456         if ((cf_section_parse(conf, inst, module_config) < 0) ||
1457             (parse_sub_section(conf, inst,
1458                                &inst->accounting,
1459                                RLM_COMPONENT_ACCT) < 0) ||
1460             (parse_sub_section(conf, inst,
1461                                &inst->postauth,
1462                                RLM_COMPONENT_POST_AUTH) < 0)) {
1463                 radlog(L_ERR, "rlm_ldap (%s): Failed parsing configuration",
1464                        inst->xlat_name);
1465                 goto error;
1466         }
1467
1468         if (inst->server == NULL) {
1469                 radlog(L_ERR, "rlm_ldap (%s): Missing 'server' directive",
1470                        inst->xlat_name);
1471                 goto error;
1472         }
1473
1474         /*
1475          *      Check for URLs.  If they're used and the library doesn't
1476          *      support them, then complain.
1477          */
1478         inst->is_url = 0;
1479         if (ldap_is_ldap_url(inst->server)) {
1480 #ifdef HAVE_LDAP_INITIALIZE
1481                 inst->is_url = 1;
1482                 inst->port = 0;
1483 #else
1484                 radlog(L_ERR, "rlm_ldap (%s): 'server' directive is in URL "
1485                        "form but ldap_initialize() is not available",
1486                        inst->xlat_name);
1487                 goto error;
1488 #endif
1489         }
1490
1491         /* workaround for servers which support LDAPS but not START TLS */
1492         if (inst->port == LDAPS_PORT || inst->tls_mode) {
1493                 inst->tls_mode = LDAP_OPT_X_TLS_HARD;
1494         } else {
1495                 inst->tls_mode = 0;
1496         }
1497
1498 #if LDAP_SET_REBIND_PROC_ARGS != 3
1499         /*
1500          *      The 2-argument rebind doesn't take an instance
1501          *      variable.  Our rebind function needs the instance
1502          *      variable for the username, password, etc.
1503          */
1504         if (inst->rebind == 1) {
1505                 radlog(L_ERR, "rlm_ldap (%s): Cannot use 'rebind' directive "
1506                        "as this version of libldap does not support the API "
1507                        "that we need", inst->xlat-name);
1508                 goto error;
1509         }
1510 #endif
1511
1512         /*
1513          *      Build the attribute map
1514          */
1515         cs = cf_section_sub_find(conf, "update");
1516         if (cs) {       
1517                 if (build_attrmap(cs, &(inst->user_map)) < 0) {
1518                         goto error;
1519                 }
1520         }
1521
1522         /*
1523          *      Group comparison checks.
1524          */
1525         paircompare_register(PW_LDAP_GROUP, PW_USER_NAME, ldap_groupcmp, inst); 
1526         if (cf_section_name2(conf)) {
1527                 DICT_ATTR *da;
1528                 ATTR_FLAGS flags;
1529                 char buffer[256];
1530
1531                 snprintf(buffer, sizeof(buffer), "%s-Ldap-Group",
1532                          inst->xlat_name);
1533                 memset(&flags, 0, sizeof(flags));
1534
1535                 dict_addattr(buffer, -1, 0, PW_TYPE_STRING, flags);
1536                 da = dict_attrbyname(buffer);
1537                 if (!da) {
1538                         radlog(L_ERR, "rlm_ldap (%s): Failed creating "
1539                                "attribute %s", inst->xlat_name, buffer);
1540                         goto error;
1541                 }
1542
1543                 paircompare_register(da->attr, PW_USER_NAME, ldap_groupcmp,
1544                                      inst);
1545         }
1546
1547         xlat_register(inst->xlat_name, ldap_xlat, inst);
1548
1549         /*
1550          *      Initialize the socket pool.
1551          */
1552         inst->pool = fr_connection_pool_init(inst->cs, inst,
1553                                              ldap_conn_create,
1554                                              NULL,
1555                                              ldap_conn_delete);
1556         if (!inst->pool) {
1557                 ldap_detach(inst);
1558                 return -1;
1559         }
1560         
1561         *instance = inst;
1562         return 0;
1563         
1564         error:
1565         ldap_detach(inst);
1566         return -1;
1567 }
1568
1569 static int check_access(ldap_instance *inst, REQUEST* request, LDAP_CONN *conn,
1570                         LDAPMessage *entry)
1571 {
1572         int rcode = -1;
1573         char **vals = NULL;
1574
1575         vals = ldap_get_values(conn->handle, entry, inst->access_attr);
1576         if (vals) {
1577                 if (inst->positive_access_attr) {
1578                         if (strncmp(vals[0], "FALSE", 5) == 0) {
1579                                 RDEBUG("Dialup access disabled");
1580
1581                         } else {
1582                                 rcode = 0;
1583                         }
1584
1585                 } else {
1586                         RDEBUG("\"%s\" attribute exists - access denied by"
1587                                " default", inst->access_attr);
1588                 }
1589
1590                 ldap_value_free(vals);
1591
1592         } else if (inst->positive_access_attr) {
1593                 RDEBUG("No %s attribute - access denied by default",
1594                        inst->access_attr);
1595
1596         } else {
1597                 rcode = 0;
1598         }
1599
1600         return rcode;
1601 }
1602
1603
1604 static VALUE_PAIR *ldap_getvalue(REQUEST *request, const VALUE_PAIR_TMPL *dst,
1605                                  void *ctx)
1606 {
1607         rlm_ldap_result_t *self = ctx;
1608         VALUE_PAIR *head, **tail, *vp;
1609         int i;
1610         
1611         request = request;
1612         
1613         head = NULL;
1614         tail = &head;
1615         
1616         /*
1617          *      Iterate over all the retrieved values,
1618          *      don't try and be clever about changing operators
1619          *      just use whatever was set in the attribute map. 
1620          */
1621         for (i = 0; i < self->count; i++) {
1622                 vp = pairalloc(dst->da);
1623                 rad_assert(vp);
1624
1625                 pairparsevalue(vp, self->values[i]);
1626                 
1627                 *tail = vp;
1628                 tail = &(vp->next);
1629         }
1630         
1631         return head;            
1632 }
1633
1634
1635 static void xlat_attrsfree(const xlat_attrs_t *expanded)
1636 {
1637         const VALUE_PAIR_MAP *map;
1638         unsigned int total = 0;
1639         
1640         const char *name;
1641         
1642         for (map = expanded->maps; map != NULL; map = map->next)
1643         {
1644                 name = expanded->attrs[total++];
1645                 if (!name) return;
1646                 
1647                 if (map->src->do_xlat) {
1648                         rad_cfree(name);
1649                 }
1650         }
1651 }
1652
1653
1654 static int xlat_attrs(REQUEST *request, const VALUE_PAIR_MAP *maps,
1655                       xlat_attrs_t *expanded)
1656 {
1657         const VALUE_PAIR_MAP *map;
1658         unsigned int total = 0;
1659         
1660         size_t len;
1661         char *buffer;
1662
1663         for (map = maps; map != NULL; map = map->next)
1664         {
1665                 if (map->src->do_xlat) {
1666                         buffer = rad_malloc(MAX_ATTR_STR_LEN);
1667                         len = radius_xlat(buffer, MAX_ATTR_STR_LEN,
1668                                           map->src->name, request, NULL, NULL);
1669                                           
1670                         if (!len) {
1671                                 RDEBUG("Expansion of LDAP attribute "
1672                                        "\"%s\" failed", map->src->name);
1673                                        
1674                                 expanded->attrs[total] = NULL;
1675                                 
1676                                 xlat_attrsfree(expanded);
1677                                 
1678                                 return -1;
1679                         }
1680                         
1681                         expanded->attrs[total++] = buffer;
1682                 } else {
1683                         expanded->attrs[total++] = map->src->name;
1684                 }
1685         }
1686         
1687         expanded->attrs[total] = NULL;
1688         expanded->maps = maps;
1689         
1690         return 0;
1691 }
1692
1693
1694 /** Convert attribute map into valuepairs
1695  *
1696  * Use the attribute map built earlier to convert LDAP values into valuepairs
1697  * and insert them into whichever list they need to go into.
1698  *
1699  * This is *NOT* atomic, but there's no condition in which we should error
1700  * out...
1701  */
1702 static void do_attrmap(UNUSED ldap_instance *inst, REQUEST *request,
1703                        LDAP *handle, const xlat_attrs_t *expanded,
1704                        LDAPMessage *entry)
1705 {
1706         const VALUE_PAIR_MAP    *map;
1707         unsigned int            total = 0;
1708         
1709         rlm_ldap_result_t       result;
1710         const char              *name;
1711
1712         for (map = expanded->maps; map != NULL; map = map->next)
1713         {
1714                 name = expanded->attrs[total++];
1715                 
1716                 result.values = ldap_get_values(handle, entry, name);
1717                 if (!result.values) {
1718                         RDEBUG2("Attribute \"%s\" not found in LDAP object",
1719                                 name);
1720                                 
1721                         goto next;
1722                 }
1723                 
1724                 /*
1725                  *      Find out how many values there are for the
1726                  *      attribute and extract all of them.
1727                  */
1728                 result.count = ldap_count_values(result.values);
1729                 
1730                 /*
1731                  *      If something bad happened, just skip, this is probably
1732                  *      a case of the dst being incorrect for the current
1733                  *      request context
1734                  */
1735                 if (radius_map2request(request, map, name, ldap_getvalue,
1736                                        &result) < 0) {
1737                         goto next;
1738                 }
1739                 
1740                 next:
1741                 
1742                 ldap_value_free(result.values);
1743         }
1744 }
1745
1746
1747 static void do_check_reply(ldap_instance *inst, REQUEST *request)
1748 {
1749        /*
1750         *       More warning messages for people who can't be bothered
1751         *       to read the documentation.
1752         */
1753         if (inst->expect_password && (debug_flag > 1)) {
1754                 if (!pairfind(request->config_items,PW_CLEARTEXT_PASSWORD, 0) &&
1755                         !pairfind(request->config_items,
1756                                   PW_NT_PASSWORD, 0) &&
1757                         !pairfind(request->config_items,
1758                                   PW_USER_PASSWORD, 0) &&
1759                         !pairfind(request->config_items,
1760                                   PW_PASSWORD_WITH_HEADER, 0) &&
1761                         !pairfind(request->config_items,
1762                                   PW_CRYPT_PASSWORD, 0)) {
1763                                 RDEBUG("WARNING: No \"known good\" password "
1764                                        "was found in LDAP.  Are you sure that "
1765                                        "the user is configured correctly?");
1766                }
1767        }
1768 }
1769
1770
1771 static void apply_profile(ldap_instance *inst, REQUEST *request,
1772                           LDAP_CONN **pconn, const char *profile,
1773                           const xlat_attrs_t *expanded)
1774 {
1775         int rcode;
1776         LDAPMessage     *result, *entry;
1777         int             ldap_errno;
1778         LDAP            *handle = (*pconn)->handle;
1779         char            filter[MAX_FILTER_STR_LEN];
1780
1781         if (!profile || !*profile) return;
1782
1783         strlcpy(filter, inst->base_filter, sizeof(filter));
1784
1785         rcode = perform_search(inst, request, pconn, profile, LDAP_SCOPE_BASE,
1786                                filter, expanded->attrs, &result);
1787                 
1788         if (rcode < 0) {
1789                 if (rcode == -2) {
1790                         RDEBUG("Profile \"%s\" not found", profile);
1791                 }
1792                 goto free_result;
1793         }
1794
1795         entry = ldap_first_entry(handle, result);
1796         if (!entry) {
1797                 ldap_get_option(handle, LDAP_OPT_RESULT_CODE,
1798                                 &ldap_errno);
1799                 radlog(L_ERR, "rlm_ldap (%s): Failed retrieving entry: %s", 
1800                        inst->xlat_name,
1801                        ldap_err2string(ldap_errno));
1802                        
1803                 goto free_result;
1804         }
1805         
1806         do_attrmap(inst, request, handle, expanded, entry);
1807
1808 free_result:
1809         ldap_msgfree(result);
1810 }
1811
1812
1813 /** Check if user is authorized for remote access
1814  *
1815  */
1816 static int ldap_authorize(void *instance, REQUEST * request)
1817 {
1818         int rcode;
1819         int module_rcode = RLM_MODULE_OK;
1820         ldap_instance   *inst = instance;
1821         char            *user_dn;
1822         char            **vals;
1823         VALUE_PAIR      *vp;
1824         LDAP_CONN       *conn;
1825         LDAPMessage     *result, *entry;
1826         int             ldap_errno;
1827         char            filter[MAX_FILTER_STR_LEN];
1828         char            basedn[MAX_FILTER_STR_LEN];
1829         xlat_attrs_t    expanded; /* faster that mallocing every time */
1830         
1831         if (!request->username) {
1832                 RDEBUG2("Attribute \"User-Name\" is required for "
1833                         "authorization.");
1834                 return RLM_MODULE_NOOP;
1835         }
1836
1837         /*
1838          *      Check for valid input, zero length names not permitted
1839          */
1840         if (request->username->length == 0) {
1841                 RDEBUG2("Zero length username not permitted");
1842                 return RLM_MODULE_INVALID;
1843         }
1844
1845         if (!radius_xlat(filter, sizeof(filter), inst->filter,
1846                          request, ldap_escape_func, NULL)) {
1847                 radlog(L_ERR, "rlm_ldap (%s): Failed creating filter",
1848                        inst->xlat_name);
1849                 return RLM_MODULE_INVALID;
1850         }
1851
1852         if (!radius_xlat(basedn, sizeof(basedn), inst->basedn,
1853                          request, ldap_escape_func, NULL)) {
1854                 radlog(L_ERR, "rlm_ldap (%s): Failed creating basedn",
1855                        inst->xlat_name);
1856                 return RLM_MODULE_INVALID;
1857         }
1858
1859         conn = ldap_get_socket(inst);
1860         if (!conn) return RLM_MODULE_FAIL;
1861         
1862         if (xlat_attrs(request, inst->user_map, &expanded) < 0) {
1863                 return RLM_MODULE_FAIL;
1864         }
1865         
1866         rcode = perform_search(inst, request, &conn, basedn,
1867                                LDAP_SCOPE_SUBTREE, filter, expanded.attrs,
1868                                &result);
1869         
1870         if (rcode < 0) {
1871                 if (rcode == -2) {
1872                         module_failure_msg(request,
1873                                            "rlm_ldap (%s): User object not "
1874                                            " found",
1875                                            inst->xlat_name);
1876                                            
1877                         RDEBUG("User object not found", inst->xlat_name);
1878                                
1879                         module_rcode = RLM_MODULE_NOTFOUND;
1880                         goto free_socket;
1881                 }
1882
1883                 goto free_socket;
1884         }
1885
1886         entry = ldap_first_entry(conn->handle, result);
1887         if (!entry) {
1888                 ldap_get_option(conn->handle, LDAP_OPT_RESULT_CODE,
1889                                 &ldap_errno);
1890                 radlog(L_ERR, "rlm_ldap (%s): Failed retrieving entry: %s", 
1891                        inst->xlat_name,
1892                        ldap_err2string(ldap_errno));
1893                        
1894                 goto free_result;
1895         }
1896
1897         user_dn = ldap_get_dn(conn->handle, entry);
1898         if (!user_dn) {
1899                 ldap_get_option(conn->handle, LDAP_OPT_RESULT_CODE,
1900                                 &ldap_errno);
1901                 radlog(L_ERR, "rlm_ldap (%s): ldap_get_dn() failed: %s",
1902                        inst->xlat_name,
1903                        ldap_err2string(ldap_errno));
1904                 goto free_result;
1905         }
1906         
1907         RDEBUG2("User found at DN \"%s\"", user_dn);
1908         /*
1909          *      Adding attribute containing the Users' DN.
1910          */
1911         pairadd(&request->config_items,
1912                 pairmake("Ldap-UserDn", user_dn, T_OP_EQ));
1913
1914 #ifdef WITH_EDIR
1915         /*
1916          *      We already have a Cleartext-Password.  Skip edir.
1917          */
1918         if (inst->edir && pairfind(request->config_items,
1919                                    PW_CLEARTEXT_PASSWORD, 0)) {
1920                 goto skip_edir;
1921         }
1922
1923         /*
1924          *      Retrieve Universal Password if we use eDirectory
1925          */
1926         if (inst->edir) {
1927                 int res = 0;
1928                 size_t bufsize;
1929                 char buffer[256];
1930
1931                 bufsize = sizeof(buffer);
1932
1933                 /* retrive universal password */
1934                 res = nmasldap_get_password(conn->handle, user_dn,
1935                                             buffer, &bufsize);
1936                 if (res != 0) {
1937                         RDEBUG2("Failed to retrieve eDirectory password. Check your configuration !");
1938                         module_rcode = RLM_MODULE_NOOP;
1939                         goto free_result;
1940                 }
1941
1942                 /* add Cleartext-Password attribute to the request */
1943                 vp = radius_paircreate(request, &request->config_items,
1944                                        PW_CLEARTEXT_PASSWORD, 0, PW_TYPE_STRING);
1945                 strlcpy(vp->vp_strvalue, buffer, sizeof(vp->vp_strvalue));
1946                 vp->length = strlen(vp->vp_strvalue);
1947                 
1948                 RDEBUG2("Added eDirectory password in check items as %s = %s",
1949                         vp->name, vp->vp_strvalue);
1950         }
1951
1952 skip_edir:
1953 #endif
1954
1955         ldap_memfree(user_dn);
1956
1957         /*
1958          *      Check for access.
1959          */
1960         if (inst->access_attr) {
1961                 if (check_access(inst, request, conn, entry) < 0) {
1962                         module_rcode = RLM_MODULE_USERLOCK;
1963                         goto free_result;
1964                 }
1965         }
1966
1967         /*
1968          *      Apply ONE user profile, or a default user profile.
1969          */
1970         vp = pairfind(request->config_items, PW_USER_PROFILE, 0);
1971         if (vp || inst->default_profile) {
1972                 char *profile = inst->default_profile;
1973
1974                 if (vp) profile = vp->vp_strvalue;
1975
1976                 apply_profile(inst, request, &conn, profile, &expanded);
1977         }
1978
1979         /*
1980          *      Apply a SET of user profiles.
1981          */
1982         if (inst->profile_attr) {
1983                 vals = ldap_get_values(conn->handle, entry, inst->profile_attr);
1984                 if (vals != NULL) {
1985                         int i;
1986         
1987                         for (i = 0; (vals[i] != NULL) && (*vals[i] != '\0');
1988                              i++) {
1989                                 apply_profile(inst, request, &conn, vals[i],
1990                                               &expanded);
1991                         }
1992         
1993                         ldap_value_free(vals);
1994                 }
1995         }
1996
1997         if (inst->user_map) {
1998                 do_attrmap(inst, request, conn->handle, &expanded, entry);
1999                 do_check_reply(inst, request);
2000         }
2001         
2002 free_result:
2003         xlat_attrsfree(&expanded);
2004         ldap_msgfree(result);
2005 free_socket:
2006         ldap_release_socket(inst, conn);
2007
2008         return module_rcode;
2009 }
2010
2011
2012 /** Check the user's password against ldap database
2013  *
2014  */
2015 static int ldap_authenticate(void *instance, REQUEST * request)
2016 {
2017         int             module_rcode;
2018         const char      *user_dn;
2019         ldap_instance   *inst = instance;
2020         LDAP_CONN       *conn;
2021
2022         /*
2023          * Ensure that we're being passed a plain-text password, and not
2024          * anything else.
2025          */
2026
2027         if (!request->username) {
2028                 radlog(L_AUTH, "rlm_ldap (%s): Attribute \"User-Name\" is "
2029                        "required for authentication", inst->xlat_name);
2030                 return RLM_MODULE_INVALID;
2031         }
2032
2033         if (!request->password) {
2034                 radlog(L_AUTH, "rlm_ldap (%s): Attribute \"User-Password\" "
2035                        "is required for authentication.", inst->xlat_name);
2036                 RDEBUG2("  You have set \"Auth-Type := LDAP\" somewhere.");
2037                 RDEBUG2("  *********************************************");
2038                 RDEBUG2("  * THAT CONFIGURATION IS WRONG.  DELETE IT.   ");
2039                 RDEBUG2("  * YOU ARE PREVENTING THE SERVER FROM WORKING.");
2040                 RDEBUG2("  *********************************************");
2041                 return RLM_MODULE_INVALID;
2042         }
2043
2044         if (request->password->attribute != PW_USER_PASSWORD) {
2045                 radlog(L_AUTH, "rlm_ldap (%s): Attribute \"User-Password\" "
2046                        "is required for authentication. Cannot use \"%s\".",
2047                        inst->xlat_name, request->password->name);
2048                 return RLM_MODULE_INVALID;
2049         }
2050
2051         if (request->password->length == 0) {
2052                 module_failure_msg(request,
2053                                    "rlm_ldap (%s): Empty password supplied",
2054                                    inst->xlat_name);
2055                 return RLM_MODULE_INVALID;
2056         }
2057
2058         conn = ldap_get_socket(inst);
2059         if (!conn) return RLM_MODULE_FAIL;
2060
2061         RDEBUG("Login attempt by \"%s\" with password \"%s\"",
2062                request->username->vp_strvalue, request->password->vp_strvalue);
2063
2064         /*
2065          *      Get the DN by doing a search.
2066          */
2067         user_dn = get_userdn(&conn, request, &module_rcode);
2068         if (!user_dn) {
2069                 ldap_release_socket(inst, conn);
2070                 return module_rcode;
2071         }
2072
2073         /*
2074          *      Bind as the user
2075          */
2076         conn->rebound = TRUE;
2077         module_rcode = ldap_bind_wrapper(&conn, user_dn,
2078                                          request->password->vp_strvalue,
2079                                          NULL, TRUE);
2080         if (module_rcode == RLM_MODULE_OK) {
2081                 RDEBUG("Bind as user \"%s\" was successful", user_dn);
2082         }
2083
2084         ldap_release_socket(inst, conn);
2085         return module_rcode;
2086 }
2087
2088 /** Modify user's object in LDAP
2089  *
2090  */
2091 static int user_modify(ldap_instance *inst, REQUEST *request,
2092                        ldap_acct_section_t *section)
2093 {
2094         int             module_rcode = RLM_MODULE_OK;
2095         int             ldap_errno;
2096         const char      *error_string;
2097         
2098         LDAP_CONN       *conn;
2099         LDAPMod         *modify[MAX_ATTRMAP];
2100         LDAPMod         **mod_p = modify;
2101         
2102         char            *passed[MAX_ATTRMAP * 2];
2103         int             i, last_pass = 0;
2104         
2105         char            *expanded[MAX_ATTRMAP];
2106         int             last_exp = 0;
2107         
2108         const char      *attr;
2109         const char      *value;
2110         
2111         int             presult = 0;
2112         
2113         const char      *user_dn;
2114
2115         conn = ldap_get_socket(inst);
2116         if (!conn) return RLM_MODULE_FAIL;
2117
2118         /*
2119          *      Build our set of modifications using the update sections in
2120          *      the config.
2121          */
2122         CONF_ITEM       *ci;
2123         CONF_PAIR       *cp;
2124         CONF_SECTION    *cs;
2125         FR_TOKEN        op;
2126         char            path[MAX_STRING_LEN];
2127         
2128         char    *p = path;
2129
2130         rad_assert(section);
2131         
2132         /*
2133          *      Locate the update section were going to be using
2134          */
2135         if (section->reference[0] != '.')
2136                 *p++ = '.';
2137         
2138         if (!radius_xlat(p, (sizeof(path) - (p - path)) - 1,
2139                          section->reference, request, NULL, NULL)) {
2140                 goto error;     
2141         }
2142
2143         ci = cf_reference_item(NULL, section->cs, path);
2144         if (!ci) {
2145                 goto error;     
2146         }
2147         
2148         if (!cf_item_is_section(ci)){
2149                 radlog(L_ERR, "rlm_ldap (%s): Reference must resolve to a "
2150                        "section", inst->xlat_name);
2151                 
2152                 goto error;     
2153         }
2154         
2155         cs = cf_section_sub_find(cf_itemtosection(ci), "update");
2156         if (!cs) {
2157                 radlog(L_ERR, "rlm_ldap (%s): Section must contain 'update' "
2158                        "subsection",
2159                        inst->xlat_name);
2160                 
2161                 goto error;
2162         }
2163         
2164         /*
2165          *      Iterate over all the pairs, building our mods array
2166          */
2167         for (ci = cf_item_find_next(cs, NULL);
2168              ci != NULL;
2169              ci = cf_item_find_next(cs, ci)) {
2170                 int do_xlat = FALSE;
2171                 
2172                 if ((modify - mod_p) == MAX_ATTRMAP) {
2173                         radlog(L_ERR, "rlm_ldap (%s): Modify map size exceeded",
2174                                inst->xlat_name);
2175         
2176                         goto error;
2177                 }
2178                 
2179                 if (!cf_item_is_pair(ci)) {
2180                         radlog(L_ERR, "rlm_ldap (%s): Entry is not in "
2181                                "\"ldap-attribute = value\" format",
2182                                inst->xlat_name);
2183                                
2184                         goto error;
2185                 }
2186         
2187                 cp = cf_itemtopair(ci);
2188                 
2189                 switch (cf_pair_value_type(cp))
2190                 {
2191                         case T_BARE_WORD:
2192                         case T_SINGLE_QUOTED_STRING:
2193                         break;
2194                         case T_BACK_QUOTED_STRING:
2195                         case T_DOUBLE_QUOTED_STRING:
2196                                 do_xlat = TRUE;         
2197                         break;
2198                         default:
2199                                 rad_assert(0);
2200                                 goto error;
2201                 }
2202                 
2203                 attr = cf_pair_attr(cp);
2204                 value = cf_pair_value(cp);
2205                 
2206                 if (do_xlat) {
2207                         p = rad_malloc(1024);   
2208                         
2209                         if (radius_xlat(p, 1024, value, request,
2210                                         NULL, NULL) == 0) {
2211                                 RDEBUG("xlat failed or expanded to empty "
2212                                        "string, skipping attribute \"%s\"",
2213                                        attr);
2214                         
2215                                 free(p);
2216                                 
2217                                 continue;                               
2218                         }
2219                         
2220                         expanded[last_exp++] = p;
2221                         
2222                         passed[last_pass] = p;
2223                 } else {
2224                         passed[last_pass] = value;
2225                 }
2226                 
2227                 passed[last_pass + 1] = NULL;
2228                 
2229                 (*mod_p)->mod_values = &passed[last_pass];
2230                                         
2231                 last_pass += 2;
2232                 
2233                 /*
2234                  *      Now we know the value is ok, copy the pointers into
2235                  *      the ldapmod struct.
2236                  */
2237                 memcpy(&((*mod_p)->mod_type), &(attr),
2238                        sizeof((*mod_p)->mod_type));
2239
2240                 op = cf_pair_operator(cp);
2241                 switch (op)
2242                 {
2243                         /*
2244                          *  T_OP_EQ is *NOT* supported, it is impossible to
2245                          *  support because of the lack of transactions in LDAP
2246                          */
2247                         case T_OP_ADD:
2248                                 (*mod_p)->mod_op = LDAP_MOD_ADD;
2249                         break;
2250                         case T_OP_SET:
2251                                 (*mod_p)->mod_op = LDAP_MOD_REPLACE;
2252                         break;
2253                         case T_OP_SUB:
2254                                 (*mod_p)->mod_op = LDAP_MOD_DELETE;
2255                         break;
2256                         default:
2257                                 radlog(L_ERR, "rlm_ldap (%s): Operator '%s' "
2258                                        "is not supported for LDAP modify "
2259                                        "operations", inst->xlat_name,
2260                                        fr_int2str(fr_tokens, op, "¿unknown?"));
2261                                        
2262                                 goto error;
2263                 }
2264                 
2265                 mod_p++;
2266         }
2267         
2268         *mod_p = NULL;
2269         
2270         /*
2271          *      Perform all modifications as the default admin user.
2272          */
2273         if (conn->rebound) {
2274                 ldap_errno = ldap_bind_wrapper(&conn,
2275                                                inst->login, inst->password,
2276                                                NULL, TRUE);
2277                 if (ldap_errno != RLM_MODULE_OK) {
2278                         goto error;
2279                 }
2280
2281                 rad_assert(conn != NULL);
2282                 conn->rebound = FALSE;
2283         }
2284
2285         user_dn = get_userdn(&conn, request, &module_rcode);
2286         if (!user_dn) {
2287                 module_rcode = RLM_MODULE_NOTFOUND;
2288                 goto release;
2289         }
2290         
2291         RDEBUG2("Modifying user object with DN \"%s\"", user_dn);
2292         
2293         ldap_errno = ldap_modify_ext(conn->handle, user_dn, modify, NULL, NULL,
2294                                      &presult);
2295                              
2296         if (ldap_errno < 0) {
2297                 ldap_get_option(conn->handle, LDAP_OPT_ERROR_NUMBER,
2298                                 &ldap_errno);
2299                                 
2300                 error_string = ldap_err2string(ldap_errno);
2301
2302                 radlog(L_ERR, "rlm_ldap (%s): Modifying DN \"%s\" failed: %s",
2303                        inst->xlat_name, user_dn, error_string);
2304                 
2305         error:
2306                 module_rcode = RLM_MODULE_FAIL;
2307                 
2308                 goto release;
2309         }
2310         
2311         RDEBUG2("Modification successful!");
2312         
2313         release:
2314         
2315         /*
2316          *      Free up any buffers we allocated for xlat expansion
2317          */     
2318         for (i = 0; i < last_exp; i++) {
2319                 free(expanded[i]);
2320         }
2321         
2322         ldap_release_socket(inst, conn);
2323         
2324         return module_rcode;
2325 }
2326
2327
2328 static int ldap_accounting(void *instance, REQUEST * request) {
2329         ldap_instance *inst = instance;         
2330
2331         if (inst->accounting) {
2332                 return user_modify(inst, request, inst->accounting); 
2333         }
2334         
2335         return RLM_MODULE_NOOP;
2336 }
2337
2338
2339 /** Check the user's password against ldap database
2340  *
2341  */
2342 static int ldap_postauth(void *instance, REQUEST * request)
2343 {
2344         ldap_instance   *inst = instance;
2345 #ifdef WITH_EDIR
2346         int             module_rcode;
2347         const char      *user_dn;
2348         LDAP_CONN       *conn;
2349         VALUE_PAIR      *vp;
2350
2351
2352         conn = ldap_get_socket(inst);
2353         if (!conn) return RLM_MODULE_FAIL;
2354         
2355         /*
2356          *      Ensure that we have a username and a
2357          *      Cleartext-Password in the request
2358          */
2359         if (!request->username) {
2360                 radlog(L_AUTH, "rlm_ldap (%s): Attribute \"User-Name\" is "
2361                        "required for authentication", inst->xlat_name);
2362                 return RLM_MODULE_INVALID;
2363         }
2364
2365         vp = pairfind(request->config_items, PW_CLEARTEXT_PASSWORD, 0);
2366         if (!vp) {
2367                 radlog(L_AUTH, "rlm_ldap (%s): Attribute \"Cleartext-Password\" "
2368                        "is required for authentication.", inst->xlat_name);
2369                 return RLM_MODULE_INVALID;
2370         }
2371
2372         if (!*vp->vp_strvalue) {
2373                 radlog(L_AUTH, "rlm_ldap (%s): Attribute \"Cleartext-Password\" "
2374                        "is empty.", inst->xlat_name);
2375                 return RLM_MODULE_INVALID;
2376         }
2377
2378         RDEBUG("Login attempt by \"%s\" with password \"%s\"",
2379                request->username->vp_strvalue, vp->vp_strvalue);
2380
2381         /*
2382          *      Get the DN by doing a search.
2383          */
2384         user_dn = get_userdn(&conn, request, &module_rcode);
2385         if (!user_dn) {
2386                 ldap_release_socket(inst, conn);
2387                 return module_rcode;
2388         }
2389
2390         /*
2391          *      Bind as the user
2392          */
2393         conn->rebound = TRUE;
2394         module_rcode = ldap_bind_wrapper(&conn, user_dn,
2395                                          vp->vp_strvalue,
2396                                          NULL, TRUE);
2397         if (module_rcode == RLM_MODULE_OK) {
2398                 RDEBUG("Bind as user \"%s\" was successful", user_dn);
2399         }
2400         
2401         ldap_release_socket(inst, conn);
2402         return module_rcode;
2403 #endif
2404
2405         if (inst->postauth) {
2406                 return user_modify(inst, request, inst->postauth); 
2407         }
2408
2409         return RLM_MODULE_NOOP;
2410 }
2411
2412
2413 /* globally exported name */
2414 module_t rlm_ldap = {
2415         RLM_MODULE_INIT,
2416         "ldap",
2417         RLM_TYPE_THREAD_SAFE,   /* type: reserved        */
2418         ldap_instantiate,       /* instantiation         */
2419         ldap_detach,            /* detach                */
2420         {
2421                 ldap_authenticate,      /* authentication        */
2422                 ldap_authorize,         /* authorization         */
2423                 NULL,                   /* preaccounting         */
2424                 ldap_accounting,        /* accounting            */
2425                 NULL,                   /* checksimul            */
2426                 NULL,                   /* pre-proxy             */
2427                 NULL,                   /* post-proxy            */
2428                 ldap_postauth           /* post-auth */
2429         },
2430 };