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