Fixup xlat calls in rlm_ldap to work with new function prototypes
[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,2000,2001,2002,2003,2004,2005,2006,2007,2008,
19  *             2009,2010,2011,1012 The FreeRADIUS Server Project.
20  *
21  *   Copyright 2012 Alan DeKok <aland@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        "mapping.h"
35
36 #define MAX_FILTER_STR_LEN      1024
37
38 typedef struct {
39         CONF_SECTION   *cs;
40         fr_connection_pool_t *pool;
41         char           *server;
42         int             port;
43
44         char           *login;
45         char           *password;
46
47         char           *filter;
48         char           *basedn;
49
50         int             chase_referrals;
51         int             rebind;
52
53         int             ldap_debug; /* Debug flag for LDAP SDK */
54         const char      *xlat_name; /* name used to xlat */
55
56         const char      *map_file;
57         TLDAP_RADIUS    *check_map;
58         TLDAP_RADIUS    *reply_map;
59         char            **attrs;
60
61         int             do_xlat;
62
63         /*
64          *      Access related configuration
65          */
66         char           *access_attr;
67         int             positive_access_attr;
68
69         /*
70          *      Profiles
71          */
72         char           *base_filter;
73         char           *default_profile;
74         char           *profile_attr;
75
76         /*
77          *      Group checking.
78          */
79         char           *groupname_attr;
80         char           *groupmemb_filt;
81         char           *groupmemb_attr;
82
83         /*
84          *      TLS items.  We should really normalize these with the
85          *      TLS code in 3.0.
86          */
87         int             tls_mode;
88         int             start_tls;
89         char            *tls_cacertfile;
90         char            *tls_cacertdir;
91         char            *tls_certfile;
92         char            *tls_keyfile;
93         char            *tls_randfile;
94         char            *tls_require_cert;
95
96         /*
97          *      Options
98          */
99         int             timelimit;
100         int             net_timeout;
101         int             timeout;
102         int             is_url;
103
104         /*
105          *      For keep-alives.
106          */
107 #ifdef LDAP_OPT_X_KEEPALIVE_IDLE
108         int             keepalive_idle;
109 #endif
110 #ifdef LDAP_OPT_X_KEEPALIVE_PROBES
111         int             keepalive_probes;
112 #endif
113 #ifdef LDAP_OPT_ERROR_NUMBER
114         int             keepalive_interval;
115 #endif
116
117 }  ldap_instance;
118
119 /* The default setting for TLS Certificate Verification */
120 #define TLS_DEFAULT_VERIFY "allow"
121
122 /*
123  *      TLS Configuration
124  */
125 static CONF_PARSER tls_config[] = {
126         {"start_tls", PW_TYPE_BOOLEAN,
127          offsetof(ldap_instance,start_tls), NULL, "no"},
128         {"cacertfile", PW_TYPE_FILENAME,
129          offsetof(ldap_instance,tls_cacertfile), NULL, NULL},
130         {"cacertdir", PW_TYPE_FILENAME,
131          offsetof(ldap_instance,tls_cacertdir), NULL, NULL},
132         {"certfile", PW_TYPE_FILENAME,
133          offsetof(ldap_instance,tls_certfile), NULL, NULL},
134         {"keyfile", PW_TYPE_FILENAME,
135          offsetof(ldap_instance,tls_keyfile), NULL, NULL},
136         {"randfile", PW_TYPE_STRING_PTR, /* OK if it changes on HUP */
137          offsetof(ldap_instance,tls_randfile), NULL, NULL},
138         {"require_cert", PW_TYPE_STRING_PTR,
139          offsetof(ldap_instance,tls_require_cert), NULL, TLS_DEFAULT_VERIFY},
140         { NULL, -1, 0, NULL, NULL }
141 };
142
143
144 static CONF_PARSER attr_config[] = {
145         /*
146          *      Access limitations
147          */
148         /* LDAP attribute name that controls remote access */
149         {"access_attr", PW_TYPE_STRING_PTR,
150          offsetof(ldap_instance,access_attr), NULL, NULL},
151         {"positive_access_attr", PW_TYPE_BOOLEAN,
152          offsetof(ldap_instance,positive_access_attr), NULL, "yes"},
153
154         {"base_filter", PW_TYPE_STRING_PTR,
155          offsetof(ldap_instance,base_filter), NULL, "(objectclass=radiusprofile)"},
156         {"default_profile", PW_TYPE_STRING_PTR,
157          offsetof(ldap_instance,default_profile), NULL, NULL},
158         {"profile_attribute", PW_TYPE_STRING_PTR,
159          offsetof(ldap_instance,profile_attr), NULL, NULL},
160
161         { NULL, -1, 0, NULL, NULL }
162 };
163
164
165 /*
166  *      Group configuration
167  */
168 static CONF_PARSER group_config[] = {
169         /*
170          *      Group checks.  These could probably be done
171          *      via dynamic xlat's.
172          */
173         {"name_attribute", PW_TYPE_STRING_PTR,
174          offsetof(ldap_instance,groupname_attr), NULL, "cn"},
175         {"membership_filter", PW_TYPE_STRING_PTR,
176          offsetof(ldap_instance,groupmemb_filt), NULL, "(|(&(objectClass=GroupOfNames)(member=%{Ldap-UserDn}))(&(objectClass=GroupOfUniqueNames)(uniquemember=%{Ldap-UserDn})))"},
177         {"membership_attribute", PW_TYPE_STRING_PTR,
178          offsetof(ldap_instance,groupmemb_attr), NULL, NULL},
179
180
181         { NULL, -1, 0, NULL, NULL }
182 };
183
184 /*
185  *      Various options that don't belong in the main configuration.
186  *
187  *      Note that these overlap a bit with the connection pool code!
188  */
189 static CONF_PARSER option_config[] = {
190         /*
191          *      Debugging flags to the server
192          */
193         {"ldap_debug", PW_TYPE_INTEGER,
194          offsetof(ldap_instance,ldap_debug), NULL, "0x0000"},
195
196         {"chase_referrals", PW_TYPE_BOOLEAN,
197          offsetof(ldap_instance,chase_referrals), NULL, NULL},
198
199         {"rebind", PW_TYPE_BOOLEAN,
200          offsetof(ldap_instance,rebind), NULL, NULL},
201
202         /* timeout on network activity */
203         {"net_timeout", PW_TYPE_INTEGER,
204          offsetof(ldap_instance,net_timeout), NULL, "10"},
205
206         /* timeout for search results */
207         {"timeout", PW_TYPE_INTEGER,
208          offsetof(ldap_instance,timeout), NULL, "20"},
209
210         /* allow server unlimited time for search (server-side limit) */
211         {"timelimit", PW_TYPE_INTEGER,
212          offsetof(ldap_instance,timelimit), NULL, "20"},
213
214 #ifdef LDAP_OPT_X_KEEPALIVE_IDLE
215         {"idle", PW_TYPE_INTEGER, offsetof(ldap_instance,keepalive_idle), NULL, "60"},
216 #endif
217 #ifdef LDAP_OPT_X_KEEPALIVE_PROBES
218         {"probes", PW_TYPE_INTEGER, offsetof(ldap_instance,keepalive_probes), NULL, "3"},
219 #endif
220 #ifdef LDAP_OPT_ERROR_NUMBER
221         {"interval", PW_TYPE_INTEGER, offsetof(ldap_instance,keepalive_interval), NULL, "30"},
222 #endif
223         { NULL, -1, 0, NULL, NULL }
224 };
225
226
227 static const CONF_PARSER module_config[] = {
228         {"server", PW_TYPE_STRING_PTR,
229          offsetof(ldap_instance,server), NULL, "localhost"},
230         {"port", PW_TYPE_INTEGER,
231          offsetof(ldap_instance,port), NULL, "389"},
232
233         {"password", PW_TYPE_STRING_PTR,
234          offsetof(ldap_instance,password), NULL, ""},
235         {"identity", PW_TYPE_STRING_PTR,
236          offsetof(ldap_instance,login), NULL, ""},
237
238         /*
239          *      DN's and filters.
240          */
241         {"basedn", PW_TYPE_STRING_PTR,
242          offsetof(ldap_instance,basedn), NULL, "o=notexist"},
243
244         {"filter", PW_TYPE_STRING_PTR,
245          offsetof(ldap_instance,filter), NULL, "(uid=%u)"},
246
247         /* file with mapping between LDAP and RADIUS attributes */
248         {"dictionary_mapping", PW_TYPE_FILENAME,
249          offsetof(ldap_instance, map_file), NULL, NULL},
250
251         /*
252          *      Terrible things which should be deleted.
253          */
254         {"do_xlat", PW_TYPE_BOOLEAN,
255          offsetof(ldap_instance,do_xlat), NULL, "yes"},
256
257         { "profiles", PW_TYPE_SUBSECTION, 0, NULL, (const void *) attr_config },
258
259         { "group", PW_TYPE_SUBSECTION, 0, NULL, (const void *) group_config },
260
261         { "options", PW_TYPE_SUBSECTION, 0, NULL, (const void *) option_config },
262
263         { "tls", PW_TYPE_SUBSECTION, 0, NULL, (const void *) tls_config },
264
265         { "profiles", PW_TYPE_SUBSECTION, 0, NULL, (const void *) attr_config },
266
267         {NULL, -1, 0, NULL, NULL}
268 };
269
270 typedef struct ldap_conn {
271         LDAP    *ld;
272         int     rebound;
273         int     referred;
274         ldap_instance *inst;
275 } LDAP_CONN;
276
277
278 #if LDAP_SET_REBIND_PROC_ARGS == 3
279 /*
280  *      Rebind && chase referral stuff
281  */
282 static int ldap_rebind(LDAP *ld, LDAP_CONST char *url,
283                        UNUSED ber_tag_t request, UNUSED ber_int_t msgid,
284                        void *ctx )
285 {
286         LDAP_CONN *conn = ctx;
287
288         conn->referred = TRUE;
289         conn->rebound = TRUE;   /* not really, but oh well... */
290         rad_assert(ld == conn->ld);
291
292         DEBUG("  [%s] rebind to URL %s", conn->inst->xlat_name, url);
293         return ldap_bind_s(ld, conn->inst->login, conn->inst->password,
294                            LDAP_AUTH_SIMPLE);
295 }
296 #endif
297
298 static int ldap_bind_wrapper(LDAP_CONN **pconn, const char *user,
299                              const char *password,
300                              const char **perror_str, int do_rebind)
301 {
302         int             rcode, ldap_errno;
303         int             module_rcode = RLM_MODULE_FAIL;
304         int             reconnect = FALSE;
305         const char      *error_string;
306         LDAP_CONN       *conn = *pconn;
307         ldap_instance   *inst = conn->inst;
308         LDAPMessage     *result = NULL;
309         struct timeval tv;
310
311 redo:
312         ldap_errno = ldap_bind(conn->ld, user, password, LDAP_AUTH_SIMPLE);
313         if (ldap_errno < 0) {
314         get_error:
315                 ldap_get_option(conn->ld, LDAP_OPT_ERROR_NUMBER, &ldap_errno);
316                 error_string = ldap_err2string(ldap_errno);
317
318                 if (do_rebind && !reconnect) {
319                         conn = fr_connection_reconnect(inst->pool, conn);
320                         *pconn = conn;
321                         if (!conn) return RLM_MODULE_FAIL;
322                         goto redo;
323                 }
324
325         print_error:
326                 if (perror_str) *perror_str = error_string;
327
328 #ifdef HAVE_LDAP_INITIALIZE
329                 if (inst->is_url) {
330                         radlog(L_ERR, "  [%s] %s bind to %s failed: %s",
331                                inst->xlat_name, user,
332                                inst->server, error_string);
333                 } else
334 #endif
335                 {
336                         radlog(L_ERR, "  [%s] %s bind to %s:%d failed: %s",
337                                inst->xlat_name, user,
338                                inst->server, inst->port,
339                                error_string);
340                 }
341
342                 return module_rcode; /* caller closes the connection */
343         }
344
345         DEBUG3("  [%s] waiting for bind result ...", inst->xlat_name);
346
347         tv.tv_sec = inst->timeout;
348         tv.tv_usec = 0;
349         rcode = ldap_result(conn->ld, ldap_errno, 1, &tv, &result);
350         if (rcode < 0) goto get_error;
351
352         if (rcode == 0) {
353                 error_string = "timeout";
354                 goto print_error;
355         }
356
357         ldap_errno = ldap_result2error(conn->ld, result, 1);
358         switch (ldap_errno) {
359         case LDAP_SUCCESS:
360                 break;
361
362         case LDAP_INVALID_CREDENTIALS:
363         case LDAP_CONSTRAINT_VIOLATION:
364                 rcode = RLM_MODULE_REJECT;
365                 /* FALL-THROUGH */
366
367         default:
368                 goto get_error;
369         }
370
371         return RLM_MODULE_OK;
372 }
373
374 /*************************************************************************
375  *
376  *      Function: ldap_conn_create
377  *
378  *      Purpose: Create and return a new connection
379  *      This function is probably too big.
380  *
381  *************************************************************************/
382 static void *ldap_conn_create(void *ctx)
383 {
384         int module_rcode;
385         int ldap_errno, ldap_version;
386         struct timeval tv;
387         ldap_instance *inst = ctx;
388         LDAP *ld = NULL;
389         LDAP_CONN *conn = NULL;
390         const char *error;
391
392 #ifdef HAVE_LDAP_INITIALIZE
393         if (inst->is_url) {
394                 DEBUG("  [%s] Connect to %s", inst->xlat_name, inst->server);
395
396                 ldap_errno = ldap_initialize(&ld, inst->server);
397
398                 if (ldap_errno != LDAP_SUCCESS) {
399                         radlog(L_ERR, "  [%s] ldap_initialize() failed: %s",
400                                inst->xlat_name, ldap_err2string(ldap_errno));
401                         goto conn_fail;
402                 }
403         } else
404 #endif
405         {
406                 DEBUG("  [%s] Connect to %s:%d", inst->xlat_name,
407                       inst->server, inst->port);
408
409                 ld = ldap_init(inst->server, inst->port);
410                 if (!ld) {
411                         radlog(L_ERR, "  [%s] ldap_init() failed", inst->xlat_name);
412                 conn_fail:
413                         if (ld) ldap_unbind_s(ld);
414                         return NULL;
415                 }
416         }
417
418         /*
419          *      We now have a connection structure, but no actual TCP connection.
420          *
421          *      Set a bunch of LDAP options, using common code.
422          */
423
424 #define do_ldap_option(_option, _name, _value) if (ldap_set_option(ld, _option, _value) != LDAP_OPT_SUCCESS) { \
425                 ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &ldap_errno); \
426                 radlog(L_ERR, "  [%s] Could not set %s: %s", inst->xlat_name, _name, ldap_err2string(ldap_errno)); \
427         }
428                 
429         if (inst->ldap_debug) {
430                 do_ldap_option(LDAP_OPT_DEBUG_LEVEL, "ldap_debug", &(inst->ldap_debug));
431         }
432
433         /*
434          *      Leave "chase_referrals" unset to use the OpenLDAP
435          *      default.
436          */
437         if (inst->chase_referrals != 2) {
438                 if (inst->chase_referrals) {
439                         do_ldap_option(LDAP_OPT_REFERRALS, "chase_referrals", LDAP_OPT_ON);
440                         
441 #if LDAP_SET_REBIND_PROC_ARGS == 3
442                         if (inst->rebind == 1) {
443                                 ldap_set_rebind_proc(ld, ldap_rebind, inst);
444                         }
445 #endif
446                 } else {
447                         do_ldap_option(LDAP_OPT_REFERRALS, "chase_referrals", LDAP_OPT_OFF);
448                 }
449         }
450
451         tv.tv_sec = inst->net_timeout;
452         tv.tv_usec = 0;
453         do_ldap_option(LDAP_OPT_NETWORK_TIMEOUT, "net_timeout", &tv);
454
455         do_ldap_option(LDAP_OPT_TIMELIMIT, "timelimit", &(inst->timelimit));
456
457         ldap_version = LDAP_VERSION3;
458         do_ldap_option(LDAP_OPT_PROTOCOL_VERSION, "ldap_version", &ldap_version);
459
460 #ifdef LDAP_OPT_X_KEEPALIVE_IDLE
461         do_ldap_option(LDAP_OPT_X_KEEPALIVE_IDLE, "keepalive idle", &(inst->keepalive_idle));
462 #endif
463
464 #ifdef LDAP_OPT_X_KEEPALIVE_PROBES
465         do_ldap_option(LDAP_OPT_X_KEEPALIVE_PROBES, "keepalive probes", &(inst->keepalive_probes));
466 #endif
467
468 #ifdef LDAP_OPT_X_KEEPALIVE_INTERVAL
469         do_ldap_option(LDAP_OPT_X_KEEPALIVE_INTERVAL, "keepalive interval", &(inst->keepalive_interval));
470 #endif
471
472 #ifdef HAVE_LDAP_START_TLS
473         /*
474          *      Set all of the TLS options
475          */
476         if (inst->tls_mode) {
477                 do_ldap_option(LDAP_OPT_X_TLS, "tls_mode", &(inst->tls_mode));
478         }
479
480 #define maybe_ldap_option(_option, _name, _value) if (_value) do_ldap_option(_option, _name, _value)
481
482         maybe_ldap_option(LDAP_OPT_X_TLS_CACERTFILE,
483                           "cacertfile", inst->tls_cacertfile);
484         maybe_ldap_option(LDAP_OPT_X_TLS_CACERTDIR,
485                           "cacertdir", inst->tls_cacertdir);
486
487 #ifdef HAVE_LDAP_INT_TLS_CONFIG
488         if (ldap_int_tls_config(NULL, LDAP_OPT_X_TLS_REQUIRE_CERT,
489                                 (inst->tls_require_cert)) != LDAP_OPT_SUCCESS) {
490                 ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &ldap_errno);
491                 radlog(L_ERR, "  [%s] could not set ", 
492                        "LDAP_OPT_X_TLS_REQUIRE_CERT option to %s: %s",
493                        inst->xlat_name, 
494                        inst->tls_require_cert,
495                        ldap_err2string(ldap_errno));
496         }
497 #endif
498
499         maybe_ldap_option(LDAP_OPT_X_TLS_CERTFILE,
500                           "certfile", inst->tls_certfile);
501         maybe_ldap_option(LDAP_OPT_X_TLS_KEYFILE,
502                           "keyfile", inst->tls_keyfile);
503         maybe_ldap_option(LDAP_OPT_X_TLS_RANDOM_FILE,
504                           "randfile", inst->tls_randfile);
505
506         /*
507          *      And finally start the TLS code.
508          */
509         if (inst->start_tls && (inst->port != 636)) {
510                 ldap_errno = ldap_start_tls_s(ld, NULL, NULL);
511                 if (ldap_errno != LDAP_SUCCESS) {
512                         ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER,
513                                         &ldap_errno);
514                         radlog(L_ERR, "  [%s] could not start TLS: %s",
515                                inst->xlat_name,
516                                ldap_err2string(ldap_errno));
517                         goto conn_fail;
518                 }
519         }
520 #endif /* HAVE_LDAP_START_TLS */
521
522         conn = rad_malloc(sizeof(*conn));
523         conn->inst = inst;
524         conn->ld = ld;
525         conn->rebound = FALSE;
526         conn->referred = FALSE;
527
528         module_rcode = ldap_bind_wrapper(&conn, inst->login, inst->password,
529                                          &error, FALSE);
530         if (module_rcode != RLM_MODULE_OK) {
531                 radlog(L_ERR, "  [%s] Failed binding to LDAP server: %s",
532                        inst->xlat_name, error);
533
534                 /*
535                  *      FIXME: print "check config, morians!
536                  */
537                 goto conn_fail;
538         }
539
540         return conn;
541 }
542
543
544 /*************************************************************************
545  *
546  *      Function: ldap_conn_delete
547  *
548  *      Purpose: Close and delete a connection
549  *
550  *************************************************************************/
551 static int ldap_conn_delete(UNUSED void *ctx, void *connection)
552 {
553         LDAP_CONN *conn = connection;
554
555         ldap_unbind_s(conn->ld);
556         free(conn);
557
558         return 0;
559 }
560
561
562 /*************************************************************************
563  *
564  *      Function: ldap_get_socket
565  *
566  *      Purpose: Gets an LDAP socket from the connection pool
567  *
568  *************************************************************************/
569 static LDAP_CONN *ldap_get_socket(ldap_instance *inst)
570 {
571         LDAP_CONN *conn;
572
573         conn = fr_connection_get(inst->pool);
574         if (!conn) {
575                 radlog(L_ERR, "  [%s] All ldap connections are in use",
576                        inst->xlat_name);
577                 return NULL;
578         }
579
580         return conn;
581 }
582
583 /*************************************************************************
584  *
585  *      Function: ldap_release_socket
586  *
587  *      Purpose: Frees an LDAP socket back to the connection pool
588  *
589  *************************************************************************/
590 static void ldap_release_socket(ldap_instance *inst, LDAP_CONN *conn)
591 {
592         /*
593          *      Could have already been free'd due to a previous error.
594          */
595         if (!conn) return;
596
597         /*
598          *      We chased a referral to another server.
599          *
600          *      This connection is no longer part of the pool which is
601          *      connected to and bound to the configured server.
602          *      Close it.
603          *
604          *      Note that we do NOT close it if it was bound to
605          *      another user.  Instead, we let the next caller do the
606          *      rebind.
607          */
608         if (conn->referred) {
609                 fr_connection_del(inst->pool, conn);
610                 return;
611         }
612
613         fr_connection_release(inst->pool, conn);
614         return;
615 }
616
617
618 /*************************************************************************
619  *
620  *      Function: ldap_escape_func
621  *
622  *      Purpose: Converts "bad" strings into ones which are safe for LDAP
623  *
624  *************************************************************************/
625 static size_t ldap_escape_func(UNUSED REQUEST *request, char *out,
626                                size_t outlen, const char *in, UNUSED void *arg)
627 {
628         size_t len = 0;
629
630         while (in[0]) {
631                 /*
632                  *      Encode unsafe characters.
633                  */
634                 if (((len == 0) &&
635                     ((in[0] == ' ') || (in[0] == '#'))) ||
636                     (strchr(",+\"\\<>;*=()", *in))) {
637                         static const char hex[] = "0123456789abcdef";
638
639                         /*
640                          *      Only 3 or less bytes available.
641                          */
642                         if (outlen <= 3) {
643                                 break;
644                         }
645
646                         *(out++) = '\\';
647                         *(out++) = hex[((*in) >> 4) & 0x0f];
648                         *(out++) = hex[(*in) & 0x0f];
649                         outlen -= 3;
650                         len += 3;
651                         in++;
652                         continue;
653                 }
654
655                 /*
656                  *      Only one byte left.
657                  */
658                 if (outlen <= 1) {
659                         break;
660                 }
661
662                 /*
663                  *      Allowed character.
664                  */
665                 *(out++) = *(in++);
666                 outlen--;
667                 len++;
668         }
669         *out = '\0';
670         return len;
671 }
672
673 /*************************************************************************
674  *
675  *      Function: perform_search
676  *
677  *      Purpose: Do a search and get a response
678  *
679  *************************************************************************/
680 static int perform_search(ldap_instance *inst, LDAP_CONN **pconn,
681                           char *search_basedn, int scope, char *filter,
682                           char **attrs, LDAPMessage **presult)
683 {
684         int             ldap_errno;
685         int             reconnect = FALSE;
686         LDAP_CONN       *conn = *pconn;
687         struct timeval  tv;
688
689         *presult = NULL;
690
691         /*
692          *      Do all searches as the default admin user.
693          */
694         if (conn->rebound) {
695                 ldap_errno = ldap_bind_wrapper(pconn,
696                                                inst->login, inst->password,
697                                                NULL, TRUE);
698                 if (ldap_errno != RLM_MODULE_OK) {
699                         return -1;
700                 }
701
702                 rad_assert(*pconn != NULL);
703                 conn = *pconn;
704                 conn->rebound = FALSE;
705         }
706
707         tv.tv_sec = inst->timeout;
708         tv.tv_usec = 0;
709         DEBUG2("  [%s] Performing search in '%s' with filter '%s'", inst->xlat_name, 
710                search_basedn ? search_basedn : "(null)" , filter);
711
712 retry:
713         ldap_errno = ldap_search_st(conn->ld, search_basedn, scope, filter,
714                                     attrs, 0, &tv, presult);
715         switch (ldap_errno) {
716         case LDAP_SUCCESS:
717         case LDAP_NO_SUCH_OBJECT:
718                 break;
719
720         case LDAP_SERVER_DOWN:
721         do_reconnect:
722                 ldap_msgfree(*presult);
723
724                 if (reconnect) return -1;
725                 reconnect = TRUE;
726
727                 conn = fr_connection_reconnect(inst->pool, conn);
728                 *pconn = conn;  /* tell the caller we have a new connection */
729                 if (!conn) return -1;
730                 goto retry;
731
732         case LDAP_INSUFFICIENT_ACCESS:
733                 radlog(L_ERR, "  [%s] ldap_search() failed: Insufficient access. Check the identity and password configuration directives.", inst->xlat_name);
734                 ldap_msgfree(*presult);
735                 return -1;
736
737         case LDAP_TIMEOUT:
738                 exec_trigger(NULL, inst->cs, "modules.ldap.timeout", TRUE);
739                 radlog(L_ERR, "  [%s] ldap_search() failed: Timed out while waiting for server to respond. Please increase the timeout.", inst->xlat_name);
740                 ldap_msgfree(*presult);
741                 return -1;
742
743         case LDAP_FILTER_ERROR:
744                 radlog(L_ERR, "  [%s] ldap_search() failed: Bad search filter: %s", inst->xlat_name,filter);
745                 ldap_msgfree(*presult);
746                 return -1;
747
748         case LDAP_TIMELIMIT_EXCEEDED:
749                 exec_trigger(NULL, inst->cs, "modules.ldap.timeout", TRUE);
750
751         case LDAP_BUSY:
752         case LDAP_UNAVAILABLE:
753                 /*
754                  *      Reconnect.  There's an issue with the socket
755                  *      or LDAP server.
756                  */
757                 ldap_get_option(conn->ld, LDAP_OPT_ERROR_NUMBER, &ldap_errno);
758                 radlog(L_ERR, "  [%s] ldap_search() failed: %s", inst->xlat_name,
759                        ldap_err2string(ldap_errno));
760                 goto do_reconnect;
761
762         default:
763                 ldap_get_option(conn->ld, LDAP_OPT_ERROR_NUMBER, &ldap_errno);
764                 radlog(L_ERR, "  [%s] ldap_search() failed: %s", inst->xlat_name,
765                        ldap_err2string(ldap_errno));
766                 ldap_msgfree(*presult);
767                 return -1;
768         }
769
770         ldap_errno = ldap_count_entries(conn->ld, *presult);
771         if (ldap_errno == 0) {
772                 ldap_msgfree(*presult);
773                 DEBUG("  [%s] object not found", inst->xlat_name);
774                 return -2;
775         }
776
777         if (ldap_errno != 1) {
778                 ldap_msgfree(*presult);
779                 DEBUG("  [%s] got ambiguous search result (%d results)", inst->xlat_name, ldap_errno);
780                 return -2;
781         }
782
783         return 0;
784 }
785
786 /*************************************************************************
787  *
788  *      Function: ldap_xlat
789  *
790  *      Purpose: Expand an LDAP URL into a query, and return a string
791  *              result from that query.
792  *
793  *************************************************************************/
794 static size_t ldap_xlat(void *instance, REQUEST *request, const char *fmt,
795                         char *out, size_t freespace)
796 {
797         int rcode;
798         size_t length = 0;
799         ldap_instance *inst = instance;
800         LDAPURLDesc *ldap_url;
801         LDAPMessage *result = NULL;
802         LDAPMessage *msg = NULL;
803         char **vals;
804         LDAP_CONN *conn;
805         const char *url;
806         char buffer[MAX_FILTER_STR_LEN];
807
808         if (strchr(fmt, '%') != NULL) {
809                 if (!radius_xlat(buffer, sizeof(buffer), fmt, request, ldap_escape_func, NULL)) {
810                         radlog (L_ERR, "  [%s] Unable to create LDAP URL.", inst->xlat_name);
811                         return 0;
812                 }
813                 url = buffer;
814         } else {
815                 url = fmt;
816         }
817
818         if (!ldap_is_ldap_url(url)) {
819                 radlog (L_ERR, "  [%s] String passed does not look like an LDAP URL.",
820                         inst->xlat_name);
821                 return 0;
822         }
823
824         if (ldap_url_parse(url, &ldap_url)){
825                 radlog (L_ERR, "  [%s] LDAP URL parse failed.", inst->xlat_name);
826                 return 0;
827         }
828
829         /*
830          *      Nothing, empty string, "*" string, or got 2 things, die.
831          */
832         if (!ldap_url->lud_attrs || !ldap_url->lud_attrs[0] ||
833             !*ldap_url->lud_attrs[0] || (strcmp(ldap_url->lud_attrs[0], "*") == 0) ||
834             ldap_url->lud_attrs[1]) {
835                 radlog (L_ERR, "  [%s] Invalid Attribute(s) request.",
836                         inst->xlat_name);
837                 goto free_urldesc;
838         }
839
840         if (ldap_url->lud_host &&
841             ((strncmp(inst->server, ldap_url->lud_host, strlen(inst->server)) != 0) ||
842              (ldap_url->lud_port != inst->port))) {
843                 DEBUG("  [%s] Requested server/port is .", inst->xlat_name);
844                 goto free_urldesc;
845         }
846
847         conn = ldap_get_socket(inst);
848         if (!conn) goto free_urldesc;
849
850         rcode = perform_search(inst, &conn, ldap_url->lud_dn, ldap_url->lud_scope,
851                                ldap_url->lud_filter, ldap_url->lud_attrs, &result);
852         if (rcode < 0) {
853                 if (rcode == -2) {
854                         DEBUG("  [%s] Search returned not found", inst->xlat_name);
855                         goto free_socket;
856                 }
857                 DEBUG("  [%s] Search returned error", inst->xlat_name);
858                 goto free_socket;
859         }
860
861         msg = ldap_first_entry(conn->ld, result);
862         if (!msg) {
863                 DEBUG("  [%s] ldap_first_entry() failed", inst->xlat_name);
864                 goto free_result;
865         }
866
867         vals = ldap_get_values(conn->ld, msg, ldap_url->lud_attrs[0]);
868         if (!vals) {
869                 DEBUG("  [%s] ldap_get_values failed", inst->xlat_name);
870                 goto free_result;
871         }
872
873         length = strlen(vals[0]);
874         if (length >= freespace){
875
876                 goto free_vals;
877         }
878
879         strlcpy(out, vals[0], freespace);
880
881 free_vals:
882         ldap_value_free(vals);
883 free_result:
884         ldap_msgfree(result);
885 free_socket:
886         ldap_release_socket(inst, conn);
887 free_urldesc:
888         ldap_free_urldesc(ldap_url);
889
890         return length;
891 }
892
893
894 static char *get_userdn(LDAP_CONN **pconn, REQUEST *request, int *module_rcode)
895 {
896         int             rcode;
897         VALUE_PAIR      *vp;
898         ldap_instance   *inst = (*pconn)->inst;
899         LDAPMessage    *result, *msg;
900         static char     firstattr[] = "uid";
901         char           *user_dn, *attrs[] = {firstattr, NULL};
902         char            filter[MAX_FILTER_STR_LEN];     
903         char            basedn[MAX_FILTER_STR_LEN];     
904
905         *module_rcode = RLM_MODULE_FAIL;
906
907         vp = pairfind(request->config_items, PW_LDAP_USERDN, 0);
908         if (vp) return vp->vp_strvalue;
909
910         if (!radius_xlat(filter, sizeof(filter), inst->filter,
911                          request, ldap_escape_func, NULL)) {
912                 radlog(L_ERR, "  [%s] unable to create filter.", inst->xlat_name);
913                 *module_rcode = RLM_MODULE_INVALID;
914                 return NULL;
915         }
916
917         if (!radius_xlat(basedn, sizeof(basedn), inst->basedn,
918                          request, ldap_escape_func, NULL)) {
919                 radlog(L_ERR, "  [%s] unable to create basedn.", inst->xlat_name);
920                 *module_rcode = RLM_MODULE_INVALID;
921                 return NULL;
922         }
923
924         rcode = perform_search(inst, pconn, basedn, LDAP_SCOPE_SUBTREE,
925                                filter, attrs, &result);
926         if (rcode < 0) {
927                 if (rcode == -2) {
928                         *module_rcode = RLM_MODULE_NOTFOUND;
929                 }
930
931                 return NULL;
932         }
933
934         if ((msg = ldap_first_entry((*pconn)->ld, result)) == NULL) {
935                 ldap_msgfree(result);
936                 return NULL;
937         }
938
939         if ((user_dn = ldap_get_dn((*pconn)->ld, msg)) == NULL) {
940                 ldap_msgfree(result);
941                 return NULL;
942         }
943
944         vp = pairmake("LDAP-UserDn", user_dn, T_OP_EQ);
945         if (!vp) {
946                 ldap_memfree(user_dn);
947                 ldap_msgfree(result);
948                 return NULL;
949         }
950         
951         pairadd(&request->config_items, vp);
952         ldap_memfree(user_dn);
953         ldap_msgfree(result);
954
955         return vp->vp_strvalue;
956 }
957
958
959 /*****************************************************************************
960  *
961  *      Perform LDAP-Group comparison checking
962  *
963  *****************************************************************************/
964 static int ldap_groupcmp(void *instance, REQUEST *request,
965                          UNUSED VALUE_PAIR *thing, VALUE_PAIR *check,
966                          UNUSED VALUE_PAIR *check_pairs,
967                          UNUSED VALUE_PAIR **reply_pairs)
968 {
969         ldap_instance   *inst = instance;
970         int             i, rcode, found;
971         LDAPMessage     *result = NULL;
972         LDAPMessage     *msg = NULL;
973         static char     firstattr[] = "dn";
974         char            *attrs[] = {firstattr,NULL};
975         char            **vals;
976         char            *group_attrs[] = {inst->groupmemb_attr,NULL};
977         LDAP_CONN       *conn;
978         char            *user_dn;
979         int             module_rcode;
980         char            gr_filter[MAX_FILTER_STR_LEN];
981         char            filter[MAX_FILTER_STR_LEN];
982         char            basedn[MAX_FILTER_STR_LEN];
983         
984         if (check->length == 0) {
985                 RDEBUG("Cannot do comparison: group name is empty");
986                 return 1;
987         }
988
989         conn = ldap_get_socket(inst);
990         if (!conn) return 1;
991
992         /*
993          *      This is used in the default membership filter.
994          */
995         user_dn = get_userdn(&conn, request, &module_rcode);
996         if (!user_dn) {
997                 ldap_release_socket(inst, conn);
998                 return 1;
999         }
1000
1001         if (!inst->groupmemb_filt) goto check_attr;
1002
1003         if (!radius_xlat(filter, sizeof(filter),
1004                          inst->groupmemb_filt, request, ldap_escape_func, NULL)) {
1005                 RDEBUG("Failed creating group filter");
1006                 return 1;
1007         }
1008
1009         /*
1010          *      If it's a DN, use that.
1011          */
1012         if (strchr(check->vp_strvalue,',') != NULL) {
1013                 strlcpy(filter, gr_filter, sizeof(filter));
1014                 strlcpy(basedn, check->vp_strvalue, sizeof(basedn));
1015                 
1016         } else {
1017                 snprintf(filter, sizeof(filter), "(&(%s=%s)%s)",
1018                          inst->groupname_attr,
1019                          check->vp_strvalue, gr_filter);
1020
1021                 /*
1022                  *      get_userdn does this, too.  Oh well.
1023                  */
1024                 if (!radius_xlat(basedn, sizeof(basedn), inst->basedn,
1025                                  request, ldap_escape_func, NULL)) {
1026                         radlog(L_ERR, "  [%s] unable to create basedn.\n",
1027                                inst->xlat_name);
1028                         return 1;
1029                 }
1030         }
1031
1032         rcode = perform_search(inst, &conn, basedn, LDAP_SCOPE_SUBTREE,
1033                                filter, attrs, &result);
1034         if (rcode == 0) {
1035                 ldap_release_socket(inst, conn);
1036                 ldap_msgfree(result);
1037                 RDEBUG("User found in group %s", check->vp_strvalue);
1038                 return 0;
1039         }
1040
1041         if (rcode == -1) {
1042                 ldap_release_socket(inst, conn);
1043                 RDEBUG("Failed performing search");
1044                 return 1;
1045         }
1046
1047         /* else the search returned -2, for "not found" */
1048
1049         /*
1050          *      Else the search returned NOTFOUND.  See if we're
1051          *      configured to search for group membership using user
1052          *      object attribute.
1053          */
1054         if (!inst->groupmemb_attr) {
1055                 ldap_release_socket(inst, conn);
1056                 RDEBUG("Group %s was not found, or user is not a member",
1057                        check->vp_strvalue);
1058                 return 1;
1059         }
1060
1061 check_attr:
1062         snprintf(filter ,sizeof(filter), "(objectclass=*)");
1063
1064         rcode = perform_search(inst, &conn, user_dn, LDAP_SCOPE_BASE,
1065                                filter, group_attrs, &result);
1066         if (rcode < 0) {
1067                 RDEBUG("Search failed for group attrs");
1068                 ldap_release_socket(inst, conn);
1069                 return 1;
1070         }
1071
1072         msg = ldap_first_entry(conn->ld, result);
1073         if (!msg) {
1074                 RDEBUG("First entry failed for group attrs");
1075                 ldap_release_socket(inst, conn);
1076                 ldap_msgfree(result);
1077                 return 1;
1078         }
1079
1080         vals = ldap_get_values(conn->ld, msg, inst->groupmemb_attr);
1081         if (!vals) {
1082                 RDEBUG("Get values failed for group attrs");
1083                 ldap_release_socket(inst, conn);
1084                 ldap_msgfree(result);
1085                 return 1;
1086         }
1087
1088         /*
1089          *      Loop over the list of groups the user is a member of,
1090          *      looking for a match.
1091          */
1092         found = FALSE;
1093         for (i = 0; i < ldap_count_values(vals); i++){
1094                 LDAPMessage *gr_result = NULL;
1095
1096                 if (strcmp(vals[i], check->vp_strvalue) == 0){
1097                         found = TRUE;
1098                         break;
1099                 }
1100
1101                 /*
1102                  *      The group isn't a DN: ignore it.
1103                  */
1104                 if (strchr(vals[i], ',') == NULL) continue;
1105
1106                 /* This looks like a DN.  Do tons more work. */
1107                 snprintf(filter,sizeof(filter), "(%s=%s)",
1108                          inst->groupname_attr, check->vp_strvalue);
1109
1110                 rcode = perform_search(inst, &conn, vals[i], LDAP_SCOPE_BASE,
1111                                        filter, attrs, &gr_result);
1112                 if (rcode == -1) {
1113                         RDEBUG("Failed doing group search");
1114                         ldap_value_free(vals);
1115                         ldap_msgfree(result);
1116                         ldap_release_socket(inst, conn);
1117                         return 1;
1118                 }
1119
1120                 ldap_msgfree(gr_result);
1121                 found = TRUE;
1122                 break;
1123         }
1124         ldap_value_free(vals);
1125         ldap_msgfree(result);
1126         ldap_release_socket(inst, conn);
1127
1128         if (!found){
1129                 RDEBUG("groupcmp: Group %s not found, or user is not a member",
1130                        check->vp_strvalue);
1131                 return 1;
1132         }
1133
1134         return 0;
1135 }
1136
1137
1138 /*****************************************************************************
1139  *
1140  *      Detach from the LDAP server and cleanup internal state.
1141  *
1142  *****************************************************************************/
1143 static int ldap_detach(void *instance)
1144 {
1145         ldap_instance *inst = instance;
1146
1147         fr_connection_pool_delete(inst->pool);
1148
1149         if (inst->map_file) {
1150                 rlm_ldap_map_free(&inst->check_map);
1151                 rlm_ldap_map_free(&inst->reply_map);
1152                 free(inst->attrs);
1153         }
1154
1155         free(inst);
1156
1157         return 0;
1158 }
1159
1160 /*************************************************************************
1161  *
1162  *      Function: rlm_ldap_instantiate
1163  *
1164  *      Purpose: Uses section of radiusd config file passed as parameter
1165  *               to create an instance of the module.
1166  *
1167  *************************************************************************/
1168 static int ldap_instantiate(CONF_SECTION * conf, void **instance)
1169 {
1170         ldap_instance *inst;
1171
1172         inst = rad_malloc(sizeof *inst);
1173         if (!inst) {
1174                 return -1;
1175         }
1176         memset(inst, 0, sizeof(*inst));
1177         inst->cs = conf;
1178
1179         inst->chase_referrals = 2; /* use OpenLDAP defaults */
1180         inst->rebind = 2;
1181
1182         if (cf_section_parse(conf, inst, module_config) < 0) {
1183                 free(inst);
1184                 return -1;
1185         }
1186
1187         if (inst->server == NULL) {
1188                 radlog(L_ERR, "rlm_ldap: missing 'server' directive.");
1189                 ldap_detach(inst);
1190                 return -1;
1191         }
1192
1193         /*
1194          *      Check for URLs.  If they're used and the library doesn't
1195          *      support them, then complain.
1196          */
1197         inst->is_url = 0;
1198         if (ldap_is_ldap_url(inst->server)) {
1199 #ifdef HAVE_LDAP_INITIALIZE
1200                 inst->is_url = 1;
1201                 inst->port = 0;
1202 #else
1203                 radlog(L_ERR, "rlm_ldap: 'server' directive is in URL form but ldap_initialize() is not available.");
1204                 ldap_detach(inst);
1205                 return -1;
1206 #endif
1207         }
1208
1209         /* workaround for servers which support LDAPS but not START TLS */
1210         if (inst->port == LDAPS_PORT || inst->tls_mode) {
1211                 inst->tls_mode = LDAP_OPT_X_TLS_HARD;
1212         } else {
1213                 inst->tls_mode = 0;
1214         }
1215
1216         inst->xlat_name = cf_section_name2(conf);
1217         if (!inst->xlat_name) inst->xlat_name = cf_section_name1(conf);
1218
1219 #if LDAP_SET_REBIND_PROC_ARGS != 3
1220         /*
1221          *      The 2-argument rebind doesn't take an instance
1222          *      variable.  Our rebind function needs the instance
1223          *      variable for the username, password, etc.
1224          */
1225         if (inst->rebind == 1) {
1226                 radlog(L_ERR, "%s: Cannot use 'rebind' directive as this version of libldap does not support the API that we need.", inst->xlat-name);
1227                 ldap_detach(inst);
1228                 return -1;
1229         }
1230 #endif
1231
1232         if (inst->map_file) {
1233                 int offset = 0;
1234
1235                 inst->attrs = rad_malloc(sizeof(inst->attrs[0]) * MAX_ATTRMAP);
1236                 inst->attrs[0] = NULL;
1237
1238                 if (inst->profile_attr) inst->attrs[offset++] = inst->profile_attr;
1239                 if (inst->access_attr) inst->attrs[offset++] = inst->access_attr;
1240
1241                 if (rlm_ldap_map_read(inst->xlat_name, inst->map_file,
1242                                       &inst->check_map, &inst->reply_map,
1243                                       offset,
1244                                       inst->attrs) < 0) {
1245                         ldap_detach(inst);
1246                         return -1;
1247                 }
1248
1249                 if (!inst->check_map || !inst->reply_map) {
1250                         radlog(L_ERR, "%s: Empty file: %s",
1251                                inst->xlat_name, inst->map_file);
1252                         ldap_detach(inst);
1253                         return -1;
1254                 }
1255
1256         } else {
1257                 if (inst->default_profile || inst->profile_attr) {
1258                         radlog(L_ERR, "%s: You MUST specify \"dictionary_mapping\" to use the profile attributes", inst->xlat_name);
1259                         ldap_detach(inst);
1260                         return -1;
1261                 }
1262         }
1263
1264         /*
1265          *      Group comparison checks.
1266          */
1267         paircompare_register(PW_LDAP_GROUP, PW_USER_NAME, ldap_groupcmp, inst); 
1268         if (cf_section_name2(conf)) {
1269                 DICT_ATTR *da;
1270                 ATTR_FLAGS flags;
1271                 char buffer[256];
1272
1273                 snprintf(buffer, sizeof(buffer), "%s-Ldap-Group", inst->xlat_name);
1274                 memset(&flags, 0, sizeof(flags));
1275
1276                 dict_addattr(buffer, -1, 0, PW_TYPE_STRING, flags);
1277                 da = dict_attrbyname(buffer);
1278                 if (!da) {
1279                         radlog(L_ERR, "%s: Failed creating attribute %s",
1280                                inst->xlat_name, buffer);
1281                         ldap_detach(inst);
1282                         return -1;
1283                 }
1284
1285                 paircompare_register(da->attr, PW_USER_NAME, ldap_groupcmp, inst);
1286         }
1287
1288         xlat_register(inst->xlat_name, ldap_xlat, inst);
1289
1290         /*
1291          *      Initialize the socket pool.
1292          */
1293         inst->pool = fr_connection_pool_init(inst->cs, inst,
1294                                              ldap_conn_create,
1295                                              NULL,
1296                                              ldap_conn_delete);
1297         if (!inst->pool) {
1298                 ldap_detach(inst);
1299                 return -1;
1300         }
1301         
1302         *instance = inst;
1303         return 0;
1304 }
1305
1306
1307 static void module_failure_msg(VALUE_PAIR **vps, const char *fmt, ...)
1308 {
1309         va_list ap;
1310         VALUE_PAIR *vp;
1311
1312         va_start(ap, fmt);
1313         vp = paircreate(PW_MODULE_FAILURE_MESSAGE, 0, PW_TYPE_STRING);
1314         if (!vp) {
1315                 va_end(ap);
1316                 return;
1317         }
1318
1319         vsnprintf(vp->vp_strvalue, sizeof(vp->vp_strvalue), fmt, ap);
1320
1321         pairadd(vps, vp);
1322 }
1323
1324
1325 static int check_access(ldap_instance *inst, LDAP_CONN *conn, LDAPMessage *msg)
1326 {
1327         int rcode = -1;
1328         char **vals = NULL;
1329
1330         vals = ldap_get_values(conn->ld, msg, inst->access_attr);
1331         if (vals) {
1332                 if (inst->positive_access_attr) {
1333                         if (strncmp(vals[0], "FALSE", 5) == 0) {
1334                                 DEBUG("dialup access disabled");
1335
1336                         } else {
1337                                 rcode = 0;
1338                         }
1339
1340                 } else {
1341                         DEBUG("%s attribute exists - access denied by default",
1342                                 inst->access_attr);
1343                 }
1344
1345                 ldap_value_free(vals);
1346
1347         } else if (inst->positive_access_attr) {
1348                 DEBUG("No %s attribute - access denied by default", inst->access_attr);
1349
1350         } else {
1351                 rcode = 0;
1352         }
1353
1354         return rcode;
1355 }
1356
1357
1358 static void apply_profile(ldap_instance *inst, LDAP_CONN **pconn,
1359                           REQUEST *request, char *profile)
1360 {
1361         int rcode;
1362         LDAPMessage     *result, *msg;
1363         VALUE_PAIR      *check_tmp, *reply_tmp;
1364         char            filter[MAX_FILTER_STR_LEN];
1365
1366         if (!profile || !*profile) return;
1367
1368         strlcpy(filter,inst->base_filter,sizeof(filter));
1369
1370         rcode = perform_search(inst, pconn, profile, LDAP_SCOPE_BASE, filter,
1371                                inst->attrs, &result);
1372         if (rcode < 0) {
1373                 RDEBUG("FAILED Searching profile %s", profile);
1374                 return;
1375         }
1376
1377         msg = ldap_first_entry((*pconn)->ld, result);
1378         if (!msg) goto free_result;
1379
1380         check_tmp = rlm_ldap_pairget(inst->xlat_name, (*pconn)->ld, msg,
1381                                      inst->check_map, &request->config_items, 1);
1382         if (check_tmp) {
1383                 pairfree(&check_tmp);
1384         }
1385
1386         reply_tmp = rlm_ldap_pairget(inst->xlat_name, (*pconn)->ld, msg,
1387                                      inst->reply_map, &request->packet->vps, 0);
1388         if (reply_tmp) {
1389                 pairfree(&reply_tmp);
1390         }
1391
1392 free_result:
1393         ldap_msgfree(result);
1394 }
1395
1396
1397 static void do_one_map(ldap_instance *inst, LDAP *ld, REQUEST *request,
1398                        LDAPMessage *msg, TLDAP_RADIUS *map, VALUE_PAIR **vps,
1399                        int is_check)
1400 {
1401         VALUE_PAIR *vp;
1402
1403         vp = rlm_ldap_pairget(inst->xlat_name, ld, msg, map, vps, is_check);
1404         if (vp) {
1405                 if (inst->do_xlat) {
1406                         pairxlatmove(request, vps, &vp);
1407                         pairfree(&vp);
1408
1409                 } else {
1410                         pairadd(vps, vp);
1411                 }
1412         }
1413
1414 }
1415
1416 static void do_check_reply(ldap_instance *inst, LDAP *ld, REQUEST *request,
1417                            LDAPMessage *msg)
1418 {
1419         do_one_map(inst, ld, request, msg, inst->check_map, &request->config_items, 1);
1420         do_one_map(inst, ld, request, msg, inst->reply_map, &request->reply->vps, 0);
1421
1422        /*
1423         *       More warning messages for people who can't be bothered
1424         *       to read the documentation.
1425         */
1426        if (debug_flag > 1) {
1427                if (!pairfind(request->config_items, PW_CLEARTEXT_PASSWORD, 0) &&
1428                    !pairfind(request->config_items, PW_NT_PASSWORD, 0) &&
1429                    !pairfind(request->config_items, PW_USER_PASSWORD, 0) &&
1430                    !pairfind(request->config_items, PW_PASSWORD_WITH_HEADER, 0) &&
1431                    !pairfind(request->config_items, PW_CRYPT_PASSWORD, 0)) {
1432                        DEBUG("WARNING: No \"known good\" password was found in LDAP.  Are you sure that the user is configured correctly?");
1433                }
1434        }
1435 }
1436
1437
1438 /******************************************************************************
1439  *
1440  *      Function: ldap_authorize
1441  *
1442  *      Purpose: Check if user is authorized for remote access
1443  *
1444  ******************************************************************************/
1445 static int ldap_authorize(void *instance, REQUEST * request)
1446 {
1447         int rcode, did_work;
1448         int module_rcode = RLM_MODULE_NOOP;
1449         ldap_instance   *inst = instance;
1450         char            *user_dn;
1451         char            **vals;
1452         VALUE_PAIR      *vp;
1453         LDAP_CONN       *conn;
1454         LDAPMessage     *result, *msg;
1455         char            filter[MAX_FILTER_STR_LEN];
1456         char            basedn[MAX_FILTER_STR_LEN];
1457
1458         did_work = FALSE;       /* for debugging user problems */
1459
1460         if (!request->username) {
1461                 RDEBUG2("Attribute \"User-Name\" is required for authorization.\n");
1462                 return RLM_MODULE_NOOP;
1463         }
1464
1465         /*
1466          *      Check for valid input, zero length names not permitted
1467          */
1468         if (request->username->length == 0) {
1469                 RDEBUG2("zero length username not permitted\n");
1470                 return RLM_MODULE_INVALID;
1471         }
1472
1473         if (!radius_xlat(filter, sizeof(filter), inst->filter,
1474                          request, ldap_escape_func, NULL)) {
1475                 radlog(L_ERR, "  [%s] Failed creating filter.\n", inst->xlat_name);
1476                 return RLM_MODULE_INVALID;
1477         }
1478
1479         if (!radius_xlat(basedn, sizeof(basedn), inst->basedn,
1480                          request, ldap_escape_func, NULL)) {
1481                 radlog(L_ERR, "  [%s] Failed creating basedn.\n", inst->xlat_name);
1482                 return RLM_MODULE_INVALID;
1483         }
1484
1485         conn = ldap_get_socket(inst);
1486         if (!conn) return RLM_MODULE_FAIL;
1487
1488         rcode = perform_search(inst, &conn, basedn, LDAP_SCOPE_SUBTREE, filter,
1489                                inst->attrs, &result);
1490         if (rcode < 0) {
1491                 if (rcode == -2) {
1492                         module_failure_msg(&request->packet->vps,
1493                                            "[%s] Search returned not found",
1494                                            inst->xlat_name);
1495                         DEBUG("  [%s] Search returned not found", inst->xlat_name);
1496                         module_rcode = RLM_MODULE_NOTFOUND;
1497                         goto free_socket;
1498                 }
1499                 DEBUG("  [%s] Search returned error", inst->xlat_name);
1500                 goto free_socket;
1501         }
1502
1503         msg = ldap_first_entry(conn->ld, result);
1504         if (!msg) {
1505                 RDEBUG2("ldap_first_entry() failed");
1506                 goto free_result;
1507         }
1508
1509         user_dn = ldap_get_dn(conn->ld, msg);
1510         if (!user_dn) {
1511                 RDEBUG2("ldap_get_dn() failed");
1512                 goto free_result;
1513         }
1514
1515         /*
1516          *      Adding attribute containing the Users' DN.
1517          */
1518         pairadd(&request->config_items, pairmake("Ldap-UserDn", user_dn, T_OP_EQ));
1519         ldap_memfree(user_dn);
1520
1521         /*
1522          *      Check for access.
1523          */
1524         if (inst->access_attr) {
1525                 did_work = TRUE;
1526
1527                 if (check_access(inst, conn, msg) < 0) {
1528                         module_rcode = RLM_MODULE_USERLOCK;
1529                         goto free_result;
1530                 }
1531         }
1532
1533         /*
1534          *      Apply ONE user profile, or a default user profile.
1535          */
1536         vp = pairfind(request->config_items, PW_USER_PROFILE, 0);
1537         if (vp || inst->default_profile) {
1538                 char *profile = inst->default_profile;
1539
1540                 if (vp) profile = vp->vp_strvalue;
1541
1542                 did_work = TRUE;
1543                 apply_profile(inst, &conn, request, profile);
1544         }
1545
1546         /*
1547          *      Apply a SET of user profiles.
1548          */
1549         if (inst->profile_attr &&
1550             (vals = ldap_get_values(conn->ld, msg, inst->profile_attr)) != NULL) {
1551
1552                 int i;
1553
1554                 for (i = 0; (vals[i] != NULL) && (*vals[i] != '\0'); i++) {
1555                         apply_profile(inst, &conn, request, vals[i]);
1556                 }
1557
1558                 did_work = TRUE;
1559                 ldap_value_free(vals);
1560         }
1561
1562         if (inst->map_file) {
1563                 did_work = TRUE;
1564                 do_check_reply(inst, conn->ld, request, msg);
1565         }
1566
1567         if (!did_work) {
1568                 RDEBUG("WARNING: The module did NOTHING in the 'authorize' section.  Why is it listed?");
1569                 RDEBUG("WARNING: You can probably delete '%s' from 'authorize'",
1570                        inst->xlat_name);
1571         }       
1572
1573 free_result:
1574         ldap_msgfree(result);
1575 free_socket:
1576         ldap_release_socket(inst, conn);
1577
1578         return module_rcode;
1579 }
1580
1581
1582 /*****************************************************************************
1583  *
1584  *      Function: ldap_authenticate
1585  *
1586  *      Purpose: Check the user's password against ldap database
1587  *
1588  *****************************************************************************/
1589 static int ldap_authenticate(void *instance, REQUEST * request)
1590 {
1591         int             module_rcode;
1592         const char      *user_dn;
1593         ldap_instance   *inst = instance;
1594         LDAP_CONN       *conn;
1595
1596         /*
1597          * Ensure that we're being passed a plain-text password, and not
1598          * anything else.
1599          */
1600
1601         if (!request->username) {
1602                 radlog(L_AUTH, "  [%s] Attribute \"User-Name\" is required for authentication.", inst->xlat_name);
1603                 return RLM_MODULE_INVALID;
1604         }
1605
1606         if (!request->password) {
1607                 radlog(L_AUTH, "  [%s] Attribute \"User-Password\" is required for authentication.", inst->xlat_name);
1608                 RDEBUG2("  You seem to have set \"Auth-Type := LDAP\" somewhere.");
1609                 RDEBUG2("  *******************************************************");
1610                 RDEBUG2("  * THAT CONFIGURATION IS WRONG.  DELETE IT.");
1611                 RDEBUG2("  * YOU ARE PREVENTING THE SERVER FROM WORKING PROPERLY.");
1612                 RDEBUG2("  *******************************************************");
1613                 return RLM_MODULE_INVALID;
1614         }
1615
1616         if (request->password->attribute != PW_USER_PASSWORD) {
1617                 radlog(L_AUTH, "  [%s] Attribute \"User-Password\" is required for authentication. Cannot use \"%s\".", inst->xlat_name, request->password->name);
1618                 return RLM_MODULE_INVALID;
1619         }
1620
1621         if (request->password->length == 0) {
1622                 module_failure_msg(&request->packet->vps,
1623                                    "[%s] empty password supplied", inst->xlat_name);
1624                 return RLM_MODULE_INVALID;
1625         }
1626
1627         conn = ldap_get_socket(inst);
1628         if (!conn) return RLM_MODULE_FAIL;
1629
1630         RDEBUG("login attempt by \"%s\" with password \"%s\"",
1631                request->username->vp_strvalue, request->password->vp_strvalue);
1632
1633         /*
1634          *      Get the DN by doing a search.
1635          */
1636         user_dn = get_userdn(&conn, request, &module_rcode);
1637         if (!user_dn) {
1638                 ldap_release_socket(inst, conn);
1639                 return module_rcode;
1640         }
1641
1642         /*
1643          *      Bind as the user
1644          */
1645         conn->rebound = TRUE;
1646         module_rcode = ldap_bind_wrapper(&conn, user_dn,
1647                                          request->password->vp_strvalue,
1648                                          NULL, TRUE);
1649         if (module_rcode == RLM_MODULE_OK) {
1650                 RDEBUG("  [%s] Bind as user '%s' was successful", inst->xlat_name,
1651                         user_dn);
1652         }
1653
1654         ldap_release_socket(inst, conn);
1655         return module_rcode;
1656 }
1657
1658
1659 /* globally exported name */
1660 module_t rlm_ldap = {
1661         RLM_MODULE_INIT,
1662         "ldap",
1663         RLM_TYPE_THREAD_SAFE,   /* type: reserved        */
1664         ldap_instantiate,       /* instantiation         */
1665         ldap_detach,            /* detach                */
1666         {
1667                 ldap_authenticate,      /* authentication        */
1668                 ldap_authorize,         /* authorization         */
1669                 NULL,                   /* preaccounting         */
1670                 NULL,                   /* accounting            */
1671                 NULL,                   /* checksimul            */
1672                 NULL,                   /* pre-proxy             */
1673                 NULL,                   /* post-proxy            */
1674                 NULL
1675         },
1676 };