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");
178 struct berval cookie;
183 if (new_cookie) *new_cookie =
false;
188 bv_ret = ber_peek_tag(ber, &len);
189 if ((bv_ret != LDAP_TAG_SYNC_COOKIE) && (bv_ret != LDAP_TAG_SYNC_NEW_COOKIE))
return 0;
191 bv_ret = ber_scanf(ber,
"m", &cookie);
192 if (bv_ret == LBER_ERROR) {
193 ERROR(
"Malformed cookie tag");
201 if ((!cookie.bv_val) || (cookie.bv_len == 0))
return 0;
204 if (talloc_array_length(sync->
cookie) == cookie.bv_len) {
205 cookie_len = talloc_array_length(sync->
cookie);
206 if (memcmp(sync->
cookie, cookie.bv_val, cookie.bv_len) == 0) {
207 WARN(
"Ignoring new cookie \"%pV\": Identical to old cookie",
216 cookie_len = talloc_array_length(sync->
cookie);
217 DEBUG3(
"Got new cookie value \"%pV\" (%zu)",
220 if (new_cookie) *new_cookie =
true;
264 BerElement *ber = NULL;
265 struct berval entry_uuid = { 0 };
275 ERROR(
"searchResEntry missing syncStateValue control");
288 for (i = 0; ctrls[i] != NULL; i++) {
289 if (strcmp(ctrls[i]->ldctl_oid, LDAP_CONTROL_SYNC_STATE) == 0)
break;
291 if (!ctrls[i])
goto missing_control;
296 ber = ber_init(&ctrls[i]->ldctl_value);
298 ERROR(
"Failed allocating ber to handle syncStateValue control");
301 if (ber) ber_free(ber, 1);
306 bv_ret = ber_scanf(ber,
"{em", &op, &entry_uuid);
307 if ((bv_ret == LBER_ERROR) || (entry_uuid.bv_len == 0)) {
308 ERROR(
"Malformed syncUUID value");
314 if (ber_scanf(ber,
"}") == LBER_ERROR ) {
315 ERROR(
"Malformed syncStatevalue sequence");
321 switch (sync->
phase) {
332 ERROR(
"Entries with %s state are not allowed during refresh %s phase",
340 switch (sync->
phase) {
360 switch (sync->
phase) {
372 ERROR(
"Unknown entry state (%i)", op);
383 DEBUG3(
"Processing %s (%s), dn \"%s\", entryUUID %pV",
386 entry_dn ? entry_dn :
"<unknown>",
389 ldap_memfree(entry_dn);
395 switch (ldap_msgtype(
msg)) {
396 case LDAP_RES_SEARCH_ENTRY:
400 case LDAP_RES_SEARCH_REFERENCE:
412 if ((ret == 0) && new_cookie) {
456 struct berval *
data = NULL;
457 BerElement *ber = NULL;
459 ber_tag_t sync_info_tag;
460 int refresh_deletes = 0;
461 BerVarray sync_uuids = NULL;
464 int refresh_done =
false;
473 if (!oid || (strcmp(oid, LDAP_SYNC_INFO) != 0)) {
474 WARN(
"Ignoring intermediateResult with unexpected OID \"%s\"", oid ? oid :
"<unknown>");
478 ber = ber_init(
data);
480 ERROR(
"Failed allocating ber to handle syncInfo data");
485 sync_info_tag = ber_peek_tag(ber, &len);
488 switch (sync_info_tag) {
494 case LDAP_TAG_SYNC_NEW_COOKIE:
497 if (sync_uuids) ber_bvarray_free(sync_uuids);
498 if (ber) ber_free(ber, 1);
500 if (oid) ldap_memfree(oid);
506 ERROR(
"Missing cookie value");
515 case LDAP_TAG_SYNC_REFRESH_PRESENT:
516 switch (sync->
phase) {
525 ERROR(
"Invalid refresh phase transition (%s->%s)",
531 if (ber_scanf(ber,
"{") == LBER_ERROR) {
532 ERROR(
"Malformed refreshPresent sequence");
538 if (ber_peek_tag(ber, &len) == LDAP_TAG_REFRESHDONE) {
539 if (ber_scanf(ber,
"b", &refresh_done) == LBER_ERROR) {
540 ERROR(
"Malformed refresh sequence: Missing refreshDone tag value");
547 if (ber_scanf(ber,
"}") == LBER_ERROR ) {
548 ERROR(
"Malformed refreshPresent sequence");
559 case LDAP_TAG_SYNC_REFRESH_DELETE:
560 switch (sync->
phase) {
570 ERROR(
"Invalid refresh phase transition (%s->%s)",
577 if (ber_scanf(ber,
"{") == LBER_ERROR) {
578 ERROR(
"Malformed refreshPresent sequence");
584 if (ber_peek_tag(ber, &len) == LDAP_TAG_REFRESHDONE) {
585 if (ber_scanf(ber,
"b", &refresh_done) == LBER_ERROR) {
586 ERROR(
"Malformed refresh sequence: Missing refreshDone tag value");
593 if (ber_scanf(ber,
"}") == LBER_ERROR ) {
594 ERROR(
"Malformed refreshPresent sequence");
606 case LDAP_TAG_SYNC_ID_SET:
607 if (ber_scanf( ber,
"{") == LBER_ERROR) {
608 ERROR(
"Malformed syncIDSet");
614 if (ber_peek_tag(ber, &len) == LDAP_TAG_REFRESHDELETES) {
615 if (ber_scanf(ber,
"b", &refresh_deletes) == LBER_ERROR) {
616 ERROR(
"Malformed refresh_deletes tag");
621 if ((ber_scanf(ber,
"[W]}", &sync_uuids) == LBER_ERROR) || !sync_uuids) {
622 ERROR(
"syncIDSet missing set of IDs");
626 if (refresh_deletes) {
631 switch (sync->
phase) {
641 ERROR(
"Invalid refresh phase transition (%s->%s)",
651 switch (sync->
phase) {
660 ERROR(
"Invalid refresh phase transition (%s->%s)",
671 for (i = 0; sync_uuids[i].bv_val != NULL; i++) {
674 "bytes got %zu bytes", sync_uuids[i].bv_len);
679 if (ret < 0)
goto error;
682 ber_bvarray_free(sync_uuids);
687 ERROR(
"Invalid syncInfo tag %lu", sync_info_tag);
696 if (ber) ber_free(ber, 1);
697 if (oid) ldap_memfree(oid);
719 int refresh_deletes = 0;
722 BerElement *ber = NULL;
724 bool new_cookie =
false;
737 for (i = 0; ctrls[i] != NULL; i++) {
738 if (strcmp(ctrls[i]->ldctl_oid, LDAP_CONTROL_SYNC_DONE) == 0)
break;
742 ber = ber_init(&ctrls[i]->ldctl_value);
744 ERROR(
"Failed allocating ber to handle syncDoneValue control");
747 if (ber) ber_free(ber, 1);
751 if (ber_scanf( ber,
"{" ) == LBER_ERROR)
goto error;
755 if (ber_peek_tag(ber, &len) == LDAP_TAG_REFRESHDELETES) {
756 if (ber_scanf(ber,
"b", &refresh_deletes) == LBER_ERROR) {
757 ERROR(
"Malformed refresh sequence: Missing refreshDeletes tag value");
762 if (ber_scanf( ber,
"}" ) == LBER_ERROR) {
763 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.
void * uctx
User data associated with the handle.
connection_t * conn
Connection state 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.
#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.
bool fr_rb_insert(fr_rb_tree_t *tree, void const *data)
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)