Dont fail if the update section is specified but empty
[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 * const *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 int build_attrmap(CONF_SECTION *cs, VALUE_PAIR_MAP **head)
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;
1187         *head = NULL;
1188         tail = head;
1189         
1190         if (!cs) return 0;
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 -1;
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 -1;
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 0;
1234         
1235         error:
1236                 radius_mapfree(head);
1237                 return -1;
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                 if (build_attrmap(cs, &(inst->user_map)) < 0) {
1342                         ldap_detach(inst);
1343                         return -1;
1344                 }
1345         }
1346
1347         /*
1348          *      Group comparison checks.
1349          */
1350         paircompare_register(PW_LDAP_GROUP, PW_USER_NAME, ldap_groupcmp, inst); 
1351         if (cf_section_name2(conf)) {
1352                 DICT_ATTR *da;
1353                 ATTR_FLAGS flags;
1354                 char buffer[256];
1355
1356                 snprintf(buffer, sizeof(buffer), "%s-Ldap-Group", inst->xlat_name);
1357                 memset(&flags, 0, sizeof(flags));
1358
1359                 dict_addattr(buffer, -1, 0, PW_TYPE_STRING, flags);
1360                 da = dict_attrbyname(buffer);
1361                 if (!da) {
1362                         radlog(L_ERR, "%s: Failed creating attribute %s",
1363                                inst->xlat_name, buffer);
1364                         ldap_detach(inst);
1365                         return -1;
1366                 }
1367
1368                 paircompare_register(da->attr, PW_USER_NAME, ldap_groupcmp, inst);
1369         }
1370
1371         xlat_register(inst->xlat_name, ldap_xlat, inst);
1372
1373         /*
1374          *      Initialize the socket pool.
1375          */
1376         inst->pool = fr_connection_pool_init(inst->cs, inst,
1377                                              ldap_conn_create,
1378                                              NULL,
1379                                              ldap_conn_delete);
1380         if (!inst->pool) {
1381                 ldap_detach(inst);
1382                 return -1;
1383         }
1384         
1385         *instance = inst;
1386         return 0;
1387 }
1388
1389
1390 static void module_failure_msg(VALUE_PAIR **vps, const char *fmt, ...)
1391 {
1392         va_list ap;
1393         VALUE_PAIR *vp;
1394
1395         va_start(ap, fmt);
1396         vp = paircreate(PW_MODULE_FAILURE_MESSAGE, 0, PW_TYPE_STRING);
1397         if (!vp) {
1398                 va_end(ap);
1399                 return;
1400         }
1401
1402         vsnprintf(vp->vp_strvalue, sizeof(vp->vp_strvalue), fmt, ap);
1403
1404         pairadd(vps, vp);
1405 }
1406
1407
1408 static int check_access(ldap_instance *inst, LDAP_CONN *conn, LDAPMessage *entry)
1409 {
1410         int rcode = -1;
1411         char **vals = NULL;
1412
1413         vals = ldap_get_values(conn->handle, entry, inst->access_attr);
1414         if (vals) {
1415                 if (inst->positive_access_attr) {
1416                         if (strncmp(vals[0], "FALSE", 5) == 0) {
1417                                 DEBUG("dialup access disabled");
1418
1419                         } else {
1420                                 rcode = 0;
1421                         }
1422
1423                 } else {
1424                         DEBUG("%s attribute exists - access denied by default",
1425                                 inst->access_attr);
1426                 }
1427
1428                 ldap_value_free(vals);
1429
1430         } else if (inst->positive_access_attr) {
1431                 DEBUG("No %s attribute - access denied by default", inst->access_attr);
1432
1433         } else {
1434                 rcode = 0;
1435         }
1436
1437         return rcode;
1438 }
1439
1440
1441 static VALUE_PAIR *ldap_getvalue(REQUEST *request, VALUE_PAIR_TMPL *dst,
1442                                  void *ctx)
1443 {
1444         rlm_ldap_result_t *self = ctx;
1445         VALUE_PAIR *head, **tail, *vp;
1446         int i;
1447         
1448         request = request;
1449         
1450         head = NULL;
1451         tail = &head;
1452         
1453         /*
1454          *      Iterate over all the retrieved values,
1455          *      don't try and be clever about changing operators
1456          *      just use whatever was set in the attribute map. 
1457          */
1458         for (i = 0; i < self->count; i++) {
1459                 vp = pairalloc(dst->da);
1460                 rad_assert(vp);
1461
1462                 pairparsevalue(vp, self->values[i]);
1463                 
1464                 *tail = vp;
1465                 tail = &(vp->next);
1466         }
1467         
1468         return head;            
1469 }
1470
1471
1472 static void xlat_attrsfree(const xlat_attrs_t *expanded)
1473 {
1474         const VALUE_PAIR_MAP *map;
1475         unsigned int total = 0;
1476         
1477         char *name;
1478         
1479         for (map = expanded->maps; map != NULL; map = map->next)
1480         {
1481                 memcpy(&name, &(expanded->attrs[total++]), sizeof(name));
1482                 
1483                 if (!name) return;
1484                 
1485                 if (map->src.do_xlat) {
1486                         free(name);
1487                 }
1488         }
1489 }
1490
1491
1492 static int xlat_attrs(REQUEST *request, const VALUE_PAIR_MAP *maps,
1493                       xlat_attrs_t *expanded)
1494 {
1495         const VALUE_PAIR_MAP *map;
1496         unsigned int total = 0;
1497         
1498         size_t len;
1499         char *buffer;
1500
1501         for (map = maps; map != NULL; map = map->next)
1502         {
1503                 if (map->src.do_xlat) {
1504                         buffer = rad_malloc(MAX_ATTR_STR_LEN);
1505                         len = radius_xlat(buffer, MAX_ATTR_STR_LEN,
1506                                           map->src.name, request, NULL, NULL);
1507                                           
1508                         if (!len) {
1509                                 DEBUG2("WARNING: Expansion of LDAP attribute "
1510                                        "\"%s\" failed", map->src.name);
1511                                        
1512                                 expanded->attrs[total] = NULL;
1513                                 
1514                                 xlat_attrsfree(expanded);
1515                                 
1516                                 return -1;
1517                         }
1518                         
1519                         expanded->attrs[total++] = buffer;
1520                 } else {
1521                         expanded->attrs[total++] = map->src.name;
1522                 }
1523         }
1524         
1525         expanded->attrs[total] = NULL;
1526         expanded->maps = maps;
1527         
1528         return 0;
1529 }
1530
1531
1532 /** Convert attribute map into valuepairs
1533  *
1534  * Use the attribute map built earlier to convert LDAP values into valuepairs
1535  * and insert them into whichever list they need to go into.
1536  *
1537  * This is *NOT* atomic, but there's no condition in which we should error
1538  * out...
1539  */
1540 static void do_attrmap(UNUSED ldap_instance *inst, REQUEST *request,
1541                        LDAP *handle, const xlat_attrs_t *expanded,
1542                        LDAPMessage *entry)
1543 {
1544         const VALUE_PAIR_MAP    *map;
1545         unsigned int            total = 0;
1546         
1547         rlm_ldap_result_t       result;
1548         const char              *name;
1549
1550         for (map = expanded->maps; map != NULL; map = map->next)
1551         {
1552                 name = expanded->attrs[total++];
1553                 
1554                 result.values = ldap_get_values(handle, entry, name);
1555                 if (!result.values) {
1556                         DEBUG2("WARNING: Attribute \"%s\" not found in LDAP "
1557                                "object", name);
1558                                 
1559                         goto next;
1560                 }
1561                 
1562                 /*
1563                  *      Find out how many values there are for the
1564                  *      attribute and extract all of them.
1565                  */
1566                 result.count = ldap_count_values(result.values);
1567                 
1568                 /*
1569                  *      If something bad happened, just skip, this is probably
1570                  *      a case of the dst being incorrect for the current
1571                  *      request context
1572                  */
1573                 if (radius_map2request(request, map, name, ldap_getvalue,
1574                                        &result) < 0) {
1575                         goto next;
1576                 }
1577                 
1578                 next:
1579                 
1580                 ldap_value_free(result.values);
1581         }
1582 }
1583
1584
1585 static void do_check_reply(ldap_instance *inst, REQUEST *request)
1586 {
1587        /*
1588         *       More warning messages for people who can't be bothered
1589         *       to read the documentation.
1590         */
1591        if (inst->expect_password && (debug_flag > 1)) {
1592                if (!pairfind(request->config_items, PW_CLEARTEXT_PASSWORD, 0) &&
1593                    !pairfind(request->config_items, PW_NT_PASSWORD, 0) &&
1594                    !pairfind(request->config_items, PW_USER_PASSWORD, 0) &&
1595                    !pairfind(request->config_items, PW_PASSWORD_WITH_HEADER, 0) &&
1596                    !pairfind(request->config_items, PW_CRYPT_PASSWORD, 0)) {
1597                        DEBUG("WARNING: No \"known good\" password was found in LDAP.  Are you sure that the user is configured correctly?");
1598                }
1599        }
1600 }
1601
1602
1603 static void apply_profile(ldap_instance *inst, REQUEST *request,
1604                           LDAP_CONN **pconn, const char *profile,
1605                           const xlat_attrs_t *expanded)
1606 {
1607         int rcode;
1608         LDAPMessage     *result, *entry;
1609         char            filter[MAX_FILTER_STR_LEN];
1610
1611         if (!profile || !*profile) return;
1612
1613         strlcpy(filter, inst->base_filter, sizeof(filter));
1614
1615         rcode = perform_search(inst, pconn, profile, LDAP_SCOPE_BASE,
1616                                filter, expanded->attrs, &result);
1617                 
1618         if (rcode < 0) {
1619                 RDEBUG("FAILED Searching profile %s", profile);
1620                 goto free_result;
1621         }
1622
1623         entry = ldap_first_entry((*pconn)->handle, result);
1624         if (!entry) goto free_result;
1625
1626         do_attrmap(inst, request, (*pconn)->handle, expanded, entry);
1627
1628 free_result:
1629         ldap_msgfree(result);
1630 }
1631
1632
1633 /******************************************************************************
1634  *
1635  *      Function: ldap_authorize
1636  *
1637  *      Purpose: Check if user is authorized for remote access
1638  *
1639  ******************************************************************************/
1640 static int ldap_authorize(void *instance, REQUEST * request)
1641 {
1642         int rcode;
1643         int module_rcode = RLM_MODULE_OK;
1644         ldap_instance   *inst = instance;
1645         char            *user_dn;
1646         char            **vals;
1647         VALUE_PAIR      *vp;
1648         LDAP_CONN       *conn;
1649         LDAPMessage     *result, *entry;
1650         char            filter[MAX_FILTER_STR_LEN];
1651         char            basedn[MAX_FILTER_STR_LEN];
1652         xlat_attrs_t    expanded; /* faster that mallocing every time */
1653         
1654         if (!request->username) {
1655                 RDEBUG2("attribute \"User-Name\" is required for authorization.\n");
1656                 return RLM_MODULE_NOOP;
1657         }
1658
1659         /*
1660          *      Check for valid input, zero length names not permitted
1661          */
1662         if (request->username->length == 0) {
1663                 RDEBUG2("zero length username not permitted\n");
1664                 return RLM_MODULE_INVALID;
1665         }
1666
1667         if (!radius_xlat(filter, sizeof(filter), inst->filter,
1668                          request, ldap_escape_func, NULL)) {
1669                 radlog(L_ERR, "  [%s] Failed creating filter.\n", inst->xlat_name);
1670                 return RLM_MODULE_INVALID;
1671         }
1672
1673         if (!radius_xlat(basedn, sizeof(basedn), inst->basedn,
1674                          request, ldap_escape_func, NULL)) {
1675                 radlog(L_ERR, "  [%s] Failed creating basedn.\n", inst->xlat_name);
1676                 return RLM_MODULE_INVALID;
1677         }
1678
1679         conn = ldap_get_socket(inst);
1680         if (!conn) return RLM_MODULE_FAIL;
1681         
1682         if (xlat_attrs(request, inst->user_map, &expanded) < 0) {
1683                 return RLM_MODULE_FAIL;
1684         }
1685         
1686         rcode = perform_search(inst, &conn, basedn, LDAP_SCOPE_SUBTREE, filter,
1687                                expanded.attrs, &result);
1688         
1689         if (rcode < 0) {
1690                 if (rcode == -2) {
1691                         module_failure_msg(&request->packet->vps,
1692                                            "[%s] Search returned not found",
1693                                            inst->xlat_name);
1694                         DEBUG("  [%s] Search returned not found", inst->xlat_name);
1695                         module_rcode = RLM_MODULE_NOTFOUND;
1696                         goto free_socket;
1697                 }
1698                 DEBUG("  [%s] Search returned error", inst->xlat_name);
1699                 goto free_socket;
1700         }
1701
1702         entry = ldap_first_entry(conn->handle, result);
1703         if (!entry) {
1704                 RDEBUG2("ldap_first_entry() failed");
1705                 goto free_result;
1706         }
1707
1708         user_dn = ldap_get_dn(conn->handle, entry);
1709         if (!user_dn) {
1710                 RDEBUG2("ldap_get_dn() failed");
1711                 goto free_result;
1712         }
1713         
1714         RDEBUG2("User found, dn is \"%s\"", user_dn);
1715         /*
1716          *      Adding attribute containing the Users' DN.
1717          */
1718         pairadd(&request->config_items, pairmake("Ldap-UserDn", user_dn, T_OP_EQ));
1719         ldap_memfree(user_dn);
1720
1721         /*
1722          *      Check for access.
1723          */
1724         if (inst->access_attr) {
1725                 if (check_access(inst, conn, entry) < 0) {
1726                         module_rcode = RLM_MODULE_USERLOCK;
1727                         goto free_result;
1728                 }
1729         }
1730
1731         /*
1732          *      Apply ONE user profile, or a default user profile.
1733          */
1734         vp = pairfind(request->config_items, PW_USER_PROFILE, 0);
1735         if (vp || inst->default_profile) {
1736                 char *profile = inst->default_profile;
1737
1738                 if (vp) profile = vp->vp_strvalue;
1739
1740                 apply_profile(inst, request, &conn, profile, &expanded);
1741         }
1742
1743         /*
1744          *      Apply a SET of user profiles.
1745          */
1746         if (inst->profile_attr &&
1747             (vals = ldap_get_values(conn->handle, entry, inst->profile_attr)) != NULL) {
1748
1749                 int i;
1750
1751                 for (i = 0; (vals[i] != NULL) && (*vals[i] != '\0'); i++) {
1752                         apply_profile(inst, request, &conn, vals[i], &expanded);
1753                 }
1754
1755                 ldap_value_free(vals);
1756         }
1757
1758         if (inst->user_map) {
1759                 do_attrmap(inst, request, conn->handle, &expanded, entry);
1760                 do_check_reply(inst, request);
1761         }
1762         
1763 free_result:
1764         xlat_attrsfree(&expanded);
1765         ldap_msgfree(result);
1766 free_socket:
1767         ldap_release_socket(inst, conn);
1768
1769         return module_rcode;
1770 }
1771
1772
1773 /*****************************************************************************
1774  *
1775  *      Function: ldap_authenticate
1776  *
1777  *      Purpose: Check the user's password against ldap database
1778  *
1779  *****************************************************************************/
1780 static int ldap_authenticate(void *instance, REQUEST * request)
1781 {
1782         int             module_rcode;
1783         const char      *user_dn;
1784         ldap_instance   *inst = instance;
1785         LDAP_CONN       *conn;
1786
1787         /*
1788          * Ensure that we're being passed a plain-text password, and not
1789          * anything else.
1790          */
1791
1792         if (!request->username) {
1793                 radlog(L_AUTH, "  [%s] Attribute \"User-Name\" is required for authentication.", inst->xlat_name);
1794                 return RLM_MODULE_INVALID;
1795         }
1796
1797         if (!request->password) {
1798                 radlog(L_AUTH, "  [%s] Attribute \"User-Password\" is required for authentication.", inst->xlat_name);
1799                 RDEBUG2("  You seem to have set \"Auth-Type := LDAP\" somewhere.");
1800                 RDEBUG2("  *******************************************************");
1801                 RDEBUG2("  * THAT CONFIGURATION IS WRONG.  DELETE IT.");
1802                 RDEBUG2("  * YOU ARE PREVENTING THE SERVER FROM WORKING PROPERLY.");
1803                 RDEBUG2("  *******************************************************");
1804                 return RLM_MODULE_INVALID;
1805         }
1806
1807         if (request->password->attribute != PW_USER_PASSWORD) {
1808                 radlog(L_AUTH, "  [%s] Attribute \"User-Password\" is required for authentication. Cannot use \"%s\".", inst->xlat_name, request->password->name);
1809                 return RLM_MODULE_INVALID;
1810         }
1811
1812         if (request->password->length == 0) {
1813                 module_failure_msg(&request->packet->vps,
1814                                    "[%s] empty password supplied", inst->xlat_name);
1815                 return RLM_MODULE_INVALID;
1816         }
1817
1818         conn = ldap_get_socket(inst);
1819         if (!conn) return RLM_MODULE_FAIL;
1820
1821         RDEBUG("login attempt by \"%s\" with password \"%s\"",
1822                request->username->vp_strvalue, request->password->vp_strvalue);
1823
1824         /*
1825          *      Get the DN by doing a search.
1826          */
1827         user_dn = get_userdn(&conn, request, &module_rcode);
1828         if (!user_dn) {
1829                 ldap_release_socket(inst, conn);
1830                 return module_rcode;
1831         }
1832
1833         /*
1834          *      Bind as the user
1835          */
1836         conn->rebound = TRUE;
1837         module_rcode = ldap_bind_wrapper(&conn, user_dn,
1838                                          request->password->vp_strvalue,
1839                                          NULL, TRUE);
1840         if (module_rcode == RLM_MODULE_OK) {
1841                 RDEBUG("  [%s] Bind as user '%s' was successful", inst->xlat_name,
1842                         user_dn);
1843         }
1844
1845         ldap_release_socket(inst, conn);
1846         return module_rcode;
1847 }
1848
1849
1850 /* globally exported name */
1851 module_t rlm_ldap = {
1852         RLM_MODULE_INIT,
1853         "ldap",
1854         RLM_TYPE_THREAD_SAFE,   /* type: reserved        */
1855         ldap_instantiate,       /* instantiation         */
1856         ldap_detach,            /* detach                */
1857         {
1858                 ldap_authenticate,      /* authentication        */
1859                 ldap_authorize,         /* authorization         */
1860                 NULL,                   /* preaccounting         */
1861                 NULL,                   /* accounting            */
1862                 NULL,                   /* checksimul            */
1863                 NULL,                   /* pre-proxy             */
1864                 NULL,                   /* post-proxy            */
1865                 NULL
1866         },
1867 };