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