Add module failure message to rlm_exec
[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 static int check_access(ldap_instance *inst, REQUEST* request, LDAP_CONN *conn,
1530                         LDAPMessage *entry)
1531 {
1532         int rcode = -1;
1533         char **vals = NULL;
1534
1535         vals = ldap_get_values(conn->handle, entry, inst->access_attr);
1536         if (vals) {
1537                 if (inst->positive_access_attr) {
1538                         if (strncmp(vals[0], "FALSE", 5) == 0) {
1539                                 RDEBUG("Dialup access disabled");
1540
1541                         } else {
1542                                 rcode = 0;
1543                         }
1544
1545                 } else {
1546                         RDEBUG("\"%s\" attribute exists - access denied by"
1547                                " default", inst->access_attr);
1548                 }
1549
1550                 ldap_value_free(vals);
1551
1552         } else if (inst->positive_access_attr) {
1553                 RDEBUG("No %s attribute - access denied by default",
1554                        inst->access_attr);
1555
1556         } else {
1557                 rcode = 0;
1558         }
1559
1560         return rcode;
1561 }
1562
1563
1564 static VALUE_PAIR *ldap_getvalue(REQUEST *request, const VALUE_PAIR_TMPL *dst,
1565                                  void *ctx)
1566 {
1567         rlm_ldap_result_t *self = ctx;
1568         VALUE_PAIR *head, **tail, *vp;
1569         int i;
1570         
1571         request = request;
1572         
1573         head = NULL;
1574         tail = &head;
1575         
1576         /*
1577          *      Iterate over all the retrieved values,
1578          *      don't try and be clever about changing operators
1579          *      just use whatever was set in the attribute map. 
1580          */
1581         for (i = 0; i < self->count; i++) {
1582                 vp = pairalloc(dst->da);
1583                 rad_assert(vp);
1584
1585                 pairparsevalue(vp, self->values[i]);
1586                 
1587                 *tail = vp;
1588                 tail = &(vp->next);
1589         }
1590         
1591         return head;            
1592 }
1593
1594
1595 static void xlat_attrsfree(const xlat_attrs_t *expanded)
1596 {
1597         const VALUE_PAIR_MAP *map;
1598         unsigned int total = 0;
1599         
1600         char *name;
1601         
1602         for (map = expanded->maps; map != NULL; map = map->next)
1603         {
1604                 memcpy(&name, &(expanded->attrs[total++]), sizeof(name));
1605                 
1606                 if (!name) return;
1607                 
1608                 if (map->src.do_xlat) {
1609                         free(name);
1610                 }
1611         }
1612 }
1613
1614
1615 static int xlat_attrs(REQUEST *request, const VALUE_PAIR_MAP *maps,
1616                       xlat_attrs_t *expanded)
1617 {
1618         const VALUE_PAIR_MAP *map;
1619         unsigned int total = 0;
1620         
1621         size_t len;
1622         char *buffer;
1623
1624         for (map = maps; map != NULL; map = map->next)
1625         {
1626                 if (map->src.do_xlat) {
1627                         buffer = rad_malloc(MAX_ATTR_STR_LEN);
1628                         len = radius_xlat(buffer, MAX_ATTR_STR_LEN,
1629                                           map->src.name, request, NULL, NULL);
1630                                           
1631                         if (!len) {
1632                                 RDEBUG("Expansion of LDAP attribute "
1633                                        "\"%s\" failed", map->src.name);
1634                                        
1635                                 expanded->attrs[total] = NULL;
1636                                 
1637                                 xlat_attrsfree(expanded);
1638                                 
1639                                 return -1;
1640                         }
1641                         
1642                         expanded->attrs[total++] = buffer;
1643                 } else {
1644                         expanded->attrs[total++] = map->src.name;
1645                 }
1646         }
1647         
1648         expanded->attrs[total] = NULL;
1649         expanded->maps = maps;
1650         
1651         return 0;
1652 }
1653
1654
1655 /** Convert attribute map into valuepairs
1656  *
1657  * Use the attribute map built earlier to convert LDAP values into valuepairs
1658  * and insert them into whichever list they need to go into.
1659  *
1660  * This is *NOT* atomic, but there's no condition in which we should error
1661  * out...
1662  */
1663 static void do_attrmap(UNUSED ldap_instance *inst, REQUEST *request,
1664                        LDAP *handle, const xlat_attrs_t *expanded,
1665                        LDAPMessage *entry)
1666 {
1667         const VALUE_PAIR_MAP    *map;
1668         unsigned int            total = 0;
1669         
1670         rlm_ldap_result_t       result;
1671         const char              *name;
1672
1673         for (map = expanded->maps; map != NULL; map = map->next)
1674         {
1675                 name = expanded->attrs[total++];
1676                 
1677                 result.values = ldap_get_values(handle, entry, name);
1678                 if (!result.values) {
1679                         DEBUG2("Attribute \"%s\" not found in LDAP object",
1680                                name);
1681                                 
1682                         goto next;
1683                 }
1684                 
1685                 /*
1686                  *      Find out how many values there are for the
1687                  *      attribute and extract all of them.
1688                  */
1689                 result.count = ldap_count_values(result.values);
1690                 
1691                 /*
1692                  *      If something bad happened, just skip, this is probably
1693                  *      a case of the dst being incorrect for the current
1694                  *      request context
1695                  */
1696                 if (radius_map2request(request, map, name, ldap_getvalue,
1697                                        &result) < 0) {
1698                         goto next;
1699                 }
1700                 
1701                 next:
1702                 
1703                 ldap_value_free(result.values);
1704         }
1705 }
1706
1707
1708 static void do_check_reply(ldap_instance *inst, REQUEST *request)
1709 {
1710        /*
1711         *       More warning messages for people who can't be bothered
1712         *       to read the documentation.
1713         */
1714         if (inst->expect_password && (debug_flag > 1)) {
1715                 if (!pairfind(request->config_items,PW_CLEARTEXT_PASSWORD, 0) &&
1716                         !pairfind(request->config_items,
1717                                   PW_NT_PASSWORD, 0) &&
1718                         !pairfind(request->config_items,
1719                                   PW_USER_PASSWORD, 0) &&
1720                         !pairfind(request->config_items,
1721                                   PW_PASSWORD_WITH_HEADER, 0) &&
1722                         !pairfind(request->config_items,
1723                                   PW_CRYPT_PASSWORD, 0)) {
1724                                 RDEBUG("WARNING: No \"known good\" password "
1725                                        "was found in LDAP.  Are you sure that "
1726                                        "the user is configured correctly?");
1727                }
1728        }
1729 }
1730
1731
1732 static void apply_profile(ldap_instance *inst, REQUEST *request,
1733                           LDAP_CONN **pconn, const char *profile,
1734                           const xlat_attrs_t *expanded)
1735 {
1736         int rcode;
1737         LDAPMessage     *result, *entry;
1738         int             ldap_errno;
1739         LDAP            *handle = (*pconn)->handle;
1740         char            filter[MAX_FILTER_STR_LEN];
1741
1742         if (!profile || !*profile) return;
1743
1744         strlcpy(filter, inst->base_filter, sizeof(filter));
1745
1746         rcode = perform_search(inst, request, pconn, profile, LDAP_SCOPE_BASE,
1747                                filter, expanded->attrs, &result);
1748                 
1749         if (rcode < 0) {
1750                 if (rcode == -2) {
1751                         RDEBUG("Profile \"%s\" not found", profile);
1752                 }
1753                 goto free_result;
1754         }
1755
1756         entry = ldap_first_entry(handle, result);
1757         if (!entry) {
1758                 ldap_get_option(handle, LDAP_OPT_RESULT_CODE,
1759                                 &ldap_errno);
1760                 radlog(L_ERR, "rlm_ldap (%s): Failed retrieving entry: %s", 
1761                        inst->xlat_name,
1762                        ldap_err2string(ldap_errno));
1763                        
1764                 goto free_result;
1765         }
1766         
1767         do_attrmap(inst, request, handle, expanded, entry);
1768
1769 free_result:
1770         ldap_msgfree(result);
1771 }
1772
1773
1774 /******************************************************************************
1775  *
1776  *      Function: ldap_authorize
1777  *
1778  *      Purpose: Check if user is authorized for remote access
1779  *
1780  ******************************************************************************/
1781 static int ldap_authorize(void *instance, REQUEST * request)
1782 {
1783         int rcode;
1784         int module_rcode = RLM_MODULE_OK;
1785         ldap_instance   *inst = instance;
1786         char            *user_dn;
1787         char            **vals;
1788         VALUE_PAIR      *vp;
1789         LDAP_CONN       *conn;
1790         LDAPMessage     *result, *entry;
1791         int             ldap_errno;
1792         char            filter[MAX_FILTER_STR_LEN];
1793         char            basedn[MAX_FILTER_STR_LEN];
1794         xlat_attrs_t    expanded; /* faster that mallocing every time */
1795         
1796         if (!request->username) {
1797                 RDEBUG2("Attribute \"User-Name\" is required for "
1798                         "authorization.");
1799                 return RLM_MODULE_NOOP;
1800         }
1801
1802         /*
1803          *      Check for valid input, zero length names not permitted
1804          */
1805         if (request->username->length == 0) {
1806                 RDEBUG2("Zero length username not permitted");
1807                 return RLM_MODULE_INVALID;
1808         }
1809
1810         if (!radius_xlat(filter, sizeof(filter), inst->filter,
1811                          request, ldap_escape_func, NULL)) {
1812                 radlog(L_ERR, "rlm_ldap (%s): Failed creating filter",
1813                        inst->xlat_name);
1814                 return RLM_MODULE_INVALID;
1815         }
1816
1817         if (!radius_xlat(basedn, sizeof(basedn), inst->basedn,
1818                          request, ldap_escape_func, NULL)) {
1819                 radlog(L_ERR, "rlm_ldap (%s): Failed creating basedn",
1820                        inst->xlat_name);
1821                 return RLM_MODULE_INVALID;
1822         }
1823
1824         conn = ldap_get_socket(inst);
1825         if (!conn) return RLM_MODULE_FAIL;
1826         
1827         if (xlat_attrs(request, inst->user_map, &expanded) < 0) {
1828                 return RLM_MODULE_FAIL;
1829         }
1830         
1831         rcode = perform_search(inst, request, &conn, basedn,
1832                                LDAP_SCOPE_SUBTREE, filter, expanded.attrs,
1833                                &result);
1834         
1835         if (rcode < 0) {
1836                 if (rcode == -2) {
1837                         module_failure_msg(request,
1838                                            "rlm_ldap (%s): User object not "
1839                                            " found",
1840                                            inst->xlat_name);
1841                                            
1842                         RDEBUG("User object not found", inst->xlat_name);
1843                                
1844                         module_rcode = RLM_MODULE_NOTFOUND;
1845                         goto free_socket;
1846                 }
1847
1848                 goto free_socket;
1849         }
1850
1851         entry = ldap_first_entry(conn->handle, result);
1852         if (!entry) {
1853                 ldap_get_option(conn->handle, LDAP_OPT_RESULT_CODE,
1854                                 &ldap_errno);
1855                 radlog(L_ERR, "rlm_ldap (%s): Failed retrieving entry: %s", 
1856                        inst->xlat_name,
1857                        ldap_err2string(ldap_errno));
1858                        
1859                 goto free_result;
1860         }
1861
1862         user_dn = ldap_get_dn(conn->handle, entry);
1863         if (!user_dn) {
1864                 ldap_get_option(conn->handle, LDAP_OPT_RESULT_CODE,
1865                                 &ldap_errno);
1866                 radlog(L_ERR, "rlm_ldap (%s): ldap_get_dn() failed: %s",
1867                        inst->xlat_name,
1868                        ldap_err2string(ldap_errno));
1869                 goto free_result;
1870         }
1871         
1872         RDEBUG2("User found at DN \"%s\"", user_dn);
1873         /*
1874          *      Adding attribute containing the Users' DN.
1875          */
1876         pairadd(&request->config_items,
1877                 pairmake("Ldap-UserDn", user_dn, T_OP_EQ));
1878         ldap_memfree(user_dn);
1879
1880         /*
1881          *      Check for access.
1882          */
1883         if (inst->access_attr) {
1884                 if (check_access(inst, request, conn, entry) < 0) {
1885                         module_rcode = RLM_MODULE_USERLOCK;
1886                         goto free_result;
1887                 }
1888         }
1889
1890         /*
1891          *      Apply ONE user profile, or a default user profile.
1892          */
1893         vp = pairfind(request->config_items, PW_USER_PROFILE, 0);
1894         if (vp || inst->default_profile) {
1895                 char *profile = inst->default_profile;
1896
1897                 if (vp) profile = vp->vp_strvalue;
1898
1899                 apply_profile(inst, request, &conn, profile, &expanded);
1900         }
1901
1902         /*
1903          *      Apply a SET of user profiles.
1904          */
1905         if (inst->profile_attr) {
1906                 vals = ldap_get_values(conn->handle, entry, inst->profile_attr);
1907                 if (vals != NULL) {
1908                         int i;
1909         
1910                         for (i = 0; (vals[i] != NULL) && (*vals[i] != '\0');
1911                              i++) {
1912                                 apply_profile(inst, request, &conn, vals[i],
1913                                               &expanded);
1914                         }
1915         
1916                         ldap_value_free(vals);
1917                 }
1918         }
1919
1920         if (inst->user_map) {
1921                 do_attrmap(inst, request, conn->handle, &expanded, entry);
1922                 do_check_reply(inst, request);
1923         }
1924         
1925 free_result:
1926         xlat_attrsfree(&expanded);
1927         ldap_msgfree(result);
1928 free_socket:
1929         ldap_release_socket(inst, conn);
1930
1931         return module_rcode;
1932 }
1933
1934
1935 /*****************************************************************************
1936  *
1937  *      Function: ldap_authenticate
1938  *
1939  *      Purpose: Check the user's password against ldap database
1940  *
1941  *****************************************************************************/
1942 static int ldap_authenticate(void *instance, REQUEST * request)
1943 {
1944         int             module_rcode;
1945         const char      *user_dn;
1946         ldap_instance   *inst = instance;
1947         LDAP_CONN       *conn;
1948
1949         /*
1950          * Ensure that we're being passed a plain-text password, and not
1951          * anything else.
1952          */
1953
1954         if (!request->username) {
1955                 radlog(L_AUTH, "rlm_ldap (%s): Attribute \"User-Name\" is "
1956                        "required for authentication", inst->xlat_name);
1957                 return RLM_MODULE_INVALID;
1958         }
1959
1960         if (!request->password) {
1961                 radlog(L_AUTH, "rlm_ldap (%s): Attribute \"User-Password\" "
1962                        "is required for authentication.", inst->xlat_name);
1963                 RDEBUG2("  You have set \"Auth-Type := LDAP\" somewhere.");
1964                 RDEBUG2("  *********************************************");
1965                 RDEBUG2("  * THAT CONFIGURATION IS WRONG.  DELETE IT.   ");
1966                 RDEBUG2("  * YOU ARE PREVENTING THE SERVER FROM WORKING.");
1967                 RDEBUG2("  *********************************************");
1968                 return RLM_MODULE_INVALID;
1969         }
1970
1971         if (request->password->attribute != PW_USER_PASSWORD) {
1972                 radlog(L_AUTH, "rlm_ldap (%s): Attribute \"User-Password\" "
1973                        "is required for authentication. Cannot use \"%s\".",
1974                        inst->xlat_name, request->password->name);
1975                 return RLM_MODULE_INVALID;
1976         }
1977
1978         if (request->password->length == 0) {
1979                 module_failure_msg(request,
1980                                    "rlm_ldap (%s): Empty password supplied",
1981                                    inst->xlat_name);
1982                 return RLM_MODULE_INVALID;
1983         }
1984
1985         conn = ldap_get_socket(inst);
1986         if (!conn) return RLM_MODULE_FAIL;
1987
1988         RDEBUG("Login attempt by \"%s\" with password \"%s\"",
1989                request->username->vp_strvalue, request->password->vp_strvalue);
1990
1991         /*
1992          *      Get the DN by doing a search.
1993          */
1994         user_dn = get_userdn(&conn, request, &module_rcode);
1995         if (!user_dn) {
1996                 ldap_release_socket(inst, conn);
1997                 return module_rcode;
1998         }
1999
2000         /*
2001          *      Bind as the user
2002          */
2003         conn->rebound = TRUE;
2004         module_rcode = ldap_bind_wrapper(&conn, user_dn,
2005                                          request->password->vp_strvalue,
2006                                          NULL, TRUE);
2007         if (module_rcode == RLM_MODULE_OK) {
2008                 RDEBUG("Bind as user \"%s\" was successful", user_dn);
2009         }
2010
2011         ldap_release_socket(inst, conn);
2012         return module_rcode;
2013 }
2014
2015
2016 /* globally exported name */
2017 module_t rlm_ldap = {
2018         RLM_MODULE_INIT,
2019         "ldap",
2020         RLM_TYPE_THREAD_SAFE,   /* type: reserved        */
2021         ldap_instantiate,       /* instantiation         */
2022         ldap_detach,            /* detach                */
2023         {
2024                 ldap_authenticate,      /* authentication        */
2025                 ldap_authorize,         /* authorization         */
2026                 NULL,                   /* preaccounting         */
2027                 NULL,                   /* accounting            */
2028                 NULL,                   /* checksimul            */
2029                 NULL,                   /* pre-proxy             */
2030                 NULL,                   /* post-proxy            */
2031                 NULL
2032         },
2033 };