From: Nick Porter Date: Wed, 13 Oct 2021 19:35:26 +0000 (+0100) Subject: v4: Move rlm_ldap to use trunk connections in place of connection pool (#4265) X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=8365ed0709ed673119e72fbaa053868b4d41c520;p=thirdparty%2Ffreeradius-server.git v4: Move rlm_ldap to use trunk connections in place of connection pool (#4265) * 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 --- diff --git a/src/lib/ldap/base.h b/src/lib/ldap/base.h index 6a1a24786e5..bef33084cf9 100644 --- a/src/lib/ldap/base.h +++ b/src/lib/ldap/base.h @@ -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); /* diff --git a/src/lib/ldap/map.c b/src/lib/ldap/map.c index c2957c9a9ee..1ad59110156 100644 --- a/src/lib/ldap/map.c +++ b/src/lib/ldap/map.c @@ -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++) { diff --git a/src/modules/proto_ldap_sync/proto_ldap_sync.c b/src/modules/proto_ldap_sync/proto_ldap_sync.c index f4b88f2fd78..b46616a6f28 100644 --- a/src/modules/proto_ldap_sync/proto_ldap_sync.c +++ b/src/modules/proto_ldap_sync/proto_ldap_sync.c @@ -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); diff --git a/src/modules/rlm_ldap/groups.c b/src/modules/rlm_ldap/groups.c index 522b9918326..4f3e5f315a4 100644 --- a/src/modules/rlm_ldap/groups.c +++ b/src/modules/rlm_ldap/groups.c @@ -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); } diff --git a/src/modules/rlm_ldap/rlm_ldap.c b/src/modules/rlm_ldap/rlm_ldap.c index f8c7d641d12..8c5a50b9889 100644 --- a/src/modules/rlm_ldap/rlm_ldap.c +++ b/src/modules/rlm_ldap/rlm_ldap.c @@ -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 :/// 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; diff --git a/src/modules/rlm_ldap/rlm_ldap.h b/src/modules/rlm_ldap/rlm_ldap.h index 0bc704067c8..e268f07b327 100644 --- a/src/modules/rlm_ldap/rlm_ldap.h +++ b/src/modules/rlm_ldap/rlm_ldap.h @@ -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, diff --git a/src/modules/rlm_ldap/user.c b/src/modules/rlm_ldap/user.c index b84768a5d4f..dc44d6ef3e1 100644 --- a/src/modules/rlm_ldap/user.c +++ b/src/modules/rlm_ldap/user.c @@ -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",