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