From: Nick Porter Date: Mon, 31 Oct 2022 18:11:04 +0000 (+0000) Subject: v4: Add functionality to rate limit LDAP sync store Cookie (#4784) X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=9511ca9d765dd4253f7e57186f53e37a11070e07;p=thirdparty%2Ffreeradius-server.git v4: Add functionality to rate limit LDAP sync store Cookie (#4784) * Simplify arguments for ldap_sync_cookie_store * Add config items for cookie store interval * Add module instance to sync_state_t And pass it to sync initialisation functions to populate the sync_state_t * Define structure for tracking sync packets * Add list to sync_state for tracking pending packets * Create sync packet ctx to track progress of each change * Add counters for batching cookie storing * Store received cookies in list of pending packets rather than sending immediately * Use counters to send cookies based on number of processed changes * Use timer to send cookies on a periodic basis --- diff --git a/raddb/sites-available/ldap_sync b/raddb/sites-available/ldap_sync index 6b5f17f2210..8e8b874e940 100644 --- a/raddb/sites-available/ldap_sync +++ b/raddb/sites-available/ldap_sync @@ -151,6 +151,29 @@ server ldap_sync { } } + # + # When directories provide cookies to track progress through + # the list of changes, these can be provided on every update, + # which can be an excessive rate. + # + # FreeRADIUS keeps track of pending change and will only call + # store Cookie once the preceding changes have been processed. + # + # These options rate limit how often cookies will be stored. + # Provided all preceding changes have been processed, cookie Store + # will be called on a timed interval or after a number of changes + # have been completed, whichever occurs first. + # + # How often to store cookies. + # + cookie_interval = 10 + + # + # Number of completed changes which will prompt the storing + # of a cookie + # + cookie_changes = 100 + # # Persistent searches. # diff --git a/src/listen/ldap_sync/active_directory.c b/src/listen/ldap_sync/active_directory.c index 3c5c7fd02bf..2a303d5ce46 100644 --- a/src/listen/ldap_sync/active_directory.c +++ b/src/listen/ldap_sync/active_directory.c @@ -43,13 +43,14 @@ static int active_directory_sync_attr_add(char const *attr, void *uctx) * Neither of these controls take values. * * @param[in] conn Connection to issue the search request on. - * @param[in] config containing callbacks and search parameters. + * @param[in] sync_no number of the sync in the array of configs. + * @param[in] inst instance of ldap_sync this query relates to. * @param[in] cookie unused for Active Directory * @return * - 0 on success * - -1 on failure */ -int active_directory_sync_state_init(fr_ldap_connection_t *conn, size_t sync_no, sync_config_t const *config, +int active_directory_sync_state_init(fr_ldap_connection_t *conn, size_t sync_no, proto_ldap_sync_t const *inst, UNUSED uint8_t const *cookie) { static char const *notify_oid = LDAP_SERVER_NOTIFICATION_OID; @@ -60,6 +61,7 @@ int active_directory_sync_state_init(fr_ldap_connection_t *conn, size_t sync_no, sync_state_t *sync; fr_rb_tree_t *tree; char const *filter = NULL; + sync_config_t const *config = inst->sync_config[sync_no]; fr_assert(conn); fr_assert(config); @@ -75,7 +77,7 @@ int active_directory_sync_state_init(fr_ldap_connection_t *conn, size_t sync_no, tree = talloc_get_type_abort(conn->uctx, fr_rb_tree_t); } - sync = sync_state_alloc(tree, conn, sync_no, config); + sync = sync_state_alloc(tree, conn, inst, sync_no, config); /* * Notification control - marks this as a persistent search. diff --git a/src/listen/ldap_sync/active_directory.h b/src/listen/ldap_sync/active_directory.h index 50fb36e6c65..c96a8971db0 100644 --- a/src/listen/ldap_sync/active_directory.h +++ b/src/listen/ldap_sync/active_directory.h @@ -26,7 +26,7 @@ #include #include "proto_ldap_sync_ldap.h" -int active_directory_sync_state_init(fr_ldap_connection_t *conn, size_t sync_no, sync_config_t const *config, - UNUSED uint8_t const *cookie); +int active_directory_sync_state_init(fr_ldap_connection_t *conn, size_t sync_no, + proto_ldap_sync_t const *inst, UNUSED uint8_t const *cookie); int active_directory_sync_search_entry(sync_state_t *sync, LDAPMessage *msg, UNUSED LDAPControl **ctrls); diff --git a/src/listen/ldap_sync/persistent_search.c b/src/listen/ldap_sync/persistent_search.c index f18ece80050..ac2964c0a15 100644 --- a/src/listen/ldap_sync/persistent_search.c +++ b/src/listen/ldap_sync/persistent_search.c @@ -46,10 +46,11 @@ * an ldap_abandon message to the server to tell it to cancel the search. * * @param[in] conn Connection to issue the search request on. - * @param[in] config containing callbacks and search parameters. + * @param[in] sync_no number of the sync in the array of configs. + * @param[in] inst instance of ldap_sync this query relates to. * @param[in] cookie not applicable to persistent search LDAP servers. */ -int persistent_sync_state_init(fr_ldap_connection_t *conn, size_t sync_no, sync_config_t const *config, UNUSED uint8_t const *cookie) +int persistent_sync_state_init(fr_ldap_connection_t *conn, size_t sync_no, proto_ldap_sync_t const *inst, UNUSED uint8_t const *cookie) { static char const *notify_oid = LDAP_CONTROL_PERSIST_REQUEST; LDAPControl ctrl = {0}, *ctrls[2] = { &ctrl, NULL }; @@ -57,6 +58,7 @@ int persistent_sync_state_init(fr_ldap_connection_t *conn, size_t sync_no, sync_ int ret; sync_state_t *sync; fr_rb_tree_t *tree; + sync_config_t *config = inst->sync_config[sync_no]; fr_assert(conn); fr_assert(config); @@ -81,7 +83,7 @@ int persistent_sync_state_init(fr_ldap_connection_t *conn, size_t sync_no, sync_ return -1; } - sync = sync_state_alloc(tree, conn, sync_no, config); + sync = sync_state_alloc(tree, conn, inst, sync_no, config); memcpy(&ctrl.ldctl_oid, ¬ify_oid, sizeof(ctrl.ldctl_oid)); @@ -127,6 +129,13 @@ int persistent_sync_state_init(fr_ldap_connection_t *conn, size_t sync_no, sync_ DEBUG3("Sync created with msgid %i", sync->msgid); + /* + * Register event to store cookies at a regular interval + * Whilst persistent search LDAP servers don't provide cookies as such + * we treat change numbers, if provided, as cookies. + */ + fr_event_timer_in(sync, conn->conn->el, &sync->cookie_ev, inst->cookie_interval, ldap_sync_cookie_event, sync); + return 0; } @@ -255,7 +264,7 @@ int persistent_sync_search_entry(sync_state_t *sync, LDAPMessage *msg, LDAPContr */ if (sync->cookie) talloc_free(sync->cookie); sync->cookie = (uint8_t *)talloc_asprintf(sync, "%d", change_no); - if (ldap_sync_cookie_store(sync, sync->cookie, false) < 0) goto error; + if (ldap_sync_cookie_store(sync, false) < 0) goto error; } if (ber_scanf(ber, "}") == LBER_ERROR) { diff --git a/src/listen/ldap_sync/persistent_search.h b/src/listen/ldap_sync/persistent_search.h index affb0ab5d55..711eb6776bb 100644 --- a/src/listen/ldap_sync/persistent_search.h +++ b/src/listen/ldap_sync/persistent_search.h @@ -26,7 +26,7 @@ #include #include "proto_ldap_sync_ldap.h" -int persistent_sync_state_init(fr_ldap_connection_t *conn, size_t sync_no, sync_config_t const *config, +int persistent_sync_state_init(fr_ldap_connection_t *conn, size_t sync_no, proto_ldap_sync_t const *inst, UNUSED uint8_t const *cookie); int persistent_sync_search_entry(sync_state_t *sync, LDAPMessage *msg, LDAPControl **ctrls); diff --git a/src/listen/ldap_sync/proto_ldap_sync.c b/src/listen/ldap_sync/proto_ldap_sync.c index 4ac2f145f50..17d0b355e7c 100644 --- a/src/listen/ldap_sync/proto_ldap_sync.c +++ b/src/listen/ldap_sync/proto_ldap_sync.c @@ -53,6 +53,8 @@ static CONF_PARSER const proto_ldap_sync_config[] = { { FR_CONF_OFFSET("max_packet_size", FR_TYPE_UINT32, proto_ldap_sync_t, max_packet_size) }, { FR_CONF_OFFSET("num_messages", FR_TYPE_UINT32, proto_ldap_sync_t, num_messages) }, + { FR_CONF_OFFSET("cookie_interval", FR_TYPE_TIME_DELTA, proto_ldap_sync_t, cookie_interval), .dflt = "10" }, + { FR_CONF_OFFSET("cookie_changes", FR_TYPE_UINT32, proto_ldap_sync_t, cookie_changes), .dflt = "100" }, /* * Areas of the DIT to listen on diff --git a/src/listen/ldap_sync/proto_ldap_sync.h b/src/listen/ldap_sync/proto_ldap_sync.h index 8fe3978b0f5..35b2b7a8bfb 100644 --- a/src/listen/ldap_sync/proto_ldap_sync.h +++ b/src/listen/ldap_sync/proto_ldap_sync.h @@ -54,6 +54,10 @@ typedef struct { uint32_t num_messages; //!< for message ring buffer uint32_t priority; //!< for packet processing. + fr_time_delta_t cookie_interval; //!< Interval between storing cookies. + uint32_t cookie_changes; //!< Number of LDAP changes to process between + //!< each cookie store operation. + fr_schedule_t *sc; fr_listen_t *listen; //!< The listener structure which describes @@ -80,13 +84,14 @@ typedef struct sync_state_s sync_state_t; * controls for type of directory in use. * * @param[in] conn to initialise the sync on - * @param[in] config for the sync + * @param[in] sync_no number of the sync in the array of configs. + * @param[in] inst instance of ldap_sync this query relates to * @param[in] cookie to send with the query (RFC 4533 only) * @return * - 0 on success. * - -1 on error. */ - typedef int (*sync_init_t)(fr_ldap_connection_t *conn, size_t sync_no, sync_config_t const *config, + typedef int (*sync_init_t)(fr_ldap_connection_t *conn, size_t sync_no, proto_ldap_sync_t const *inst, uint8_t const *cookie); /** Received an LDAP message related to a sync diff --git a/src/listen/ldap_sync/proto_ldap_sync_ldap.c b/src/listen/ldap_sync/proto_ldap_sync_ldap.c index 6706d756449..c4693c49b82 100644 --- a/src/listen/ldap_sync/proto_ldap_sync_ldap.c +++ b/src/listen/ldap_sync/proto_ldap_sync_ldap.c @@ -158,16 +158,20 @@ static int sync_state_free(sync_state_t *sync) * @param[in] config for the sync. * @return new sync state. */ -sync_state_t *sync_state_alloc(TALLOC_CTX *ctx, fr_ldap_connection_t *conn, size_t sync_no, sync_config_t const *config) +sync_state_t *sync_state_alloc(TALLOC_CTX *ctx, fr_ldap_connection_t *conn, proto_ldap_sync_t const *inst, + size_t sync_no, sync_config_t const *config) { sync_state_t *sync; MEM(sync = talloc_zero(ctx, sync_state_t)); sync->conn = conn; + sync->inst = inst; sync->config = config; sync->sync_no = sync_no; sync->phase = SYNC_PHASE_INIT; + fr_dlist_talloc_init(&sync->pending, sync_packet_ctx_t, entry); + /* * If the connection is freed, all the sync state is also freed */ @@ -176,27 +180,86 @@ sync_state_t *sync_state_alloc(TALLOC_CTX *ctx, fr_ldap_connection_t *conn, size return sync; } -/** Enque a new cookie store packet +/** Add a new cookie packet ctx to the pending list * - * Create a new internal packet containing the cookie we received from the LDAP server. - * This allows the administrator to store the cookie and provide it on a future call to - * load Cookie. + * Does not actually send the packet. * * @param[in] sync the cookie was received for. - * @param[in] cookie received from the LDAP server. Can be NULL to indicate the stored cookie should be cleared. * @param[in] refresh the sync after storing this cookie. * @return * - 0 on success. * - -1 on failure */ -int ldap_sync_cookie_store(sync_state_t *sync, uint8_t const *cookie, bool refresh) +int ldap_sync_cookie_store(sync_state_t *sync, bool refresh) +{ + sync_packet_ctx_t *sync_packet_ctx = NULL; + uint8_t *cookie = sync->cookie; + + MEM(sync_packet_ctx = talloc_zero(sync, sync_packet_ctx_t)); + sync_packet_ctx->sync = sync; + + sync_packet_ctx->type = SYNC_PACKET_TYPE_COOKIE; + if (cookie) sync_packet_ctx->cookie = talloc_memdup(sync_packet_ctx, cookie, talloc_array_length(cookie)); + sync_packet_ctx->refresh = refresh; + + if (fr_dlist_insert_tail(&sync->pending, sync_packet_ctx) < 0) { + talloc_free(sync_packet_ctx); + return -1; + } + sync->pending_cookies++; + + return 0; +} + +/** Event to handle storing of cookies on a timed basis + * + * Looks at the head of the list of pending sync packets for a cookie. + * A cookie at the head says that all the previous changes have been + * completed, so the cookie can be sent. + */ +void ldap_sync_cookie_event(fr_event_list_t *el, UNUSED fr_time_t now, void *uctx) +{ + sync_state_t *sync = talloc_get_type_abort(uctx, sync_state_t); + sync_packet_ctx_t *sync_packet_ctx; + + if (sync->pending_cookies == 0) goto finish; + + /* + * Check the head entry in the list - is it a pending cookie + */ + sync_packet_ctx = fr_dlist_head(&sync->pending); + if ((sync_packet_ctx->type != SYNC_PACKET_TYPE_COOKIE) || + (sync_packet_ctx->status != SYNC_PACKET_PENDING)) goto finish; + + ldap_sync_cookie_send(sync_packet_ctx); + +finish: + fr_event_timer_in(sync, el, &sync->cookie_ev, sync->inst->cookie_interval, ldap_sync_cookie_event, sync); +} + +/** Enque a new cookie store packet + * + * Create a new internal packet containing the cookie we received from the LDAP server. + * This allows the administrator to store the cookie and provide it on a future call to + * load Cookie. + * + * @param[in] sync_packet_ctx packet context containing the cookie to store. + * @return + * - 0 on success. + * - -1 on failure. +*/ +int ldap_sync_cookie_send(sync_packet_ctx_t *sync_packet_ctx) { + sync_state_t *sync = sync_packet_ctx->sync; proto_ldap_sync_ldap_thread_t *thread = talloc_get_type_abort(sync->config->user_ctx, proto_ldap_sync_ldap_thread_t); fr_dbuff_t *dbuff; - sync_refresh_packet_t *refresh_packet = NULL; fr_pair_list_t pairs; fr_pair_t *vp; TALLOC_CTX *local = NULL; + uint8_t *cookie = sync->cookie; + + if (sync_packet_ctx->status != SYNC_PACKET_PENDING) return 0; + sync_packet_ctx->status = SYNC_PACKET_PREPARING; FR_DBUFF_TALLOC_THREAD_LOCAL(&dbuff, 1024, 4096); @@ -226,23 +289,12 @@ int ldap_sync_cookie_store(sync_state_t *sync, uint8_t const *cookie, bool refre if (!vp) goto error; } - /* - * The LDAP server has indicated that the sync needs a refresh. - * Create a tracking structure to trigger the refresh once the cookie is stored. - */ - if (refresh) { - MEM(refresh_packet = talloc_zero(thread, sync_refresh_packet_t)); - if (cookie) { - refresh_packet->refresh_cookie = talloc_memdup(refresh_packet, cookie, talloc_array_length(cookie)); - } - refresh_packet->sync = sync; - } - if (fr_internal_encode_list(dbuff, &pairs, NULL) < 0) goto error; talloc_free(local); fr_network_listen_send_packet(thread->nr, thread->li, thread->li, fr_dbuff_buff(dbuff), - fr_dbuff_used(dbuff), fr_time(), refresh_packet); + fr_dbuff_used(dbuff), fr_time(), sync_packet_ctx); + sync_packet_ctx->status = SYNC_PACKET_PROCESSING; return 0; } @@ -276,6 +328,7 @@ int ldap_sync_entry_send(sync_state_t *sync, uint8_t const uuid[SYNC_UUID_LENGTH fr_pair_list_t pairs; fr_pair_t *vp; TALLOC_CTX *local = NULL; + sync_packet_ctx_t *sync_packet_ctx = NULL; FR_DBUFF_TALLOC_THREAD_LOCAL(&dbuff, 1024, 4096); @@ -285,6 +338,7 @@ int ldap_sync_entry_send(sync_state_t *sync, uint8_t const uuid[SYNC_UUID_LENGTH error: if (msg) ldap_msgfree(msg); talloc_free(local); + if (sync_packet_ctx) talloc_free(sync_packet_ctx); return -1; }; @@ -360,8 +414,14 @@ int ldap_sync_entry_send(sync_state_t *sync, uint8_t const uuid[SYNC_UUID_LENGTH if (fr_internal_encode_list(dbuff, &pairs, NULL) < 0) goto error; + MEM(sync_packet_ctx = talloc_zero(sync, sync_packet_ctx_t)); + sync_packet_ctx->sync = sync; + + if (fr_dlist_insert_tail(&sync->pending, sync_packet_ctx) < 0) goto error; + fr_network_listen_send_packet(thread->nr, thread->li, thread->li, - fr_dbuff_buff(dbuff), fr_dbuff_used(dbuff), fr_time(), NULL); + fr_dbuff_buff(dbuff), fr_dbuff_used(dbuff), fr_time(), sync_packet_ctx); + sync_packet_ctx->status = SYNC_PACKET_PROCESSING; talloc_free(local); @@ -610,10 +670,13 @@ static ssize_t proto_ldap_child_mod_write(fr_listen_t *li, void *packet_ctx, UNU fr_pair_t *vp = NULL; ssize_t ret; TALLOC_CTX *local; + sync_packet_ctx_t *sync_packet_ctx = NULL; local = talloc_new(NULL); fr_dbuff_init(&dbuff, buffer, buffer_len); + if (packet_ctx) sync_packet_ctx = talloc_get_type_abort(packet_ctx, sync_packet_ctx_t); + /* * Extract returned attributes into a temporary list */ @@ -654,7 +717,7 @@ static ssize_t proto_ldap_child_mod_write(fr_listen_t *li, void *packet_ctx, UNU vp = fr_pair_find_by_da_nested(&tmp, NULL, attr_ldap_sync_cookie); if (vp) cookie = talloc_memdup(inst, vp->vp_octets, vp->vp_length); - inst->parent->sync_config[packet_id]->init(thread->conn->h, packet_id, inst->parent->sync_config[packet_id], cookie); + inst->parent->sync_config[packet_id]->init(thread->conn->h, packet_id, inst->parent, cookie); } break; @@ -663,26 +726,17 @@ static ssize_t proto_ldap_child_mod_write(fr_listen_t *li, void *packet_ctx, UNU case FR_LDAP_SYNC_CODE_COOKIE_STORE_RESPONSE: { - sync_refresh_packet_t *refresh_packet; sync_config_t const *sync_config; - if (!packet_ctx) break; - - /* - * If there is a packet_ctx, it will be the tracking structure - * indicating that we need to refresh the sync. - */ - refresh_packet = talloc_get_type_abort(packet_ctx, sync_refresh_packet_t); + if (!sync_packet_ctx || !sync_packet_ctx->refresh) break; /* * Abandon the old sync and start a new one with the relevant cookie. */ - sync_config = refresh_packet->sync->config; + sync_config = sync_packet_ctx->sync->config; DEBUG3("Restarting sync with base %s", sync_config->base_dn); - talloc_free(refresh_packet->sync); - inst->parent->sync_config[packet_id]->init(thread->conn->h, packet_id, sync_config, refresh_packet->refresh_cookie); - - talloc_free(refresh_packet); + talloc_free(sync_packet_ctx->sync); + inst->parent->sync_config[packet_id]->init(thread->conn->h, packet_id, inst->parent, sync_packet_ctx->cookie); } break; @@ -691,6 +745,54 @@ static ssize_t proto_ldap_child_mod_write(fr_listen_t *li, void *packet_ctx, UNU break; } + if (sync_packet_ctx) { + sync_state_t *sync = sync_packet_ctx->sync; + sync_packet_ctx_t *pc; + proto_ldap_sync_t *ldap_sync = inst->parent; + + sync_packet_ctx->status = SYNC_PACKET_COMPLETE; + + /* + * A cookie has been stored, reset the counter of changes + */ + if (sync_packet_ctx->type == SYNC_PACKET_TYPE_COOKIE) sync->changes_since_cookie = 0; + + /* + * Pop any processed updates from the head of the list + */ + while ((pc = fr_dlist_head(&sync->pending))) { + /* + * If the head entry in the list is a pending cookie but we have + * not processed enough entries and there are more pending + * cookies, mark this one as processed. + */ + if ((pc->type == SYNC_PACKET_TYPE_COOKIE) && (pc->status == SYNC_PACKET_PENDING) && + (sync->changes_since_cookie < ldap_sync->cookie_changes) && + (sync->pending_cookies > 1)) pc->status = SYNC_PACKET_COMPLETE; + + if (pc->status != SYNC_PACKET_COMPLETE) break; + + /* + * Update counters depending on entry type + */ + if (pc->type == SYNC_PACKET_TYPE_COOKIE) { + sync->pending_cookies--; + } else { + sync->changes_since_cookie++; + } + pc = fr_dlist_pop_head(&sync->pending); + talloc_free(pc); + } + + /* + * If the head of the list is a cookie which has not yet + * been processed and sufficient changes have been recorded + * send the cookie. + */ + if (pc && (pc->type == SYNC_PACKET_TYPE_COOKIE) && (pc->status == SYNC_PACKET_PENDING) && + (sync->changes_since_cookie >= ldap_sync->cookie_changes)) ldap_sync_cookie_send(pc); + } + fr_pair_list_free(&tmp); talloc_free(local); diff --git a/src/listen/ldap_sync/proto_ldap_sync_ldap.h b/src/listen/ldap_sync/proto_ldap_sync_ldap.h index 5a6ec6b9e63..7cdd3931419 100644 --- a/src/listen/ldap_sync/proto_ldap_sync_ldap.h +++ b/src/listen/ldap_sync/proto_ldap_sync_ldap.h @@ -59,6 +59,16 @@ struct sync_state_s { //!< before passing packets to the worker. //!< Predominantly to overcome Active Directory's lack //!< of filtering in persistent searches. + + proto_ldap_sync_t const *inst; //!< Module instance for this sync. + + fr_dlist_head_t pending; //!< List of pending changes in progress. + + uint32_t pending_cookies; //!< How many cookies are in the pending heap + uint32_t changes_since_cookie; //!< How many changes have been added since + //!< the last cookie was stored. + + fr_event_timer_t const *cookie_ev; //!< Timer event for sending cookies. }; typedef struct sync_state_s sync_state_t; @@ -104,24 +114,46 @@ typedef struct { fr_connection_t *conn; //!< Our connection to the LDAP directory. } proto_ldap_sync_ldap_thread_t; -/** Tracking structure for connections requiring refresh +typedef enum { + SYNC_PACKET_PENDING = 0, //!< Packet not yet sent. + SYNC_PACKET_PREPARING, //!< Packet being prepared. + SYNC_PACKET_PROCESSING, //!< Packet sent to worker. + SYNC_PACKET_COMPLETE, //!< Packet response received from worker. +} sync_packet_status_t; + +typedef enum { + SYNC_PACKET_TYPE_CHANGE = 0, //!< Packet is an entry change. + SYNC_PACKET_TYPE_COOKIE +} sync_packet_type_t; + +/** Tracking structure for ldap sync packets */ -struct sync_refresh_packet_s { - sync_state_t *sync; //!< Sync requiring refresh +struct sync_packet_ctx_s { + sync_packet_type_t type; //!< Type of packet. + sync_packet_status_t status; //!< Status of this packet. + sync_state_t *sync; //!< Sync packet relates to. + + uint8_t *cookie; //!< Cookie to store - can be NULL. + bool refresh; //!< Does the sync require a refresh. - uint8_t *refresh_cookie; //!< Cookie provided by the server for the refresh. + fr_dlist_t entry; //!< Entry in list of pending packets. }; -typedef struct sync_refresh_packet_s sync_refresh_packet_t; +typedef struct sync_packet_ctx_s sync_packet_ctx_t; extern fr_table_num_sorted_t const sync_op_table[]; extern size_t sync_op_table_len; int8_t sync_state_cmp(void const *one, void const *two); -sync_state_t *sync_state_alloc(TALLOC_CTX *ctx, fr_ldap_connection_t *conn, size_t sync_no, sync_config_t const *config); +sync_state_t *sync_state_alloc(TALLOC_CTX *ctx, fr_ldap_connection_t *conn, proto_ldap_sync_t const *inst, + size_t sync_no, sync_config_t const *config); + +int ldap_sync_cookie_store(sync_state_t *sync, bool refresh); + +void ldap_sync_cookie_event(fr_event_list_t *el, fr_time_t now, void *uctx); -int ldap_sync_cookie_store(sync_state_t *sync, uint8_t const *cookie, bool refresh); +int ldap_sync_cookie_send(sync_packet_ctx_t *sync_packet_ctx); int ldap_sync_entry_send(sync_state_t *sync, uint8_t const uuid[SYNC_UUID_LENGTH], struct berval *orig_dn, LDAPMessage *msg, sync_op_t op); diff --git a/src/listen/ldap_sync/rfc4533.c b/src/listen/ldap_sync/rfc4533.c index 091c094a547..ae2a3cdae5d 100644 --- a/src/listen/ldap_sync/rfc4533.c +++ b/src/listen/ldap_sync/rfc4533.c @@ -71,7 +71,7 @@ static size_t const sync_phase_table_len = NUM_ELEMENTS(sync_phase_table); * * The Sync Request Control is only applicable to the SearchRequest Message. */ -int rfc4533_sync_init(fr_ldap_connection_t *conn, size_t sync_no, sync_config_t const *config, uint8_t const *cookie) +int rfc4533_sync_init(fr_ldap_connection_t *conn, size_t sync_no, proto_ldap_sync_t const *inst, uint8_t const *cookie) { LDAPControl ctrl = {0}, *ctrls[2] = { &ctrl, NULL }; BerElement *ber = NULL; @@ -79,6 +79,7 @@ int rfc4533_sync_init(fr_ldap_connection_t *conn, size_t sync_no, sync_config_t int ret; fr_rb_tree_t *tree; sync_state_t *sync; + sync_config_t const *config = inst->sync_config[sync_no]; fr_assert(conn); fr_assert(config); @@ -96,7 +97,7 @@ int rfc4533_sync_init(fr_ldap_connection_t *conn, size_t sync_no, sync_config_t return -1; } - sync = sync_state_alloc(tree, conn, sync_no, config); + sync = sync_state_alloc(tree, conn, inst, sync_no, config); /* * Might not necessarily have a cookie @@ -144,6 +145,11 @@ int rfc4533_sync_init(fr_ldap_connection_t *conn, size_t sync_no, sync_config_t DEBUG3("Sync created with msgid %i", sync->msgid); + /* + * Register event to store cookies at a regular interval + */ + fr_event_timer_in(sync, conn->conn->el, &sync->cookie_ev, inst->cookie_interval, ldap_sync_cookie_event, sync); + return 0; } @@ -394,7 +400,7 @@ int rfc4533_sync_search_entry(sync_state_t *sync, LDAPMessage *msg, LDAPControl * We have a new cookie - store it */ if ((ret == 0) && new_cookie) { - ret = ldap_sync_cookie_store(sync, sync->cookie, false); + ret = ldap_sync_cookie_store(sync, false); } ber_free(ber, 1); @@ -674,7 +680,7 @@ int rfc4533_sync_intermediate(sync_state_t *sync, LDAPMessage *msg, UNUSED LDAPC } if (new_cookie) { - ret = ldap_sync_cookie_store(sync, sync->cookie, false); + ret = ldap_sync_cookie_store(sync, false); } if (ber) ber_free(ber, 1); @@ -762,5 +768,5 @@ int rfc4533_sync_refresh_required(sync_state_t *sync, LDAPMessage *msg, LDAPCont new_cookie = true; } - return ldap_sync_cookie_store(sync, sync->cookie, true); + return ldap_sync_cookie_store(sync, true); } diff --git a/src/listen/ldap_sync/rfc4533.h b/src/listen/ldap_sync/rfc4533.h index a9c41dc21fc..a5dae4066ce 100644 --- a/src/listen/ldap_sync/rfc4533.h +++ b/src/listen/ldap_sync/rfc4533.h @@ -26,7 +26,8 @@ #include #include "proto_ldap_sync_ldap.h" -int rfc4533_sync_init(fr_ldap_connection_t *conn, size_t sync_no, sync_config_t const *config, uint8_t const *cookie); +int rfc4533_sync_init(fr_ldap_connection_t *conn, size_t sync_no, + proto_ldap_sync_t const *inst, uint8_t const *cookie); int rfc4533_sync_search_entry(sync_state_t *sync, LDAPMessage *msg, LDAPControl **ctrls);