From: Nick Porter Date: Tue, 20 Sep 2022 16:47:20 +0000 (+0100) Subject: Use async user DN lookup in LDAP authentication X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=e665d913c93851e98a3d908786e33549700b079d;p=thirdparty%2Ffreeradius-server.git Use async user DN lookup in LDAP authentication --- diff --git a/src/modules/rlm_ldap/rlm_ldap.c b/src/modules/rlm_ldap/rlm_ldap.c index b4925d59a1..10758b1623 100644 --- a/src/modules/rlm_ldap/rlm_ldap.c +++ b/src/modules/rlm_ldap/rlm_ldap.c @@ -257,6 +257,18 @@ global_lib_autoinst_t const *rlm_ldap_lib[] = { GLOBAL_LIB_TERMINATOR }; +/** Holds state of in progress async authentication + * + */ +typedef struct { + char const *dn; + char const *password; + rlm_ldap_t const *inst; + fr_ldap_thread_t *thread; + fr_ldap_thread_trunk_t *ttrunk; + ldap_auth_mod_env_t *mod_env; +} ldap_auth_ctx_t; + static xlat_arg_parser_t const ldap_escape_xlat_arg[] = { { .required = true, .concat = true, .type = FR_TYPE_STRING }, XLAT_ARG_PARSER_TERMINATOR @@ -1028,13 +1040,55 @@ cleanup: return 1; } +/** Perform async lookup of user DN if required for authentication + * + */ +static unlang_action_t mod_authenticate_start(UNUSED rlm_rcode_t *p_result, UNUSED int *priority, + request_t *request, void *uctx) +{ + ldap_auth_ctx_t *auth_ctx = talloc_get_type_abort(uctx, ldap_auth_ctx_t); + + return rlm_ldap_find_user_async(auth_ctx, auth_ctx->inst, request, &auth_ctx->mod_env->user_base, + &auth_ctx->mod_env->user_filter, auth_ctx->ttrunk, NULL, NULL); +} + +/** Initiate async LDAP bind to authenticate user + * + */ +static unlang_action_t mod_authenticate_resume(rlm_rcode_t *p_result, UNUSED int *priority, + request_t *request, void *uctx) +{ + ldap_auth_ctx_t *auth_ctx = talloc_get_type_abort(uctx, ldap_auth_ctx_t); + + /* + * Arriving here from an LDAP search will mean the dn in auth_ctx is NULL. + */ + if (!auth_ctx->dn) auth_ctx->dn = rlm_find_user_dn_cached(request); + + /* + * No DN found - can't authenticate the user. + */ + if (!auth_ctx->dn) { + fail: + talloc_free(auth_ctx); + RETURN_MODULE_FAIL; + } + + /* + * Attempt a bind using the thread specific connection for bind auths + */ + if (fr_ldap_bind_auth_async(request, auth_ctx->thread, auth_ctx->dn, auth_ctx->password) < 0) goto fail; + + RETURN_MODULE_RCODE(unlang_interpret_synchronous(unlang_interpret_event_list(request), request)); +} + 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->inst->data, rlm_ldap_t); fr_ldap_thread_t *thread = talloc_get_type_abort(module_rlm_thread_by_data(inst)->data, fr_ldap_thread_t); - rlm_rcode_t rcode; - char const *dn; fr_ldap_thread_trunk_t *ttrunk = NULL; + ldap_auth_ctx_t *auth_ctx; + ldap_auth_mod_env_t *mod_env = talloc_get_type_abort(mctx->env_data, ldap_auth_mod_env_t); char sasl_mech_buff[LDAP_MAX_DN_STR_LEN]; char sasl_proxy_buff[LDAP_MAX_DN_STR_LEN]; @@ -1096,16 +1150,15 @@ static unlang_action_t CC_HINT(nonnull) mod_authenticate(rlm_rcode_t *p_result, if (tmpl_expand(&sasl.mech, sasl_mech_buff, sizeof(sasl_mech_buff), request, inst->user_sasl.mech, fr_ldap_escape_func, inst) < 0) { RPEDEBUG("Failed expanding user.sasl.mech"); - rcode = RLM_MODULE_FAIL; - goto finish; + fail: + RETURN_MODULE_RCODE(RLM_MODULE_FAIL); } if (inst->user_sasl.proxy) { if (tmpl_expand(&sasl.proxy, sasl_proxy_buff, sizeof(sasl_proxy_buff), request, inst->user_sasl.proxy, fr_ldap_escape_func, inst) < 0) { RPEDEBUG("Failed expanding user.sasl.proxy"); - rcode = RLM_MODULE_FAIL; - goto finish; + goto fail; } } @@ -1113,30 +1166,31 @@ static unlang_action_t CC_HINT(nonnull) mod_authenticate(rlm_rcode_t *p_result, if (tmpl_expand(&sasl.realm, sasl_realm_buff, sizeof(sasl_realm_buff), request, inst->user_sasl.realm, fr_ldap_escape_func, inst) < 0) { RPEDEBUG("Failed expanding user.sasl.realm"); - rcode = RLM_MODULE_FAIL; - goto finish; + goto fail; } } } RDEBUG2("Login attempt by \"%pV\"", &username->data); - /* - * Get the DN by doing a search. - */ - dn = rlm_ldap_find_user(inst, request, ttrunk, NULL, false, NULL, NULL, &rcode); - if (!dn) RETURN_MODULE_RCODE(rcode); + auth_ctx = talloc(unlang_interpret_frame_talloc_ctx(request), ldap_auth_ctx_t); + *auth_ctx = (ldap_auth_ctx_t){ + .password = password->vp_strvalue, + .thread = thread, + .inst = inst, + .mod_env = mod_env, + .ttrunk = ttrunk + }; /* - * Attempt a bind using the thread specific connection for bind auths + * Check for a cahed copy of the DN */ - if (fr_ldap_bind_auth_async(request, thread, dn, password->vp_strvalue) < 0) RETURN_MODULE_FAIL; + auth_ctx->dn = rlm_find_user_dn_cached(request); - rcode = unlang_interpret_synchronous(unlang_interpret_event_list(request), request); + if (unlang_function_push(request, auth_ctx->dn ? NULL : mod_authenticate_start, mod_authenticate_resume, + NULL, 0, UNLANG_SUB_FRAME, auth_ctx) < 0) RETURN_MODULE_FAIL; -finish: - - RETURN_MODULE_RCODE(rcode); + return UNLANG_ACTION_PUSHED_CHILD; } /** Search for and apply an LDAP profile