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