25 #define LOG_PREFIX "ldap_sync_rfc4533"
28 #include <freeradius-devel/util/debug.h>
33 {
L(
"newCookie"), LDAP_TAG_SYNC_NEW_COOKIE },
34 {
L(
"refreshDelete"), LDAP_TAG_SYNC_REFRESH_DELETE },
35 {
L(
"refreshIDSet"), LDAP_TAG_SYNC_ID_SET },
36 {
L(
"refreshPresent"), LDAP_TAG_SYNC_REFRESH_PRESENT }
76 LDAPControl ctrl = {0}, *ctrls[2] = { &ctrl, NULL };
77 BerElement *ber = NULL;
78 static char const *sync_ctl_oid = LDAP_CONTROL_SYNC;
94 ber = ber_alloc_t(LBER_USE_DER);
96 ERROR(
"Failed allocating ber for sync control");
109 HEXDUMP2(cookie, talloc_array_length(cookie),
"Sync starting with cookie: ");
110 memcpy(&bv_val, &cookie,
sizeof(bv_val));
113 bvc.bv_len = talloc_array_length(cookie);
115 ber_printf(ber,
"{eOb}", LDAP_SYNC_REFRESH_AND_PERSIST, &bvc,
false);
117 DEBUG2(
"Sync starting without a cookie");
118 ber_printf(ber,
"{eb}", LDAP_SYNC_REFRESH_AND_PERSIST,
false);
121 ret = ber_flatten2(ber, &ctrls[0]->ldctl_value, 0);
123 ERROR(
"Failed creating sync control");
130 memcpy(&ctrls[0]->ldctl_oid, &sync_ctl_oid,
sizeof(ctrls[0]->ldctl_oid));
131 ctrl.ldctl_iscritical = 1;
138 ERROR(
"Failed to start RFC 4533 query");
143 ERROR(
"Duplicate sync (msgid %i)", sync->
msgid);
147 DEBUG3(
"Sync created with base dn \"%s\", filter \"%s\", msgid %i",
157 PERROR(
"Inserting LDAP cookie timer failed");
177 struct berval cookie;
182 if (new_cookie) *new_cookie =
false;
187 bv_ret = ber_peek_tag(ber, &len);
188 if ((bv_ret != LDAP_TAG_SYNC_COOKIE) && (bv_ret != LDAP_TAG_SYNC_NEW_COOKIE))
return 0;
190 bv_ret = ber_scanf(ber,
"m", &cookie);
191 if (bv_ret == LBER_ERROR) {
192 ERROR(
"Malformed cookie tag");
200 if ((!cookie.bv_val) || (cookie.bv_len == 0))
return 0;
203 if (talloc_array_length(sync->
cookie) == cookie.bv_len) {
204 cookie_len = talloc_array_length(sync->
cookie);
205 if (memcmp(sync->
cookie, cookie.bv_val, cookie.bv_len) == 0) {
206 WARN(
"Ignoring new cookie \"%pV\": Identical to old cookie",
215 cookie_len = talloc_array_length(sync->
cookie);
216 DEBUG3(
"Got new cookie value \"%pV\" (%zu)",
219 if (new_cookie) *new_cookie =
true;
263 BerElement *ber = NULL;
264 struct berval entry_uuid = { 0 };
274 ERROR(
"searchResEntry missing syncStateValue control");
287 for (i = 0; ctrls[i] != NULL; i++) {
288 if (strcmp(ctrls[i]->ldctl_oid, LDAP_CONTROL_SYNC_STATE) == 0)
break;
290 if (!ctrls[i])
goto missing_control;
295 ber = ber_init(&ctrls[i]->ldctl_value);
297 ERROR(
"Failed allocating ber to handle syncStateValue control");
300 if (ber) ber_free(ber, 1);
305 bv_ret = ber_scanf(ber,
"{em", &op, &entry_uuid);
306 if ((bv_ret == LBER_ERROR) || (entry_uuid.bv_len == 0)) {
307 ERROR(
"Malformed syncUUID value");
313 if (ber_scanf(ber,
"}") == LBER_ERROR ) {
314 ERROR(
"Malformed syncStatevalue sequence");
320 switch (sync->
phase) {
331 ERROR(
"Entries with %s state are not allowed during refresh %s phase",
339 switch (sync->
phase) {
359 switch (sync->
phase) {
371 ERROR(
"Unknown entry state (%i)", op);
382 DEBUG3(
"Processing %s (%s), dn \"%s\", entryUUID %pV",
385 entry_dn ? entry_dn :
"<unknown>",
388 ldap_memfree(entry_dn);
394 switch (ldap_msgtype(
msg)) {
395 case LDAP_RES_SEARCH_ENTRY:
399 case LDAP_RES_SEARCH_REFERENCE:
411 if ((ret == 0) && new_cookie) {
455 struct berval *
data = NULL;
456 BerElement *ber = NULL;
458 ber_tag_t sync_info_tag;
459 int refresh_deletes = 0;
460 BerVarray sync_uuids = NULL;
463 int refresh_done =
false;
472 if (!oid || (strcmp(oid, LDAP_SYNC_INFO) != 0)) {
473 WARN(
"Ignoring intermediateResult with unexpected OID \"%s\"", oid ? oid :
"<unknown>");
477 ber = ber_init(
data);
479 ERROR(
"Failed allocating ber to handle syncInfo data");
484 sync_info_tag = ber_peek_tag(ber, &len);
487 switch (sync_info_tag) {
493 case LDAP_TAG_SYNC_NEW_COOKIE:
496 if (sync_uuids) ber_bvarray_free(sync_uuids);
497 if (ber) ber_free(ber, 1);
499 if (oid) ldap_memfree(oid);
505 ERROR(
"Missing cookie value");
514 case LDAP_TAG_SYNC_REFRESH_PRESENT:
515 switch (sync->
phase) {
524 ERROR(
"Invalid refresh phase transition (%s->%s)",
530 if (ber_scanf(ber,
"{") == LBER_ERROR) {
531 ERROR(
"Malformed refreshPresent sequence");
537 if (ber_peek_tag(ber, &len) == LDAP_TAG_REFRESHDONE) {
538 if (ber_scanf(ber,
"b", &refresh_done) == LBER_ERROR) {
539 ERROR(
"Malformed refresh sequence: Missing refreshDone tag value");
546 if (ber_scanf(ber,
"}") == LBER_ERROR ) {
547 ERROR(
"Malformed refreshPresent sequence");
558 case LDAP_TAG_SYNC_REFRESH_DELETE:
559 switch (sync->
phase) {
569 ERROR(
"Invalid refresh phase transition (%s->%s)",
576 if (ber_scanf(ber,
"{") == LBER_ERROR) {
577 ERROR(
"Malformed refreshPresent sequence");
583 if (ber_peek_tag(ber, &len) == LDAP_TAG_REFRESHDONE) {
584 if (ber_scanf(ber,
"b", &refresh_done) == LBER_ERROR) {
585 ERROR(
"Malformed refresh sequence: Missing refreshDone tag value");
592 if (ber_scanf(ber,
"}") == LBER_ERROR ) {
593 ERROR(
"Malformed refreshPresent sequence");
605 case LDAP_TAG_SYNC_ID_SET:
606 if (ber_scanf( ber,
"{") == LBER_ERROR) {
607 ERROR(
"Malformed syncIDSet");
613 if (ber_peek_tag(ber, &len) == LDAP_TAG_REFRESHDELETES) {
614 if (ber_scanf(ber,
"b", &refresh_deletes) == LBER_ERROR) {
615 ERROR(
"Malformed refresh_deletes tag");
620 if ((ber_scanf(ber,
"[W]}", &sync_uuids) == LBER_ERROR) || !sync_uuids) {
621 ERROR(
"syncIDSet missing set of IDs");
625 if (refresh_deletes) {
630 switch (sync->
phase) {
640 ERROR(
"Invalid refresh phase transition (%s->%s)",
650 switch (sync->
phase) {
659 ERROR(
"Invalid refresh phase transition (%s->%s)",
670 for (i = 0; sync_uuids[i].bv_val != NULL; i++) {
673 "bytes got %zu bytes", sync_uuids[i].bv_len);
678 if (ret < 0)
goto error;
681 ber_bvarray_free(sync_uuids);
686 ERROR(
"Invalid syncInfo tag %lu", sync_info_tag);
695 if (ber) ber_free(ber, 1);
696 if (oid) ldap_memfree(oid);
718 int refresh_deletes = 0;
721 BerElement *ber = NULL;
723 bool new_cookie =
false;
736 for (i = 0; ctrls[i] != NULL; i++) {
737 if (strcmp(ctrls[i]->ldctl_oid, LDAP_CONTROL_SYNC_DONE) == 0)
break;
741 ber = ber_init(&ctrls[i]->ldctl_value);
743 ERROR(
"Failed allocating ber to handle syncDoneValue control");
746 if (ber) ber_free(ber, 1);
750 if (ber_scanf( ber,
"{" ) == LBER_ERROR)
goto error;
754 if (ber_peek_tag(ber, &len) == LDAP_TAG_REFRESHDELETES) {
755 if (ber_scanf(ber,
"b", &refresh_deletes) == LBER_ERROR) {
756 ERROR(
"Malformed refresh sequence: Missing refreshDeletes tag value");
761 if (ber_scanf( ber,
"}" ) == LBER_ERROR) {
762 ERROR(
"Malformed syncDoneValue sequence");
#define L(_str)
Helper for initialising arrays of string literals.
#define fr_cond_assert(_x)
Calls panic_action ifndef NDEBUG, else logs error and evaluates to value of _x.
#define fr_event_timer_in(...)
unlang_interpret_t * unlang_interpret_get_thread_default(void)
Get the default interpreter for this thread.
static void fr_ldap_berval_to_value_shallow(fr_value_box_t *value, struct berval *berval)
Inline function to copy pointers from a berval to a valuebox.
uint8_t * fr_ldap_berval_to_bin(TALLOC_CTX *ctx, struct berval const *in)
Convert a berval to a talloced buffer.
LDAP * handle
libldap handle.
fr_connection_t * conn
Connection state handle.
void * uctx
User data associated with the handle.
@ LDAP_PROC_SUCCESS
Operation was successful.
Tracks the state of a libldap connection handle.
fr_ldap_rcode_t fr_ldap_search_async(int *msgid, request_t *request, fr_ldap_connection_t *pconn, char const *dn, int scope, char const *filter, char const *const *attrs, LDAPControl **serverctrls, LDAPControl **clientctrls)
Search for something in the LDAP directory.
#define HEXDUMP2(_data, _len, _fmt,...)
#define DEBUG_ENABLED3
True if global debug level 1-3 messages are enabled.
static const conf_parser_t config[]
char const * filter
Filter to retrieve only user objects.
sync_op_t
Operations to perform on entries.
@ SYNC_OP_ADD
Entry should be added to our copy.
@ SYNC_OP_MODIFY
Entry should be updated in our copy.
@ SYNC_OP_INVALID
Invalid sync operation.
@ SYNC_OP_DELETE
Entry should be deleted from our copy.
@ SYNC_OP_PRESENT
Entry is present and unchanged on the server.
char const * base_dn
DN to search for users under.
An instance of a proto_ldap_sync listen section.
Areas of the directory to receive notifications for.
int ldap_sync_cookie_store(sync_state_t *sync, bool refresh)
Add a new cookie packet ctx to the pending list.
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)
Enqueue a new entry change packet.
fr_table_num_sorted_t const sync_op_table[]
Operations performed on entries.
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)
Allocate a sync state.
void ldap_sync_cookie_event(fr_event_list_t *el, UNUSED fr_time_t now, void *uctx)
Event to handle storing of cookies on a timed basis.
int8_t sync_state_cmp(void const *one, void const *two)
Compare two sync state structures on msgid.
uint8_t * cookie
Opaque cookie, used to resume synchronisation.
sync_phases_t phase
Phase this sync is in.
int msgid
The unique identifier for this sync session.
sync_config_t const * config
Configuration for this sync.
static fr_table_num_sorted_t const sync_ldap_msg_table[]
Types of LDAP messages relevant to LDAP sync.
@ SYNC_PHASE_DELETE
Currently in the delete phase.
@ SYNC_PHASE_DONE
Refresh phase is complete.
@ SYNC_PHASE_INIT
We haven't entered any of the refresh phases.
@ SYNC_PHASE_PRESENT
Currently in the present phase.
fr_event_timer_t const * cookie_ev
Timer event for sending cookies.
fr_ldap_connection_t * conn
Connection the sync is running on.
fr_pair_list_t trigger_args
Arguments to make available in triggers.
State of an individual sync.
bool fr_rb_insert(fr_rb_tree_t *tree, void const *data)
Insert data into a tree.
#define fr_rb_inline_talloc_alloc(_ctx, _type, _field, _data_cmp, _data_free)
Allocs a red black that verifies elements are of a specific talloc type.
The main red black tree structure.
static size_t const sync_info_tag_table_len
int rfc4533_sync_refresh_required(sync_state_t *sync, LDAPMessage *msg, LDAPControl **ctrls)
Handle result code of e-syncRefreshRequired.
static size_t const sync_phase_table_len
static fr_table_num_sorted_t const sync_info_tag_table[]
Types of Sync Info messages.
int rfc4533_sync_search_entry(sync_state_t *sync, LDAPMessage *msg, LDAPControl **ctrls)
Handle a SearchResultEntry or SearchResultReference response from an RFC 4533 server.
int rfc4533_sync_init(fr_ldap_connection_t *conn, size_t sync_no, proto_ldap_sync_t const *inst, uint8_t const *cookie)
Allocate and initialise RFC 4533 sync queries.
static int sync_new_cookie(bool *new_cookie, sync_state_t *sync, BerElement *ber)
Check for the presence of a cookie in a ber value.
static fr_table_num_sorted_t const sync_phase_table[]
Phases of an RFC 4533 sync.
int rfc4533_sync_intermediate(sync_state_t *sync, LDAPMessage *msg, UNUSED LDAPControl **ctrls)
Handle a LDAP_RES_INTERMEDIATE (SyncInfo) response.
MEM(pair_append_request(&vp, attr_eap_aka_sim_identity) >=0)
eap_aka_sim_process_conf_t * inst
#define fr_table_str_by_value(_table, _number, _def)
Convert an integer to a string.
An element in a lexicographically sorted array of name to num mappings.
int trigger_exec(unlang_interpret_t *intp, CONF_SECTION const *cs, char const *name, bool rate_limit, fr_pair_list_t *args)
Execute a trigger - call an executable to process an event.
#define fr_box_strvalue_len(_val, _len)