]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
v4: Move rlm_ldap to use trunk connections in place of connection pool (#4265)
authorNick Porter <nick@portercomputing.co.uk>
Wed, 13 Oct 2021 19:35:26 +0000 (20:35 +0100)
committerGitHub <noreply@github.com>
Wed, 13 Oct 2021 19:35:26 +0000 (14:35 -0500)
* Amend fr_ldap_map_do to take LDAP handle instead of fr_ldap_connection_t

* Amend rlm_ldap_find_user() to use trunk connection

* Amend rlm_ldap_check_access() to take LDAP handle

* Amend rlm_ldap_check_reply() to take trunk connection

* Amend rlm_ldap_group_name2dn() to take fr_ldap_thread_trunk_t

* Amend rlm_ldap_group_dn2name() to take fr_ldap_thread_trunk_t

* Amend rlm_ldap_cacheable_userobj() to take fr_ldap_thread_trunk_t

* Amend rlm_ldap_cacheable_groupobj() to take fr_ldap_thread_trunk_t

* Amend rlm_ldap_check_groupobj_dynamic() to take fr_ldap_thread_trunk_t

* Amend rlm_ldap_check_userobj_dynamic() to take fr_ldap_thread_trunk_t

* Amend LDAP mod_map_proc() to use fr_ldap_thread_trunk_t connections

* Amend rlm_ldap_groupcmp to use fr_ldap_thread_trunk_t connections

* Amend mod_authenticate to use fr_ldap_thread_trunk_t connections

* Amend rlm_ldap_map_profile to take fr_ldap_thread_trunk_t

* Amend user_modify to use fr_ldap_thread_trunk_t connections

* Amend mod_authorize to use fr_ldap_thread_trunk_t connections

* Amend mod_authenticate() to use async bind in place of fr_ldap_bind()

* Amend mod_authorize to use async LDAP bind in place of fr_ldap_bind()

* rlm_ldap no longer uses a connection pool

* Parse trunk config for LDAP trunks

src/lib/ldap/base.h
src/lib/ldap/map.c
src/modules/proto_ldap_sync/proto_ldap_sync.c
src/modules/rlm_ldap/groups.c
src/modules/rlm_ldap/rlm_ldap.c
src/modules/rlm_ldap/rlm_ldap.h
src/modules/rlm_ldap/user.c

index 6a1a24786e549f5af03377deefff05b0befb9dfa..bef33084cf96ef30714cfab059ac6f2adcba4a63 100644 (file)
@@ -705,7 +705,7 @@ int         fr_ldap_map_verify(map_t *map, void *instance);
 
 int            fr_ldap_map_expand(fr_ldap_map_exp_t *expanded, request_t *request, fr_map_list_t const *maps);
 
-int            fr_ldap_map_do(request_t *request, fr_ldap_connection_t *conn,
+int            fr_ldap_map_do(request_t *request, LDAP *handle,
                               char const *valuepair_attr, fr_ldap_map_exp_t const *expanded, LDAPMessage *entry);
 
 /*
index c2957c9a9eed6b55e69d5dfa3bb5761f53372e3e..1ad59110156eea88da30486451ad633756639cb3 100644 (file)
@@ -296,7 +296,7 @@ int fr_ldap_map_expand(fr_ldap_map_exp_t *expanded, request_t *request, fr_map_l
  * This is *NOT* atomic, but there's no condition for which we should error out...
  *
  * @param[in] request          Current request.
- * @param[in] conn             associated with entry.
+ * @param[in] handle           associated with entry.
  * @param[in] valuepair_attr   Treat attribute with this name as holding complete AVP definitions.
  * @param[in] expanded         attributes (rhs of map).
  * @param[in] entry            to retrieve attributes from.
@@ -304,7 +304,7 @@ int fr_ldap_map_expand(fr_ldap_map_exp_t *expanded, request_t *request, fr_map_l
  *     - Number of maps successfully applied.
  *     - -1 on failure.
  */
-int fr_ldap_map_do(request_t *request, fr_ldap_connection_t *conn,
+int fr_ldap_map_do(request_t *request, LDAP *handle,
                   char const *valuepair_attr, fr_ldap_map_exp_t const *expanded, LDAPMessage *entry)
 {
        map_t const             *map = NULL;
@@ -322,7 +322,7 @@ int fr_ldap_map_do(request_t *request, fr_ldap_connection_t *conn,
                /*
                 *      Binary safe
                 */
-               result.values = ldap_get_values_len(conn->handle, entry, name);
+               result.values = ldap_get_values_len(handle, entry, name);
                if (!result.values) {
                        RDEBUG3("Attribute \"%s\" not found in LDAP object", name);
 
@@ -361,7 +361,7 @@ int fr_ldap_map_do(request_t *request, fr_ldap_connection_t *conn,
                struct berval   **values;
                int             count, i;
 
-               values = ldap_get_values_len(conn->handle, entry, valuepair_attr);
+               values = ldap_get_values_len(handle, entry, valuepair_attr);
                count = ldap_count_values_len(values);
 
                for (i = 0; i < count; i++) {
index f4b88f2fd78ac5bf191aac6ee6aed5b73744d4bb..b46616a6f28e40065e2b4a15f7218f2366b2401c 100644 (file)
@@ -754,7 +754,7 @@ static int _proto_ldap_entry(fr_ldap_connection_t *conn, sync_config_t const *co
                talloc_free(request);
                return -1;
        }
-       if (fr_ldap_map_do(request, conn, NULL, &expanded, msg) < 0) goto error;
+       if (fr_ldap_map_do(request, conn->handle, NULL, &expanded, msg) < 0) goto error;
 
 //     request_enqueue(request);
 
index 522b9918326af78e2ac73c92c626169ca722c1e3..4f3e5f315a42ec637577ce3edc4bc6ff22c322f5 100644 (file)
@@ -44,7 +44,7 @@ USES_APPLE_DEPRECATED_API
  * @param[out] p_result                The result of trying to resolve a group name to a dn.
  * @param[in] inst             rlm_ldap configuration.
  * @param[in] request          Current request.
- * @param[in,out] pconn                to use. May change as this function calls functions which auto re-connect.
+ * @param[in] ttrunk           to use.
  * @param[in] names            to convert to DNs (NULL terminated).
  * @param[out] out             Where to write the DNs. DNs must be freed with
  *                             ldap_memfree(). Will be NULL terminated.
@@ -52,18 +52,18 @@ USES_APPLE_DEPRECATED_API
  * @return One of the RLM_MODULE_* values.
  */
 static unlang_action_t rlm_ldap_group_name2dn(rlm_rcode_t *p_result, rlm_ldap_t const *inst, request_t *request,
-                                             fr_ldap_connection_t **pconn,
+                                             fr_ldap_thread_trunk_t *ttrunk,
                                              char **names, char **out, size_t outlen)
 {
        rlm_rcode_t rcode = RLM_MODULE_OK;
-       fr_ldap_rcode_t status;
        int ldap_errno;
 
        unsigned int name_cnt = 0;
        unsigned int entry_cnt;
        char const *attrs[] = { NULL };
 
-       LDAPMessage *result = NULL, *entry;
+       LDAPMessage *entry;
+       fr_ldap_query_t *query = NULL;
 
        char **name = names;
        char **dn = out;
@@ -110,13 +110,18 @@ static unlang_action_t rlm_ldap_group_name2dn(rlm_rcode_t *p_result, rlm_ldap_t
                RETURN_MODULE_INVALID;
        }
 
-       status = fr_ldap_search(&result, request, pconn, base_dn, inst->groupobj_scope,
-                               filter, attrs, NULL, NULL);
-       switch (status) {
-       case LDAP_PROC_SUCCESS:
+       if (fr_ldap_trunk_search(unlang_interpret_frame_talloc_ctx(request), &query, request, ttrunk, base_dn,
+                                inst->groupobj_scope, filter, attrs, NULL, NULL) < 0 ) {
+               rcode = RLM_MODULE_FAIL;
+               goto finish;
+       }
+       rcode = unlang_interpret_synchronous(unlang_interpret_event_list(request), request);
+
+       switch (rcode) {
+       case RLM_MODULE_OK:
                break;
 
-       case LDAP_PROC_NO_RESULT:
+       case RLM_MODULE_NOTFOUND:
                RDEBUG2("Tried to resolve group name(s) to DNs but got no results");
                goto finish;
 
@@ -125,7 +130,7 @@ static unlang_action_t rlm_ldap_group_name2dn(rlm_rcode_t *p_result, rlm_ldap_t
                goto finish;
        }
 
-       entry_cnt = ldap_count_entries((*pconn)->handle, result);
+       entry_cnt = ldap_count_entries(query->ldap_conn->handle, query->result);
        if (entry_cnt > name_cnt) {
                REDEBUG("Number of DNs exceeds number of names, group and/or dn should be more restrictive");
                rcode = RLM_MODULE_INVALID;
@@ -145,9 +150,9 @@ static unlang_action_t rlm_ldap_group_name2dn(rlm_rcode_t *p_result, rlm_ldap_t
                        name_cnt, entry_cnt);
        }
 
-       entry = ldap_first_entry((*pconn)->handle, result);
+       entry = ldap_first_entry(query->ldap_conn->handle, query->result);
        if (!entry) {
-               ldap_get_option((*pconn)->handle, LDAP_OPT_RESULT_CODE, &ldap_errno);
+               ldap_get_option(query->ldap_conn->handle, LDAP_OPT_RESULT_CODE, &ldap_errno);
                REDEBUG("Failed retrieving entry: %s", ldap_err2string(ldap_errno));
 
                rcode = RLM_MODULE_FAIL;
@@ -155,9 +160,9 @@ static unlang_action_t rlm_ldap_group_name2dn(rlm_rcode_t *p_result, rlm_ldap_t
        }
 
        do {
-               *dn = ldap_get_dn((*pconn)->handle, entry);
+               *dn = ldap_get_dn(query->ldap_conn->handle, entry);
                if (!*dn) {
-                       ldap_get_option((*pconn)->handle, LDAP_OPT_RESULT_CODE, &ldap_errno);
+                       ldap_get_option(query->ldap_conn->handle, LDAP_OPT_RESULT_CODE, &ldap_errno);
                        REDEBUG("Retrieving object DN from entry failed: %s", ldap_err2string(ldap_errno));
 
                        rcode = RLM_MODULE_FAIL;
@@ -167,13 +172,12 @@ static unlang_action_t rlm_ldap_group_name2dn(rlm_rcode_t *p_result, rlm_ldap_t
 
                RDEBUG2("Got group DN \"%s\"", *dn);
                dn++;
-       } while((entry = ldap_next_entry((*pconn)->handle, entry)));
+       } while((entry = ldap_next_entry(query->ldap_conn->handle, entry)));
 
        *dn = NULL;
 
 finish:
        talloc_free(filter);
-       if (result) ldap_msgfree(result);
 
        /*
         *      Be nice and cleanup the output array if we error out.
@@ -195,21 +199,21 @@ finish:
  * @param[out] p_result                The result of trying to resolve a dn to a group name.
  * @param[in] inst             rlm_ldap configuration.
  * @param[in] request          Current request.
- * @param[in,out]              pconn to use. May change as this function calls functions which auto re-connect.
+ * @param[in] ttrunk           to use.
  * @param[in] dn               to resolve.
  * @param[out] out             Where to write group name (must be freed with talloc_free).
  * @return One of the RLM_MODULE_* values.
  */
 static unlang_action_t rlm_ldap_group_dn2name(rlm_rcode_t *p_result, rlm_ldap_t const *inst, request_t *request,
-                                             fr_ldap_connection_t **pconn, char const *dn, char **out)
+                                             fr_ldap_thread_trunk_t *ttrunk, char const *dn, char **out)
 {
        rlm_rcode_t rcode = RLM_MODULE_OK;
-       fr_ldap_rcode_t status;
        int ldap_errno;
 
        struct berval **values = NULL;
        char const *attrs[] = { inst->groupobj_name_attr, NULL };
-       LDAPMessage *result = NULL, *entry;
+       LDAPMessage     *entry;
+       fr_ldap_query_t *query = NULL;
 
        *out = NULL;
 
@@ -221,12 +225,17 @@ static unlang_action_t rlm_ldap_group_dn2name(rlm_rcode_t *p_result, rlm_ldap_t
 
        RDEBUG2("Resolving group DN \"%s\" to group name", dn);
 
-       status = fr_ldap_search(&result, request, pconn, dn, LDAP_SCOPE_BASE, NULL, attrs, NULL, NULL);
-       switch (status) {
-       case LDAP_PROC_SUCCESS:
+       if (fr_ldap_trunk_search(unlang_interpret_frame_talloc_ctx(request), &query, request, ttrunk, dn,
+                                LDAP_SCOPE_BASE, NULL, attrs, NULL, NULL) < 0) {
+               RETURN_MODULE_FAIL;
+       }
+       rcode = unlang_interpret_synchronous(unlang_interpret_event_list(request), request);
+
+       switch (rcode) {
+       case RLM_MODULE_OK:
                break;
 
-       case LDAP_PROC_NO_RESULT:
+       case RLM_MODULE_NOTFOUND:
                REDEBUG("Group DN \"%s\" did not resolve to an object", dn);
                RETURN_MODULE_RCODE(inst->allow_dangling_group_refs ? RLM_MODULE_NOOP : RLM_MODULE_INVALID);
 
@@ -234,16 +243,16 @@ static unlang_action_t rlm_ldap_group_dn2name(rlm_rcode_t *p_result, rlm_ldap_t
                RETURN_MODULE_FAIL;
        }
 
-       entry = ldap_first_entry((*pconn)->handle, result);
+       entry = ldap_first_entry(query->ldap_conn->handle, query->result);
        if (!entry) {
-               ldap_get_option((*pconn)->handle, LDAP_OPT_RESULT_CODE, &ldap_errno);
+               ldap_get_option(query->ldap_conn->handle, LDAP_OPT_RESULT_CODE, &ldap_errno);
                REDEBUG("Failed retrieving entry: %s", ldap_err2string(ldap_errno));
 
                rcode = RLM_MODULE_INVALID;
                goto finish;
        }
 
-       values = ldap_get_values_len((*pconn)->handle, entry, inst->groupobj_name_attr);
+       values = ldap_get_values_len(query->ldap_conn->handle, entry, inst->groupobj_name_attr);
        if (!values) {
                REDEBUG("No %s attributes found in object", inst->groupobj_name_attr);
 
@@ -256,7 +265,6 @@ static unlang_action_t rlm_ldap_group_dn2name(rlm_rcode_t *p_result, rlm_ldap_t
        RDEBUG2("Group DN \"%s\" resolves to name \"%s\"", dn, *out);
 
 finish:
-       if (result) ldap_msgfree(result);
        if (values) ldap_value_free_len(values);
 
        RETURN_MODULE_RCODE(rcode);
@@ -267,14 +275,15 @@ finish:
  * @param[out] p_result                The result of trying to resolve a dn to a group name.
  * @param[in] inst             rlm_ldap configuration.
  * @param[in] request          Current request.
- * @param[in,out] pconn                to use. May change as this function calls functions which auto re-connect.
+ * @param[in] ttrunk           to use.
  * @param[in] entry            retrieved by rlm_ldap_find_user or fr_ldap_search.
+ * @param[in] handle           on which original object was found.
  * @param[in] attr             membership attribute to look for in the entry.
  * @return One of the RLM_MODULE_* values.
  */
 unlang_action_t rlm_ldap_cacheable_userobj(rlm_rcode_t *p_result, rlm_ldap_t const *inst,
-                                          request_t *request, fr_ldap_connection_t **pconn,
-                                          LDAPMessage *entry, char const *attr)
+                                          request_t *request, fr_ldap_thread_trunk_t *ttrunk,
+                                          LDAPMessage *entry, LDAP *handle, char const *attr)
 {
        rlm_rcode_t rcode = RLM_MODULE_OK;
 
@@ -300,7 +309,7 @@ unlang_action_t rlm_ldap_cacheable_userobj(rlm_rcode_t *p_result, rlm_ldap_t con
        /*
         *      Parse the membership information we got in the initial user query.
         */
-       values = ldap_get_values_len((*pconn)->handle, entry, attr);
+       values = ldap_get_values_len(handle, entry, attr);
        if (!values) {
                RDEBUG2("No cacheable group memberships found in user object");
 
@@ -363,7 +372,7 @@ unlang_action_t rlm_ldap_cacheable_userobj(rlm_rcode_t *p_result, rlm_ldap_t con
                                char *dn;
 
                                dn = fr_ldap_berval_to_string(value_ctx, values[i]);
-                               rlm_ldap_group_dn2name(&rcode, inst, request, pconn, dn, &name);
+                               rlm_ldap_group_dn2name(&rcode, inst, request, ttrunk, dn, &name);
                                talloc_free(dn);
 
                                if (rcode == RLM_MODULE_NOOP) continue;
@@ -385,7 +394,7 @@ unlang_action_t rlm_ldap_cacheable_userobj(rlm_rcode_t *p_result, rlm_ldap_t con
        }
        *name_p = NULL;
 
-       rlm_ldap_group_name2dn(&rcode, inst, request, pconn, group_name, group_dn, sizeof(group_dn));
+       rlm_ldap_group_name2dn(&rcode, inst, request, ttrunk, group_name, group_dn, sizeof(group_dn));
 
        ldap_value_free_len(values);
        talloc_free(value_ctx);
@@ -422,18 +431,17 @@ unlang_action_t rlm_ldap_cacheable_userobj(rlm_rcode_t *p_result, rlm_ldap_t con
  * @param[out] p_result                The result of trying to resolve a dn to a group name.
  * @param[in] inst             rlm_ldap configuration.
  * @param[in] request          Current request.
- * @param[in,out] pconn                to use. May change as this function calls functions which auto re-connect.
+ * @param[in] ttrunk           to use.
  * @return One of the RLM_MODULE_* values.
  */
 unlang_action_t rlm_ldap_cacheable_groupobj(rlm_rcode_t *p_result, rlm_ldap_t const *inst,
-                                           request_t *request, fr_ldap_connection_t **pconn)
+                                           request_t *request, fr_ldap_thread_trunk_t *ttrunk)
 {
        rlm_rcode_t rcode = RLM_MODULE_OK;
-       fr_ldap_rcode_t status;
        int ldap_errno;
 
-       LDAPMessage *result = NULL;
        LDAPMessage *entry;
+       fr_ldap_query_t *query;
 
        char const *base_dn;
        char base_dn_buff[LDAP_MAX_DN_STR_LEN];
@@ -467,13 +475,18 @@ unlang_action_t rlm_ldap_cacheable_groupobj(rlm_rcode_t *p_result, rlm_ldap_t co
                RETURN_MODULE_INVALID;
        }
 
-       status = fr_ldap_search(&result, request, pconn, base_dn,
-                               inst->groupobj_scope, filter, attrs, NULL, NULL);
-       switch (status) {
-       case LDAP_PROC_SUCCESS:
+       if (fr_ldap_trunk_search(unlang_interpret_frame_talloc_ctx(request), &query, request, ttrunk, base_dn,
+                                inst->groupobj_scope, filter, attrs, NULL, NULL) < 0) {
+               rcode = RLM_MODULE_FAIL;
+               goto finish;
+       }
+       rcode = unlang_interpret_synchronous(unlang_interpret_event_list(request), request);
+
+       switch (rcode) {
+       case RLM_MODULE_OK:
                break;
 
-       case LDAP_PROC_NO_RESULT:
+       case RLM_MODULE_NOTFOUND:
                RDEBUG2("No cacheable group memberships found in group objects");
                goto finish;
 
@@ -482,9 +495,9 @@ unlang_action_t rlm_ldap_cacheable_groupobj(rlm_rcode_t *p_result, rlm_ldap_t co
                goto finish;
        }
 
-       entry = ldap_first_entry((*pconn)->handle, result);
+       entry = ldap_first_entry(query->ldap_conn->handle, query->result);
        if (!entry) {
-               ldap_get_option((*pconn)->handle, LDAP_OPT_RESULT_CODE, &ldap_errno);
+               ldap_get_option(query->ldap_conn->handle, LDAP_OPT_RESULT_CODE, &ldap_errno);
                REDEBUG("Failed retrieving entry: %s", ldap_err2string(ldap_errno));
 
                goto finish;
@@ -493,9 +506,9 @@ unlang_action_t rlm_ldap_cacheable_groupobj(rlm_rcode_t *p_result, rlm_ldap_t co
        RDEBUG2("Adding cacheable group object memberships");
        do {
                if (inst->cacheable_group_dn) {
-                       dn = ldap_get_dn((*pconn)->handle, entry);
+                       dn = ldap_get_dn(query->ldap_conn->handle, entry);
                        if (!dn) {
-                               ldap_get_option((*pconn)->handle, LDAP_OPT_RESULT_CODE, &ldap_errno);
+                               ldap_get_option(query->ldap_conn->handle, LDAP_OPT_RESULT_CODE, &ldap_errno);
                                REDEBUG("Retrieving object DN from entry failed: %s", ldap_err2string(ldap_errno));
 
                                goto finish;
@@ -514,7 +527,7 @@ unlang_action_t rlm_ldap_cacheable_groupobj(rlm_rcode_t *p_result, rlm_ldap_t co
                if (inst->cacheable_group_name) {
                        struct berval **values;
 
-                       values = ldap_get_values_len((*pconn)->handle, entry, inst->groupobj_name_attr);
+                       values = ldap_get_values_len(query->ldap_conn->handle, entry, inst->groupobj_name_attr);
                        if (!values) continue;
 
                        MEM(pair_append_control(&vp, inst->cache_da) == 0);
@@ -526,10 +539,9 @@ unlang_action_t rlm_ldap_cacheable_groupobj(rlm_rcode_t *p_result, rlm_ldap_t co
 
                        ldap_value_free_len(values);
                }
-       } while ((entry = ldap_next_entry((*pconn)->handle, entry)));
+       } while ((entry = ldap_next_entry(query->ldap_conn->handle, entry)));
 
 finish:
-       if (result) ldap_msgfree(result);
 
        RETURN_MODULE_RCODE(rcode);
 }
@@ -539,13 +551,14 @@ finish:
  * @param[out] p_result                Result of calling the module.
  * @param[in] inst             rlm_ldap configuration.
  * @param[in] request          Current request.
- * @param[in,out] pconn                to use. May change as this function calls functions which auto re-connect.
+ * @param[in] ttrunk           to use.
  * @param[in] check            vp containing the group value (name or dn).
  */
 unlang_action_t rlm_ldap_check_groupobj_dynamic(rlm_rcode_t *p_result, rlm_ldap_t const *inst, request_t *request,
-                                               fr_ldap_connection_t **pconn, fr_pair_t const *check)
+                                               fr_ldap_thread_trunk_t *ttrunk, fr_pair_t const *check)
 {
-       fr_ldap_rcode_t status;
+       rlm_rcode_t     rcode;
+       fr_ldap_query_t *query = NULL;
 
        char const      *base_dn;
        char            base_dn_buff[LDAP_MAX_DN_STR_LEN + 1];
@@ -617,14 +630,19 @@ unlang_action_t rlm_ldap_check_groupobj_dynamic(rlm_rcode_t *p_result, rlm_ldap_
        }
 
        RINDENT();
-       status = fr_ldap_search(NULL, request, pconn, base_dn, inst->groupobj_scope, filter, NULL, NULL, NULL);
+       if (fr_ldap_trunk_search(unlang_interpret_frame_talloc_ctx(request), &query, request, ttrunk, base_dn,
+                                inst->groupobj_scope, filter, NULL, NULL, NULL) < 0) {
+               REXDENT();
+               RETURN_MODULE_FAIL;
+       }
+       rcode = unlang_interpret_synchronous(unlang_interpret_event_list(request), request);
        REXDENT();
-       switch (status) {
-       case LDAP_PROC_SUCCESS:
+       switch (rcode) {
+       case RLM_MODULE_OK:
                RDEBUG2("User found in group object \"%s\"", base_dn);
                break;
 
-       case LDAP_PROC_NO_RESULT:
+       case RLM_MODULE_NOTFOUND:
                RETURN_MODULE_NOTFOUND;
 
        default:
@@ -639,19 +657,18 @@ unlang_action_t rlm_ldap_check_groupobj_dynamic(rlm_rcode_t *p_result, rlm_ldap_
  * @param[out] p_result                Result of calling the module.
  * @param[in] inst             rlm_ldap configuration.
  * @param[in] request          Current request.
- * @param[in,out] pconn                to use. May change as this function calls functions which auto re-connect.
+ * @param[in] ttrunk           to use.
  * @param[in] dn               of user object.
  * @param[in] check            vp containing the group value (name or dn).
  */
 unlang_action_t rlm_ldap_check_userobj_dynamic(rlm_rcode_t *p_result, rlm_ldap_t const *inst, request_t *request,
-                                              fr_ldap_connection_t **pconn,
+                                              fr_ldap_thread_trunk_t *ttrunk,
                                               char const *dn, fr_pair_t const *check)
 {
        rlm_rcode_t     rcode = RLM_MODULE_NOTFOUND, ret;
-       fr_ldap_rcode_t status;
        bool            name_is_dn = false, value_is_dn = false;
+       fr_ldap_query_t *query;
 
-       LDAPMessage     *result = NULL;
        LDAPMessage     *entry = NULL;
        struct berval   **values = NULL;
 
@@ -660,25 +677,28 @@ unlang_action_t rlm_ldap_check_userobj_dynamic(rlm_rcode_t *p_result, rlm_ldap_t
 
        RDEBUG2("Checking user object's %s attributes", inst->userobj_membership_attr);
        RINDENT();
-       status = fr_ldap_search(&result, request, pconn, dn, LDAP_SCOPE_BASE, NULL, attrs, NULL, NULL);
+       if (fr_ldap_trunk_search(unlang_interpret_frame_talloc_ctx(request), &query, request, ttrunk, dn,
+                                LDAP_SCOPE_BASE, NULL, attrs, NULL, NULL) < 0) {
+               REXDENT();
+               goto finish;
+       }
+       rcode = unlang_interpret_synchronous(unlang_interpret_event_list(request), request);
        REXDENT();
-       switch (status) {
-       case LDAP_PROC_SUCCESS:
+       switch (rcode) {
+       case RLM_MODULE_OK:
                break;
 
-       case LDAP_PROC_NO_RESULT:
+       case RLM_MODULE_NOTFOUND:
                RDEBUG2("Can't check membership attributes, user object not found");
 
-               rcode = RLM_MODULE_NOTFOUND;
-
                FALL_THROUGH;
        default:
                goto finish;
        }
 
-       entry = ldap_first_entry((*pconn)->handle, result);
+       entry = ldap_first_entry(query->ldap_conn->handle, query->result);
        if (!entry) {
-               ldap_get_option((*pconn)->handle, LDAP_OPT_RESULT_CODE, &ldap_errno);
+               ldap_get_option(query->ldap_conn->handle, LDAP_OPT_RESULT_CODE, &ldap_errno);
                REDEBUG("Failed retrieving entry: %s", ldap_err2string(ldap_errno));
 
                rcode = RLM_MODULE_FAIL;
@@ -686,7 +706,7 @@ unlang_action_t rlm_ldap_check_userobj_dynamic(rlm_rcode_t *p_result, rlm_ldap_t
                goto finish;
        }
 
-       values = ldap_get_values_len((*pconn)->handle, entry, inst->userobj_membership_attr);
+       values = ldap_get_values_len(query->ldap_conn->handle, entry, inst->userobj_membership_attr);
        if (!values) {
                RDEBUG2("No group membership attribute(s) found in user object");
 
@@ -753,7 +773,7 @@ unlang_action_t rlm_ldap_check_userobj_dynamic(rlm_rcode_t *p_result, rlm_ldap_t
                        bool eq = false;
 
                        RINDENT();
-                       rlm_ldap_group_dn2name(&ret, inst, request, pconn, check->vp_strvalue, &resolved);
+                       rlm_ldap_group_dn2name(&ret, inst, request, ttrunk, check->vp_strvalue, &resolved);
                        REXDENT();
 
                        if (ret == RLM_MODULE_NOOP) continue;
@@ -789,7 +809,7 @@ unlang_action_t rlm_ldap_check_userobj_dynamic(rlm_rcode_t *p_result, rlm_ldap_t
 
                        value = fr_ldap_berval_to_string(request, values[i]);
                        RINDENT();
-                       rlm_ldap_group_dn2name(&ret, inst, request, pconn, value, &resolved);
+                       rlm_ldap_group_dn2name(&ret, inst, request, ttrunk, value, &resolved);
                        REXDENT();
                        talloc_free(value);
 
@@ -818,7 +838,6 @@ unlang_action_t rlm_ldap_check_userobj_dynamic(rlm_rcode_t *p_result, rlm_ldap_t
 
 finish:
        if (values) ldap_value_free_len(values);
-       if (result) ldap_msgfree(result);
 
        RETURN_MODULE_RCODE(rcode);
 }
index f8c7d641d12087173c4b5d330df9edc9b0a6b798..8c5a50b988949d91395936ad19cea235f2d26873 100644 (file)
@@ -244,6 +244,9 @@ static const CONF_PARSER module_config[] = {
        { FR_CONF_POINTER("global", FR_TYPE_SUBSECTION, NULL), .subcs = (void const *) global_config },
 
        { FR_CONF_OFFSET("tls", FR_TYPE_SUBSECTION, rlm_ldap_t, handle_config), .subcs = (void const *) tls_config },
+
+       { FR_CONF_OFFSET("pool", FR_TYPE_SUBSECTION, rlm_ldap_t, trunk_conf), .subcs = (void const *) fr_trunk_config },
+
        CONF_PARSER_TERMINATOR
 };
 
@@ -725,18 +728,17 @@ static rlm_rcode_t mod_map_proc(void *mod_inst, UNUSED void *proc_inst, request_
 {
        rlm_rcode_t             rcode = RLM_MODULE_UPDATED;
        rlm_ldap_t              *inst = talloc_get_type_abort(mod_inst, rlm_ldap_t);
-       fr_ldap_rcode_t         status;
+       fr_ldap_thread_t        *thread = talloc_get_type_abort(module_thread_by_data(inst)->data, fr_ldap_thread_t);
 
        LDAPURLDesc             *ldap_url;
 
-       LDAPMessage             *result = NULL;
        LDAPMessage             *entry = NULL;
        map_t const             *map;
        char const              *url_str;
 
-       fr_ldap_connection_t            *conn;
-
-       LDAPControl             *server_ctrls[] = { NULL, NULL };
+       char                    *host_url;
+       fr_ldap_query_t         *query;
+       fr_ldap_thread_trunk_t  *ttrunk;
 
        fr_ldap_map_exp_t       expanded; /* faster than allocing every time */
        fr_value_box_t          *url_head = fr_dlist_head(url);
@@ -776,43 +778,47 @@ static rlm_rcode_t mod_map_proc(void *mod_inst, UNUSED void *proc_inst, request_
                goto free_urldesc;
        }
 
-       conn = mod_conn_get(inst, request);
-       if (!conn) goto free_expanded;
+       /*
+        *      If the URL is <scheme>:/// the parsed host will be NULL - use config default
+        */
+       if (!ldap_url->lud_host) {
+               host_url = inst->handle_config.server;
+       } else {
+               host_url = talloc_asprintf(unlang_interpret_frame_talloc_ctx(request), "%s://%s:%d",
+                                          ldap_url->lud_scheme, ldap_url->lud_host, ldap_url->lud_port);
+       }
 
-       if (fr_ldap_parse_url_extensions(&server_ctrls[0], request, conn, ldap_url->lud_exts) < 0) goto free_socket;
+       ttrunk =  fr_thread_ldap_trunk_get(thread, host_url, inst->handle_config.admin_identity,
+                                          inst->handle_config.admin_password, request, &inst->handle_config);
+       if (!ttrunk) goto free_expanded;
 
-       status = fr_ldap_search(&result, request, &conn, ldap_url->lud_dn, ldap_url->lud_scope,
-                               ldap_url->lud_filter, expanded.attrs, server_ctrls, NULL);
+       fr_ldap_trunk_search(unlang_interpret_frame_talloc_ctx(request), &query, request, ttrunk, ldap_url->lud_dn,
+                            ldap_url->lud_scope, ldap_url->lud_filter, expanded.attrs, NULL, NULL);
 
-#ifdef HAVE_LDAP_CREATE_SORT_CONTROL
-       if (server_ctrls[0]) ldap_control_free(server_ctrls[0]);
-#endif
+       rcode = unlang_interpret_synchronous(unlang_interpret_event_list(request), request);
 
-       switch (status) {
-       case LDAP_PROC_SUCCESS:
+       switch (rcode) {
+       case RLM_MODULE_OK:
+               rcode = RLM_MODULE_UPDATED;
                break;
 
-       case LDAP_PROC_NO_RESULT:
-               rcode = RLM_MODULE_NOOP;
-               goto free_socket;
+       case RLM_MODULE_NOTFOUND:
+               goto free_expanded;
 
        default:
                rcode = RLM_MODULE_FAIL;
-               goto free_socket;
+               goto free_expanded;
        }
 
-       fr_assert(conn);
-       fr_assert(result);
-
-       for (entry = ldap_first_entry(conn->handle, result);
+       for (entry = ldap_first_entry(query->ldap_conn->handle, query->result);
             entry;
-            entry = ldap_next_entry(conn->handle, entry)) {
+            entry = ldap_next_entry(query->ldap_conn->handle, entry)) {
                char    *dn = NULL;
                int     i;
 
 
                if (RDEBUG_ENABLED2) {
-                       dn = ldap_get_dn(conn->handle, entry);
+                       dn = ldap_get_dn(query->ldap_conn->handle, entry);
                        RDEBUG2("Processing \"%s\"", dn);
                }
 
@@ -823,7 +829,7 @@ static rlm_rcode_t mod_map_proc(void *mod_inst, UNUSED void *proc_inst, request_
                        int                     ret;
                        fr_ldap_result_t        attr;
 
-                       attr.values = ldap_get_values_len(conn->handle, entry, expanded.attrs[i]);
+                       attr.values = ldap_get_values_len(query->ldap_conn->handle, entry, expanded.attrs[i]);
                        if (!attr.values) {
                                /*
                                 *      Many LDAP directories don't expose the DN of
@@ -834,7 +840,7 @@ static rlm_rcode_t mod_map_proc(void *mod_inst, UNUSED void *proc_inst, request_
                                        struct berval value;
                                        struct berval *values[2] = { &value, NULL };
 
-                                       if (!dn) dn = ldap_get_dn(conn->handle, entry);
+                                       if (!dn) dn = ldap_get_dn(query->ldap_conn->handle, entry);
                                        value.bv_val = dn;
                                        value.bv_len = strlen(dn);
 
@@ -845,7 +851,7 @@ static rlm_rcode_t mod_map_proc(void *mod_inst, UNUSED void *proc_inst, request_
                                        if (ret == -1) {
                                                rcode = RLM_MODULE_FAIL;
                                                ldap_memfree(dn);
-                                               goto free_result;
+                                               goto free_expanded;
                                        }
                                        continue;
                                }
@@ -861,17 +867,13 @@ static rlm_rcode_t mod_map_proc(void *mod_inst, UNUSED void *proc_inst, request_
                        if (ret == -1) {
                                rcode = RLM_MODULE_FAIL;
                                ldap_memfree(dn);
-                               goto free_result;
+                               goto free_expanded;
                        }
                }
                ldap_memfree(dn);
                REXDENT();
        }
 
-free_result:
-       ldap_msgfree(result);
-free_socket:
-       ldap_mod_conn_release(inst, request, conn);
 free_expanded:
        talloc_free(expanded.ctx);
 free_urldesc:
@@ -895,12 +897,13 @@ free_urldesc:
 static int rlm_ldap_groupcmp(void *instance, request_t *request, UNUSED fr_pair_list_t *request_list, fr_pair_t const *check)
 {
        rlm_ldap_t const        *inst = talloc_get_type_abort_const(instance, rlm_ldap_t);
+       fr_ldap_thread_t        *thread = talloc_get_type_abort(module_thread_by_data(inst)->data, fr_ldap_thread_t);
        rlm_rcode_t             rcode;
 
        bool                    found = false;
        bool                    check_is_dn;
 
-       fr_ldap_connection_t    *conn = NULL;
+       fr_ldap_thread_trunk_t  *ttrunk = NULL;
        char const              *user_dn;
        fr_pair_t               *check_p = NULL;
 
@@ -958,19 +961,15 @@ static int rlm_ldap_groupcmp(void *instance, request_t *request, UNUSED fr_pair_
                }
        }
 
-       conn = mod_conn_get(inst, request);
-       if (!conn) goto cleanup;
+       ttrunk =  fr_thread_ldap_trunk_get(thread, inst->handle_config.server, inst->handle_config.admin_identity,
+                                          inst->handle_config.admin_password, request, &inst->handle_config);
+       if (!ttrunk) goto cleanup;
 
        /*
         *      This is used in the default membership filter.
         */
-       user_dn = rlm_ldap_find_user(inst, request, &conn, NULL, false, NULL, &rcode);
-       if (!user_dn) {
-               ldap_mod_conn_release(inst, request, conn);
-               goto cleanup;
-       }
-
-       fr_assert(conn);
+       user_dn = rlm_ldap_find_user(inst, request, ttrunk, NULL, false, NULL, NULL, &rcode);
+       if (!user_dn) goto cleanup;
 
        /*
         *      Check groupobj user membership
@@ -978,7 +977,7 @@ static int rlm_ldap_groupcmp(void *instance, request_t *request, UNUSED fr_pair_
        if (inst->groupobj_membership_filter) {
                rlm_rcode_t our_rcode;
 
-               rlm_ldap_check_groupobj_dynamic(&our_rcode, inst, request, &conn, check);
+               rlm_ldap_check_groupobj_dynamic(&our_rcode, inst, request, ttrunk, check);
                switch (our_rcode) {
                case RLM_MODULE_NOTFOUND:
                        break;
@@ -992,15 +991,13 @@ static int rlm_ldap_groupcmp(void *instance, request_t *request, UNUSED fr_pair_
                }
        }
 
-       fr_assert(conn);
-
        /*
         *      Check userobj group membership
         */
        if (inst->userobj_membership_attr) {
                rlm_rcode_t our_rcode;
 
-               rlm_ldap_check_userobj_dynamic(&our_rcode, inst, request, &conn, user_dn, check);
+               rlm_ldap_check_userobj_dynamic(&our_rcode, inst, request, ttrunk, user_dn, check);
                switch (our_rcode) {
                case RLM_MODULE_NOTFOUND:
                        break;
@@ -1014,11 +1011,7 @@ static int rlm_ldap_groupcmp(void *instance, request_t *request, UNUSED fr_pair_
                }
        }
 
-       fr_assert(conn);
-
 finish:
-       if (conn) ldap_mod_conn_release(inst, request, conn);
-
        if (found) {
                talloc_free(check_p);
                return 0;
@@ -1034,10 +1027,10 @@ cleanup:
 static unlang_action_t CC_HINT(nonnull) mod_authenticate(rlm_rcode_t *p_result, module_ctx_t const *mctx, request_t *request)
 {
        rlm_ldap_t const        *inst = talloc_get_type_abort_const(mctx->instance, rlm_ldap_t);
+       fr_ldap_thread_t        *thread = talloc_get_type_abort(module_thread_by_data(inst)->data, fr_ldap_thread_t);
        rlm_rcode_t             rcode;
-       fr_ldap_rcode_t         status;
        char const              *dn;
-       fr_ldap_connection_t    *conn;
+       fr_ldap_thread_trunk_t  *ttrunk = NULL;
 
        char                    sasl_mech_buff[LDAP_MAX_DN_STR_LEN];
        char                    sasl_proxy_buff[LDAP_MAX_DN_STR_LEN];
@@ -1086,8 +1079,9 @@ static unlang_action_t CC_HINT(nonnull) mod_authenticate(rlm_rcode_t *p_result,
                RDEBUG2("Login attempt with password");
        }
 
-       conn = mod_conn_get(inst, request);
-       if (!conn) RETURN_MODULE_FAIL;
+       ttrunk =  fr_thread_ldap_trunk_get(thread, inst->handle_config.server, inst->handle_config.admin_identity,
+                                          inst->handle_config.admin_password, request, &inst->handle_config);
+       if (!ttrunk) RETURN_MODULE_FAIL;
 
        /*
         *      Expand dynamic SASL fields
@@ -1126,48 +1120,17 @@ static unlang_action_t CC_HINT(nonnull) mod_authenticate(rlm_rcode_t *p_result,
        /*
         *      Get the DN by doing a search.
         */
-       dn = rlm_ldap_find_user(inst, request, &conn, NULL, false, NULL, &rcode);
-       if (!dn) {
-               ldap_mod_conn_release(inst, request, conn);
-
-               RETURN_MODULE_RCODE(rcode);
-       }
-       conn->rebound = true;
-       status = fr_ldap_bind(request,
-                             &conn,
-                             dn, password->vp_strvalue,
-                             inst->user_sasl.mech ? &sasl : NULL,
-                             fr_time_delta_wrap(0),
-                             NULL, NULL);
-       switch (status) {
-       case LDAP_PROC_SUCCESS:
-               rcode = RLM_MODULE_OK;
-               RDEBUG2("Bind as user \"%s\" was successful", dn);
-               break;
-
-       case LDAP_PROC_NOT_PERMITTED:
-               rcode = RLM_MODULE_DISALLOW;
-               break;
-
-       case LDAP_PROC_REJECT:
-               rcode = RLM_MODULE_REJECT;
-               break;
+       dn = rlm_ldap_find_user(inst, request, ttrunk, NULL, false, NULL, NULL, &rcode);
+       if (!dn) RETURN_MODULE_RCODE(rcode);
 
-       case LDAP_PROC_BAD_DN:
-               rcode = RLM_MODULE_INVALID;
-               break;
+       /*
+        *      Attempt a bind using the thread specific connection for bind auths
+        */
+       if (fr_ldap_bind_auth_async(request, thread, dn, password->vp_strvalue) < 0) RETURN_MODULE_FAIL;
 
-       case LDAP_PROC_NO_RESULT:
-               rcode = RLM_MODULE_NOTFOUND;
-               break;
-
-       default:
-               rcode = RLM_MODULE_FAIL;
-               break;
-       };
+       rcode = unlang_interpret_synchronous(unlang_interpret_event_list(request), request);
 
 finish:
-       ldap_mod_conn_release(inst, request, conn);
 
        RETURN_MODULE_RCODE(rcode);
 }
@@ -1180,23 +1143,23 @@ finish:
  * @param[out] p_result                the result of applying the profile.
  * @param[in] inst             rlm_ldap configuration.
  * @param[in] request          Current request.
- * @param[in,out] pconn                to use. May change as this function calls functions which auto re-connect.
+ * @param[in] ttrunk           to use.
  * @param[in] dn               of profile object to apply.
  * @param[in] expanded         Structure containing a list of xlat
  *                             expanded attribute names and mapping information.
  * @return One of the RLM_MODULE_* values.
  */
 static unlang_action_t rlm_ldap_map_profile(rlm_rcode_t *p_result, rlm_ldap_t const *inst,
-                                           request_t *request, fr_ldap_connection_t **pconn,
+                                           request_t *request, fr_ldap_thread_trunk_t *ttrunk,
                                            char const *dn, fr_ldap_map_exp_t const *expanded)
 {
        rlm_rcode_t     rcode = RLM_MODULE_OK;
-       fr_ldap_rcode_t status;
-       LDAPMessage     *result = NULL, *entry = NULL;
+       LDAPMessage     *entry = NULL;
        int             ldap_errno;
-       LDAP            *handle = (*pconn)->handle;
+       LDAP            *handle;
        char const      *filter;
        char            filter_buff[LDAP_MAX_FILTER_STR_LEN];
+       fr_ldap_query_t *query;
 
        fr_assert(inst->profile_filter);        /* We always have a default filter set */
 
@@ -1209,14 +1172,16 @@ static unlang_action_t rlm_ldap_map_profile(rlm_rcode_t *p_result, rlm_ldap_t co
                RETURN_MODULE_INVALID;
        }
 
-       status = fr_ldap_search(&result, request, pconn, dn,
-                               LDAP_SCOPE_BASE, filter, expanded->attrs, NULL, NULL);
-       switch (status) {
-       case LDAP_PROC_SUCCESS:
+       if (fr_ldap_trunk_search(unlang_interpret_frame_talloc_ctx(request), &query, request, ttrunk, dn,
+                                LDAP_SCOPE_BASE, filter, expanded->attrs, NULL, NULL) < 0) RETURN_MODULE_FAIL;
+
+       rcode = unlang_interpret_synchronous(unlang_interpret_event_list(request), request);
+
+       switch (rcode) {
+       case RLM_MODULE_OK:
                break;
 
-       case LDAP_PROC_BAD_DN:
-       case LDAP_PROC_NO_RESULT:
+       case RLM_MODULE_NOTFOUND:
                RDEBUG2("Profile object \"%s\" not found", dn);
                RETURN_MODULE_NOTFOUND;
 
@@ -1224,44 +1189,38 @@ static unlang_action_t rlm_ldap_map_profile(rlm_rcode_t *p_result, rlm_ldap_t co
                RETURN_MODULE_FAIL;
        }
 
-       fr_assert(*pconn);
-       fr_assert(result);
+       fr_assert(query->result);
+       handle = query->ldap_conn->handle;
 
-       entry = ldap_first_entry(handle, result);
+       entry = ldap_first_entry(handle, query->result);
        if (!entry) {
                ldap_get_option(handle, LDAP_OPT_RESULT_CODE, &ldap_errno);
                REDEBUG("Failed retrieving entry: %s", ldap_err2string(ldap_errno));
 
-               rcode = RLM_MODULE_NOTFOUND;
-
-               goto free_result;
+               RETURN_MODULE_RCODE(RLM_MODULE_NOTFOUND);
        }
 
        RDEBUG2("Processing profile attributes");
        RINDENT();
-       if (fr_ldap_map_do(request, *pconn, inst->valuepair_attr, expanded, entry) > 0) rcode = RLM_MODULE_UPDATED;
+       if (fr_ldap_map_do(request, query->ldap_conn->handle, inst->valuepair_attr, expanded, entry) > 0) rcode = RLM_MODULE_UPDATED;
        REXDENT();
 
-free_result:
-       ldap_msgfree(result);
-
        RETURN_MODULE_RCODE(rcode);
 }
 
 static unlang_action_t CC_HINT(nonnull) mod_authorize(rlm_rcode_t *p_result, module_ctx_t const *mctx, request_t *request)
 {
        rlm_ldap_t const        *inst = talloc_get_type_abort_const(mctx->instance, rlm_ldap_t);
+       fr_ldap_thread_t        *thread = talloc_get_type_abort(module_thread_by_data(inst)->data, fr_ldap_thread_t);
        rlm_rcode_t             rcode = RLM_MODULE_OK;
        int                     ldap_errno;
        int                     i;
        struct berval           **values;
-       fr_ldap_connection_t    *conn;
+       fr_ldap_thread_trunk_t  *ttrunk;
+       LDAP                    *handle;
        LDAPMessage             *result, *entry;
        char const              *dn = NULL;
        fr_ldap_map_exp_t       expanded; /* faster than allocing every time */
-#ifdef WITH_EDIR
-       fr_ldap_rcode_t         status;
-#endif
 
        /*
         *      Don't be tempted to add a check for User-Name or
@@ -1271,8 +1230,9 @@ static unlang_action_t CC_HINT(nonnull) mod_authorize(rlm_rcode_t *p_result, mod
 
        if (fr_ldap_map_expand(&expanded, request, &inst->user_map) < 0) RETURN_MODULE_FAIL;
 
-       conn = mod_conn_get(inst, request);
-       if (!conn) RETURN_MODULE_FAIL;
+       ttrunk =  fr_thread_ldap_trunk_get(thread, inst->handle_config.server, inst->handle_config.admin_identity,
+                                          inst->handle_config.admin_password, request, &inst->handle_config);
+       if (!ttrunk) RETURN_MODULE_FAIL;
 
        /*
         *      Add any additional attributes we need for checking access, memberships, and profiles
@@ -1295,14 +1255,14 @@ static unlang_action_t CC_HINT(nonnull) mod_authorize(rlm_rcode_t *p_result, mod
 
        expanded.attrs[expanded.count] = NULL;
 
-       dn = rlm_ldap_find_user(inst, request, &conn, expanded.attrs, true, &result, &rcode);
+       dn = rlm_ldap_find_user(inst, request, ttrunk, expanded.attrs, true, &result, &handle, &rcode);
        if (!dn) {
                goto finish;
        }
 
-       entry = ldap_first_entry(conn->handle, result);
+       entry = ldap_first_entry(handle, result);
        if (!entry) {
-               ldap_get_option(conn->handle, LDAP_OPT_RESULT_CODE, &ldap_errno);
+               ldap_get_option(handle, LDAP_OPT_RESULT_CODE, &ldap_errno);
                REDEBUG("Failed retrieving entry: %s", ldap_err2string(ldap_errno));
 
                goto finish;
@@ -1312,7 +1272,7 @@ static unlang_action_t CC_HINT(nonnull) mod_authorize(rlm_rcode_t *p_result, mod
         *      Check for access.
         */
        if (inst->userobj_access_attr) {
-               rcode = rlm_ldap_check_access(inst, request, conn, entry);
+               rcode = rlm_ldap_check_access(inst, request, handle, entry);
                if (rcode != RLM_MODULE_OK) {
                        goto finish;
                }
@@ -1323,13 +1283,13 @@ static unlang_action_t CC_HINT(nonnull) mod_authorize(rlm_rcode_t *p_result, mod
         */
        if (inst->cacheable_group_dn || inst->cacheable_group_name) {
                if (inst->userobj_membership_attr) {
-                       rlm_ldap_cacheable_userobj(&rcode, inst, request, &conn, entry, inst->userobj_membership_attr);
+                       rlm_ldap_cacheable_userobj(&rcode, inst, request, ttrunk, entry, handle, inst->userobj_membership_attr);
                        if (rcode != RLM_MODULE_OK) {
                                goto finish;
                        }
                }
 
-               rlm_ldap_cacheable_groupobj(&rcode, inst, request, &conn);
+               rlm_ldap_cacheable_groupobj(&rcode, inst, request, ttrunk);
                if (rcode != RLM_MODULE_OK) {
                        goto finish;
                }
@@ -1353,7 +1313,7 @@ static unlang_action_t CC_HINT(nonnull) mod_authorize(rlm_rcode_t *p_result, mod
                /*
                 *      Retrive universal password
                 */
-               res = fr_ldap_edir_get_password(conn->handle, dn, password, &pass_size);
+               res = fr_ldap_edir_get_password(handle, dn, password, &pass_size);
                if (res != 0) {
                        REDEBUG("Failed to retrieve eDirectory password: (%i) %s", res, fr_ldap_edir_errstr(res));
                        rcode = RLM_MODULE_FAIL;
@@ -1378,35 +1338,14 @@ static unlang_action_t CC_HINT(nonnull) mod_authorize(rlm_rcode_t *p_result, mod
                        /*
                         *      Bind as the user
                         */
-                       conn->rebound = true;
-                       status = fr_ldap_bind(request, &conn, dn, vp->vp_strvalue, NULL,
-                                             fr_time_delta_wrap(0), NULL, NULL);
-                       switch (status) {
-                       case LDAP_PROC_SUCCESS:
-                               rcode = RLM_MODULE_OK;
-                               RDEBUG2("Bind as user '%s' was successful", dn);
-                               break;
-
-                       case LDAP_PROC_NOT_PERMITTED:
-                               rcode = RLM_MODULE_DISALLOW;
-                               goto finish;
-
-                       case LDAP_PROC_REJECT:
-                               rcode = RLM_MODULE_REJECT;
-                               goto finish;
-
-                       case LDAP_PROC_BAD_DN:
-                               rcode = RLM_MODULE_INVALID;
+                       if (fr_ldap_bind_auth_async(request, thread, dn, vp->vp_strvalue) < 0) {
+                               rcode = RLM_MODULE_FAIL;
                                goto finish;
+                       }
 
-                       case LDAP_PROC_NO_RESULT:
-                               rcode = RLM_MODULE_NOTFOUND;
-                               goto finish;
+                       rcode = unlang_interpret_synchronous(unlang_interpret_event_list(request), request);
 
-                       default:
-                               rcode = RLM_MODULE_FAIL;
-                               goto finish;
-                       };
+                       if (rcode != RLM_MODULE_OK) goto finish;
                }
        }
 
@@ -1429,7 +1368,7 @@ skip_edir:
                        goto finish;
                }
 
-               rlm_ldap_map_profile(&ret, inst, request, &conn, profile, &expanded);
+               rlm_ldap_map_profile(&ret, inst, request, ttrunk, profile, &expanded);
                switch (ret) {
                case RLM_MODULE_INVALID:
                        rcode = RLM_MODULE_INVALID;
@@ -1451,14 +1390,14 @@ skip_edir:
         *      Apply a SET of user profiles.
         */
        if (inst->profile_attr) {
-               values = ldap_get_values_len(conn->handle, entry, inst->profile_attr);
+               values = ldap_get_values_len(handle, entry, inst->profile_attr);
                if (values != NULL) {
                        for (i = 0; values[i] != NULL; i++) {
                                rlm_rcode_t ret;
                                char *value;
 
                                value = fr_ldap_berval_to_string(request, values[i]);
-                               rlm_ldap_map_profile(&ret, inst, request, &conn, value, &expanded);
+                               rlm_ldap_map_profile(&ret, inst, request, ttrunk, value, &expanded);
                                talloc_free(value);
                                if (ret == RLM_MODULE_FAIL) {
                                        ldap_value_free_len(values);
@@ -1474,16 +1413,14 @@ skip_edir:
        if (!fr_dlist_empty(&inst->user_map) || inst->valuepair_attr) {
                RDEBUG2("Processing user attributes");
                RINDENT();
-               if (fr_ldap_map_do(request, conn, inst->valuepair_attr,
+               if (fr_ldap_map_do(request, handle, inst->valuepair_attr,
                                   &expanded, entry) > 0) rcode = RLM_MODULE_UPDATED;
                REXDENT();
-               rlm_ldap_check_reply(inst, request, conn);
+               rlm_ldap_check_reply(inst, request, ttrunk);
        }
 
 finish:
        talloc_free(expanded.ctx);
-       if (result) ldap_msgfree(result);
-       ldap_mod_conn_release(inst, request, conn);
 
        RETURN_MODULE_RCODE(rcode);
 }
@@ -1502,9 +1439,10 @@ static unlang_action_t user_modify(rlm_rcode_t *p_result, rlm_ldap_t const *inst
                                   request_t *request, ldap_acct_section_t *section)
 {
        rlm_rcode_t     rcode = RLM_MODULE_OK;
-       fr_ldap_rcode_t status;
+       fr_ldap_thread_t        *thread = talloc_get_type_abort(module_thread_by_data(inst)->data, fr_ldap_thread_t);
 
-       fr_ldap_connection_t    *conn = NULL;
+       fr_ldap_thread_trunk_t  *ttrunk = NULL;
+       fr_ldap_query_t         *query = NULL;
 
        LDAPMod         *mod_p[LDAP_MAX_ATTRMAP + 1], mod_s[LDAP_MAX_ATTRMAP];
        LDAPMod         **modify = mod_p;
@@ -1684,22 +1622,28 @@ static unlang_action_t user_modify(rlm_rcode_t *p_result, rlm_ldap_t const *inst
 
        mod_p[total] = NULL;
 
-       conn = mod_conn_get(inst, request);
-       if (!conn) RETURN_MODULE_FAIL;
+       ttrunk = fr_thread_ldap_trunk_get(thread, inst->handle_config.server, inst->handle_config.admin_identity,
+                                         inst->handle_config.admin_password, request, &inst->handle_config);
 
 
-       dn = rlm_ldap_find_user(inst, request, &conn, NULL, false, NULL, &rcode);
+       dn = rlm_ldap_find_user(inst, request, ttrunk, NULL, false, NULL, NULL, &rcode);
        if (!dn || (rcode != RLM_MODULE_OK)) {
                goto error;
        }
 
-       status = fr_ldap_modify(request, &conn, dn, modify, NULL, NULL);
-       switch (status) {
-       case LDAP_PROC_SUCCESS:
+       if (fr_ldap_trunk_modify(unlang_interpret_frame_talloc_ctx(request), &query, request, ttrunk, dn,
+                                modify, NULL, NULL) < 0 ){
+               rcode = RLM_MODULE_FAIL;
+               goto error;
+       }
+
+       rcode = unlang_interpret_synchronous(unlang_interpret_event_list(request), request);
+
+       switch (rcode) {
+       case RLM_MODULE_OK:
                break;
 
-       case LDAP_PROC_REJECT:
-       case LDAP_PROC_BAD_DN:
+       case RLM_MODULE_NOTFOUND:
                rcode = RLM_MODULE_INVALID;
                break;
 
@@ -1715,8 +1659,6 @@ error:
         */
        for (i = 0; i < last_exp; i++) talloc_free(expanded[i]);
 
-       ldap_mod_conn_release(inst, request, conn);
-
        RETURN_MODULE_RCODE(rcode);
 }
 
@@ -2409,13 +2351,6 @@ if (inst->handle_config.tls_min_version_str) {
         */
        if (fr_ldap_init() < 0) goto error;
 
-       /*
-        *      Initialize the socket pool.
-        */
-       inst->pool = module_connection_pool_init(inst->cs, &inst->handle_config,
-                                                ldap_mod_conn_create, NULL, NULL, NULL, NULL);
-       if (!inst->pool) goto error;
-
        fr_ldap_global_config(inst->ldap_debug, inst->tls_random_file);
 
        return 0;
index 0bc704067c8332e742a3de018b864e5fe89d053e..e268f07b327c9f71fa7414c51c7ac35d83182763 100644 (file)
@@ -164,30 +164,29 @@ extern fr_dict_attr_t const *attr_user_name;
 /*
  *     user.c - User lookup functions
  */
-char const *rlm_ldap_find_user(rlm_ldap_t const *inst, request_t *request, fr_ldap_connection_t **pconn,
-                              char const *attrs[], bool force, LDAPMessage **result, rlm_rcode_t *rcode);
+char const *rlm_ldap_find_user(rlm_ldap_t const *inst, request_t *request, fr_ldap_thread_trunk_t *tconn,
+                              char const *attrs[], bool force, LDAPMessage **result, LDAP **handle, rlm_rcode_t *rcode);
 
-rlm_rcode_t rlm_ldap_check_access(rlm_ldap_t const *inst, request_t *request,
-                                 fr_ldap_connection_t const *conn, LDAPMessage *entry);
+rlm_rcode_t rlm_ldap_check_access(rlm_ldap_t const *inst, request_t *request, LDAP *handle, LDAPMessage *entry);
 
-void rlm_ldap_check_reply(rlm_ldap_t const *inst, request_t *request, fr_ldap_connection_t const *conn);
+void rlm_ldap_check_reply(rlm_ldap_t const *inst, request_t *request, fr_ldap_thread_trunk_t const *ttrunk);
 
 /*
  *     groups.c - Group membership functions.
  */
 unlang_action_t rlm_ldap_cacheable_userobj(rlm_rcode_t *p_result, rlm_ldap_t const *inst,
-                                          request_t *request, fr_ldap_connection_t **pconn,
-                                          LDAPMessage *entry, char const *attr);
+                                          request_t *request, fr_ldap_thread_trunk_t *ttrunk,
+                                          LDAPMessage *entry, LDAP *handle, char const *attr);
 
 unlang_action_t rlm_ldap_cacheable_groupobj(rlm_rcode_t *p_result,
-                                           rlm_ldap_t const *inst, request_t *request, fr_ldap_connection_t **pconn);
+                                           rlm_ldap_t const *inst, request_t *request, fr_ldap_thread_trunk_t *ttrunk);
 
 unlang_action_t rlm_ldap_check_groupobj_dynamic(rlm_rcode_t *p_result,
-                                               rlm_ldap_t const *inst, request_t *request, fr_ldap_connection_t **pconn,
+                                               rlm_ldap_t const *inst, request_t *request, fr_ldap_thread_trunk_t *ttrunk,
                                                fr_pair_t const *check);
 
 unlang_action_t rlm_ldap_check_userobj_dynamic(rlm_rcode_t *p_result,
-                                              rlm_ldap_t const *inst, request_t *request, fr_ldap_connection_t **pconn,
+                                              rlm_ldap_t const *inst, request_t *request, fr_ldap_thread_trunk_t *ttrunk,
                                               char const *dn, fr_pair_t const *check);
 
 unlang_action_t rlm_ldap_check_cached(rlm_rcode_t *p_result,
index b84768a5d4fc9c01f9c52602f4446e6b2dac05b7..dc44d6ef3e101b3f061f950dfc7d77c24138e723 100644 (file)
@@ -47,19 +47,18 @@ USES_APPLE_DEPRECATED_API
  *
  * @param[in] inst rlm_ldap configuration.
  * @param[in] request Current request.
- * @param[in,out] pconn to use. May change as this function calls functions which auto re-connect.
+ * @param[in] ttrunk LDAP thread trunk to use.
  * @param[in] attrs Additional attributes to retrieve, may be NULL.
  * @param[in] force Query even if the User-DN already exists.
  * @param[out] result Where to write the result, may be NULL in which case result is discarded.
  * @param[out] rcode The status of the operation, one of the RLM_MODULE_* codes.
  * @return The user's DN or NULL on error.
  */
-char const *rlm_ldap_find_user(rlm_ldap_t const *inst, request_t *request, fr_ldap_connection_t **pconn,
-                              char const *attrs[], bool force, LDAPMessage **result, rlm_rcode_t *rcode)
+char const *rlm_ldap_find_user(rlm_ldap_t const *inst, request_t *request, fr_ldap_thread_trunk_t *ttrunk,
+                              char const *attrs[], bool force, LDAPMessage **result, LDAP **handle, rlm_rcode_t *rcode)
 {
        static char const *tmp_attrs[] = { NULL };
 
-       fr_ldap_rcode_t status;
        fr_pair_t       *vp = NULL;
        LDAPMessage     *tmp_msg = NULL, *entry = NULL;
        int             ldap_errno;
@@ -70,6 +69,7 @@ char const *rlm_ldap_find_user(rlm_ldap_t const *inst, request_t *request, fr_ld
        char const      *base_dn;
        char            base_dn_buff[LDAP_MAX_DN_STR_LEN];
        LDAPControl     *serverctrls[] = { inst->userobj_sort_ctrl, NULL };
+       fr_ldap_query_t *query = NULL;
 
        bool freeit = false;                                    //!< Whether the message should
                                                                //!< be freed after being processed.
@@ -98,23 +98,6 @@ char const *rlm_ldap_find_user(rlm_ldap_t const *inst, request_t *request, fr_ld
                }
        }
 
-       /*
-        *      Perform all searches as the admin user.
-        */
-       if ((*pconn)->rebound) {
-               status = fr_ldap_bind(request, pconn, (*pconn)->config->admin_identity,
-                                     (*pconn)->config->admin_password, &(*pconn)->config->admin_sasl,
-                                     fr_time_delta_wrap(0), NULL, NULL);
-               if (status != LDAP_PROC_SUCCESS) {
-                       *rcode = RLM_MODULE_FAIL;
-                       return NULL;
-               }
-
-               fr_assert(*pconn);
-
-               (*pconn)->rebound = false;
-       }
-
        if (inst->userobj_filter) {
                if (tmpl_expand(&filter, filter_buff, sizeof(filter_buff), request, inst->userobj_filter,
                                fr_ldap_escape_func, NULL) < 0) {
@@ -133,23 +116,16 @@ char const *rlm_ldap_find_user(rlm_ldap_t const *inst, request_t *request, fr_ld
                return NULL;
        }
 
-       status = fr_ldap_search(result, request, pconn, base_dn,
-                               inst->userobj_scope, filter, attrs, serverctrls, NULL);
-       switch (status) {
-       case LDAP_PROC_SUCCESS:
-               break;
-
-       case LDAP_PROC_BAD_DN:
-       case LDAP_PROC_NO_RESULT:
-               *rcode = RLM_MODULE_NOTFOUND;
-               return NULL;
-
-       default:
+       if (fr_ldap_trunk_search(unlang_interpret_frame_talloc_ctx(request), &query ,request, ttrunk, base_dn,
+                               inst->userobj_scope, filter, attrs, serverctrls, NULL) < 0) {
                *rcode = RLM_MODULE_FAIL;
                return NULL;
        }
+       *rcode = unlang_interpret_synchronous(unlang_interpret_event_list(request), request);
+
+       if (*rcode != RLM_MODULE_OK) return NULL;
 
-       fr_assert(*pconn);
+       *result = query->result;
 
        /*
         *      Forbid the use of unsorted search results that
@@ -157,16 +133,16 @@ char const *rlm_ldap_find_user(rlm_ldap_t const *inst, request_t *request, fr_ld
         *      security issue, and likely non deterministic.
         */
        if (!inst->userobj_sort_ctrl) {
-               cnt = ldap_count_entries((*pconn)->handle, *result);
+               cnt = ldap_count_entries(query->ldap_conn->handle, *result);
                if (cnt > 1) {
                        REDEBUG("Ambiguous search result, returned %i unsorted entries (should return 1 or 0).  "
                                "Enable sorting, or specify a more restrictive base_dn, filter or scope", cnt);
                        REDEBUG("The following entries were returned:");
                        RINDENT();
-                       for (entry = ldap_first_entry((*pconn)->handle, *result);
+                       for (entry = ldap_first_entry(query->ldap_conn->handle, *result);
                             entry;
-                            entry = ldap_next_entry((*pconn)->handle, entry)) {
-                               dn = ldap_get_dn((*pconn)->handle, entry);
+                            entry = ldap_next_entry(query->ldap_conn->handle, entry)) {
+                               dn = ldap_get_dn(query->ldap_conn->handle, entry);
                                REDEBUG("%s", dn);
                                ldap_memfree(dn);
                        }
@@ -176,18 +152,18 @@ char const *rlm_ldap_find_user(rlm_ldap_t const *inst, request_t *request, fr_ld
                }
        }
 
-       entry = ldap_first_entry((*pconn)->handle, *result);
+       entry = ldap_first_entry(query->ldap_conn->handle, *result);
        if (!entry) {
-               ldap_get_option((*pconn)->handle, LDAP_OPT_RESULT_CODE, &ldap_errno);
+               ldap_get_option(query->ldap_conn->handle, LDAP_OPT_RESULT_CODE, &ldap_errno);
                REDEBUG("Failed retrieving entry: %s",
                        ldap_err2string(ldap_errno));
 
                goto finish;
        }
 
-       dn = ldap_get_dn((*pconn)->handle, entry);
+       dn = ldap_get_dn(query->ldap_conn->handle, entry);
        if (!dn) {
-               ldap_get_option((*pconn)->handle, LDAP_OPT_RESULT_CODE, &ldap_errno);
+               ldap_get_option(query->ldap_conn->handle, LDAP_OPT_RESULT_CODE, &ldap_errno);
                REDEBUG("Retrieving object DN from entry failed: %s", ldap_err2string(ldap_errno));
 
                goto finish;
@@ -198,15 +174,15 @@ char const *rlm_ldap_find_user(rlm_ldap_t const *inst, request_t *request, fr_ld
 
        MEM(pair_update_control(&vp, attr_ldap_userdn) >= 0);
        fr_pair_value_strdup(vp, dn, false);
-       *rcode = RLM_MODULE_OK;
+       if (handle) *handle = query->ldap_conn->handle;
 
        ldap_memfree(dn);
 
 finish:
-       if ((freeit || (*rcode != RLM_MODULE_OK)) && *result) {
-               ldap_msgfree(*result);
-               *result = NULL;
-       }
+       /*
+        *      Actual freeing of the result is handled by the query destructor
+        */
+       if ((freeit || (*rcode != RLM_MODULE_OK)) && *result) *result = NULL;
 
        return vp ? vp->vp_strvalue : NULL;
 }
@@ -215,19 +191,18 @@ finish:
  *
  * @param[in] inst rlm_ldap configuration.
  * @param[in] request Current request.
- * @param[in] conn used to retrieve access attributes.
+ * @param[in] handle used to retrieve access attributes.
  * @param[in] entry retrieved by rlm_ldap_find_user or fr_ldap_search.
  * @return
  *     - #RLM_MODULE_DISALLOW if the user was denied access.
  *     - #RLM_MODULE_OK otherwise.
  */
-rlm_rcode_t rlm_ldap_check_access(rlm_ldap_t const *inst, request_t *request,
-                                 fr_ldap_connection_t const *conn, LDAPMessage *entry)
+rlm_rcode_t rlm_ldap_check_access(rlm_ldap_t const *inst, request_t *request, LDAP *handle, LDAPMessage *entry)
 {
        rlm_rcode_t rcode = RLM_MODULE_OK;
        struct berval **values = NULL;
 
-       values = ldap_get_values_len(conn->handle, entry, inst->userobj_access_attr);
+       values = ldap_get_values_len(handle, entry, inst->userobj_access_attr);
        if (values) {
                if (inst->access_positive) {
                        if ((values[0]->bv_len >= 5) && (strncasecmp(values[0]->bv_val, "false", 5) == 0)) {
@@ -255,9 +230,9 @@ rlm_rcode_t rlm_ldap_check_access(rlm_ldap_t const *inst, request_t *request,
  *
  * @param inst rlm_ldap configuration.
  * @param request Current request.
- * @param conn the connection handle
+ * @param ttrunk the connection thread trunk.
  */
-void rlm_ldap_check_reply(rlm_ldap_t const *inst, request_t *request, fr_ldap_connection_t const *conn)
+void rlm_ldap_check_reply(rlm_ldap_t const *inst, request_t *request, fr_ldap_thread_trunk_t const *ttrunk)
 {
        /*
        *       More warning messages for people who can't be bothered to read the documentation.
@@ -272,7 +247,7 @@ void rlm_ldap_check_reply(rlm_ldap_t const *inst, request_t *request, fr_ldap_co
            !fr_pair_find_by_da(&request->control_pairs, attr_user_password, 0) &&
            !fr_pair_find_by_da(&request->control_pairs, attr_password_with_header, 0) &&
            !fr_pair_find_by_da(&request->control_pairs, attr_crypt_password, 0)) {
-               switch (conn->directory->type) {
+               switch (ttrunk->directory->type) {
                case FR_LDAP_DIRECTORY_ACTIVE_DIRECTORY:
                        RWDEBUG2("!!! Found map between LDAP attribute and a FreeRADIUS password attribute");
                        RWDEBUG2("!!! Active Directory does not allow passwords to be read via LDAP");
@@ -303,13 +278,13 @@ void rlm_ldap_check_reply(rlm_ldap_t const *inst, request_t *request, fr_ldap_co
                        break;
 
                default:
-                       if (!conn->config->admin_identity) {
+                       if (!ttrunk->config.admin_identity) {
                                RWDEBUG2("!!! Found map between LDAP attribute and a FreeRADIUS password attribute");
                                RWDEBUG2("!!! but no password attribute found in search result");
                                RWDEBUG2("!!! Either:");
                                RWDEBUG2("!!!  - Ensure the user object contains a password attribute, and that");
                                RWDEBUG2("!!!    \"%s\" has permission to read that password attribute (recommended)",
-                                        conn->config->admin_identity);
+                                        ttrunk->config.admin_identity);
                                RWDEBUG2("!!!  - Bind as the user by listing %s in the authenticate section, and",
                                         inst->name);
                                RWDEBUG2("!!!   setting attribute &control.Auth-Type := '%s' in the authorize section",