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