More consistent
[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("Searching for user in group \"%s\"", check->vp_strvalue);
1085
1086         if (check->length == 0) {
1087                 RDEBUG("Cannot do comparison (group name is empty)");
1088                 return 1;
1089         }
1090
1091         conn = ldap_get_socket(inst);
1092         if (!conn) return 1;
1093
1094         /*
1095          *      This is used in the default membership filter.
1096          */
1097         user_dn = get_userdn(&conn, request, &module_rcode);
1098         if (!user_dn) {
1099                 ldap_release_socket(inst, conn);
1100                 return 1;
1101         }
1102
1103         if (!inst->groupmemb_filter) goto check_attr;
1104
1105         if (!radius_xlat(gr_filter, sizeof(gr_filter),
1106                          inst->groupmemb_filter, request, ldap_escape_func,
1107                          NULL)) {
1108                 radlog(L_ERR, "rlm_ldap (%s): Failed creating group filter",
1109                        inst->xlat_name);
1110                 return 1;
1111         }
1112
1113         /*
1114          *      If it's a DN, use that.
1115          */
1116         check_is_dn = strchr(check->vp_strvalue,',') == NULL ? FALSE : TRUE;
1117         
1118         if (check_is_dn) {
1119                 strlcpy(filter, gr_filter, sizeof(filter));
1120                 strlcpy(basedn, check->vp_strvalue, sizeof(basedn));    
1121         } else {
1122                 snprintf(filter, sizeof(filter), "(&(%s=%s)%s)",
1123                          inst->groupname_attr,
1124                          check->vp_strvalue, gr_filter);
1125
1126                 /*
1127                  *      get_userdn does this, too.  Oh well.
1128                  */
1129                 if (!radius_xlat(basedn, sizeof(basedn), inst->basedn,
1130                                  request, ldap_escape_func, NULL)) {
1131                         radlog(L_ERR, "rlm_ldap (%s): Failed creating basedn",
1132                                inst->xlat_name);
1133                         return 1;
1134                 }
1135         }
1136
1137         rcode = perform_search(inst, request, &conn, basedn, LDAP_SCOPE_SUBTREE,
1138                                filter, attrs, &result);
1139         if (rcode == 0) {
1140                 ldap_release_socket(inst, conn);
1141                 ldap_msgfree(result);
1142                         
1143                 RDEBUG("User found in group object");
1144                 
1145                 return 0;
1146         }
1147
1148         if (rcode == -1) {
1149                 ldap_release_socket(inst, conn);
1150                 return 1;
1151         }
1152
1153         /* else the search returned -2, for "not found" */
1154
1155         /*
1156          *      Else the search returned NOTFOUND.  See if we're
1157          *      configured to search for group membership using user
1158          *      object attribute.
1159          */
1160         if (!inst->groupmemb_attr) {
1161                 ldap_release_socket(inst, conn);
1162                 RDEBUG("Group object \"%s\" not found, or user is not a member",
1163                        check->vp_strvalue);
1164                 return 1;
1165         }
1166
1167 check_attr:
1168         RDEBUG2("Checking user object membership (%s) attributes",
1169                 inst->groupmemb_attr);
1170
1171         snprintf(filter ,sizeof(filter), "(objectclass=*)");
1172
1173         rcode = perform_search(inst, request, &conn, user_dn, LDAP_SCOPE_BASE,
1174                                filter, group_attrs, &result);
1175         if (rcode < 0) {
1176                 if (rcode == -2) {
1177                         RDEBUG("Can't check membership attributes, user object "
1178                                "not found");
1179                 }
1180                 ldap_release_socket(inst, conn);
1181                 return 1;
1182         }
1183
1184         entry = ldap_first_entry(conn->handle, result);
1185         if (!entry) {
1186                 ldap_get_option(conn->handle, LDAP_OPT_RESULT_CODE,
1187                                 &ldap_errno);
1188                 radlog(L_ERR, "rlm_ldap (%s): Failed retrieving entry: %s", 
1189                        inst->xlat_name,
1190                        ldap_err2string(ldap_errno));
1191                                
1192                 ldap_release_socket(inst, conn);
1193                 ldap_msgfree(result);
1194                 return 1;
1195         }
1196
1197         vals = ldap_get_values(conn->handle, entry, inst->groupmemb_attr);
1198         if (!vals) {
1199                 RDEBUG("No group membership attribute(s) found in user object");
1200                 ldap_release_socket(inst, conn);
1201                 ldap_msgfree(result);
1202                 return 1;
1203         }
1204
1205         /*
1206          *      Loop over the list of groups the user is a member of,
1207          *      looking for a match.
1208          */
1209         found = FALSE;
1210         for (i = 0; i < ldap_count_values(vals); i++) {
1211                 LDAPMessage *gr_result = NULL;
1212                 
1213                 value_is_dn = strchr(vals[i], ',') == NULL ? FALSE : TRUE;
1214                 
1215                 RDEBUG2("Processing group membership value \"%s\"", vals[i]);
1216
1217                 /*
1218                  *      Both literal group names, do case sensitive comparison
1219                  */
1220                 if (!check_is_dn && !value_is_dn) {
1221                         if (strcmp(vals[i], check->vp_strvalue) == 0){
1222                                 RDEBUG("User found (membership value matches "
1223                                        "check value)");
1224                                
1225                                 found = TRUE;
1226                                 break;
1227                         }
1228                         
1229                         continue;
1230                 }
1231
1232                 /*
1233                  *      Both DNs, do case insensitive comparison
1234                  */
1235                 if (check_is_dn && value_is_dn) {
1236                         if (strcasecmp(vals[i], check->vp_strvalue) == 0){
1237                                 RDEBUG("User found (membership DN matches "
1238                                        "check DN)");
1239                                
1240                                 found = TRUE;
1241                                 break;
1242                         }
1243                         
1244                         continue;
1245                 }
1246                 
1247                 /*
1248                  *      If the value is not a DN, or the check item is a DN
1249                  *      there's nothing more we can do.
1250                  */
1251                 if (!value_is_dn && check_is_dn) continue;
1252
1253                 /*
1254                  *      We have a value which is a DN, and a check item which
1255                  *      specifies the name of a group, search using the value
1256                  *      DN for the group, and see if it has a groupname_attr
1257                  *      which matches our check val.
1258                  */
1259                 RDEBUG2("Searching with membership DN and group name");
1260
1261                 snprintf(filter,sizeof(filter), "(%s=%s)",
1262                          inst->groupname_attr, check->vp_strvalue);
1263
1264                 rcode = perform_search(inst, request, &conn, vals[i],
1265                                        LDAP_SCOPE_BASE, filter, attrs,
1266                                        &gr_result);
1267                                        
1268                 ldap_msgfree(gr_result);
1269
1270                 /* Error occurred */
1271                 if (rcode == -1) {
1272                         ldap_value_free(vals);
1273                         ldap_msgfree(result);
1274                         ldap_release_socket(inst, conn);
1275                         return 1;
1276                 }
1277                 
1278                 /*
1279                  *      Either the group DN wasn't found, or it didn't have the
1280                  *      correct name. Continue looping over the attributes.
1281                  */
1282                 if (rcode == -2) {
1283                         ldap_msgfree(gr_result);
1284                         continue;
1285                 }
1286
1287                 found = TRUE;
1288
1289                 RDEBUG("User found (group name in membership DN matches check "
1290                        "value)");
1291
1292                 break;
1293         }
1294
1295         ldap_value_free(vals);
1296         ldap_msgfree(result);
1297         ldap_release_socket(inst, conn);
1298
1299         if (!found){
1300                 RDEBUG("User is not a member of specified group");
1301                 return 1;
1302         }
1303
1304         return 0;
1305 }
1306
1307 /*
1308  *      Verify that the ldap update section makes sense, and add attribute names
1309  *      to array of attributes for efficient querying later.
1310  */
1311 static int build_attrmap(CONF_SECTION *cs, VALUE_PAIR_MAP **head)
1312 {
1313         const char *cs_list, *p;
1314
1315         request_refs_t request_def = REQUEST_CURRENT;
1316         pair_lists_t list_def = PAIR_LIST_REQUEST;
1317
1318         CONF_ITEM *ci = cf_sectiontoitem(cs);
1319         CONF_PAIR *cp;
1320
1321         unsigned int total = 0;
1322         VALUE_PAIR_MAP **tail, *map;
1323         *head = NULL;
1324         tail = head;
1325         
1326         if (!cs) return 0;
1327         
1328         cs_list = p = cf_section_name2(cs);
1329         if (cs_list) {
1330                 request_def = radius_request_name(&p, REQUEST_UNKNOWN);
1331                 if (request_def == REQUEST_UNKNOWN) {
1332                         cf_log_err(ci, "rlm_ldap: Default request specified "
1333                                    "in mapping section is invalid");
1334                         return -1;
1335                 }
1336                 
1337                 list_def = fr_str2int(pair_lists, p, PAIR_LIST_UNKNOWN);
1338                 if (list_def == PAIR_LIST_UNKNOWN) {
1339                         cf_log_err(ci, "rlm_ldap: Default list specified "
1340                                    "in mapping section is invalid");
1341                         return -1;
1342                 }
1343         }
1344
1345         for (ci = cf_item_find_next(cs, NULL);
1346              ci != NULL;
1347              ci = cf_item_find_next(cs, ci)) {
1348                 if (total++ == MAX_ATTRMAP) {
1349                         cf_log_err(ci, "rlm_ldap: Attribute map size exceeded");
1350                         goto error;
1351                 }
1352                 
1353                 if (!cf_item_is_pair(ci)) {
1354                         cf_log_err(ci, "rlm_ldap: Entry is not in \"attribute ="
1355                                        " ldap-attribute\" format");
1356                         goto error;
1357                 }
1358         
1359                 cp = cf_itemtopair(ci);
1360                 map = radius_cp2map(cp, REQUEST_CURRENT, list_def);
1361                 if (!map) {
1362                         goto error;
1363                 }
1364                 
1365                 *tail = map;
1366                 tail = &(map->next);
1367         }
1368
1369         return 0;
1370         
1371         error:
1372                 radius_mapfree(head);
1373                 return -1;
1374 }
1375
1376 /*****************************************************************************
1377  *
1378  *      Detach from the LDAP server and cleanup internal state.
1379  *
1380  *****************************************************************************/
1381 static int ldap_detach(void *instance)
1382 {
1383         ldap_instance *inst = instance;
1384
1385         fr_connection_pool_delete(inst->pool);
1386         
1387         if (inst->user_map) {
1388                 radius_mapfree(&inst->user_map);
1389         }
1390
1391         free(inst);
1392
1393         return 0;
1394 }
1395
1396 /*************************************************************************
1397  *
1398  *      Function: rlm_ldap_instantiate
1399  *
1400  *      Purpose: Uses section of radiusd config file passed as parameter
1401  *               to create an instance of the module.
1402  *
1403  *************************************************************************/
1404 static int ldap_instantiate(CONF_SECTION * conf, void **instance)
1405 {
1406         ldap_instance *inst;
1407         CONF_SECTION *cs;
1408
1409         inst = rad_malloc(sizeof *inst);
1410         if (!inst) {
1411                 return -1;
1412         }
1413         memset(inst, 0, sizeof(*inst));
1414         inst->cs = conf;
1415
1416         inst->chase_referrals = 2; /* use OpenLDAP defaults */
1417         inst->rebind = 2;
1418
1419         if (cf_section_parse(conf, inst, module_config) < 0) {
1420                 free(inst);
1421                 return -1;
1422         }
1423         
1424         inst->xlat_name = cf_section_name2(conf);
1425         if (!inst->xlat_name) inst->xlat_name = cf_section_name1(conf);
1426
1427         if (inst->server == NULL) {
1428                 radlog(L_ERR, "rlm_ldap (%s): missing 'server' directive",
1429                        inst->xlat_name);
1430                 ldap_detach(inst);
1431                 return -1;
1432         }
1433
1434         /*
1435          *      Check for URLs.  If they're used and the library doesn't
1436          *      support them, then complain.
1437          */
1438         inst->is_url = 0;
1439         if (ldap_is_ldap_url(inst->server)) {
1440 #ifdef HAVE_LDAP_INITIALIZE
1441                 inst->is_url = 1;
1442                 inst->port = 0;
1443 #else
1444                 radlog(L_ERR, "rlm_ldap (%s): 'server' directive is in URL "
1445                        "form but ldap_initialize() is not available",
1446                        inst->xlat_name);
1447                 ldap_detach(inst);
1448                 return -1;
1449 #endif
1450         }
1451
1452         /* workaround for servers which support LDAPS but not START TLS */
1453         if (inst->port == LDAPS_PORT || inst->tls_mode) {
1454                 inst->tls_mode = LDAP_OPT_X_TLS_HARD;
1455         } else {
1456                 inst->tls_mode = 0;
1457         }
1458
1459 #if LDAP_SET_REBIND_PROC_ARGS != 3
1460         /*
1461          *      The 2-argument rebind doesn't take an instance
1462          *      variable.  Our rebind function needs the instance
1463          *      variable for the username, password, etc.
1464          */
1465         if (inst->rebind == 1) {
1466                 radlog(L_ERR, "rlm_ldap (%s): Cannot use 'rebind' directive "
1467                        "as this version of libldap does not support the API "
1468                        "that we need", inst->xlat-name);
1469                 ldap_detach(inst);
1470                 return -1;
1471         }
1472 #endif
1473
1474         /*
1475          *      Build the attribute map
1476          */
1477         cs = cf_section_sub_find(conf, "update");
1478         if (cs) {       
1479                 if (build_attrmap(cs, &(inst->user_map)) < 0) {
1480                         ldap_detach(inst);
1481                         return -1;
1482                 }
1483         }
1484
1485         /*
1486          *      Group comparison checks.
1487          */
1488         paircompare_register(PW_LDAP_GROUP, PW_USER_NAME, ldap_groupcmp, inst); 
1489         if (cf_section_name2(conf)) {
1490                 DICT_ATTR *da;
1491                 ATTR_FLAGS flags;
1492                 char buffer[256];
1493
1494                 snprintf(buffer, sizeof(buffer), "%s-Ldap-Group",
1495                          inst->xlat_name);
1496                 memset(&flags, 0, sizeof(flags));
1497
1498                 dict_addattr(buffer, -1, 0, PW_TYPE_STRING, flags);
1499                 da = dict_attrbyname(buffer);
1500                 if (!da) {
1501                         radlog(L_ERR, "rlm_ldap (%s): Failed creating "
1502                                "attribute %s", inst->xlat_name, buffer);
1503                         ldap_detach(inst);
1504                         return -1;
1505                 }
1506
1507                 paircompare_register(da->attr, PW_USER_NAME, ldap_groupcmp,
1508                                      inst);
1509         }
1510
1511         xlat_register(inst->xlat_name, ldap_xlat, inst);
1512
1513         /*
1514          *      Initialize the socket pool.
1515          */
1516         inst->pool = fr_connection_pool_init(inst->cs, inst,
1517                                              ldap_conn_create,
1518                                              NULL,
1519                                              ldap_conn_delete);
1520         if (!inst->pool) {
1521                 ldap_detach(inst);
1522                 return -1;
1523         }
1524         
1525         *instance = inst;
1526         return 0;
1527 }
1528
1529
1530 static void module_failure_msg(VALUE_PAIR **vps, const char *fmt, ...)
1531 {
1532         va_list ap;
1533         VALUE_PAIR *vp;
1534
1535         va_start(ap, fmt);
1536         vp = paircreate(PW_MODULE_FAILURE_MESSAGE, 0, PW_TYPE_STRING);
1537         if (!vp) {
1538                 va_end(ap);
1539                 return;
1540         }
1541
1542         vsnprintf(vp->vp_strvalue, sizeof(vp->vp_strvalue), fmt, ap);
1543
1544         pairadd(vps, vp);
1545 }
1546
1547
1548 static int check_access(ldap_instance *inst, REQUEST* request, LDAP_CONN *conn,
1549                         LDAPMessage *entry)
1550 {
1551         int rcode = -1;
1552         char **vals = NULL;
1553
1554         vals = ldap_get_values(conn->handle, entry, inst->access_attr);
1555         if (vals) {
1556                 if (inst->positive_access_attr) {
1557                         if (strncmp(vals[0], "FALSE", 5) == 0) {
1558                                 RDEBUG("Dialup access disabled");
1559
1560                         } else {
1561                                 rcode = 0;
1562                         }
1563
1564                 } else {
1565                         RDEBUG("\"%s\" attribute exists - access denied by"
1566                                " default", inst->access_attr);
1567                 }
1568
1569                 ldap_value_free(vals);
1570
1571         } else if (inst->positive_access_attr) {
1572                 RDEBUG("No %s attribute - access denied by default",
1573                        inst->access_attr);
1574
1575         } else {
1576                 rcode = 0;
1577         }
1578
1579         return rcode;
1580 }
1581
1582
1583 static VALUE_PAIR *ldap_getvalue(REQUEST *request, const VALUE_PAIR_TMPL *dst,
1584                                  void *ctx)
1585 {
1586         rlm_ldap_result_t *self = ctx;
1587         VALUE_PAIR *head, **tail, *vp;
1588         int i;
1589         
1590         request = request;
1591         
1592         head = NULL;
1593         tail = &head;
1594         
1595         /*
1596          *      Iterate over all the retrieved values,
1597          *      don't try and be clever about changing operators
1598          *      just use whatever was set in the attribute map. 
1599          */
1600         for (i = 0; i < self->count; i++) {
1601                 vp = pairalloc(dst->da);
1602                 rad_assert(vp);
1603
1604                 pairparsevalue(vp, self->values[i]);
1605                 
1606                 *tail = vp;
1607                 tail = &(vp->next);
1608         }
1609         
1610         return head;            
1611 }
1612
1613
1614 static void xlat_attrsfree(const xlat_attrs_t *expanded)
1615 {
1616         const VALUE_PAIR_MAP *map;
1617         unsigned int total = 0;
1618         
1619         char *name;
1620         
1621         for (map = expanded->maps; map != NULL; map = map->next)
1622         {
1623                 memcpy(&name, &(expanded->attrs[total++]), sizeof(name));
1624                 
1625                 if (!name) return;
1626                 
1627                 if (map->src.do_xlat) {
1628                         free(name);
1629                 }
1630         }
1631 }
1632
1633
1634 static int xlat_attrs(REQUEST *request, const VALUE_PAIR_MAP *maps,
1635                       xlat_attrs_t *expanded)
1636 {
1637         const VALUE_PAIR_MAP *map;
1638         unsigned int total = 0;
1639         
1640         size_t len;
1641         char *buffer;
1642
1643         for (map = maps; map != NULL; map = map->next)
1644         {
1645                 if (map->src.do_xlat) {
1646                         buffer = rad_malloc(MAX_ATTR_STR_LEN);
1647                         len = radius_xlat(buffer, MAX_ATTR_STR_LEN,
1648                                           map->src.name, request, NULL, NULL);
1649                                           
1650                         if (!len) {
1651                                 RDEBUG("Expansion of LDAP attribute "
1652                                        "\"%s\" failed", map->src.name);
1653                                        
1654                                 expanded->attrs[total] = NULL;
1655                                 
1656                                 xlat_attrsfree(expanded);
1657                                 
1658                                 return -1;
1659                         }
1660                         
1661                         expanded->attrs[total++] = buffer;
1662                 } else {
1663                         expanded->attrs[total++] = map->src.name;
1664                 }
1665         }
1666         
1667         expanded->attrs[total] = NULL;
1668         expanded->maps = maps;
1669         
1670         return 0;
1671 }
1672
1673
1674 /** Convert attribute map into valuepairs
1675  *
1676  * Use the attribute map built earlier to convert LDAP values into valuepairs
1677  * and insert them into whichever list they need to go into.
1678  *
1679  * This is *NOT* atomic, but there's no condition in which we should error
1680  * out...
1681  */
1682 static void do_attrmap(UNUSED ldap_instance *inst, REQUEST *request,
1683                        LDAP *handle, const xlat_attrs_t *expanded,
1684                        LDAPMessage *entry)
1685 {
1686         const VALUE_PAIR_MAP    *map;
1687         unsigned int            total = 0;
1688         
1689         rlm_ldap_result_t       result;
1690         const char              *name;
1691
1692         for (map = expanded->maps; map != NULL; map = map->next)
1693         {
1694                 name = expanded->attrs[total++];
1695                 
1696                 result.values = ldap_get_values(handle, entry, name);
1697                 if (!result.values) {
1698                         DEBUG2("Attribute \"%s\" not found in LDAP object",
1699                                name);
1700                                 
1701                         goto next;
1702                 }
1703                 
1704                 /*
1705                  *      Find out how many values there are for the
1706                  *      attribute and extract all of them.
1707                  */
1708                 result.count = ldap_count_values(result.values);
1709                 
1710                 /*
1711                  *      If something bad happened, just skip, this is probably
1712                  *      a case of the dst being incorrect for the current
1713                  *      request context
1714                  */
1715                 if (radius_map2request(request, map, name, ldap_getvalue,
1716                                        &result) < 0) {
1717                         goto next;
1718                 }
1719                 
1720                 next:
1721                 
1722                 ldap_value_free(result.values);
1723         }
1724 }
1725
1726
1727 static void do_check_reply(ldap_instance *inst, REQUEST *request)
1728 {
1729        /*
1730         *       More warning messages for people who can't be bothered
1731         *       to read the documentation.
1732         */
1733         if (inst->expect_password && (debug_flag > 1)) {
1734                 if (!pairfind(request->config_items,PW_CLEARTEXT_PASSWORD, 0) &&
1735                         !pairfind(request->config_items,
1736                                   PW_NT_PASSWORD, 0) &&
1737                         !pairfind(request->config_items,
1738                                   PW_USER_PASSWORD, 0) &&
1739                         !pairfind(request->config_items,
1740                                   PW_PASSWORD_WITH_HEADER, 0) &&
1741                         !pairfind(request->config_items,
1742                                   PW_CRYPT_PASSWORD, 0)) {
1743                                 RDEBUG("WARNING: No \"known good\" password "
1744                                        "was found in LDAP.  Are you sure that "
1745                                        "the user is configured correctly?");
1746                }
1747        }
1748 }
1749
1750
1751 static void apply_profile(ldap_instance *inst, REQUEST *request,
1752                           LDAP_CONN **pconn, const char *profile,
1753                           const xlat_attrs_t *expanded)
1754 {
1755         int rcode;
1756         LDAPMessage     *result, *entry;
1757         int             ldap_errno;
1758         LDAP            *handle = (*pconn)->handle;
1759         char            filter[MAX_FILTER_STR_LEN];
1760
1761         if (!profile || !*profile) return;
1762
1763         strlcpy(filter, inst->base_filter, sizeof(filter));
1764
1765         rcode = perform_search(inst, request, pconn, profile, LDAP_SCOPE_BASE,
1766                                filter, expanded->attrs, &result);
1767                 
1768         if (rcode < 0) {
1769                 if (rcode == -2) {
1770                         RDEBUG("Profile \"%s\" not found", profile);
1771                 }
1772                 goto free_result;
1773         }
1774
1775         entry = ldap_first_entry(handle, result);
1776         if (!entry) {
1777                 ldap_get_option(handle, LDAP_OPT_RESULT_CODE,
1778                                 &ldap_errno);
1779                 radlog(L_ERR, "rlm_ldap (%s): Failed retrieving entry: %s", 
1780                        inst->xlat_name,
1781                        ldap_err2string(ldap_errno));
1782                        
1783                 goto free_result;
1784         }
1785         
1786         do_attrmap(inst, request, handle, expanded, entry);
1787
1788 free_result:
1789         ldap_msgfree(result);
1790 }
1791
1792
1793 /******************************************************************************
1794  *
1795  *      Function: ldap_authorize
1796  *
1797  *      Purpose: Check if user is authorized for remote access
1798  *
1799  ******************************************************************************/
1800 static int ldap_authorize(void *instance, REQUEST * request)
1801 {
1802         int rcode;
1803         int module_rcode = RLM_MODULE_OK;
1804         ldap_instance   *inst = instance;
1805         char            *user_dn;
1806         char            **vals;
1807         VALUE_PAIR      *vp;
1808         LDAP_CONN       *conn;
1809         LDAPMessage     *result, *entry;
1810         int             ldap_errno;
1811         char            filter[MAX_FILTER_STR_LEN];
1812         char            basedn[MAX_FILTER_STR_LEN];
1813         xlat_attrs_t    expanded; /* faster that mallocing every time */
1814         
1815         if (!request->username) {
1816                 RDEBUG2("Attribute \"User-Name\" is required for "
1817                         "authorization.");
1818                 return RLM_MODULE_NOOP;
1819         }
1820
1821         /*
1822          *      Check for valid input, zero length names not permitted
1823          */
1824         if (request->username->length == 0) {
1825                 RDEBUG2("Zero length username not permitted");
1826                 return RLM_MODULE_INVALID;
1827         }
1828
1829         if (!radius_xlat(filter, sizeof(filter), inst->filter,
1830                          request, ldap_escape_func, NULL)) {
1831                 radlog(L_ERR, "rlm_ldap (%s): Failed creating filter",
1832                        inst->xlat_name);
1833                 return RLM_MODULE_INVALID;
1834         }
1835
1836         if (!radius_xlat(basedn, sizeof(basedn), inst->basedn,
1837                          request, ldap_escape_func, NULL)) {
1838                 radlog(L_ERR, "rlm_ldap (%s): Failed creating basedn",
1839                        inst->xlat_name);
1840                 return RLM_MODULE_INVALID;
1841         }
1842
1843         conn = ldap_get_socket(inst);
1844         if (!conn) return RLM_MODULE_FAIL;
1845         
1846         if (xlat_attrs(request, inst->user_map, &expanded) < 0) {
1847                 return RLM_MODULE_FAIL;
1848         }
1849         
1850         rcode = perform_search(inst, request, &conn, basedn,
1851                                LDAP_SCOPE_SUBTREE, filter, expanded.attrs,
1852                                &result);
1853         
1854         if (rcode < 0) {
1855                 if (rcode == -2) {
1856                         module_failure_msg(&request->packet->vps,
1857                                            "rlm_ldap (%s): User object not "
1858                                            " found",
1859                                            inst->xlat_name);
1860                                            
1861                         RDEBUG("User object not found", inst->xlat_name);
1862                                
1863                         module_rcode = RLM_MODULE_NOTFOUND;
1864                         goto free_socket;
1865                 }
1866
1867                 goto free_socket;
1868         }
1869
1870         entry = ldap_first_entry(conn->handle, result);
1871         if (!entry) {
1872                 ldap_get_option(conn->handle, LDAP_OPT_RESULT_CODE,
1873                                 &ldap_errno);
1874                 radlog(L_ERR, "rlm_ldap (%s): Failed retrieving entry: %s", 
1875                        inst->xlat_name,
1876                        ldap_err2string(ldap_errno));
1877                        
1878                 goto free_result;
1879         }
1880
1881         user_dn = ldap_get_dn(conn->handle, entry);
1882         if (!user_dn) {
1883                 ldap_get_option(conn->handle, LDAP_OPT_RESULT_CODE,
1884                                 &ldap_errno);
1885                 radlog(L_ERR, "rlm_ldap (%s): ldap_get_dn() failed: %s",
1886                        inst->xlat_name,
1887                        ldap_err2string(ldap_errno));
1888                 goto free_result;
1889         }
1890         
1891         RDEBUG2("User found at DN \"%s\"", user_dn);
1892         /*
1893          *      Adding attribute containing the Users' DN.
1894          */
1895         pairadd(&request->config_items,
1896                 pairmake("Ldap-UserDn", user_dn, T_OP_EQ));
1897         ldap_memfree(user_dn);
1898
1899         /*
1900          *      Check for access.
1901          */
1902         if (inst->access_attr) {
1903                 if (check_access(inst, request, conn, entry) < 0) {
1904                         module_rcode = RLM_MODULE_USERLOCK;
1905                         goto free_result;
1906                 }
1907         }
1908
1909         /*
1910          *      Apply ONE user profile, or a default user profile.
1911          */
1912         vp = pairfind(request->config_items, PW_USER_PROFILE, 0);
1913         if (vp || inst->default_profile) {
1914                 char *profile = inst->default_profile;
1915
1916                 if (vp) profile = vp->vp_strvalue;
1917
1918                 apply_profile(inst, request, &conn, profile, &expanded);
1919         }
1920
1921         /*
1922          *      Apply a SET of user profiles.
1923          */
1924         if (inst->profile_attr) {
1925                 vals = ldap_get_values(conn->handle, entry, inst->profile_attr);
1926                 if (vals != NULL) {
1927                         int i;
1928         
1929                         for (i = 0; (vals[i] != NULL) && (*vals[i] != '\0');
1930                              i++) {
1931                                 apply_profile(inst, request, &conn, vals[i],
1932                                               &expanded);
1933                         }
1934         
1935                         ldap_value_free(vals);
1936                 }
1937         }
1938
1939         if (inst->user_map) {
1940                 do_attrmap(inst, request, conn->handle, &expanded, entry);
1941                 do_check_reply(inst, request);
1942         }
1943         
1944 free_result:
1945         xlat_attrsfree(&expanded);
1946         ldap_msgfree(result);
1947 free_socket:
1948         ldap_release_socket(inst, conn);
1949
1950         return module_rcode;
1951 }
1952
1953
1954 /*****************************************************************************
1955  *
1956  *      Function: ldap_authenticate
1957  *
1958  *      Purpose: Check the user's password against ldap database
1959  *
1960  *****************************************************************************/
1961 static int ldap_authenticate(void *instance, REQUEST * request)
1962 {
1963         int             module_rcode;
1964         const char      *user_dn;
1965         ldap_instance   *inst = instance;
1966         LDAP_CONN       *conn;
1967
1968         /*
1969          * Ensure that we're being passed a plain-text password, and not
1970          * anything else.
1971          */
1972
1973         if (!request->username) {
1974                 radlog(L_AUTH, "rlm_ldap (%s): Attribute \"User-Name\" is "
1975                        "required for authentication", inst->xlat_name);
1976                 return RLM_MODULE_INVALID;
1977         }
1978
1979         if (!request->password) {
1980                 radlog(L_AUTH, "rlm_ldap (%s): Attribute \"User-Password\" "
1981                        "is required for authentication.", inst->xlat_name);
1982                 RDEBUG2("  You have set \"Auth-Type := LDAP\" somewhere.");
1983                 RDEBUG2("  *********************************************");
1984                 RDEBUG2("  * THAT CONFIGURATION IS WRONG.  DELETE IT.   ");
1985                 RDEBUG2("  * YOU ARE PREVENTING THE SERVER FROM WORKING.");
1986                 RDEBUG2("  *********************************************");
1987                 return RLM_MODULE_INVALID;
1988         }
1989
1990         if (request->password->attribute != PW_USER_PASSWORD) {
1991                 radlog(L_AUTH, "rlm_ldap (%s): Attribute \"User-Password\" "
1992                        "is required for authentication. Cannot use \"%s\".",
1993                        inst->xlat_name, request->password->name);
1994                 return RLM_MODULE_INVALID;
1995         }
1996
1997         if (request->password->length == 0) {
1998                 module_failure_msg(&request->packet->vps,
1999                                    "rlm_ldap (%s): Empty password supplied",
2000                                    inst->xlat_name);
2001                 return RLM_MODULE_INVALID;
2002         }
2003
2004         conn = ldap_get_socket(inst);
2005         if (!conn) return RLM_MODULE_FAIL;
2006
2007         RDEBUG("Login attempt by \"%s\" with password \"%s\"",
2008                request->username->vp_strvalue, request->password->vp_strvalue);
2009
2010         /*
2011          *      Get the DN by doing a search.
2012          */
2013         user_dn = get_userdn(&conn, request, &module_rcode);
2014         if (!user_dn) {
2015                 ldap_release_socket(inst, conn);
2016                 return module_rcode;
2017         }
2018
2019         /*
2020          *      Bind as the user
2021          */
2022         conn->rebound = TRUE;
2023         module_rcode = ldap_bind_wrapper(&conn, user_dn,
2024                                          request->password->vp_strvalue,
2025                                          NULL, TRUE);
2026         if (module_rcode == RLM_MODULE_OK) {
2027                 RDEBUG("Bind as user \"%s\" was successful", user_dn);
2028         }
2029
2030         ldap_release_socket(inst, conn);
2031         return module_rcode;
2032 }
2033
2034
2035 /* globally exported name */
2036 module_t rlm_ldap = {
2037         RLM_MODULE_INIT,
2038         "ldap",
2039         RLM_TYPE_THREAD_SAFE,   /* type: reserved        */
2040         ldap_instantiate,       /* instantiation         */
2041         ldap_detach,            /* detach                */
2042         {
2043                 ldap_authenticate,      /* authentication        */
2044                 ldap_authorize,         /* authorization         */
2045                 NULL,                   /* preaccounting         */
2046                 NULL,                   /* accounting            */
2047                 NULL,                   /* checksimul            */
2048                 NULL,                   /* pre-proxy             */
2049                 NULL,                   /* post-proxy            */
2050                 NULL
2051         },
2052 };