LDAP_SYNC(3)

✨ LDAP_SYNC(3) ✨ β€” the libldap sync routines, explained by your favorite Unix bestie

okay so this is the LDAP_SYNC(3) page from the Library Functions Manual and honestly? it's giving "the whole content sync operation, but make it a group chat." sit down, hydrate, let's get into it πŸ’–


🌸 NAME 🌸

ldap_sync_init, ldap_sync_init_refresh_only, ldap_sync_init_refresh_and_persist, ldap_sync_poll β€” the LDAP sync routines, bestie. that's the whole squad ✨

πŸŽ€ LIBRARY πŸŽ€

OpenLDAP LDAP (libldap, -lldap). yes, link it like that, no cap πŸ’…

πŸ¦‹ SYNOPSIS πŸ¦‹

#include <ldap.h>

int ldap_sync_init(ldap_sync_t *ls, int mode);

int ldap_sync_init_refresh_only(ldap_sync_t *ls);

int ldap_sync_init_refresh_and_persist(ldap_sync_t *ls);

int ldap_sync_poll(ldap_sync_t *ls);

ldap_sync_t * ldap_sync_initialize(ldap_sync_t *ls);

void ldap_sync_destroy(ldap_sync_t *ls, int freeit);

typedef int (*ldap_sync_search_entry_f)(ldap_sync_t *ls,
       LDAPMessage *msg, struct berval *entryUUID,
       ldap_sync_refresh_t phase);

typedef int (*ldap_sync_search_reference_f)(ldap_sync_t *ls,
       LDAPMessage *msg);

typedef int (*ldap_sync_intermediate_f)(ldap_sync_t *ls,
       LDAPMessage *msg, BerVarray syncUUIDs,
       ldap_sync_refresh_t phase);

typedef int (*ldap_sync_search_result_f)(ldap_sync_t *ls,
       LDAPMessage *msg, int refreshDeletes);

like, look at all those function pointers. main character energy fr fr πŸ‘‘

πŸ’œ DESCRIPTION πŸ’œ

these routines are your interface to the LDAP Content Synchronization operation (RFC 4533). the vibe: you need an ldap_sync_t structure all set up with the parameters for the various phases of the operation, and that includes setting some handlers for special events. every handler takes a pointer to the ldap_sync_t structure as its first argument, plus a pointer to the LDAPMessage structure as received from the server by the client library, plus, occasionally, other specific arguments. iconic, honestly 🫢

the members of the ldap_sync_t structure are, and I'm gonna go through every single one because we don't skip:

  • char *ls_base β€” the search base. by default, it's the BASE option in ldap.conf(5).
  • int ls_scope β€” the search scope, one of LDAP_SCOPE_BASE, LDAP_SCOPE_ONELEVEL, LDAP_SCOPE_SUBORDINATE or LDAP_SCOPE_SUBTREE (peep ldap.h for the details).
  • char *ls_filter β€” the filter, RFC 4515 style. by default it's (objectClass=*).
  • char **ls_attrs β€” the requested attributes. by default NULL, which means all user attributes, periodt.
  • int ls_timelimit β€” the requested time limit, in seconds. by default 0, meaning no limit.
  • int ls_sizelimit β€” the requested size limit, in entries. by default 0, meaning no limit.
  • int ls_timeout β€” the desired timeout during polling with ldap_sync_poll(3). okay so let me break this down because the numbers matter: a value of -1 means polling is blocking, so ldap_sync_poll(3) will not return until a message is received. a value of 0 means polling returns immediately, no matter if any response is available or not. a positive value represents the timeout ldap_sync_poll(3) will wait for a response before returning, unless a message is received β€” in that case, ldap_sync_poll(3) returns as soon as the message is available. slay, that's the whole spectrum 🌈
  • ldap_sync_search_entry_f ls_search_entry β€” a function called whenever an entry is returned. the msg argument is the LDAPMessage that contains the searchResultEntry; you can parse it using the regular client API routines, like ldap_get_dn(3), ldap_first_attribute(3), and so on. the entryUUID argument contains the entryUUID of the entry. the phase argument tells you the type of operation: one of LDAP_SYNC_CAPI_PRESENT, LDAP_SYNC_CAPI_ADD, LDAP_SYNC_CAPI_MODIFY, LDAP_SYNC_CAPI_DELETE. in case of LDAP_SYNC_CAPI_PRESENT or LDAP_SYNC_CAPI_DELETE, only the DN is contained in the LDAPMessage; in case of LDAP_SYNC_CAPI_MODIFY, the whole entry is contained in the LDAPMessage, and the application is responsible for determining the differences between the new view of the entry provided by the caller and the data already known. yes, that diffing is on you, bestie 😭
  • ldap_sync_search_reference_f ls_search_reference β€” a function called whenever a search reference is returned. the msg argument is the LDAPMessage that contains the searchResultReference; it can be parsed using the regular client API routines, like ldap_parse_reference(3).
  • ldap_sync_intermediate_f ls_intermediate β€” a function called whenever something relevant occurs during the refresh phase of the search, which is marked by an intermediateResponse message type. the msg argument is the LDAPMessage that contains the intermediate response; it can be parsed using the regular client API routines, like ldap_parse_intermediate(3). the syncUUIDs argument contains an array of UUIDs of the entries, and what it means depends on the value of the phase argument:
    • in case of LDAP_SYNC_CAPI_PRESENTS, the "present" phase is being entered; this means the following sequence of results will consist in entries in "present" sync state.
    • in case of LDAP_SYNC_CAPI_DELETES, the "deletes" phase is being entered; this means the following sequence of results will consist in entries in "delete" sync state.
    • in case of LDAP_SYNC_CAPI_PRESENTS_IDSET, the message contains a set of UUIDs of entries that are present; it replaces a "presents" phase.
    • in case of LDAP_SYNC_CAPI_DELETES_IDSET, the message contains a set of UUIDs of entries that have been deleted; it replaces a "deletes" phase.
    • in case of LDAP_SYNC_CAPI_DONE, a "presents" phase with "refreshDone" set to "TRUE" has been returned to indicate that the refresh phase of refreshAndPersist is over, and the client should start polling.

and here's the catch: except for the LDAP_SYNC_CAPI_PRESENTS_IDSET and LDAP_SYNC_CAPI_DELETES_IDSET cases, syncUUIDs is NULL. noted, memorized, tattooed πŸ’€

  • ldap_sync_search_result_f ls_search_result β€” a function called whenever a searchResultDone is returned. in refreshAndPersist this can only occur when the server decides that the search must be interrupted. the msg argument is the LDAPMessage that contains the response; it can be parsed using the regular client API routines, like ldap_parse_result(3). the refreshDeletes argument is not relevant in this case; it should always be -1.
  • void *ls_private β€” a pointer to private data. the client may register here a pointer to data the handlers above may need. your little stash πŸŽ€
  • LDAP *ls_ld β€” a pointer to a LDAP structure that is used to connect to the server. it is the responsibility of the client to initialize the structure and to provide appropriate authentication and security in place. that one's on you, no takebacks πŸ’…

🌟 GENERAL USE 🌟

a ldap_sync_t structure gets initialized by calling ldap_sync_initialize(3). this simply clears out the contents of an already existing ldap_sync_t structure and sets appropriate values for some members. after that? the caller is responsible for setting up the connection (member ls_ld), eventually setting up transport security (TLS), for binding and any other initialization. the caller must also fill all the documented search-related fields of the ldap_sync_t structure. so like, the API does the clearing, you do the actual work, iykyk ✨

at the end of a session, the structure can be cleaned up by calling ldap_sync_destroy(3), which takes care of freeing all data assuming it was allocated by ldap_mem*(3) routines. otherwise, the caller should take care of destroying and zeroing out the documented search-related fields, and call ldap_sync_destroy(3) to free undocumented members set by the API. read that again if you allocated stuff with plain malloc, bestie πŸ™ˆ

πŸ“ REFRESH ONLY πŸ“

the refreshOnly functionality is obtained by periodically calling ldap_sync_init(3) with mode set to LDAP_SYNC_REFRESH_ONLY, or β€” which is equivalent β€” by directly calling ldap_sync_init_refresh_only(3). the state of the search, and the consistency of the search parameters, is preserved across calls by passing the ldap_sync_t structure as left by the previous call. so just keep handing it back, like a passed note in class πŸ“

πŸ”₯ REFRESH AND PERSIST πŸ”₯

the refreshAndPersist functionality is obtained by calling ldap_sync_init(3) with mode set to LDAP_SYNC_REFRESH_AND_PERSIST, or β€” which is equivalent β€” by directly calling ldap_sync_init_refresh_and_persist(3) and, after a successful return, by repeatedly polling with ldap_sync_poll(3) according to the desired pattern.

a client may insert a call to ldap_sync_poll(3) into an external loop to check if any modification was returned; in this case, it might be appropriate to set ls_timeout to 0, or to set it to a finite, small value. otherwise, if the client's main purpose consists in waiting for responses, a timeout of -1 is most suitable, so that the function only returns after some data has been received and handled. pick your fighter πŸ’…

😭 ERRORS 😭

all routines return any LDAP error resulting from a lower-level error in the API calls they are based on, or LDAP_SUCCESS in case of success. ldap_sync_poll(3) may return LDAP_SYNC_REFRESH_REQUIRED if a full refresh is requested by the server β€” in that case, it is appropriate to call ldap_sync_init(3) again, passing the same ldap_sync_t structure as resulted from any previous call. so don't panic, just re-init 🫢

πŸ’€ NOTES πŸ’€

the original page has this heading and then… literally nothing under it. iconic behavior honestly. no notes. ✨

🧚 SEE ALSO 🧚

πŸ‘‘ AUTHOR πŸ‘‘

designed and implemented by Pierangelo Masarati, based on RFC 4533 and loosely inspired by syncrepl code in slapd(8). king behavior 🫑

🌈 ACKNOWLEDGEMENTS 🌈

initially developed by SysNet s.n.c. OpenLDAP is developed and maintained by The OpenLDAP Project (http://www.openldap.org/). OpenLDAP is derived from University of Michigan LDAP 3.3 Release. full credit where credit is due, always πŸ’–


okay that's the whole page, every flag, every field, every LDAP_SYNC_CAPI_*, all of it β€” not me being thorough for once πŸ’… this was OpenLDAP 2.6.16, dated 2026/10/21, and that's the vibe check, we're done here bestie πŸŽ€βœ¨

πŸ“¦ where this page comes from