]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
Rework LDAP profile lookup to use async queries
authorNick Porter <nick@portercomputing.co.uk>
Thu, 30 Mar 2023 18:41:19 +0000 (19:41 +0100)
committerNick Porter <nick@portercomputing.co.uk>
Tue, 4 Apr 2023 07:30:14 +0000 (08:30 +0100)
src/modules/rlm_ldap/rlm_ldap.c
src/modules/rlm_ldap/rlm_ldap.h

index ceebe4af69f38ba3a6d92780191b5108d83305da..3514a47950b57cb05a5bc2394b6fb73eb4b3fdbe 100644 (file)
@@ -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
  *
  */
index f5089c1577e5678ca72e500f1231cae3cebb221d..df415f60ea1d6bd95b366197972f60eb3910407f 100644 (file)
@@ -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;