From: Nick Porter Date: Thu, 30 Mar 2023 18:41:19 +0000 (+0100) Subject: Rework LDAP profile lookup to use async queries X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=eac0877b9908e24cf9dc49c5a6be0cf4fc41b8a8;p=thirdparty%2Ffreeradius-server.git Rework LDAP profile lookup to use async queries --- diff --git a/src/modules/rlm_ldap/rlm_ldap.c b/src/modules/rlm_ldap/rlm_ldap.c index ceebe4af69..3514a47950 100644 --- a/src/modules/rlm_ldap/rlm_ldap.c +++ b/src/modules/rlm_ldap/rlm_ldap.c @@ -257,6 +257,16 @@ typedef struct { ldap_auth_mod_env_t *mod_env; } ldap_auth_ctx_t; +/** Holds state of in progress async profile lookups + * + */ +typedef struct { + fr_ldap_query_t *query; + char const *dn; + rlm_ldap_t const *inst; + fr_ldap_map_exp_t const *expanded; +} ldap_profile_ctx_t; + static xlat_arg_parser_t const ldap_escape_xlat_arg[] = { { .required = true, .concat = true, .type = FR_TYPE_STRING }, XLAT_ARG_PARSER_TERMINATOR @@ -1188,46 +1198,32 @@ static unlang_action_t CC_HINT(nonnull) mod_authenticate(rlm_rcode_t *p_result, return UNLANG_ACTION_PUSHED_CHILD; } -/** Search for and apply an LDAP profile +/** Process the results of a profile lookup * - * LDAP profiles are mapped using the same attribute map as user objects, they're used to add common - * sets of attributes to the request. - * - * @param[out] p_result the result of applying the profile. - * @param[in] request Current request. - * @param[in] autz_ctx Authorization context being processed. - * @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, request_t *request, ldap_autz_ctx_t *autz_ctx, - char const *dn, fr_ldap_map_exp_t const *expanded) +static unlang_action_t ldap_map_profile_resume(rlm_rcode_t *p_result, UNUSED int *priority, request_t *request, + void *uctx) { - rlm_ldap_t const *inst = autz_ctx->inst; - fr_ldap_thread_trunk_t *ttrunk = autz_ctx->ttrunk; - rlm_rcode_t rcode = RLM_MODULE_OK; - LDAPMessage *entry = NULL; - int ldap_errno; - LDAP *handle; - fr_ldap_query_t *query; - - if (!dn || !*dn) RETURN_MODULE_OK; + ldap_profile_ctx_t *profile_ctx = talloc_get_type_abort(uctx, ldap_profile_ctx_t); + fr_ldap_query_t *query = profile_ctx->query; + LDAP *handle; + LDAPMessage *entry = NULL; + int ldap_errno; + rlm_rcode_t rcode = RLM_MODULE_OK; - if (fr_ldap_trunk_search(&rcode, - unlang_interpret_frame_talloc_ctx(request), &query, request, ttrunk, dn, - LDAP_SCOPE_BASE, autz_ctx->mod_env->profile_filter.vb_strvalue, - expanded->attrs, NULL, NULL, false) < 0) RETURN_MODULE_FAIL; - switch (rcode) { - case RLM_MODULE_OK: + switch (query->ret) { + case LDAP_RESULT_SUCCESS: break; - case RLM_MODULE_NOTFOUND: - RDEBUG2("Profile object \"%s\" not found", dn); - RETURN_MODULE_NOTFOUND; + case LDAP_RESULT_NO_RESULT: + case LDAP_RESULT_BAD_DN: + RDEBUG2("Profile object \"%s\" not found", profile_ctx->dn); + rcode = RLM_MODULE_NOTFOUND; + goto finish; default: - RETURN_MODULE_FAIL; + rcode = RLM_MODULE_FAIL; + goto finish; } fr_assert(query->result); @@ -1237,18 +1233,73 @@ static unlang_action_t rlm_ldap_map_profile(rlm_rcode_t *p_result, request_t *re if (!entry) { ldap_get_option(handle, LDAP_OPT_RESULT_CODE, &ldap_errno); REDEBUG("Failed retrieving entry: %s", ldap_err2string(ldap_errno)); - - RETURN_MODULE_RCODE(RLM_MODULE_NOTFOUND); + rcode = RLM_MODULE_NOTFOUND; + goto finish; } RDEBUG2("Processing profile attributes"); RINDENT(); - if (fr_ldap_map_do(request, inst->valuepair_attr, expanded, entry) > 0) rcode = RLM_MODULE_UPDATED; + if (fr_ldap_map_do(request, profile_ctx->inst->valuepair_attr, + profile_ctx->expanded, entry) > 0) rcode = RLM_MODULE_UPDATED; REXDENT(); +finish: + talloc_free(profile_ctx); RETURN_MODULE_RCODE(rcode); } +/** Cancel an in progress profile lookup + * + */ +static void ldap_map_profile_cancel(UNUSED request_t *request, UNUSED fr_signal_t action, void *uctx) +{ + ldap_profile_ctx_t *profile_ctx = talloc_get_type_abort(uctx, ldap_profile_ctx_t); + + if (!profile_ctx->query || !profile_ctx->query->treq) return; + + fr_trunk_request_signal_cancel(profile_ctx->query->treq); +} + +/** Search for and apply an LDAP profile + * + * LDAP profiles are mapped using the same attribute map as user objects, they're used to add common + * sets of attributes to the request. + * + * @param[in] request Current request. + * @param[in] autz_ctx Authorization context being processed. + * @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(request_t *request, ldap_autz_ctx_t *autz_ctx, + char const *dn, fr_ldap_map_exp_t const *expanded) +{ + rlm_ldap_t const *inst = autz_ctx->inst; + fr_ldap_thread_trunk_t *ttrunk = autz_ctx->ttrunk; + ldap_profile_ctx_t *profile_ctx; + rlm_rcode_t ret; + + if (!dn || !*dn) return UNLANG_ACTION_CALCULATE_RESULT; + + MEM(profile_ctx = talloc(unlang_interpret_frame_talloc_ctx(request), ldap_profile_ctx_t)); + *profile_ctx = (ldap_profile_ctx_t) { + .dn = dn, + .expanded = expanded, + .inst = inst + }; + + if (unlang_function_push(request, NULL, ldap_map_profile_resume, ldap_map_profile_cancel, + ~FR_SIGNAL_CANCEL, UNLANG_SUB_FRAME, profile_ctx) < 0) { + talloc_free(profile_ctx); + return UNLANG_ACTION_FAIL; + } + + return fr_ldap_trunk_search(&ret, profile_ctx, &profile_ctx->query, request, ttrunk, dn, + LDAP_SCOPE_BASE, autz_ctx->mod_env->profile_filter.vb_strvalue, + expanded->attrs, NULL, NULL, true); +} + /** Start LDAP authorization with async lookup of user DN * */ diff --git a/src/modules/rlm_ldap/rlm_ldap.h b/src/modules/rlm_ldap/rlm_ldap.h index f5089c1577..df415f60ea 100644 --- a/src/modules/rlm_ldap/rlm_ldap.h +++ b/src/modules/rlm_ldap/rlm_ldap.h @@ -166,6 +166,9 @@ typedef struct { ldap_autz_mod_env_t *mod_env; LDAPMessage *entry; ldap_autz_status_t status; + struct berval **profile_values; + int value_idx; + char *profile_value; } ldap_autz_ctx_t; extern HIDDEN fr_dict_attr_t const *attr_cleartext_password;