From: Nick Porter Date: Tue, 28 Mar 2023 13:40:56 +0000 (+0100) Subject: Rework rlm_ldap_cacheable_groupobj() to use async queries X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=5ba9dfec97a43dee495f8f4defa371c4aa021dea;p=thirdparty%2Ffreeradius-server.git Rework rlm_ldap_cacheable_groupobj() to use async queries --- diff --git a/src/modules/rlm_ldap/groups.c b/src/modules/rlm_ldap/groups.c index c4eb380a8c..5a5cb02ca4 100644 --- a/src/modules/rlm_ldap/groups.c +++ b/src/modules/rlm_ldap/groups.c @@ -54,6 +54,18 @@ typedef struct { fr_ldap_query_t *query; //!< Current query performing group resolution. } ldap_group_userobj_ctx_t; +/** Context to use when looking up group membership using group objects. + * + */ +typedef struct { + rlm_ldap_t const *inst; //!< Module instance. + fr_value_box_t *base_dn; //!< The base DN to search for groups in. + fr_ldap_thread_trunk_t *ttrunk; //!< Trunk on which to perform additional queries. + char filter[LDAP_MAX_FILTER_STR_LEN + 1]; //!< Filter used to search for groups. + char const *attrs[2]; //!< For retrieving the group name. + fr_ldap_query_t *query; //!< Current query performing group lookup. +} ldap_group_groupojb_ctx_t; + /** Cancel a pending group lookup query * */ @@ -602,67 +614,70 @@ unlang_action_t rlm_ldap_cacheable_userobj(rlm_rcode_t *p_result, request_t *req return ldap_cacheable_userobj_store(p_result, request, group_ctx); } -/** Convert group membership information into attributes +/** Initiate an LDAP search for group membership looking at the group objects * - * @param[out] p_result The result of trying to resolve a dn to a group name. - * @param[in] inst rlm_ldap configuration. + * @param[out] p_result Result of submitting LDAP search + * @param[out] priority Unused. * @param[in] request Current request. - * @param[in] ttrunk to use. + * @param[in] uctx Group lookup context. * @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_thread_trunk_t *ttrunk) +static unlang_action_t ldap_cacheable_groupobj_start(rlm_rcode_t *p_result, UNUSED int *priority, request_t *request, + void *uctx) { - rlm_rcode_t rcode = RLM_MODULE_OK; - int ldap_errno; - - LDAPMessage *entry; - fr_ldap_query_t *query; - - char const *base_dn; - char base_dn_buff[LDAP_MAX_DN_STR_LEN]; - - char const *filters[] = { inst->groupobj_filter, inst->groupobj_membership_filter }; - char filter[LDAP_MAX_FILTER_STR_LEN + 1]; - - char const *attrs[] = { inst->groupobj_name_attr, NULL }; - - fr_pair_t *vp; - char *dn; + ldap_group_groupojb_ctx_t *group_ctx = talloc_get_type_abort(uctx, ldap_group_groupojb_ctx_t); + rlm_ldap_t const *inst = group_ctx->inst; - fr_assert(inst->groupobj_base_dn); + group_ctx->attrs[0] = inst->groupobj_name_attr; + return fr_ldap_trunk_search(p_result, group_ctx, &group_ctx->query, request, group_ctx->ttrunk, + group_ctx->base_dn->vb_strvalue, inst->groupobj_scope, + group_ctx->filter, group_ctx->attrs, NULL, NULL, true); - if (!inst->groupobj_membership_filter) { - RDEBUG2("Skipping caching group objects as directive 'group.membership_filter' is not set"); +} - RETURN_MODULE_OK; - } +/** Cancel a pending group object lookup. + * + */ +static void ldap_group_groupobj_cancel(UNUSED request_t *request, UNUSED fr_signal_t action, void *uctx) +{ + ldap_group_groupojb_ctx_t *group_ctx = talloc_get_type_abort(uctx, ldap_group_groupojb_ctx_t); - if (fr_ldap_xlat_filter(request, - filters, NUM_ELEMENTS(filters), - filter, sizeof(filter)) < 0) { - RETURN_MODULE_INVALID; - } + /* + * If the query is not in flight, just return + */ + if (!group_ctx->query || !group_ctx->query->treq) return; - if (tmpl_expand(&base_dn, base_dn_buff, sizeof(base_dn_buff), request, - inst->groupobj_base_dn, fr_ldap_escape_func, NULL) < 0) { - REDEBUG("Failed creating base_dn"); + fr_trunk_request_signal_cancel(group_ctx->query->treq); +} - RETURN_MODULE_INVALID; - } +/** Process the results of a group object lookup. + * + * @param[out] p_result Result of processing group lookup. + * @param[out] priority Unused. + * @param[in] request Current request. + * @param[in] uctx Group lookup context. + * @return One of the RLM_MODULE_* values. + */ +static unlang_action_t ldap_cacheable_groupobj_resume(rlm_rcode_t *p_result, UNUSED int *priority, request_t *request, + void *uctx) +{ + ldap_group_groupojb_ctx_t *group_ctx = talloc_get_type_abort(uctx, ldap_group_groupojb_ctx_t); + rlm_ldap_t const *inst = group_ctx->inst; + fr_ldap_query_t *query = group_ctx->query; + rlm_rcode_t rcode = RLM_MODULE_OK; + LDAPMessage *entry; + int ldap_errno; + char *dn; + fr_pair_t *vp; - if (fr_ldap_trunk_search(&rcode, - unlang_interpret_frame_talloc_ctx(request), &query, request, ttrunk, base_dn, - inst->groupobj_scope, filter, attrs, NULL, NULL, false) < 0) { - rcode = RLM_MODULE_FAIL; - goto finish; - } - switch (rcode) { - case RLM_MODULE_OK: + switch (query->ret) { + case LDAP_SUCCESS: break; - case RLM_MODULE_NOTFOUND: + case LDAP_RESULT_NO_RESULT: + case LDAP_RESULT_BAD_DN: RDEBUG2("No cacheable group memberships found in group objects"); + rcode = RLM_MODULE_NOTFOUND; goto finish; default: @@ -717,10 +732,54 @@ unlang_action_t rlm_ldap_cacheable_groupobj(rlm_rcode_t *p_result, rlm_ldap_t co } while ((entry = ldap_next_entry(query->ldap_conn->handle, entry))); finish: + talloc_free(group_ctx); RETURN_MODULE_RCODE(rcode); } +/** Convert group membership information into attributes + * + * @param[out] p_result The result of trying to resolve a dn to a group name. + * @param[in] request Current request. + * @param[in] autz_ctx Authentication context being processed. + * @return One of the RLM_MODULE_* values. + */ +unlang_action_t rlm_ldap_cacheable_groupobj(rlm_rcode_t *p_result, request_t *request, ldap_autz_ctx_t *autz_ctx) +{ + rlm_ldap_t const *inst = autz_ctx->inst; + ldap_group_groupojb_ctx_t *group_ctx; + char const *filters[] = { inst->groupobj_filter, inst->groupobj_membership_filter }; + + if (!inst->groupobj_membership_filter) { + RDEBUG2("Skipping caching group objects as directive 'group.membership_filter' is not set"); + RETURN_MODULE_OK; + } + + if (autz_ctx->mod_env->group_base.type != FR_TYPE_STRING) { + REDEBUG("Missing group base_dn"); + RETURN_MODULE_INVALID; + } + + MEM(group_ctx = talloc_zero(unlang_interpret_frame_talloc_ctx(request), ldap_group_groupojb_ctx_t)); + group_ctx->inst = inst; + group_ctx->ttrunk = autz_ctx->ttrunk; + group_ctx->base_dn = &autz_ctx->mod_env->group_base; + + if (fr_ldap_xlat_filter(request, filters, NUM_ELEMENTS(filters), + group_ctx->filter, sizeof(group_ctx->filter)) < 0) { + talloc_free(group_ctx); + RETURN_MODULE_INVALID; + } + + if (unlang_function_push(request, ldap_cacheable_groupobj_start, ldap_cacheable_groupobj_resume, + ldap_group_groupobj_cancel, ~FR_SIGNAL_CANCEL, UNLANG_SUB_FRAME, group_ctx) < 0) { + talloc_free(group_ctx); + RETURN_MODULE_FAIL; + } + + return UNLANG_ACTION_PUSHED_CHILD; +} + /** Query the LDAP directory to check if a group object includes a user object as a member * * @param[out] p_result Result of calling the module. diff --git a/src/modules/rlm_ldap/rlm_ldap.h b/src/modules/rlm_ldap/rlm_ldap.h index 64ca7d45b8..f5089c1577 100644 --- a/src/modules/rlm_ldap/rlm_ldap.h +++ b/src/modules/rlm_ldap/rlm_ldap.h @@ -208,8 +208,7 @@ void rlm_ldap_check_reply(module_ctx_t const *mctx, request_t *request, fr_ldap_ unlang_action_t rlm_ldap_cacheable_userobj(rlm_rcode_t *p_result, request_t *request, ldap_autz_ctx_t *autz_ctx, 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_thread_trunk_t *ttrunk); +unlang_action_t rlm_ldap_cacheable_groupobj(rlm_rcode_t *p_result, request_t *request, ldap_autz_ctx_t *autz_ctx); unlang_action_t rlm_ldap_check_groupobj_dynamic(rlm_rcode_t *p_result, rlm_ldap_t const *inst, request_t *request, fr_ldap_thread_trunk_t *ttrunk,