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.
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.
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
20 * @brief LDAP module library functions.
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.
27 #include <freeradius-devel/radiusd.h>
28 #include <freeradius-devel/modules.h>
29 #include <freeradius-devel/rad_assert.h>
36 /** Converts "bad" strings into ones which are safe for LDAP
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.
44 * @note This is a callback for xlat operations.
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.
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).
55 size_t rlm_ldap_escape_func(UNUSED REQUEST *request, char *out, size_t outlen, char const *in, UNUSED void *arg)
57 static char const encode[] = ",+\"\\<>;*=()";
58 static char const hextab[] = "0123456789abcdef";
61 if (*in && ((*in == ' ') || (*in == '#'))) goto encode;
65 * Encode unsafe characters.
67 if (memchr(encode, *in, sizeof(encode) - 1)) {
70 * Only 3 or less bytes available.
75 *out++ = hextab[(*in >> 4) & 0x0f];
76 *out++ = hextab[*in & 0x0f];
86 * Doesn't need encoding
97 /** Check whether a string looks like a DN
99 * @param[in] in Str to check.
100 * @param[in] inlen Length of string to check.
102 * - true if string looks like a DN.
103 * - false if string does not look like DN.
105 bool rlm_ldap_is_dn(char const *in, size_t inlen)
110 bool too_soon = true;
113 for (p = in; inlen > 0; p++, inlen--) {
120 * Invalid escape sequence, not a DN
122 if (inlen < 2) return false;
125 * Double backslash, consume two chars
134 * Special, consume two chars
156 * Invalid escape sequence, not a DN
158 if (inlen < 3) return false;
161 * Hex encoding, consume three chars
163 if (fr_hex2bin((uint8_t *) &c, 1, p + 1, 2) == 1) {
170 * Invalid escape sequence, not a DN
177 if (too_soon || (*p != want)) return false; /* Too soon after last , or = */
183 if (too_soon || (*p != want)) return false; /* Too soon after last , or = */
196 * If the string ended with , or =, or the number
197 * of components was less than 2
199 * i.e. we don't have <attr>=<val>,<attr>=<val>
201 if (too_soon || (comp < 2)) return false;
206 /** Convert a berval to a talloced string
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.
211 * For some cases this is fine, for others we require a \0 terminated
212 * buffer (feeding DNs back into libldap for example).
214 * @param ctx to allocate in.
215 * @param in Berval to copy.
216 * @return \0 terminated buffer containing in->bv_val.
218 char *rlm_ldap_berval_to_string(TALLOC_CTX *ctx, struct berval const *in)
222 out = talloc_array(ctx, char, in->bv_len + 1);
223 if (!out) return NULL;
225 memcpy(out, in->bv_val, in->bv_len);
226 out[in->bv_len] = '\0';
231 /** Normalise escape sequences in a DN
233 * Characters in a DN can either be escaped as
234 * @verbatim \<hex><hex> @endverbatim or @verbatim \<special> @endverbatim
236 * The LDAP directory chooses how characters are escaped, which can make
237 * local comparisons of DNs difficult.
239 * Here we search for hex sequences that match special chars, and convert
240 * them to the @verbatim \<special> @endverbatim form.
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.
245 * @param out Where to write the normalised DN.
246 * @param in The input DN.
247 * @return The number of bytes written to out.
249 size_t rlm_ldap_normalise_dn(char *out, char const *in)
254 for (p = in; *p != '\0'; p++) {
259 * Double backslashes get processed specially
269 * Hex encodings that have an alternative
270 * special encoding, get rewritten to the
273 if (fr_hex2bin((uint8_t *) &c, 1, p + 1, 2) == 1) {
302 /** Find the place at which the two DN strings diverge
304 * Returns the length of the non matching string in full.
307 * @param part Partial DN as returned by ldap_parse_result.
309 * - Length of the portion of full which wasn't matched
312 static size_t rlm_ldap_common_dn(char const *full, char const *part)
314 size_t f_len, p_len, i;
320 f_len = strlen(full);
326 p_len = strlen(part);
331 if ((f_len < p_len) || !f_len) {
335 for (i = 0; i < p_len; i++) {
336 if (part[p_len - i] != full[f_len - i]) {
341 return f_len - p_len;
344 /** Combine and expand filters
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.
353 ssize_t rlm_ldap_xlat_filter(REQUEST *request, char const **sub, size_t sublen, char *out, size_t outlen)
355 char buffer[LDAP_MAX_FILTER_STR_LEN + 1];
356 char const *in = NULL;
365 * Figure out how many filter elements we need to integrate
367 for (i = 0; i < sublen; i++) {
368 if (sub[i] && *sub[i]) {
387 for (i = 0; i < sublen; i++) {
388 if (sub[i] && (*sub[i] != '\0')) {
389 len += strlcpy(p + len, sub[i], outlen - len);
391 if ((size_t) len >= outlen) {
393 REDEBUG("Out of buffer space creating filter");
400 if ((outlen - len) < 2) {
410 len = radius_xlat(out, outlen, request, in, rlm_ldap_escape_func, NULL);
412 REDEBUG("Failed creating filter");
420 /** Return the error string associated with a handle
422 * @param conn to retrieve error from.
423 * @return error string.
425 char const *rlm_ldap_error_str(ldap_handle_t const *conn)
428 ldap_get_option(conn->handle, LDAP_OPT_ERROR_NUMBER, &lib_errno);
429 if (lib_errno == LDAP_SUCCESS) {
433 return ldap_err2string(lib_errno);
436 /** Parse response from LDAP server dealing with any errors
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.
441 * Will also produce extended error output including any messages the server sent, and information about partial
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.
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)
457 ldap_rcode_t status = LDAP_PROC_SUCCESS;
459 int lib_errno = LDAP_SUCCESS; // errno returned by the library.
460 int srv_errno = LDAP_SUCCESS; // errno in the result message.
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.
467 bool freeit = false; // Whether the message should be freed after being processed.
470 struct timeval tv; // Holds timeout values.
472 LDAPMessage *tmp_msg = NULL; // Temporary message pointer storage if we weren't provided with one.
474 char const *tmp_err; // Temporary error pointer storage if we weren't provided with one.
476 if (!error) error = &tmp_err;
479 if (extra) *extra = NULL;
480 if (result) *result = NULL;
483 * We always need the result, but our caller may not
491 * Check if there was an error sending the request
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 */
497 memset(&tv, 0, sizeof(tv));
498 tv.tv_sec = inst->res_timeout;
501 * Now retrieve the result and check for errors
502 * ldap_result returns -1 on failure, and 0 on timeout
504 lib_errno = ldap_result(conn->handle, msgid, 1, &tv, result);
505 if (lib_errno == 0) {
506 lib_errno = LDAP_TIMEOUT;
511 if (lib_errno == -1) {
512 ldap_get_option(conn->handle, LDAP_OPT_ERROR_NUMBER, &lib_errno);
518 * Parse the result and check for errors sent by the server
520 lib_errno = ldap_parse_result(conn->handle, *result,
522 extra ? &part_dn : NULL,
523 extra ? &srv_err : NULL,
525 if (freeit) *result = NULL;
527 if (lib_errno != LDAP_SUCCESS) {
528 ldap_get_option(conn->handle, LDAP_OPT_ERROR_NUMBER, &lib_errno);
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;
544 case LDAP_SASL_BIND_IN_PROGRESS:
545 *error = "Continuing";
546 status = LDAP_PROC_CONTINUE;
549 case LDAP_NO_SUCH_OBJECT:
550 *error = "The specified DN wasn't found";
551 status = LDAP_PROC_BAD_DN;
556 * Build our own internal diagnostic string
558 len = rlm_ldap_common_dn(dn, part_dn);
561 our_err = talloc_typed_asprintf(conn, "Match stopped here: [%.*s]%s", len, dn, part_dn ? part_dn : "");
564 case LDAP_INSUFFICIENT_ACCESS:
565 *error = "Insufficient access. Check the identity and password configuration directives";
566 status = LDAP_PROC_NOT_PERMITTED;
569 case LDAP_UNWILLING_TO_PERFORM:
570 *error = "Server was unwilling to perform";
571 status = LDAP_PROC_NOT_PERMITTED;
574 case LDAP_FILTER_ERROR:
575 *error = "Bad search filter";
576 status = LDAP_PROC_ERROR;
580 *error = "Timed out while waiting for server to respond";
583 case LDAP_TIMELIMIT_EXCEEDED:
584 *error = "Time limit exceeded";
586 exec_trigger(NULL, inst->cs, "modules.ldap.timeout", true);
590 case LDAP_UNAVAILABLE:
591 case LDAP_SERVER_DOWN:
592 status = LDAP_PROC_RETRY;
595 case LDAP_INVALID_CREDENTIALS:
596 case LDAP_CONSTRAINT_VIOLATION:
597 status = LDAP_PROC_REJECT;
600 case LDAP_OPERATIONS_ERROR:
601 *error = "Please set 'chase_referrals=yes' and 'rebind=yes'. See the ldap module configuration "
606 status = LDAP_PROC_ERROR;
609 if (!*error) *error = ldap_err2string(lib_errno);
611 if (!extra || ((lib_errno == srv_errno) && !our_err && !srv_err)) break;
614 * Output the error codes from the library and server
616 p = talloc_zero_array(conn, char, 1);
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);
632 a = talloc_asprintf_append_buffer(p, "%s. ", our_err);
642 a = talloc_asprintf_append_buffer(p, "Server said: %s. ", srv_err);
659 if (srv_err) ldap_memfree(srv_err);
660 if (part_dn) ldap_memfree(part_dn);
662 talloc_free(our_err);
664 if ((status < 0) && *result) {
665 ldap_msgfree(*result);
672 /** Bind to the LDAP directory as a user
674 * Performs a simple bind to the LDAP directory, and handles any errors that occur.
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.
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)
688 ldap_rcode_t status = LDAP_PROC_ERROR;
692 char const *error = NULL;
697 rad_assert(*pconn && (*pconn)->handle);
698 rad_assert(!retry || inst->pool);
701 rad_assert(!sasl->mech);
705 * Bind as anonymous user
710 * For sanity, for when no connections are viable,
711 * and we can't make a new one.
713 num = retry ? fr_connection_pool_get_num(inst->pool) : 0;
714 for (i = num; i >= 0; i--) {
716 if (sasl && sasl->mech) {
717 status = rlm_ldap_sasl_interactive(inst, request, *pconn, dn, password, sasl,
722 msgid = ldap_bind((*pconn)->handle, dn, password, LDAP_AUTH_SIMPLE);
724 /* We got a valid message ID */
727 RDEBUG2("Waiting for bind result...");
729 DEBUG2("rlm_ldap (%s): Waiting for bind result...", inst->name);
733 status = rlm_ldap_result(inst, *pconn, msgid, dn, NULL, &error, &extra);
737 case LDAP_PROC_SUCCESS:
738 LDAP_DBG_REQ("Bind successful");
741 case LDAP_PROC_NOT_PERMITTED:
742 LDAP_ERR_REQ("Bind was not permitted: %s", error);
747 case LDAP_PROC_REJECT:
748 LDAP_ERR_REQ("Bind credentials incorrect: %s", error);
753 case LDAP_PROC_RETRY:
755 *pconn = fr_connection_reconnect(inst->pool, *pconn);
757 LDAP_DBGW_REQ("Bind with %s to %s failed: %s. Got new socket, retrying...",
758 *dn ? dn : "(anonymous)", inst->server, error);
760 talloc_free(extra); /* don't leak debug info */
765 status = LDAP_PROC_ERROR;
768 * Were not allowed to retry, or there are no more
769 * sockets, treat this as a hard failure.
773 LDAP_ERR_REQ("Bind with %s to %s failed: %s", *dn ? dn : "(anonymous)",
774 inst->server, error);
783 if (retry && (i < 0)) {
784 LDAP_ERR_REQ("Hit reconnection limit");
785 status = LDAP_PROC_ERROR;
790 return status; /* caller closes the connection */
793 /** Search for something in the LDAP directory
795 * Binds as the administrative user and performs a search, dealing with any errors.
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.
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)
815 ldap_rcode_t status = LDAP_PROC_ERROR;
816 LDAPMessage *our_result = NULL;
818 int msgid; // Message id returned by
821 int count = 0; // Number of results we got.
823 struct timeval tv; // Holds timeout values.
825 char const *error = NULL;
830 rad_assert(*pconn && (*pconn)->handle);
833 * OpenLDAP library doesn't declare attrs array as const, but
834 * it really should be *sigh*.
837 memcpy(&search_attrs, &attrs, sizeof(attrs));
840 * Do all searches as the admin user.
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;
851 (*pconn)->rebound = false;
855 LDAP_DBG_REQ("Performing search in \"%s\" with filter \"%s\", scope \"%s\"", dn, filter,
856 fr_int2str(ldap_scope, scope, "<INVALID>"));
858 LDAP_DBG_REQ("Performing unfiltered search in \"%s\", scope \"%s\"", dn,
859 fr_int2str(ldap_scope, scope, "<INVALID>"));
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.
866 memset(&tv, 0, sizeof(tv));
867 tv.tv_sec = inst->res_timeout;
870 * For sanity, for when no connections are viable,
871 * and we can't make a new one.
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);
877 LDAP_DBG_REQ("Waiting for search result...");
878 status = rlm_ldap_result(inst, *pconn, msgid, dn, &our_result, &error, &extra);
880 case LDAP_PROC_SUCCESS:
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.
889 case LDAP_PROC_BAD_DN:
890 LDAP_DBG_REQ("%s", error);
891 if (extra) LDAP_DBG_REQ("%s", extra);
894 case LDAP_PROC_RETRY:
895 *pconn = fr_connection_reconnect(inst->pool, *pconn);
897 LDAP_DBGW_REQ("Search failed: %s. Got new socket, retrying...", error);
899 talloc_free(extra); /* don't leak debug info */
904 status = LDAP_PROC_ERROR;
908 LDAP_ERR_REQ("Failed performing search: %s", error);
909 if (extra) LDAP_ERR_REQ("%s", extra);
918 LDAP_ERR_REQ("Hit reconnection limit");
919 status = LDAP_PROC_ERROR;
924 count = ldap_count_entries((*pconn)->handle, our_result);
926 LDAP_ERR_REQ("Error counting results: %s", rlm_ldap_error_str(*pconn));
927 status = LDAP_PROC_ERROR;
929 ldap_msgfree(our_result);
931 } else if (count == 0) {
932 LDAP_DBG_REQ("Search returned no results");
933 status = LDAP_PROC_NO_RESULT;
935 ldap_msgfree(our_result);
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.
948 if (our_result) ldap_msgfree(our_result);
950 *result = our_result;
956 /** Modify something in the LDAP directory
958 * Binds as the administrative user and attempts to modify an LDAP object.
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.
967 ldap_rcode_t rlm_ldap_modify(rlm_ldap_t const *inst, REQUEST *request, ldap_handle_t **pconn,
968 char const *dn, LDAPMod *mods[])
970 ldap_rcode_t status = LDAP_PROC_ERROR;
972 int msgid; // Message id returned by ldap_search_ext.
974 char const *error = NULL;
979 rad_assert(*pconn && (*pconn)->handle);
982 * Perform all modifications as the admin user.
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;
993 (*pconn)->rebound = false;
997 * For sanity, for when no connections are viable,
998 * and we can't make a new one.
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);
1004 RDEBUG2("Waiting for modify result...");
1005 status = rlm_ldap_result(inst, *pconn, msgid, dn, NULL, &error, &extra);
1007 case LDAP_PROC_SUCCESS:
1010 case LDAP_PROC_RETRY:
1011 *pconn = fr_connection_reconnect(inst->pool, *pconn);
1013 RWDEBUG("Modify failed: %s. Got new socket, retrying...", error);
1015 talloc_free(extra); /* don't leak debug info */
1019 status = LDAP_PROC_ERROR;
1023 REDEBUG("Failed modifying object: %s", error);
1024 REDEBUG("%s", extra);
1033 LDAP_ERR_REQ("Hit reconnection limit");
1034 status = LDAP_PROC_ERROR;
1043 /** Retrieve the DN of a user object
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.
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.
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.
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)
1064 static char const *tmp_attrs[] = { NULL };
1066 ldap_rcode_t status;
1067 VALUE_PAIR *vp = NULL;
1068 LDAPMessage *tmp_msg = NULL, *entry = 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 };
1078 bool freeit = false; //!< Whether the message should
1079 //!< be freed after being processed.
1081 *rcode = RLM_MODULE_FAIL;
1090 memset(&attrs, 0, sizeof(tmp_attrs));
1094 * If the caller isn't looking for the result we can just return the current userdn value.
1097 vp = fr_pair_find_by_num(request->config, PW_LDAP_USERDN, 0, TAG_ANY);
1099 RDEBUG("Using user DN from request \"%s\"", vp->vp_strvalue);
1100 *rcode = RLM_MODULE_OK;
1101 return vp->vp_strvalue;
1106 * Perform all searches as the admin user.
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;
1118 (*pconn)->rebound = false;
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;
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;
1139 status = rlm_ldap_search(result, inst, request, pconn, base_dn,
1140 inst->userobj_scope, filter, attrs, serverctrls, NULL);
1142 case LDAP_PROC_SUCCESS:
1145 case LDAP_PROC_BAD_DN:
1146 case LDAP_PROC_NO_RESULT:
1147 *rcode = RLM_MODULE_NOTFOUND;
1151 *rcode = RLM_MODULE_FAIL;
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.
1162 if (!inst->userobj_sort_ctrl) {
1163 cnt = ldap_count_entries((*pconn)->handle, *result);
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:");
1169 for (entry = ldap_first_entry((*pconn)->handle, *result);
1171 entry = ldap_next_entry((*pconn)->handle, entry)) {
1172 dn = ldap_get_dn((*pconn)->handle, entry);
1177 *rcode = RLM_MODULE_FAIL;
1182 entry = ldap_first_entry((*pconn)->handle, *result);
1184 ldap_get_option((*pconn)->handle, LDAP_OPT_RESULT_CODE, &ldap_errno);
1185 REDEBUG("Failed retrieving entry: %s",
1186 ldap_err2string(ldap_errno));
1191 dn = ldap_get_dn((*pconn)->handle, entry);
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));
1198 rlm_ldap_normalise_dn(dn, dn);
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).
1205 * Special chars are pre-escaped by libldap, and because
1206 * we pass the string back to libldap we must not alter it.
1208 RDEBUG("User object found at DN \"%s\"", dn);
1209 vp = fr_pair_make(request, &request->config, "LDAP-UserDN", NULL, T_OP_EQ);
1211 fr_pair_value_strcpy(vp, dn);
1212 *rcode = RLM_MODULE_OK;
1217 if ((freeit || (*rcode != RLM_MODULE_OK)) && *result) {
1218 ldap_msgfree(*result);
1222 return vp ? vp->vp_strvalue : NULL;
1225 /** Check for presence of access attribute in result
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.
1232 * - #RLM_MODULE_USERLOCK if the user was denied access.
1233 * - #RLM_MODULE_OK otherwise.
1235 rlm_rcode_t rlm_ldap_check_access(rlm_ldap_t const *inst, REQUEST *request,
1236 ldap_handle_t const *conn, LDAPMessage *entry)
1238 rlm_rcode_t rcode = RLM_MODULE_OK;
1239 struct berval **values = NULL;
1241 values = ldap_get_values_len(conn->handle, entry, inst->userobj_access_attr);
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;
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;
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;
1263 /** Verify we got a password from the search
1265 * Checks to see if after the LDAP to RADIUS mapping has been completed that a reference password.
1267 * @param inst rlm_ldap configuration.
1268 * @param request Current request.
1270 void rlm_ldap_check_reply(rlm_ldap_t const *inst, REQUEST *request)
1273 * More warning messages for people who can't be bothered to read the documentation.
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.
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)");
1292 #if LDAP_SET_REBIND_PROC_ARGS == 3
1293 /** Callback for OpenLDAP to rebind and chase referrals
1295 * Called by OpenLDAP when it receives a referral and has to rebind.
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.
1303 static int rlm_ldap_rebind(LDAP *handle, LDAP_CONST char *url, UNUSED ber_tag_t request, UNUSED ber_int_t msgid,
1306 ldap_rcode_t status;
1307 ldap_handle_t *conn = talloc_get_type_abort(ctx, ldap_handle_t);
1311 conn->referred = true;
1312 conn->rebound = true; /* not really, but oh well... */
1313 rad_assert(handle == conn->handle);
1315 DEBUG("rlm_ldap (%s): Rebinding to URL %s", conn->inst->name, url);
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);
1326 return LDAP_SUCCESS;
1330 int rlm_ldap_global_init(rlm_ldap_t *inst)
1334 rad_assert(inst); /* clang scan */
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"); \
1344 #define maybe_ldap_global_option(_option, _name, _value) \
1345 if (_value) do_ldap_global_option(_option, _name, _value)
1347 #ifdef LDAP_OPT_DEBUG_LEVEL
1349 * Can't use do_ldap_global_option
1351 if (inst->ldap_debug) do_ldap_global_option(LDAP_OPT_DEBUG_LEVEL, "ldap_debug", &(inst->ldap_debug));
1354 #ifdef LDAP_OPT_X_TLS_RANDOM_FILE
1356 * OpenLDAP will error out if we attempt to set
1357 * this on a handle. Presumably it's global in
1360 maybe_ldap_global_option(LDAP_OPT_X_TLS_RANDOM_FILE, "random_file", inst->tls_random_file);
1365 /** Close and delete a connection
1367 * Unbinds the LDAP connection, informing the server and freeing any memory, then releases the memory used by the
1368 * connection handle.
1370 * @param conn to destroy.
1371 * @return always indicates success.
1373 static int _mod_conn_free(ldap_handle_t *conn)
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);
1380 ldap_unbind_s(conn->handle);
1387 /** Create and return a new connection
1389 * Create a new ldap connection and allocate memory for a new rlm_handle_t
1391 void *mod_conn_create(TALLOC_CTX *ctx, void *instance)
1393 ldap_rcode_t status;
1395 int ldap_errno, ldap_version;
1398 rlm_ldap_t *inst = instance;
1399 ldap_handle_t *conn;
1402 * Allocate memory for the handle.
1404 conn = talloc_zero(ctx, ldap_handle_t);
1405 if (!conn) return NULL;
1406 talloc_set_destructor(conn, _mod_conn_free);
1409 conn->rebound = false;
1410 conn->referred = false;
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));
1420 conn->handle = ldap_init(inst->server, inst->port);
1421 if (!conn->handle) {
1422 LDAP_ERR("ldap_init failed");
1426 DEBUG3("rlm_ldap (%s): New libldap handle %p", inst->name, conn->handle);
1429 * We now have a connection structure, but no actual connection.
1431 * Set a bunch of LDAP options, using common code.
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"); \
1441 #define maybe_ldap_option(_option, _name, _value) \
1442 if (_value) do_ldap_option(_option, _name, _value)
1445 * Leave "dereference" unset to use the OpenLDAP default.
1447 if (inst->dereference_str) {
1448 do_ldap_option(LDAP_OPT_DEREF, "dereference", &(inst->dereference));
1452 * Leave "chase_referrals" unset to use the OpenLDAP default.
1454 if (!inst->chase_referrals_unset) {
1455 if (inst->chase_referrals) {
1456 do_ldap_option(LDAP_OPT_REFERRALS, "chase_referrals", LDAP_OPT_ON);
1458 if (inst->rebind == true) {
1459 #if LDAP_SET_REBIND_PROC_ARGS == 3
1460 ldap_set_rebind_proc(conn->handle, rlm_ldap_rebind, conn);
1464 do_ldap_option(LDAP_OPT_REFERRALS, "chase_referrals", LDAP_OPT_OFF);
1468 #ifdef LDAP_OPT_NETWORK_TIMEOUT
1469 if (inst->net_timeout) {
1470 memset(&tv, 0, sizeof(tv));
1471 tv.tv_sec = inst->net_timeout;
1473 do_ldap_option(LDAP_OPT_NETWORK_TIMEOUT, "net_timeout", &tv);
1477 do_ldap_option(LDAP_OPT_TIMELIMIT, "srv_timelimit", &(inst->srv_timelimit));
1479 ldap_version = LDAP_VERSION3;
1480 do_ldap_option(LDAP_OPT_PROTOCOL_VERSION, "ldap_version", &ldap_version);
1482 #ifdef LDAP_OPT_X_KEEPALIVE_IDLE
1483 do_ldap_option(LDAP_OPT_X_KEEPALIVE_IDLE, "keepalive idle", &(inst->keepalive_idle));
1486 #ifdef LDAP_OPT_X_KEEPALIVE_PROBES
1487 do_ldap_option(LDAP_OPT_X_KEEPALIVE_PROBES, "keepalive probes", &(inst->keepalive_probes));
1490 #ifdef LDAP_OPT_X_KEEPALIVE_INTERVAL
1491 do_ldap_option(LDAP_OPT_X_KEEPALIVE_INTERVAL, "keepalive interval", &(inst->keepalive_interval));
1494 #ifdef HAVE_LDAP_START_TLS_S
1496 * Set all of the TLS options
1498 if (inst->tls_mode) {
1499 do_ldap_option(LDAP_OPT_X_TLS, "tls_mode", &(inst->tls_mode));
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);
1507 * Set certificate options
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);
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);
1519 * Counter intuitively the TLS context appears to need to be initialised
1520 * after all the TLS options are set on the handle.
1522 # ifdef LDAP_OPT_X_TLS_NEWCTX
1524 /* Always use the new TLS configuration context */
1526 do_ldap_option(LDAP_OPT_X_TLS_NEWCTX, "new TLS context", &is_server);
1532 * And finally start the TLS code.
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 "
1540 if (ldap_start_tls_s(conn->handle, NULL, NULL) != LDAP_SUCCESS) {
1541 ldap_get_option(conn->handle, LDAP_OPT_ERROR_NUMBER, &ldap_errno);
1543 LDAP_ERR("Could not start TLS: %s", ldap_err2string(ldap_errno));
1547 #endif /* HAVE_LDAP_START_TLS_S */
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) {
1563 /** Gets an LDAP socket from the connection pool
1565 * Retrieve a socket from the connection pool, or NULL on error (of if no sockets are available).
1567 * @param inst rlm_ldap configuration.
1568 * @param request Current request (may be NULL).
1570 ldap_handle_t *mod_conn_get(rlm_ldap_t const *inst, UNUSED REQUEST *request)
1572 return fr_connection_get(inst->pool);
1575 /** Frees an LDAP socket back to the connection pool
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.
1580 * @param inst rlm_ldap configuration.
1581 * @param conn to release.
1583 void mod_conn_release(rlm_ldap_t const *inst, ldap_handle_t *conn)
1586 * Could have already been free'd due to a previous error.
1591 * We chased a referral to another server.
1593 * This connection is no longer part of the pool which is
1594 * connected to and bound to the configured server.
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.
1600 if (conn->referred) {
1601 fr_connection_close(inst->pool, conn);
1605 fr_connection_release(inst->pool, conn);