Phase 0.5 of cacheable group membership
[freeradius.git] / src / modules / rlm_ldap / ldap.c
1 /*
2  *   This program is is free software; you can redistribute it and/or modify
3  *   it under the terms of the GNU General Public License, version 2 if the
4  *   License as published by the Free Software Foundation.
5  *
6  *   This program is distributed in the hope that it will be useful,
7  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
8  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
9  *   GNU General Public License for more details.
10  *
11  *   You should have received a copy of the GNU General Public License
12  *   along with this program; if not, write to the Free Software
13  *   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
14  */
15  
16 /**
17  * $Id$
18  * @file ldap.c
19  * @brief LDAP module library functions.
20  *
21  * @author Arran Cudbard-Bell <a.cudbardb@freeradius.org>
22  * @copyright 2013 Network RADIUS SARL <info@networkradius.com>
23  * @copyright 2013 The FreeRADIUS Server Project.
24  */
25 #include        <freeradius-devel/radiusd.h>
26 #include        <freeradius-devel/modules.h>
27 #include        <freeradius-devel/rad_assert.h>
28
29 #include        <stdarg.h>
30 #include        <ctype.h>
31
32 #include        <lber.h>
33 #include        <ldap.h>
34 #include        "ldap.h"
35
36
37
38 /** Converts "bad" strings into ones which are safe for LDAP
39  *
40  * This is a callback for xlat operations.
41  *
42  * Will escape any characters in input strings that would cause the string to be interpreted as part of a DN and or
43  * filter. Escape sequence is @verbatim \<hex><hex> @endverbatim
44  *
45  * @param request The current request.
46  * @param out Pointer to output buffer.
47  * @param outlen Size of the output buffer.
48  * @param in Raw unescaped string.
49  * @param arg Any additional arguments (unused).
50  */
51 size_t rlm_ldap_escape_func(UNUSED REQUEST *request, char *out, size_t outlen, const char *in, UNUSED void *arg)
52 {
53         static const char encode[] = ",+\"\\<>;*=()";
54         static const char hextab[] = "0123456789abcdef";
55         size_t left = outlen;
56         
57         if (*in && ((*in == ' ') || (*in == '#'))) {
58                 goto encode;
59         }
60         
61         while (*in) {
62                 /*
63                  *      Encode unsafe characters.
64                  */
65                 if (memchr(encode, *in, sizeof(encode) - 1)) {
66                         encode:
67
68                         /*
69                          *      Only 3 or less bytes available.
70                          */
71                         if (left <= 3) break;
72
73                         *out++ = '\\';
74                         *out++ = hextab[(*in >> 4) & 0x0f];
75                         *out++ = hextab[*in & 0x0f];
76                         in++;
77                         left -= 3;
78
79                         continue;
80                 }
81
82                 if (left <= 1) break;
83
84                 /*
85                  *      Doesn't need encoding
86                  */
87                 *out++ = *in++;
88                 left--;
89         }
90         
91         *out = '\0';
92         
93         return outlen - left;
94 }
95
96 /** Check whether a string is a DN
97  *
98  * @param str to check.
99  * @return true if string is a DN, else false.
100  */
101 int rlm_ldap_is_dn(const char *str)
102 {
103         return strrchr(str, ',') == NULL ? FALSE : TRUE;
104 }
105
106 /** Find the place at which the two DN strings diverge
107  * 
108  * Returns the length of the non matching string in full.
109  *
110  * @param full DN.
111  * @param part Partial DN as returned by ldap_parse_result.
112  * @return the length of the portion of full which wasn't matched or -1 on error.
113  */
114 static size_t rlm_ldap_common_dn(const char *full, const char *part)
115 {
116         size_t f_len, p_len, i;
117         
118         if (!full) {
119                 return -1;
120         }
121         
122         f_len = strlen(full);
123         
124         if (!part) {
125                 return f_len;
126         }
127         
128         p_len = strlen(part);
129         if (!p_len) {
130                 return f_len;
131         }
132         
133         if ((f_len < p_len) || !f_len) {
134                 return -1; 
135         }
136
137
138         for (i = 0; i < p_len; i++) {
139                 if (part[p_len - i] != full[f_len - i]) {
140                         return -1; 
141                 }
142         }
143
144         return f_len - p_len;
145 }
146
147 /** Parse response from LDAP server dealing with any errors
148  *
149  * Should be called after an LDAP operation. Will check result of operation and if it was successful, then attempt 
150  * to retrieve and parse the result.
151  *
152  * Will also produce extended error output including any messages the server sent, and information about partial 
153  * DN matches.
154  *
155  * @param[in] inst of LDAP module.
156  * @param[in] conn Current connection.
157  * @param[in] msgid returned from last operation.
158  * @param[in] dn Last search or bind DN.
159  * @param[out] result Where to write result, if NULL result will be freed.
160  * @param[out] error Where to write the error string, may be NULL, must not be freed.
161  * @param[out] extra Where to write additional error string to, may be NULL (faster) or must be freed 
162  *      (with talloc_free).
163  * @return One of the LDAP_PROC_* codes.
164  */
165 static ldap_rcode_t rlm_ldap_result(const ldap_instance_t *inst, const ldap_handle_t *conn, int msgid, const char *dn,
166                                     LDAPMessage **result, const char **error, char **extra)
167 {
168         ldap_rcode_t status = LDAP_PROC_SUCCESS;
169
170         int lib_errno = LDAP_SUCCESS;   //!< errno returned by the library.
171         int srv_errno = LDAP_SUCCESS;   //!< errno in the result message.
172         
173         char *part_dn = NULL;           //!< Partial DN match.
174         char *our_err = NULL;           //!< Our extended error message.
175         char *srv_err = NULL;           //!< Server's extended error message.
176         char *p, *a;
177
178         int freeit = FALSE;             //!< Whether the message should
179                                         //!< be freed after being processed.
180         int len;
181         
182         struct timeval tv;              //!< Holds timeout values.
183         
184         LDAPMessage *tmp_msg;           //!< Temporary message pointer storage
185                                         //!< if we weren't provided with one.
186         
187         const char *tmp_err;            //!< Temporary error pointer storage
188                                         //!< if we weren't provided with one.
189         
190         if (!error) {
191                 error = &tmp_err;
192         }
193         *error = NULL;
194         
195         if (extra) {
196                 *extra = NULL;
197         }
198         
199         /*
200          *      We always need the result, but our caller may not
201          */
202         if (!result) {
203                 result = &tmp_msg;
204                 freeit = TRUE;
205         }
206         
207         /*
208          *      Check if there was an error sending the request
209          */
210         ldap_get_option(conn->handle, LDAP_OPT_ERROR_NUMBER,
211                         &lib_errno);
212         if (lib_errno != LDAP_SUCCESS) {
213                 goto process_error;
214         }
215         
216         tv.tv_sec = inst->timeout;
217         tv.tv_usec = 0;
218
219         /*
220          *      Now retrieve the result and check for errors
221          *      ldap_result returns -1 on error, and 0 on timeout
222          */
223         lib_errno = ldap_result(conn->handle, msgid, 1, &tv, result);
224         if (lib_errno == 0) {
225                 lib_errno = LDAP_TIMEOUT;
226                 
227                 goto process_error;
228         }
229         
230         if (lib_errno == -1) {
231                 ldap_get_option(conn->handle, LDAP_OPT_ERROR_NUMBER,
232                                 &lib_errno);
233                 goto process_error;
234         }
235         
236         /*
237          *      Parse the result and check for errors sent by the server
238          */
239         lib_errno = ldap_parse_result(conn->handle, *result,
240                                       &srv_errno,
241                                       extra ? &part_dn : NULL,
242                                       extra ? &srv_err : NULL,
243                                       NULL, NULL, freeit);
244                                       
245         if (lib_errno != LDAP_SUCCESS) {
246                 ldap_get_option(conn->handle, LDAP_OPT_ERROR_NUMBER,
247                                 &lib_errno);
248                 goto process_error;
249         }
250         
251         process_error:
252         
253         if ((lib_errno == LDAP_SUCCESS) && (srv_errno != LDAP_SUCCESS)) {
254                 lib_errno = srv_errno;
255         } else if ((lib_errno != LDAP_SUCCESS) && (srv_errno == LDAP_SUCCESS)) {
256                 srv_errno = lib_errno;
257         }
258         
259         switch (lib_errno) {
260         case LDAP_SUCCESS:
261                 *error = "Success";
262                 
263                 break;
264
265         case LDAP_NO_SUCH_OBJECT:
266                 *error = "The specified object wasn't found, check basedn and admin dn";
267                 
268                 status = LDAP_PROC_BAD_DN;
269                 
270                 if (!extra) break;
271                 
272                 /* 
273                  *      Build our own internal diagnostic string
274                  */
275                 len = rlm_ldap_common_dn(dn, part_dn);
276                 if (len < 0) break;
277                 
278                 our_err = talloc_asprintf(conn, "Match stopped here: [%.*s]%s", len, part_dn, part_dn ? part_dn : "");
279
280                 goto error_string;
281
282         case LDAP_INSUFFICIENT_ACCESS:
283                 *error = "Insufficient access. Check the identity and password configuration directives";
284                 
285                 status = LDAP_PROC_NOT_PERMITTED;
286                 break;
287                 
288         case LDAP_UNWILLING_TO_PERFORM:
289                 *error = "Server was unwilling to perform";
290         
291                 status = LDAP_PROC_NOT_PERMITTED;
292                 break;
293                 
294         case LDAP_TIMEOUT:
295                 exec_trigger(NULL, inst->cs, "modules.ldap.timeout", TRUE);
296                 
297                 *error = "Timed out while waiting for server to respond";
298                        
299                 status = LDAP_PROC_ERROR;
300                 break;
301                 
302         case LDAP_FILTER_ERROR:
303                 *error = "Bad search filter";
304
305                 status = LDAP_PROC_ERROR;
306                 break;
307                 
308         case LDAP_TIMELIMIT_EXCEEDED:
309                 exec_trigger(NULL, inst->cs, "modules.ldap.timeout", TRUE);
310                 
311                 *error = "Time limit exceeded";
312                 /* FALL-THROUGH */
313
314         case LDAP_BUSY:
315         case LDAP_UNAVAILABLE:
316         case LDAP_SERVER_DOWN:
317                 status = LDAP_PROC_RETRY;
318                 
319                 goto error_string;
320                 
321         case LDAP_INVALID_CREDENTIALS:
322         case LDAP_CONSTRAINT_VIOLATION:
323                 status = LDAP_PROC_REJECT;
324                 
325                 goto error_string;
326                 
327         case LDAP_OPERATIONS_ERROR:
328                 *error = "Please set 'chase_referrals=yes' and 'rebind=yes'. See the ldap module configuration "
329                          "for details.";
330                          
331                 /* FALL-THROUGH */
332         default:
333                 status = LDAP_PROC_ERROR;
334                 
335                 error_string:
336                 
337                 if (!*error) {
338                         *error = ldap_err2string(lib_errno);
339                 }
340                 
341                 if (!extra || ((lib_errno == srv_errno) && !our_err && !srv_err)) {
342                         break;
343                 }
344                 
345                 /*
346                  *      Output the error codes from the library and server
347                  */
348                 p = talloc_strdup(conn, "");
349                 if (!p) break;
350
351                 if (lib_errno != srv_errno) {
352                         a = talloc_asprintf_append(p, "LDAP lib error: %s (%u), srv error: %s (%u)", 
353                                                    ldap_err2string(lib_errno), lib_errno,
354                                                    ldap_err2string(srv_errno), srv_errno);
355                         if (!a) {
356                                 talloc_free(p);
357                                 break;
358                         }
359                         
360                         p = a;
361                 }
362
363                 if (our_err) {
364                         a = talloc_asprintf_append_buffer(p,". %s", our_err);
365                         if (!a) {
366                                 talloc_free(p);
367                                 break;
368                         }
369                         
370                         p = a;
371                 }
372                 
373                 if (srv_err) {
374                         a = talloc_asprintf_append_buffer(p, ". Server said: %s", srv_err);
375                         if (!a) {
376                                 talloc_free(p);
377                                 break;
378                         }
379                         
380                         p = a;
381                 }
382                 
383                 *extra = p;
384                 
385                 break;
386         }
387         
388         /*
389          *      Cleanup memory
390          */
391         if (srv_err) {
392                 ldap_memfree(srv_err);
393         }
394         
395         if (part_dn) {
396                 ldap_memfree(part_dn);
397         }
398         
399         if (our_err) {
400                 talloc_free(our_err);
401         }
402         
403         if ((lib_errno || srv_errno) && *result) {
404                 ldap_msgfree(*result);
405                 *result = NULL;
406         }
407         
408         return status;
409 }
410
411 /** Bind to the LDAP directory as a user
412  *
413  * Performs a simple bind to the LDAP directory, and handles any errors that
414  * occur.
415  *
416  * @param inst rlm_ldap configuration.
417  * @param request Current request, this may be NULL, in which case all debug logging is done with radlog.
418  * @param pconn to use. May change as this function auto re-connects. Caller must check that pconn is not NULL after 
419  *      calling this function.
420  * @param dn The DN of the user, may be NULL to bind anonymously.
421  * @param password May be NULL if no password is specified.
422  * @param retry if the server is down.
423  * @return one of the LDAP_PROC_* values.
424  */
425 ldap_rcode_t rlm_ldap_bind(const ldap_instance_t *inst, REQUEST *request, ldap_handle_t **pconn, const char *dn,
426                            const char *password, int retry)
427 {
428         ldap_rcode_t    status;
429         
430         int             msgid;
431         
432         const char      *error = NULL;
433         char            *extra = NULL;
434
435         rad_assert(*pconn && (*pconn)->handle);
436         
437         /*
438          *      Bind as anonymous user
439          */
440         if (!dn) dn = "";
441
442 retry:
443         msgid = ldap_bind((*pconn)->handle, dn, password, LDAP_AUTH_SIMPLE);
444         /* We got a valid message ID */
445         if (msgid >= 0) {
446                 if (request) {
447                         RDEBUG2("Waiting for bind result...");
448                 } else {
449                         DEBUG2("rlm_ldap (%s): Waiting for bind result...", inst->xlat_name);
450                 }
451         }
452
453         status = rlm_ldap_result(inst, *pconn, msgid, dn, NULL, &error, &extra);
454         switch (status) {
455         case LDAP_PROC_SUCCESS:
456                 break;
457         case LDAP_PROC_NOT_PERMITTED:
458                 LDAP_ERR_REQ("Bind was not permitted: %s", error);
459                 LDAP_EXT_REQ();
460                 
461                 break;
462
463         case LDAP_PROC_REJECT:
464                 LDAP_ERR_REQ("Bind credentials incorrect: %s", error);
465                 LDAP_EXT_REQ();
466
467                 break;
468
469         case LDAP_PROC_RETRY:
470                 if (retry) {
471                         *pconn = fr_connection_reconnect(inst->pool, *pconn);
472                         if (*pconn) {
473                                 LDAP_DBGW_REQ("Bind with %s to %s:%d failed: %s. Got new socket, retrying...",
474                                               dn, inst->server, inst->port, error);
475                                 
476                                 talloc_free(extra); /* don't leak debug info */
477                                 
478                                 goto retry;
479                         }
480                 };
481                 
482                 status = LDAP_PROC_ERROR;
483                 
484                 /*
485                  *      Were not allowed to retry, or there are no more
486                  *      sockets, treat this as a hard failure.
487                  */
488                 /* FALL-THROUGH */
489         default:
490 #ifdef HAVE_LDAP_INITIALIZE
491                 if (inst->is_url) {
492                         LDAP_ERR_REQ("Bind with %s to %s failed: %s", dn, inst->server, error);
493                 } else
494 #endif
495                 {
496                         LDAP_ERR_REQ("Bind with %s to %s:%d failed: %s", dn, inst->server,
497                                      inst->port, error);
498                 }
499                 LDAP_EXT_REQ();
500                 
501                 break;
502         }
503
504         if (extra) talloc_free(extra);
505
506         return status; /* caller closes the connection */
507 }
508
509
510 /** Search for something in the LDAP directory
511  *
512  * Binds as the administrative user and performs a search, dealing with any
513  * errors.
514  *
515  * @param inst rlm_ldap configuration.
516  * @param request Current request.
517  * @param pconn to use. May change as this function auto re-connects. Caller must check that pconn is not NULL 
518  *      after calling this function.
519  * @param dn to use.
520  * @param scope to use.
521  * @param filter to use.
522  * @param attrs to retrieve.
523  * @param result Where to store the result. Must be freed with ldap_msgfree.
524  *      may be NULL in which case result will be automatically freed after use.
525  * @return One of the LDAP_PROC_* values.
526  */
527 ldap_rcode_t rlm_ldap_search(const ldap_instance_t *inst, REQUEST *request, ldap_handle_t **pconn,
528                              const char *dn, int scope, const char *filter, const char * const *attrs,
529                              LDAPMessage **result)
530 {
531         ldap_rcode_t    status;
532         
533         int             msgid;          //!< Message id returned by
534                                         //!< ldap_search_ext.
535                                 
536         int             count = 0;      //!< Number of results we got.
537         
538         struct timeval  tv;             //!< Holds timeout values.
539         
540         const char      *error = NULL;
541         char            *extra = NULL;
542
543         rad_assert(*pconn && (*pconn)->handle);
544         
545         /*
546          *      OpenLDAP library doesn't declare attrs array as const, but
547          *      it really should be *sigh*.
548          */
549         char **search_attrs;
550         memcpy(&search_attrs, &attrs, sizeof(attrs));
551
552         /*
553          *      Do all searches as the admin user.
554          */
555         if ((*pconn)->rebound) {
556                 status = rlm_ldap_bind(inst, request, pconn, inst->login, inst->password, TRUE);
557                 if (status != LDAP_PROC_SUCCESS) {
558                         return LDAP_PROC_ERROR;
559                 }
560
561                 rad_assert(*pconn);
562                 
563                 (*pconn)->rebound = FALSE;
564         }
565
566         RDEBUG2("Performing search in '%s' with filter '%s'", dn, filter);
567
568         /*
569          *      If LDAP search produced an error it should also be logged
570          *      to the ld. result should pick it up without us
571          *      having to pass it explicitly.
572          */
573         tv.tv_sec = inst->timeout;
574         tv.tv_usec = 0;
575 retry:  
576         (void) ldap_search_ext((*pconn)->handle, dn, scope, filter, search_attrs, 0, NULL, NULL, &tv, 0, &msgid);
577
578         RDEBUG2("Waiting for search result...");               
579         status = rlm_ldap_result(inst, *pconn, msgid, dn, result, &error, &extra);                     
580         switch (status) {
581                 case LDAP_PROC_SUCCESS:
582                         break;
583                 case LDAP_PROC_RETRY:
584                         *pconn = fr_connection_reconnect(inst->pool, *pconn);
585                         if (*pconn) {
586                                 RDEBUGW("Search failed: %s. Got new socket, retrying...", error);
587                                 
588                                 talloc_free(extra); /* don't leak debug info */
589                                 
590                                 goto retry;
591                         }
592                         
593                         status = LDAP_PROC_ERROR;
594                         
595                         /* FALL-THROUGH */
596                 default:
597                         RDEBUGE("Failed performing search: %s", error);
598                         RDEBUGE("%s", extra);
599
600                         goto finish;
601         }
602         
603         if (result) {   
604                 count = ldap_count_entries((*pconn)->handle, *result);
605                 if (count == 0) {
606                         ldap_msgfree(*result);
607                         *result = NULL;
608                 
609                         RDEBUG("Search returned no results");
610                 
611                         status = LDAP_PROC_NO_RESULT;
612                 }
613         }
614         
615         finish:
616         if (extra) talloc_free(extra);
617
618         return status;
619 }
620
621 /** Modify something in the LDAP directory
622  *
623  * Binds as the administrative user and attempts to modify an LDAP object.
624  *
625  * @param inst rlm_ldap configuration.
626  * @param request Current request.
627  * @param pconn to use. May change as this function auto re-connects. Caller must check that pconn is not NULL after 
628  *      calling this function.
629  * @param dn to modify.
630  * @param mods to make.
631  * @return One of the LDAP_PROC_* values.
632  */
633 ldap_rcode_t rlm_ldap_modify(const ldap_instance_t *inst, REQUEST *request, ldap_handle_t **pconn,
634                              const char *dn, LDAPMod *mods[])
635 {
636         ldap_rcode_t    status;
637         
638         int             msgid;          //!< Message id returned by
639                                         //!< ldap_search_ext.
640         
641         const char      *error = NULL;
642         char            *extra = NULL;                     
643
644         rad_assert(*pconn && (*pconn)->handle);
645                 
646         /*
647          *      Perform all modifications as the admin user.
648          */
649         if ((*pconn)->rebound) {
650                 status = rlm_ldap_bind(inst, request, pconn, inst->login, inst->password, TRUE);
651                 if (status != LDAP_PROC_SUCCESS) {
652                         return LDAP_PROC_ERROR;
653                 }
654
655                 rad_assert(*pconn);
656                 
657                 (*pconn)->rebound = FALSE;
658         }
659         
660         RDEBUG2("Modifying object with DN \"%s\"", dn);
661         retry:
662         (void) ldap_modify_ext((*pconn)->handle, dn, mods, NULL, NULL, &msgid);
663         
664         RDEBUG2("Waiting for modify result...");
665         status = rlm_ldap_result(inst, *pconn, msgid, dn, NULL, &error, &extra);
666         switch (status) {
667                 case LDAP_PROC_SUCCESS:
668                         break;
669                 case LDAP_PROC_RETRY:
670                         *pconn = fr_connection_reconnect(inst->pool, *pconn);
671                         if (*pconn) {
672                                 RDEBUGW("Modify failed: %s. Got new socket, retrying...", error);
673                                 
674                                 talloc_free(extra); /* don't leak debug info */
675                                 
676                                 goto retry;
677                         }
678                         
679                         status = LDAP_PROC_ERROR;
680                         
681                         /* FALL-THROUGH */
682                 default:
683                         RDEBUGE("Failed modifying object: %s", error);
684                         RDEBUGE("%s", extra);
685                         
686                         goto finish;
687         }                    
688         
689         finish:
690         if (extra) talloc_free(extra);
691
692         return status;
693 }
694
695 /** Retrieve the DN of a user object
696  *
697  * Retrieves the DN of a user and adds it to the control list as LDAP-UserDN. Will also retrieve any attributes
698  * passed and return the result in *result.
699  *
700  * This potentially allows for all authorization and authentication checks to be performed in one ldap search
701  * operation, which is a big bonus given the number of crappy, slow *cough*AD*cough* LDAP directory servers out there.
702  * 
703  * @param[in] inst rlm_ldap configuration.
704  * @param[in] request Current request.
705  * @param[in,out] pconn to use. May change as this function auto re-connects. Caller must check that pconn is not NULL 
706  *      after calling this function.
707  * @param[in] attrs Additional attributes to retrieve, may be NULL.
708  * @param[in] force Query even if the User-DN already exists.
709  * @param[out] result Where to write the result, may be NULL in which case result is discarded.
710  * @param[out] rcode The status of the operation, one of the RLM_MODULE_* codes.
711  * @return The user's DN or NULL on error.
712  */
713 const char *rlm_ldap_find_user(const ldap_instance_t *inst, REQUEST *request, ldap_handle_t **pconn,
714                                const char *attrs[], int force, LDAPMessage **result, rlm_rcode_t *rcode)
715 {
716         static const char *tmp_attrs[] = { NULL };
717         
718         ldap_rcode_t    status;
719         VALUE_PAIR      *vp = NULL;
720         LDAPMessage     *tmp_msg = NULL, *entry = NULL;
721         int             ldap_errno;
722         char            *dn = NULL;
723         char            filter[LDAP_MAX_FILTER_STR_LEN];        
724         char            basedn[LDAP_MAX_FILTER_STR_LEN];
725         
726         int freeit = FALSE;                                     //!< Whether the message should
727                                                                 //!< be freed after being processed.
728
729         *rcode = RLM_MODULE_FAIL;
730
731         if (!result) {
732                 result = &tmp_msg;
733                 freeit = TRUE;
734         }
735         *result = NULL;
736         
737         if (!attrs) {
738                 memset(&attrs, 0, sizeof(tmp_attrs));
739         }
740         
741         /*
742          *      If the caller isn't looking for the result we can just return the current userdn value.
743          */
744         if (!force) {
745                 vp = pairfind(request->config_items, PW_LDAP_USERDN, 0, TAG_ANY);
746                 if (vp) {
747                         RDEBUG("Using user DN from request \"%s\"", vp->vp_strvalue);
748                         *rcode = RLM_MODULE_OK;
749                         return vp->vp_strvalue;
750                 }
751         }
752         
753         /*
754          *      Perform all searches as the admin user.
755          */
756         if ((*pconn)->rebound) {
757                 status = rlm_ldap_bind(inst, request, pconn, inst->login, inst->password, TRUE);
758                 if (status != LDAP_PROC_SUCCESS) {
759                         *rcode = RLM_MODULE_FAIL;
760                         return NULL;
761                 }
762
763                 rad_assert(*pconn);
764                 
765                 (*pconn)->rebound = FALSE;
766         }
767
768         
769         if (!radius_xlat(filter, sizeof(filter), inst->userobj_filter, request, rlm_ldap_escape_func, NULL)) {
770                 RDEBUGE("Unable to create filter");
771                 
772                 *rcode = RLM_MODULE_INVALID;
773                 return NULL;
774         }
775
776         if (!radius_xlat(basedn, sizeof(basedn), inst->basedn, request, rlm_ldap_escape_func, NULL)) {
777                 RDEBUGE("Unable to create basedn");
778                 
779                 *rcode = RLM_MODULE_INVALID;
780                 return NULL;
781         }
782
783         status = rlm_ldap_search(inst, request, pconn, basedn, LDAP_SCOPE_SUBTREE, filter, attrs, result);
784         switch (status) {
785                 case LDAP_PROC_SUCCESS:
786                         break;
787                 case LDAP_PROC_NO_RESULT:
788                         *rcode = RLM_MODULE_NOTFOUND;
789                         return NULL;
790                 default:
791                         *rcode = RLM_MODULE_FAIL;
792                         return NULL;
793         }
794         
795         rad_assert(*pconn);
796
797         entry = ldap_first_entry((*pconn)->handle, *result);
798         if (!entry) {
799                 ldap_get_option((*pconn)->handle, LDAP_OPT_RESULT_CODE, &ldap_errno);
800                 RDEBUGE("Failed retrieving entry: %s", 
801                         ldap_err2string(ldap_errno));
802                          
803                 goto finish;
804         }
805
806         dn = ldap_get_dn((*pconn)->handle, entry);
807         if (!dn) {
808                 ldap_get_option((*pconn)->handle, LDAP_OPT_RESULT_CODE, &ldap_errno);
809                                 
810                 RDEBUGE("Retrieving object DN from entry failed: %s",
811                         ldap_err2string(ldap_errno));
812                        
813                 goto finish;
814         }
815         
816         RDEBUG("User object found at DN \"%s\"", dn);
817         vp = pairmake(request, &request->config_items, "LDAP-UserDN", dn, T_OP_EQ);
818         if (vp) {       
819                 *rcode = RLM_MODULE_OK;
820         }
821         
822         finish:
823         ldap_memfree(dn);
824         
825         if ((freeit || (*rcode != RLM_MODULE_OK)) && *result) {
826                 ldap_msgfree(*result);
827                 *result = NULL;
828         }
829
830         return vp ? vp->vp_strvalue : NULL;
831 }
832
833 rlm_rcode_t rlm_ldap_apply_profile(const ldap_instance_t *inst, REQUEST *request, ldap_handle_t **pconn,
834                                    const char *profile, const rlm_ldap_map_xlat_t *expanded)
835 {
836         rlm_rcode_t     rcode = RLM_MODULE_OK;
837         ldap_rcode_t    status;
838         LDAPMessage     *result = NULL, *entry = NULL;
839         int             ldap_errno;
840         LDAP            *handle = (*pconn)->handle;
841         char            filter[LDAP_MAX_FILTER_STR_LEN];
842
843         if (!profile || !*profile) {
844                 return RLM_MODULE_NOOP;
845         }
846         strlcpy(filter, inst->base_filter, sizeof(filter));
847
848         status = rlm_ldap_search(inst, request, pconn, profile, LDAP_SCOPE_BASE, filter, expanded->attrs, &result);
849         switch (status) {
850                 case LDAP_PROC_SUCCESS:
851                         break;
852                 case LDAP_PROC_NO_RESULT:
853                         RDEBUG("Profile \"%s\" not found", profile);
854                         return RLM_MODULE_NOTFOUND;
855                 default:
856                         return RLM_MODULE_FAIL;
857         }
858         
859         rad_assert(*pconn);
860         rad_assert(result);
861         
862         entry = ldap_first_entry(handle, result);
863         if (!entry) {
864                 ldap_get_option(handle, LDAP_OPT_RESULT_CODE, &ldap_errno);
865                 RDEBUGE("Failed retrieving entry: %s", ldap_err2string(ldap_errno));
866                 
867                 rcode = RLM_MODULE_NOTFOUND;
868                 
869                 goto free_result;
870         }
871         
872         rlm_ldap_map_do(inst, request, handle, expanded, entry);
873
874 free_result:
875         ldap_msgfree(result);
876         
877         return rcode;
878 }
879
880 /** Convert multiple group names into a DNs
881  * 
882  * Given an array of group names, builds a filter matching all names, then retrieves all group objects
883  * and stores the DN associated with each group object.
884  *
885  * @param inst rlm_ldap configuration.
886  * @param request Current request.
887  * @param conn Current connection.
888  * @param names to covert to DNs (NULL terminated).
889  * @param out Where to write the DNs. DNs must be freed with ldap_memfree(). Will be NULL terminated.
890  * @param outlen Size of out.
891  * @return One of the RLM_MODULE_* values.
892  */
893 rlm_rcode_t rlm_ldap_group_name2dn(const ldap_instance_t *inst, REQUEST *request,
894                                    ldap_handle_t **pconn, char **names, char **out,
895                                    size_t outlen)
896 {
897         rlm_rcode_t rcode;
898         ldap_rcode_t status;
899         int ldap_errno;
900         
901         unsigned int name_cnt, entry_cnt;
902         const char *attrs[] = { NULL };
903
904         LDAPMessage *result = NULL, *entry;
905
906         char **name = names;
907         char **dn = out;
908         char buffer[LDAP_MAX_GROUP_NAME_LEN + 1];
909         
910         char *filter;
911         
912         *dn = NULL;
913         
914         if (!*names) {
915                 return RLM_MODULE_OK;
916         }
917         
918         if (!inst->groupobj_name_attr) {
919                 RDEBUGE("Told to convert group names to DNs but missing 'group.name_attribute' directive");
920                 
921                 return RLM_MODULE_INVALID;
922         }
923
924         /*
925          *      It'll probably only save a few ms in network latency, but it means we can send a query
926          *      for the entire group list at once.
927          */
928         filter = talloc_asprintf(request, "(&(%s)(|(", inst->base_filter);
929         while (*name) {
930                 rlm_ldap_escape_func(request, buffer, sizeof(buffer), *++name, NULL);
931                 filter = talloc_asprintf_append_buffer(filter, "(%s=%s)", inst->groupobj_name_attr, buffer);
932                 
933                 entry_cnt++;
934         }
935         filter = talloc_strdup_append_buffer(filter, "))");
936         
937         status = rlm_ldap_search(inst, request, pconn, inst->basedn, LDAP_SCOPE_SUB, filter, attrs, &result);
938         switch (status) {
939                 case LDAP_PROC_SUCCESS:
940                         break;
941                 case LDAP_PROC_NO_RESULT:
942                         rcode = RLM_MODULE_INVALID;
943                         goto finish;
944                 default:
945                         rcode = RLM_MODULE_FAIL;
946                         goto finish;
947         }
948         
949         entry_cnt = ldap_count_entries((*pconn)->handle, result);
950         if (entry_cnt > name_cnt) {
951                 RDEBUGE("Number of DNs exceeds number of names, base_dn or base_filter should be more restrictive");
952                 rcode = RLM_MODULE_INVALID;
953                 
954                 goto finish;
955         }
956         
957         if (entry_cnt > (outlen - 1)) {
958                 RDEBUGE("Number of DNs exceeds limit (%i)", outlen - 1);
959                 rcode = RLM_MODULE_INVALID;
960                 
961                 goto finish;
962         }
963         
964         if (entry_cnt < name_cnt) {
965                 RDEBUGW("Got partial mapping of group names to DNs, membership information may be incomplete");
966         }
967         
968         entry = ldap_first_entry((*pconn)->handle, result);
969         if (!entry) {
970                 ldap_get_option((*pconn)->handle, LDAP_OPT_RESULT_CODE, &ldap_errno);
971                 RDEBUGE("Failed retrieving entry: %s", ldap_err2string(ldap_errno));
972                         
973                 rcode = RLM_MODULE_INVALID;      
974                 goto finish;
975         }
976         
977         do {
978                 *dn = ldap_get_dn((*pconn)->handle, entry);     
979         } while((entry = ldap_next_entry((*pconn)->handle, entry)));
980         
981         *dn = NULL;
982         
983         finish:
984         talloc_free(filter);
985         if (result) {
986                 ldap_msgfree(result);
987         }
988         
989         /*
990          *      Be nice and cleanup the output array if we error out.
991          */
992         if (status != RLM_MODULE_OK) {
993                 dn = out;
994                 while(*dn) ldap_memfree(*dn++);
995                 *dn = NULL;
996         }
997         
998         return status;
999 }
1000
1001 /** Convert a single group name into a DN
1002  *
1003  * Unlike the inverse conversion of a name to a DN, most LDAP directories don't allow filtering by DN,
1004  * so we need to search for each DN individually.
1005  * @param inst rlm_ldap configuration.
1006  * @param request Current request.
1007  * @param conn Current connection.
1008  * @param dn to resolve.
1009  * @param out Where to write group name (must be freed with ldap_memfree()).
1010  * @return One of the RLM_MODULE_* values.
1011  */
1012 rlm_rcode_t rlm_ldap_group_dn2name(const ldap_instance_t *inst, REQUEST *request, ldap_handle_t **pconn,
1013                                    const char *dn, char **out)
1014 {
1015         rlm_rcode_t rcode;
1016         ldap_rcode_t status;
1017         int ldap_errno;
1018         
1019         char **vals;
1020         const char *attrs[] = { inst->groupobj_name_attr, NULL };
1021         LDAPMessage *result = NULL, *entry;
1022         
1023         *out = NULL;
1024         
1025         if (!inst->groupobj_name_attr) {
1026                 RDEBUGE("Told to convert group DN to name but missing 'group.name_attribute' directive");
1027                 
1028                 return RLM_MODULE_INVALID;
1029         }
1030         
1031         status = rlm_ldap_search(inst, request, pconn, dn, LDAP_SCOPE_BASE, inst->base_filter, attrs,
1032                                  &result); 
1033         switch (status) {
1034                 case LDAP_PROC_SUCCESS:
1035                         break;
1036                 case LDAP_PROC_NO_RESULT:
1037                         return RLM_MODULE_INVALID;
1038                 default:
1039                         return RLM_MODULE_FAIL;
1040         }
1041         
1042         entry = ldap_first_entry((*pconn)->handle, result);
1043         if (!entry) {
1044                 ldap_get_option((*pconn)->handle, LDAP_OPT_RESULT_CODE, &ldap_errno);
1045                 RDEBUGE("Failed retrieving entry: %s", ldap_err2string(ldap_errno));
1046                         
1047                 rcode = RLM_MODULE_INVALID;      
1048                 goto finish;
1049         }
1050
1051         vals = ldap_get_values((*pconn)->handle, entry, inst->groupobj_name_attr);
1052         if (!vals) {
1053                 rcode = RLM_MODULE_INVALID;
1054                 goto finish;
1055         }
1056         
1057         *out = *vals;
1058         
1059         finish:
1060         if (result) {
1061                 ldap_msgfree(result);
1062         }
1063         
1064         if (vals) {
1065                 ldap_value_free(vals);        
1066         }
1067         
1068         return rcode;
1069 }
1070
1071 /** Convert group membership information into attributes
1072  *
1073  * @param inst rlm_ldap configuration.
1074  * @param request Current request.
1075  * @param conn used to retrieve entry.
1076  * @param entry retrieved by rlm_ldap_find_user or rlm_ldap_search.
1077  * @return One of the RLM_MODULE_* values.
1078  */
1079 rlm_rcode_t rlm_ldap_cacheable_membership(const ldap_instance_t *inst, REQUEST *request, ldap_handle_t **pconn,
1080                                           LDAPMessage *entry)
1081 {
1082         rlm_rcode_t rcode;
1083         char **vals;
1084
1085         char *group_name[LDAP_MAX_CACHEABLE + 1];
1086         char **name_p = group_name;
1087
1088         char *group_dn[LDAP_MAX_CACHEABLE + 1];
1089         char **dn_p;
1090         
1091         char *name;
1092         
1093         int is_dn;
1094         int i;
1095
1096         if (!inst->cacheable_group_dn && !inst->cacheable_group_name) {
1097                 return RLM_MODULE_OK;
1098         }
1099         
1100         /*
1101          *      Group membership apparently isn't stored in user objects, so jump straight to resolving groups
1102          *      with the group membership filter.
1103          */
1104         if (!inst->userobj_membership_attr) {
1105                 goto skip_userobj;
1106         }
1107         
1108         /*
1109          *      Parse the membership information we got in the initial user query.
1110          */
1111         vals = ldap_get_values((*pconn)->handle, entry, inst->userobj_membership_attr);
1112         if (!vals) {
1113                 goto skip_userobj;
1114         }
1115
1116         for (i = 0; (vals[i] != NULL) && (i < LDAP_MAX_CACHEABLE); i++) {
1117                 is_dn = rlm_ldap_is_dn(vals[i]);
1118                 
1119                 if (inst->cacheable_group_dn) {
1120                         /*
1121                          *      The easy case, were caching DNs and we got a DN.
1122                          */
1123                         if (is_dn) {
1124                                 pairmake(request, &request->config_items, "LDAP-GroupDN", vals[i], T_OP_ADD);
1125                                 RDEBUG3("Added LDAP-GroupDN with value \"%s\" to control list", vals[i]);
1126                                 
1127                         /*
1128                          *      We were told to cache DNs but we got a name, we now need to resolve this to a DN.
1129                          *      Store all the group names in an array so we can do one query.
1130                          */
1131                         } else {
1132                                 *name_p++ = vals[i];
1133                         }
1134                 }
1135                 
1136                 if (inst->cacheable_group_name) {
1137                         /*
1138                          *      The easy case, were caching names and we got a name.
1139                          */
1140                         if (!is_dn) {
1141                                 pairmake(request, &request->config_items, "LDAP-Group", vals[i], T_OP_ADD);
1142                                 RDEBUG3("Added LDAP-Group with value \"%s\" to control list", vals[i]);
1143                         /*
1144                          *      We were told to cache names but we got a DN, we now need to resolve this to a name.
1145                          *      Only Active Directory supports filtering on DN, so we have to search for each
1146                          *      individual group.
1147                          */
1148                         } else {
1149                                 rcode = rlm_ldap_group_dn2name(inst, request, pconn, vals[i], &name);
1150                                 if (rcode != RLM_MODULE_OK) {
1151                                         ldap_value_free(vals);
1152                                         
1153                                         return rcode;
1154                                 }
1155                                 
1156                                 pairmake(request, &request->config_items, "LDAP-Group", name, T_OP_ADD);
1157                                 RDEBUG3("Added LDAP-Group with value \"%s\" to control list", name);
1158                                 ldap_memfree(name);
1159                         }
1160                 }
1161         }
1162         *name_p = NULL;
1163         
1164         rcode = rlm_ldap_group_name2dn(inst, request, pconn, group_name, group_dn, sizeof(group_dn));
1165         
1166         ldap_value_free(vals);
1167         
1168         if (rcode != RLM_MODULE_OK) {
1169                 return rcode;
1170         }
1171         
1172         dn_p = group_dn;
1173         while(*dn_p) {
1174                 pairmake(request, &request->config_items, "LDAP-GroupDN", *dn_p, T_OP_ADD);
1175                 RDEBUG3("Added LDAP-GroupDN with value \"%s\" to control list", *dn_p);
1176                 ldap_memfree(*dn_p);
1177                 
1178                 dn_p++;
1179         }
1180
1181         skip_userobj:
1182         
1183         /* @todo add code to search for groups with this user as a member and add them to control list */
1184         
1185         return rcode;
1186 }               
1187
1188 /** Check for presence of access attribute in result
1189  *
1190  * @param inst rlm_ldap configuration.
1191  * @param request Current request.
1192  * @param conn used to retrieve entry.
1193  * @param entry retrieved by rlm_ldap_find_user or rlm_ldap_search.
1194  * @return RLM_MODULE_USERLOCK if the user was denied access, else RLM_MODULE_OK.
1195  */
1196 rlm_rcode_t rlm_ldap_check_access(const ldap_instance_t *inst, REQUEST *request,
1197                                   const ldap_handle_t *conn, LDAPMessage *entry)
1198 {
1199         rlm_rcode_t rcode = RLM_MODULE_OK;
1200         char **vals = NULL;
1201
1202         vals = ldap_get_values(conn->handle, entry, inst->userobj_access_attr);
1203         if (vals) {
1204                 if (inst->access_positive && (strncmp(vals[0], "FALSE", 5) == 0)) {
1205                         RDEBUG("\"%s\" attribute exists but is set to 'false' - user locked out");
1206                         rcode = RLM_MODULE_USERLOCK;
1207                 } else {
1208                         RDEBUG("\"%s\" attribute exists - user locked out", inst->userobj_access_attr);
1209                         rcode = RLM_MODULE_USERLOCK;
1210                 }
1211
1212                 ldap_value_free(vals);
1213         } else if (inst->access_positive) {
1214                 RDEBUG("No \"%s\" attribute - user locked out", inst->userobj_access_attr);
1215                 rcode = RLM_MODULE_USERLOCK;
1216         }
1217
1218         return rcode;
1219 }
1220
1221 /** Verify we got a password from the search
1222  *
1223  * Checks to see if after the LDAP to RADIUS mapping has been completed that a reference password.
1224  *
1225  * @param inst rlm_ldap configuration.
1226  * @param request Current request.
1227  */
1228 void rlm_ldap_check_reply(const ldap_instance_t *inst, REQUEST *request)
1229 {
1230        /*
1231         *       More warning messages for people who can't be bothered to read the documentation.
1232         *
1233         *       Expect_password is set when we process the mapping, and is only true if there was a mapping between
1234         *       an LDAP attribute and a password reference attribute in the control list.
1235         */
1236         if (inst->expect_password && (debug_flag > 1)) {
1237                 if (!pairfind(request->config_items, PW_CLEARTEXT_PASSWORD, 0, TAG_ANY) &&
1238                     !pairfind(request->config_items, PW_NT_PASSWORD, 0, TAG_ANY) &&
1239                     !pairfind(request->config_items, PW_USER_PASSWORD, 0, TAG_ANY) &&
1240                     !pairfind(request->config_items, PW_PASSWORD_WITH_HEADER, 0, TAG_ANY) &&
1241                     !pairfind(request->config_items, PW_CRYPT_PASSWORD, 0, TAG_ANY)) {
1242                         RDEBUGW("No \"reference\" password added. Ensure the admin user has permission to "
1243                                 "read the password attribute");
1244                         RDEBUGW("PAP authentication will *NOT* work with Active Directory (if that is what you "
1245                                 "were trying to configure)");
1246                 }
1247        }
1248 }
1249
1250 #if LDAP_SET_REBIND_PROC_ARGS == 3
1251 /** Callback for OpenLDAP to rebind and chase referrals
1252  *
1253  * Called by OpenLDAP when it receives a referral and has to rebind.
1254  *
1255  * @param handle to rebind.
1256  * @param url to bind to.
1257  * @param request that triggered the rebind.
1258  * @param msgid that triggered the rebind.
1259  * @param ctx rlm_ldap configuration.
1260  */
1261 static int rlm_ldap_rebind(LDAP *handle, LDAP_CONST char *url, UNUSED ber_tag_t request, UNUSED ber_int_t msgid,
1262                            void *ctx)
1263 {
1264         ldap_rcode_t status;
1265         ldap_handle_t *conn = ctx;
1266         
1267         int ldap_errno;
1268
1269         conn->referred = TRUE;
1270         conn->rebound = TRUE;   /* not really, but oh well... */
1271         rad_assert(handle == conn->handle);
1272
1273         DEBUG("rlm_ldap (%s): Rebinding to URL %s", conn->inst->xlat_name, url);
1274
1275         status = rlm_ldap_bind(conn->inst, NULL, &conn, conn->inst->login, conn->inst->password, FALSE);
1276         if (status != LDAP_PROC_SUCCESS) {
1277                 ldap_get_option(handle, LDAP_OPT_ERROR_NUMBER, &ldap_errno);
1278                         
1279                 return ldap_errno;
1280         }
1281         
1282
1283         return LDAP_SUCCESS;
1284 }
1285 #endif
1286
1287 /** Create and return a new connection
1288  *
1289  * Create a new ldap connection and allocate memory for a new rlm_handle_t
1290  *
1291  * @param ctx rlm_ldap instance.
1292  * @return A new connection handle or NULL on error.
1293  */
1294 void *rlm_ldap_conn_create(void *ctx)
1295 {
1296         ldap_rcode_t status;
1297         
1298         int ldap_errno, ldap_version;
1299         struct timeval tv;
1300         
1301         ldap_instance_t *inst = ctx;
1302         LDAP *handle = NULL;
1303         ldap_handle_t *conn = NULL;
1304
1305 #ifdef HAVE_LDAP_INITIALIZE
1306         if (inst->is_url) {
1307                 DEBUG("rlm_ldap (%s): Connecting to %s", inst->xlat_name, inst->server);
1308                 
1309                 ldap_errno = ldap_initialize(&handle, inst->server);
1310                 if (ldap_errno != LDAP_SUCCESS) {
1311                         LDAP_ERR("ldap_initialize failed: %s", ldap_err2string(ldap_errno));
1312                         goto error;
1313                 }
1314         } else
1315 #endif
1316         {
1317                 DEBUG("rlm_ldap (%s): Connecting to %s:%d", inst->xlat_name, inst->server, inst->port);
1318
1319                 handle = ldap_init(inst->server, inst->port);
1320                 if (!handle) {
1321                         LDAP_ERR("ldap_init() failed");
1322                         goto error;
1323                 }
1324         }
1325
1326         /*
1327          *      We now have a connection structure, but no actual TCP connection.
1328          *
1329          *      Set a bunch of LDAP options, using common code.
1330          */
1331 #define do_ldap_option(_option, _name, _value) \
1332         if (ldap_set_option(handle, _option, _value) != LDAP_OPT_SUCCESS) { \
1333                 ldap_get_option(handle, LDAP_OPT_ERROR_NUMBER, &ldap_errno); \
1334                 LDAP_ERR("Could not set %s: %s", _name, ldap_err2string(ldap_errno)); \
1335         }
1336                 
1337         if (inst->ldap_debug) {
1338                 do_ldap_option(LDAP_OPT_DEBUG_LEVEL, "ldap_debug", &(inst->ldap_debug));
1339         }
1340
1341         /*
1342          *      Leave "chase_referrals" unset to use the OpenLDAP default.
1343          */
1344         if (inst->chase_referrals != 2) {
1345                 if (inst->chase_referrals) {
1346                         do_ldap_option(LDAP_OPT_REFERRALS, "chase_referrals", LDAP_OPT_ON);
1347                         
1348                         if (inst->rebind == 1) {
1349 #if LDAP_SET_REBIND_PROC_ARGS == 3
1350                                 ldap_set_rebind_proc(handle, rlm_ldap_rebind, inst);
1351 #else
1352                                 DEBUGW("The flag 'rebind = yes' is not supported by the system LDAP library. "
1353                                        "Ignoring.");
1354 #endif
1355                         }
1356                 } else {
1357                         do_ldap_option(LDAP_OPT_REFERRALS, "chase_referrals", LDAP_OPT_OFF);
1358                 }
1359         }
1360
1361         tv.tv_sec = inst->net_timeout;
1362         tv.tv_usec = 0;
1363         do_ldap_option(LDAP_OPT_NETWORK_TIMEOUT, "net_timeout", &tv);
1364
1365         do_ldap_option(LDAP_OPT_TIMELIMIT, "timelimit", &(inst->timelimit));
1366
1367         ldap_version = LDAP_VERSION3;
1368         do_ldap_option(LDAP_OPT_PROTOCOL_VERSION, "ldap_version", &ldap_version);
1369
1370 #ifdef LDAP_OPT_X_KEEPALIVE_IDLE
1371         do_ldap_option(LDAP_OPT_X_KEEPALIVE_IDLE, "keepalive idle", &(inst->keepalive_idle));
1372 #endif
1373
1374 #ifdef LDAP_OPT_X_KEEPALIVE_PROBES
1375         do_ldap_option(LDAP_OPT_X_KEEPALIVE_PROBES, "keepalive probes", &(inst->keepalive_probes));
1376 #endif
1377
1378 #ifdef LDAP_OPT_X_KEEPALIVE_INTERVAL
1379         do_ldap_option(LDAP_OPT_X_KEEPALIVE_INTERVAL, "keepalive interval", &(inst->keepalive_interval));
1380 #endif
1381
1382 #ifdef HAVE_LDAP_START_TLS
1383         /*
1384          *      Set all of the TLS options
1385          */
1386         if (inst->tls_mode) {
1387                 do_ldap_option(LDAP_OPT_X_TLS, "tls_mode", &(inst->tls_mode));
1388         }
1389
1390 #  define maybe_ldap_option(_option, _name, _value) \
1391         if (_value) do_ldap_option(_option, _name, _value)
1392
1393         maybe_ldap_option(LDAP_OPT_X_TLS_CACERTFILE, "cacertfile", inst->tls_cacertfile);
1394         maybe_ldap_option(LDAP_OPT_X_TLS_CACERTDIR, "cacertdir", inst->tls_cacertdir);
1395
1396 #  ifdef HAVE_LDAP_INT_TLS_CONFIG
1397         if (ldap_int_tls_config(NULL, LDAP_OPT_X_TLS_REQUIRE_CERT, inst->tls_require_cert) != LDAP_OPT_SUCCESS) {
1398                 ldap_get_option(handle, LDAP_OPT_ERROR_NUMBER, &ldap_errno);
1399                 
1400                 LDAP_ERR("Could not set LDAP_OPT_X_TLS_REQUIRE_CERT option to %s: %s", inst->tls_require_cert,
1401                          ldap_err2string(ldap_errno));
1402         }
1403 #  endif
1404
1405         /*
1406          *      Set certificate options
1407          */
1408         maybe_ldap_option(LDAP_OPT_X_TLS_CERTFILE, "certfile", inst->tls_certfile);
1409         maybe_ldap_option(LDAP_OPT_X_TLS_KEYFILE, "keyfile", inst->tls_keyfile);
1410         maybe_ldap_option(LDAP_OPT_X_TLS_RANDOM_FILE, "randfile", inst->tls_randfile);
1411
1412         /*
1413          *      And finally start the TLS code.
1414          */
1415         if (inst->start_tls) {
1416                 if (inst->port == 636) {
1417                         DEBUGW("Told to Start TLS on LDAPS port this will probably fail, please correct the "
1418                                "configuration");
1419                 }
1420                 
1421                 if (ldap_start_tls_s(handle, NULL, NULL) != LDAP_SUCCESS) {
1422                         ldap_get_option(handle, LDAP_OPT_ERROR_NUMBER, &ldap_errno);
1423
1424                         LDAP_ERR("Could not start TLS: %s", ldap_err2string(ldap_errno));
1425                         goto error;
1426                 }
1427         }
1428 #endif /* HAVE_LDAP_START_TLS */
1429
1430         /*
1431          *      Allocate memory for the handle.
1432          */
1433         conn = talloc_zero(ctx, ldap_handle_t);
1434         conn->inst = inst;
1435         conn->handle = handle;
1436         conn->rebound = FALSE;
1437         conn->referred = FALSE;
1438
1439         status = rlm_ldap_bind(inst, NULL, &conn, inst->login, inst->password, FALSE);
1440         if (status != LDAP_PROC_SUCCESS) {
1441                 goto error;
1442         }
1443
1444         return conn;
1445         
1446         error:
1447         if (handle) ldap_unbind_s(handle);
1448         if (conn) talloc_free(conn);
1449         
1450         return NULL;
1451 }
1452
1453
1454 /** Close and delete a connection
1455  *
1456  * Unbinds the LDAP connection, informing the server and freeing any memory, then releases the memory used by the 
1457  * connection handle.
1458  *
1459  * @param ctx unused.
1460  * @param connection to destroy.
1461  * @return always indicates success.
1462  */
1463 int rlm_ldap_conn_delete(UNUSED void *ctx, void *connection)
1464 {
1465         ldap_handle_t *conn = connection;
1466
1467         ldap_unbind_s(conn->handle);
1468         talloc_free(conn);
1469
1470         return 0;
1471 }
1472
1473
1474 /** Gets an LDAP socket from the connection pool
1475  *
1476  * Retrieve a socket from the connection pool, or NULL on error (of if no sockets are available).
1477  *
1478  * @param inst rlm_ldap configuration.
1479  * @param request Current request.
1480  */
1481 ldap_handle_t *rlm_ldap_get_socket(const ldap_instance_t *inst, REQUEST *request)
1482 {
1483         ldap_handle_t *conn;
1484
1485         conn = fr_connection_get(inst->pool);
1486         if (!conn) {
1487                 RDEBUGE("All ldap connections are in use");
1488                 
1489                 return NULL;
1490         }
1491
1492         return conn;
1493 }
1494
1495 /** Frees an LDAP socket back to the connection pool
1496  *
1497  * If the socket was rebound chasing a referral onto another server then we destroy it.
1498  * If the socket was rebound to another user on the same server, we let the next caller rebind it.
1499  *
1500  * @param inst rlm_ldap configuration.
1501  * @param conn to release.
1502  */
1503 void rlm_ldap_release_socket(const ldap_instance_t *inst, ldap_handle_t *conn)
1504 {
1505         /*
1506          *      Could have already been free'd due to a previous error.
1507          */
1508         if (!conn) return;
1509
1510         /*
1511          *      We chased a referral to another server.
1512          *
1513          *      This connection is no longer part of the pool which is connected to and bound to the configured server.
1514          *      Close it.
1515          *
1516          *      Note that we do NOT close it if it was bound to another user.  Instead, we let the next caller do the
1517          *      rebind.
1518          */
1519         if (conn->referred) {
1520                 fr_connection_del(inst->pool, conn);
1521                 return;
1522         }
1523
1524         fr_connection_release(inst->pool, conn);
1525         return;
1526 }