From: Nick Porter Date: Fri, 28 Apr 2023 13:39:31 +0000 (+0100) Subject: Rework rlm_ldap_check_groupobj_dynamic to be async X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=cf8fd11a11ca91567419671f08de148e1fb0761f;p=thirdparty%2Ffreeradius-server.git Rework rlm_ldap_check_groupobj_dynamic to be async --- diff --git a/src/modules/rlm_ldap/groups.c b/src/modules/rlm_ldap/groups.c index d22395146b3..21aa550fb67 100644 --- a/src/modules/rlm_ldap/groups.c +++ b/src/modules/rlm_ldap/groups.c @@ -64,6 +64,7 @@ typedef struct { 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. + void *uctx; //!< Optional context for use in results parsing. } ldap_group_groupobj_ctx_t; /** Cancel a pending group lookup query @@ -780,55 +781,87 @@ unlang_action_t rlm_ldap_cacheable_groupobj(rlm_rcode_t *p_result, request_t *re return UNLANG_ACTION_PUSHED_CHILD; } -/** Query the LDAP directory to check if a group object includes a user object as a member +/** Process the results of a group object lookup. * - * @param[out] p_result Result of calling the module. - * @param[in] inst rlm_ldap configuration. + * @param[out] p_result Result of processing group lookup. + * @param[out] priority Unused. * @param[in] request Current request. - * @param[in] ttrunk to use. - * @param[in] check vp containing the group value (name or dn). + * @param[in] uctx Group lookup context. + * @return One of the RLM_MODULE_* values. */ -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, fr_pair_t const *check) +static unlang_action_t ldap_check_groupobj_resume(rlm_rcode_t *p_result, UNUSED int *priority, request_t *request, + void *uctx) { - rlm_rcode_t rcode; - fr_ldap_query_t *query = NULL; - - char const *base_dn; - char base_dn_buff[LDAP_MAX_DN_STR_LEN + 1]; - char filter[LDAP_MAX_FILTER_STR_LEN + 1]; - int ret; + ldap_group_groupobj_ctx_t *group_ctx = talloc_get_type_abort(uctx, ldap_group_groupobj_ctx_t); + ldap_memberof_xlat_ctx_t *xlat_ctx = talloc_get_type_abort(group_ctx->uctx, ldap_memberof_xlat_ctx_t); + fr_ldap_query_t *query = group_ctx->query; + rlm_rcode_t rcode = RLM_MODULE_OK; - fr_assert(inst->groupobj_base_dn); + switch (query->ret) { + case LDAP_SUCCESS: + xlat_ctx->found = true; + if (RDEBUG_ENABLED2) { + LDAPMessage *entry = NULL; + char *dn = NULL; + entry = ldap_first_entry(query->ldap_conn->handle, query->result); + if (entry) dn = ldap_get_dn(query->ldap_conn->handle, entry); + RDEBUG2("User found in group object \"%pV\"", fr_box_strvalue(dn)); + ldap_memfree(dn); + } + break; - switch (check->op) { - case T_OP_CMP_EQ: - case T_OP_CMP_FALSE: - case T_OP_CMP_TRUE: - case T_OP_REG_EQ: - case T_OP_REG_NE: + case LDAP_RESULT_NO_RESULT: + case LDAP_RESULT_BAD_DN: + rcode = RLM_MODULE_NOTFOUND; break; default: - REDEBUG("Operator \"%s\" not allowed for LDAP group comparisons", - fr_table_str_by_value(fr_tokens_table, check->op, "")); - return 1; + rcode = RLM_MODULE_FAIL; + break; } - RDEBUG2("Checking for user in group objects"); + talloc_free(group_ctx); + RETURN_MODULE_RCODE(rcode); +} + +/** Initiate an LDAP search to determine group membership, querying group objects + * + * Used by LDAP group membership xlat + * + * @param p_result Current module result code. + * @param request Current request. + * @param xlat_ctx xlat context being processed. + */ +unlang_action_t rlm_ldap_check_groupobj_dynamic(rlm_rcode_t *p_result, request_t *request, + ldap_memberof_xlat_ctx_t *xlat_ctx) +{ + rlm_ldap_t const *inst = xlat_ctx->inst; + ldap_group_groupobj_ctx_t *group_ctx; + int ret; + + MEM(group_ctx = talloc(unlang_interpret_frame_talloc_ctx(request), ldap_group_groupobj_ctx_t)); + *group_ctx = (ldap_group_groupobj_ctx_t) { + .inst = inst, + .ttrunk = xlat_ctx->ttrunk, + .uctx = xlat_ctx + }; - if (fr_ldap_util_is_dn(check->vp_strvalue, check->vp_length)) { + if (fr_ldap_util_is_dn(xlat_ctx->group->vb_strvalue, xlat_ctx->group->vb_length)) { char const *filters[] = { inst->groupobj_filter, inst->groupobj_membership_filter }; RINDENT(); ret = fr_ldap_xlat_filter(request, - filters, NUM_ELEMENTS(filters), - filter, sizeof(filter)); + filters, NUM_ELEMENTS(filters), + group_ctx->filter, sizeof(group_ctx->filter)); REXDENT(); - if (ret < 0) RETURN_MODULE_INVALID; + if (ret < 0) { + invalid: + talloc_free(group_ctx); + RETURN_MODULE_INVALID; + } - base_dn = check->vp_strvalue; + group_ctx->base_dn = xlat_ctx->group; } else { char name_filter[LDAP_MAX_FILTER_STR_LEN]; char const *filters[] = { name_filter, inst->groupobj_filter, inst->groupobj_membership_filter }; @@ -837,53 +870,27 @@ unlang_action_t rlm_ldap_check_groupobj_dynamic(rlm_rcode_t *p_result, rlm_ldap_ REDEBUG("Told to search for group by name, but missing 'group.name_attribute' " "directive"); - RETURN_MODULE_INVALID; + goto invalid; } - snprintf(name_filter, sizeof(name_filter), "(%s=%s)", inst->groupobj_name_attr, check->vp_strvalue); + snprintf(name_filter, sizeof(name_filter), "(%s=%s)", + inst->groupobj_name_attr, xlat_ctx->group->vb_strvalue); RINDENT(); ret = fr_ldap_xlat_filter(request, - filters, NUM_ELEMENTS(filters), - filter, sizeof(filter)); + filters, NUM_ELEMENTS(filters), + group_ctx->filter, sizeof(group_ctx->filter)); REXDENT(); - if (ret < 0) RETURN_MODULE_INVALID; - - - /* - * rlm_ldap_find_user does this, too. Oh well. - */ - RINDENT(); - ret = tmpl_expand(&base_dn, base_dn_buff, sizeof(base_dn_buff), request, inst->groupobj_base_dn, - fr_ldap_escape_func, NULL); - REXDENT(); - if (ret < 0) { - REDEBUG("Failed creating base_dn"); - - RETURN_MODULE_INVALID; - } - } + if (ret < 0) goto invalid; - RINDENT(); - if (fr_ldap_trunk_search(&rcode, - unlang_interpret_frame_talloc_ctx(request), &query, request, ttrunk, base_dn, - inst->groupobj_scope, filter, NULL, NULL, NULL, false) < 0) { - REXDENT(); - RETURN_MODULE_FAIL; + fr_assert(xlat_ctx->env_data); + group_ctx->base_dn = &xlat_ctx->env_data->group_base; } - REXDENT(); - switch (rcode) { - case RLM_MODULE_OK: - RDEBUG2("User found in group object \"%s\"", base_dn); - break; - - case RLM_MODULE_NOTFOUND: - RETURN_MODULE_NOTFOUND; - default: - RETURN_MODULE_FAIL; - } + if (unlang_function_push(request, ldap_cacheable_groupobj_start, ldap_check_groupobj_resume, + ldap_group_groupobj_cancel, ~FR_SIGNAL_CANCEL, + UNLANG_SUB_FRAME, group_ctx) < 0) goto invalid; - RETURN_MODULE_OK; + return UNLANG_ACTION_PUSHED_CHILD; } /** Query the LDAP directory to check if a user object is a member of a group diff --git a/src/modules/rlm_ldap/rlm_ldap.h b/src/modules/rlm_ldap/rlm_ldap.h index e02ec04a5ed..dcdf375ada6 100644 --- a/src/modules/rlm_ldap/rlm_ldap.h +++ b/src/modules/rlm_ldap/rlm_ldap.h @@ -250,9 +250,8 @@ unlang_action_t rlm_ldap_cacheable_userobj(rlm_rcode_t *p_result, request_t *req 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, - fr_pair_t const *check); +unlang_action_t rlm_ldap_check_groupobj_dynamic(rlm_rcode_t *p_result, request_t *request, + ldap_memberof_xlat_ctx_t *xlat_ctx); unlang_action_t rlm_ldap_check_userobj_dynamic(rlm_rcode_t *p_result, rlm_ldap_t const *inst, request_t *request, fr_ldap_thread_trunk_t *ttrunk,