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