]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
Add support for LDAP extended operations to async framework
authorNick Porter <nick@portercomputing.co.uk>
Thu, 20 Apr 2023 13:24:09 +0000 (14:24 +0100)
committerNick Porter <nick@portercomputing.co.uk>
Thu, 20 Apr 2023 15:54:44 +0000 (16:54 +0100)
src/lib/ldap/base.c
src/lib/ldap/base.h

index fba2da020717edfd866ab0b5a28a41d60096c99c..5b0c420bf796b7c7c2290b03ffb361ca1ae9658c 100644 (file)
@@ -836,6 +836,81 @@ fr_ldap_rcode_t fr_ldap_modify_async(int *msgid, request_t *request, fr_ldap_con
        return LDAP_PROC_SUCCESS;
 }
 
+/** Run an async LDAP "extended operation" query on a trunk connection
+ *
+ * @param[out] p_result                from synchronous evaluation.
+ * @param[in] ctx              to allocate the query in.
+ * @param[out] out             that has been allocated.
+ * @param[in] request          this query relates to.
+ * @param[in] ttrunk           to submit the query to.
+ * @param[in] reqoid           OID of extended operation.
+ * @param[in] reqdata          Request data to send.
+ * @param[in] serverctrls      specific to this query.
+ * @param[in] clientctrls      specific to this query.
+ * @return
+ *     - UNLANG_ACTION_FAIL on error.
+ *     - UNLANG_ACTION_YIELD on success.
+ *     - UNLANG_ACTION_CALCULATE_RESULT if the query was run synchronously.
+ */
+unlang_action_t fr_ldap_trunk_extended(rlm_rcode_t *p_result,
+                                      TALLOC_CTX *ctx,
+                                      fr_ldap_query_t **out, request_t *request, fr_ldap_thread_trunk_t *ttrunk,
+                                      char const *reqoid, struct berval *reqdata,
+                                      LDAPControl **serverctrls, LDAPControl **clientctrls)
+{
+       unlang_action_t action;
+       fr_ldap_query_t *query;
+
+       query = fr_ldap_extended_alloc(ctx, reqoid, reqdata, serverctrls, clientctrls);
+
+       switch (fr_trunk_request_enqueue(&query->treq, ttrunk->trunk, request, query, NULL)) {
+       case FR_TRUNK_ENQUEUE_OK:
+       case FR_TRUNK_ENQUEUE_IN_BACKLOG:
+               break;
+
+       default:
+       error:
+               *out = NULL;
+               *p_result = RLM_MODULE_FAIL;
+               talloc_free(query);
+               return UNLANG_ACTION_FAIL;
+       }
+
+       action = unlang_function_push(request, NULL, ldap_trunk_query_results, ldap_trunk_query_cancel,
+                                     ~FR_SIGNAL_CANCEL, UNLANG_SUB_FRAME, query);
+
+       if (action == UNLANG_ACTION_FAIL) goto error;
+
+       *out = query;
+
+       return UNLANG_ACTION_PUSHED_CHILD;
+}
+
+/** Initiate an LDAP extended operation
+ *
+ * Called by the trunk mux function
+ *
+ * @param[out] msgid   LDAP message ID.
+ * @param[in] request  Current request.
+ * @param[in] pconn    to use.
+ * @param[in] reqoid   OID of extended operation to perform.
+ * @param[in] reqdata  Data required for the request.
+ * @return One of the LDAP_PROC_* (#fr_ldap_rcode_t) values.
+ */
+fr_ldap_rcode_t fr_ldap_extended_async(int *msgid, request_t *request, fr_ldap_connection_t **pconn,
+                                      char const *reqoid, struct berval *reqdata)
+{
+       int     err;
+
+       fr_assert(*pconn && (*pconn)->handle);
+
+       RDEBUG2("Requesting extended operation with OID %s", reqoid);
+       err = ldap_extended_operation((*pconn)->handle, reqoid, reqdata, NULL, NULL, msgid);
+
+       if (err) return LDAP_PROC_ERROR;
+       return LDAP_PROC_SUCCESS;
+}
+
 /** Free any libldap structures when an fr_ldap_query_t is freed
  *
  * It is also possible that the connection used for this query is now closed,
@@ -889,6 +964,11 @@ static int _ldap_query_free(fr_ldap_query_t *query)
                talloc_free(query->ldap_conn);
        }
 
+       /*
+        *      Ensure the request data for extended operations are freed.
+        */
+       if (query->type == LDAP_REQUEST_EXTENDED && query->extended.reqdata) ber_bvfree(query->extended.reqdata);
+
        return 0;
 }
 
@@ -959,6 +1039,29 @@ fr_ldap_query_t *fr_ldap_modify_alloc(TALLOC_CTX *ctx, char const *dn,
        return query;
 }
 
+/** Allocate a new LDAP extended operations object
+ *
+ * @param[in] ctx              to allocate the query in.
+ * @param[in] reqoid           OID of extended operation to perform.
+ * @param[in] reqdata          Request data to send.
+ * @param[in] serverctrls      Controls to pass to the server.  May be NULL.
+ * @param[in] clientctrls      Client controls.  May be NULL.
+ * @return LDAP query object
+ */
+fr_ldap_query_t *fr_ldap_extended_alloc(TALLOC_CTX *ctx, char const *reqoid, struct berval *reqdata,
+                                       LDAPControl **serverctrls, LDAPControl **clientctrls)
+{
+       fr_ldap_query_t *query;
+
+       query = ldap_query_alloc(ctx, LDAP_REQUEST_EXTENDED);
+       query->extended.reqoid = reqoid;
+       query->extended.reqdata = reqdata;
+       SET_LDAP_CTRLS(query->serverctrls, serverctrls);
+       SET_LDAP_CTRLS(query->clientctrls, clientctrls);
+
+       return (query);
+}
+
 static int _ldap_handle_thread_local_free(void *handle)
 {
        if (ldap_unbind_ext_s(handle, NULL, NULL) < 0) return -1;
index 3669a62b8f525c0aeae36ea04950c881d8d39295..e3b78f0857e536e6fe9b4eae1d6e4971e7219ae0 100644 (file)
@@ -175,7 +175,8 @@ typedef enum {
  */
 typedef enum {
        LDAP_REQUEST_SEARCH = 1,                        //!< A lookup in an LDAP directory
-       LDAP_REQUEST_MODIFY                             //!< A modification to an LDAP entity
+       LDAP_REQUEST_MODIFY,                            //!< A modification to an LDAP entity
+       LDAP_REQUEST_EXTENDED                           //!< An extended LDAP operation
 } fr_ldap_request_type_t;
 
 /** LDAP query result codes
@@ -427,6 +428,10 @@ struct fr_ldap_query_s {
                        int             scope;          //!< Search scope.
                        char const      *filter;        //!< Filter for search.
                } search;
+               struct {
+                       char const      *reqoid;        //!< OID of extended operation to perform.
+                       struct berval   *reqdata;       //!< Data required for the request.
+               } extended;
                LDAPMod                 **mods;         //!< Changes to be applied if this query is a modification.
        };
 
@@ -700,6 +705,9 @@ fr_ldap_query_t *fr_ldap_search_alloc(TALLOC_CTX *ctx,
 fr_ldap_query_t *fr_ldap_modify_alloc(TALLOC_CTX *ctx, char const *dn,
                                      LDAPMod *mods[], LDAPControl **serverctrls, LDAPControl **clientctrls);
 
+fr_ldap_query_t *fr_ldap_extended_alloc(TALLOC_CTX *ctx, char const *reqiod, struct berval *reqdata,
+                                       LDAPControl **serverctrls, LDAPControl **clientctrls);
+
 unlang_action_t fr_ldap_trunk_search(rlm_rcode_t *p_result,
                                     TALLOC_CTX *ctx,
                                     fr_ldap_query_t **out, request_t *request, fr_ldap_thread_trunk_t *ttrunk,
@@ -713,6 +721,12 @@ unlang_action_t fr_ldap_trunk_modify(rlm_rcode_t *p_result,
                                     char const *dn, LDAPMod *mods[],
                                     LDAPControl **serverctrls, LDAPControl **clientctrls);
 
+unlang_action_t fr_ldap_trunk_extended(rlm_rcode_t *p_result,
+                                      TALLOC_CTX *ctx,
+                                      fr_ldap_query_t **out, request_t *request, fr_ldap_thread_trunk_t *ttrunk,
+                                      char const *reqoid, struct berval *reqdata,
+                                      LDAPControl **serverctrls, LDAPControl **clientctrls);
+
 /*
  *     base.c - Wrappers arounds OpenLDAP functions.
  */
@@ -736,6 +750,9 @@ fr_ldap_rcode_t     fr_ldap_modify_async(int *msgid, request_t *request, fr_ldap_con
                               char const *dn, LDAPMod *mods[],
                               LDAPControl **serverctrls, LDAPControl **clientctrls);
 
+fr_ldap_rcode_t fr_ldap_extended_async(int *msgid, request_t *request, fr_ldap_connection_t **pconn,
+                                      char const *reqiod, struct berval *reqdata);
+
 fr_ldap_rcode_t        fr_ldap_error_check(LDAPControl ***ctrls, fr_ldap_connection_t const *conn,
                                    LDAPMessage *msg, char const *dn);