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