diff options
Diffstat (limited to 'ldap/servers/plugins/replication/windows_protocol_util.c')
-rw-r--r-- | ldap/servers/plugins/replication/windows_protocol_util.c | 431 |
1 files changed, 404 insertions, 27 deletions
diff --git a/ldap/servers/plugins/replication/windows_protocol_util.c b/ldap/servers/plugins/replication/windows_protocol_util.c index 537e453a..fdcdc456 100644 --- a/ldap/servers/plugins/replication/windows_protocol_util.c +++ b/ldap/servers/plugins/replication/windows_protocol_util.c @@ -66,9 +66,9 @@ static void windows_map_mods_for_replay(Private_Repl_Protocol *prp,LDAPMod **ori static int is_subject_of_agreement_local(const Slapi_Entry *local_entry,const Repl_Agmt *ra); static int windows_create_remote_entry(Private_Repl_Protocol *prp,Slapi_Entry *original_entry, Slapi_DN *remote_sdn, Slapi_Entry **remote_entry, char** password); static int windows_get_local_entry(const Slapi_DN* local_dn,Slapi_Entry **local_entry); -static int windows_get_local_entry_by_uniqueid(Private_Repl_Protocol *prp,const char* uniqueid,Slapi_Entry **local_entry); +static int windows_get_local_entry_by_uniqueid(Private_Repl_Protocol *prp,const char* uniqueid,Slapi_Entry **local_entry, int is_global); static int windows_get_local_tombstone_by_uniqueid(Private_Repl_Protocol *prp,const char* uniqueid,Slapi_Entry **local_entry); -static int windows_search_local_entry_by_uniqueid(Private_Repl_Protocol *prp, const char *uniqueid, char ** attrs, Slapi_Entry **ret_entry, int tombstone, void * component_identity); +static int windows_search_local_entry_by_uniqueid(Private_Repl_Protocol *prp, const char *uniqueid, char ** attrs, Slapi_Entry **ret_entry, int tombstone, void * component_identity, int is_global); static int map_entry_dn_outbound(Slapi_Entry *e, Slapi_DN **dn, Private_Repl_Protocol *prp, int *missing_entry, int want_guid); static char* extract_ntuserdomainid_from_entry(Slapi_Entry *e); static char* extract_container(const Slapi_DN *entry_dn, const Slapi_DN *suffix_dn); @@ -83,7 +83,7 @@ static int is_guid_dn(Slapi_DN *remote_dn); static int map_windows_tombstone_dn(Slapi_Entry *e, Slapi_DN **dn, Private_Repl_Protocol *prp, int *exists); static int windows_check_mods_for_rdn_change(Private_Repl_Protocol *prp, LDAPMod **original_mods, Slapi_Entry *local_entry, Slapi_DN *remote_dn, char **newrdn); - +static int windows_get_superior_change(Private_Repl_Protocol *prp, Slapi_DN *local_dn, Slapi_DN *remote_dn, char **newsuperior, int to_windows); /* Controls the direction of flow for mapped attributes */ typedef enum mapping_types { @@ -261,7 +261,7 @@ static windows_attribute_map group_attribute_map[] = PRBool windows_ignore_error_and_keep_going(int error) { - int return_value; + int return_value = PR_FALSE; LDAPDebug( LDAP_DEBUG_TRACE, "=> windows_ignore_error_and_keep_going\n", 0, 0, 0 ); @@ -1140,7 +1140,7 @@ process_replay_add(Private_Repl_Protocol *prp, Slapi_Entry *add_entry, Slapi_Ent if (NULL == entryattrs) { slapi_log_error(SLAPI_LOG_FATAL, windows_repl_plugin_name, - "%s: windows_replay_update: Cannot convert entry to LDAPMods.\n", + "%s: windows_replay_add: Cannot convert entry to LDAPMods.\n", agmt_get_long_name(prp->agmt)); return_value = CONN_LOCAL_ERROR; } @@ -1157,7 +1157,7 @@ process_replay_add(Private_Repl_Protocol *prp, Slapi_Entry *add_entry, Slapi_Ent if (return_value) { slapi_log_error(SLAPI_LOG_FATAL, windows_repl_plugin_name, - "%s: windows_replay_update: Cannot replay add operation.\n", + "%s: windows_replay_add: Cannot replay add operation.\n", agmt_get_long_name(prp->agmt)); } ldap_mods_free(entryattrs, 1); @@ -1189,6 +1189,136 @@ modify_fallback: return return_value; } +/* + * If the local entry is a user, this function is called for moving a node. + * This is because the leaf RDN of the user on AD corresponds to the value of + * ntUniqueId in the entry on DS. + * + * If the local entry is a group, it is called both for moving and renaming. + * Group does not have the mapping. The leaf RDNs are shared between AD + * and DS. + */ +static ConnResult +process_replay_rename(Private_Repl_Protocol *prp, + Slapi_Entry *local_newentry, + Slapi_DN *local_origsdn, + const char *newrdn, + const char *newparent, + int deleteoldrdn, + int is_user, + int is_group) +{ + ConnResult rval = CONN_OPERATION_FAILED; + char *newsuperior = NULL; + const Repl_Agmt *winrepl_agmt; + const char *remote_subtree = NULL; /* Normalized subtree of the remote entry */ + const char *local_subtree = NULL; /* Normalized subtree of the local entry */ + char *norm_newparent = NULL; + char *p = NULL; + char *remote_rdn_val = NULL; + char *remote_rdn = NULL; + char *remote_dn = NULL; + char *local_pndn = NULL; + + if (NULL == newparent || NULL == local_origsdn || NULL == local_newentry) { + slapi_log_error(SLAPI_LOG_FATAL, windows_repl_plugin_name, + "process_replay_rename: %s is empty\n", + NULL==newparent?"newparent":NULL==local_origsdn?"local sdn": + NULL==local_newentry?"local entry":"unknown"); + goto bail; + } + if (0 == is_user && 0 == is_group) { + goto bail; /* nothing to do */ + } + + /* Generate newsuperior for AD */ + winrepl_agmt = prp->agmt; + remote_subtree = + slapi_sdn_get_ndn(windows_private_get_windows_subtree(winrepl_agmt)); + local_subtree = + slapi_sdn_get_ndn(windows_private_get_directory_subtree(winrepl_agmt)); + if (NULL == remote_subtree || NULL == local_subtree || + '\0' == *remote_subtree || '\0' == *local_subtree) { + slapi_log_error(SLAPI_LOG_FATAL, windows_repl_plugin_name, + "process_replay_rename: local subtree \"%s\" or " + "remote subtree \"%s\" is empty\n", + local_subtree?local_subtree:"empty", + remote_subtree?remote_subtree:"empty"); + goto bail; + } + norm_newparent = slapi_ch_strdup(newparent); + slapi_dn_normalize_case(norm_newparent); + p = strstr(norm_newparent, local_subtree); + if (NULL == p) { + slapi_log_error(SLAPI_LOG_FATAL, windows_repl_plugin_name, + "process_replay_rename: new superior \"%s\" is not " + "in the local subtree \"%s\"\n", + norm_newparent, local_subtree); + goto bail; /* not in the subtree */ + } + *p = '\0'; + if (p == norm_newparent) { + newsuperior = PR_smprintf("%s", remote_subtree); + } else { + newsuperior = PR_smprintf("%s%s", norm_newparent, remote_subtree); + } + + if (is_user) { + /* Newrdn remains the same when this function is called, + * as RDN on AD is CN type. If CN in RDN is modified remotely, + * is taken care in modify not in modrdn locally. */ + remote_rdn_val = slapi_entry_attr_get_charptr(local_newentry, "cn"); + if (NULL == remote_rdn_val) { + slapi_log_error(SLAPI_LOG_FATAL, windows_repl_plugin_name, + "process_replay_rename: local entry \"%s\" has no " + "ntUserDomainId\n", + slapi_entry_get_dn_const(local_newentry)); + goto bail; + } + remote_rdn = PR_smprintf("cn=%s", remote_rdn_val); + } else if (is_group) { + Slapi_RDN rdn = {0}; + const char *dn = slapi_sdn_get_dn(local_origsdn); + slapi_rdn_set_dn(&rdn, dn); + remote_rdn = slapi_ch_strdup(slapi_rdn_get_rdn(&rdn)); + slapi_rdn_done(&rdn); + } + + /* local parent normalized dn */ + local_pndn = /* strdup'ed */ + slapi_dn_parent((const char *)slapi_sdn_get_ndn(local_origsdn)); + p = strstr(local_pndn, local_subtree); + if (NULL == p) { + /* Original entry is not in the subtree. + * To add the entry after returning from this function, + * we set LDAP_NO_SUCH_OBJECT to the ldap error */ + windows_conn_set_error(prp->conn, LDAP_NO_SUCH_OBJECT); + goto bail; + } + *p = '\0'; + + /* generate a remote dn */ + remote_dn = PR_smprintf("%s,%s%s", remote_rdn, local_pndn, remote_subtree); + + if (is_user) { + rval = windows_conn_send_rename(prp->conn, remote_dn, + remote_rdn, (const char *)newsuperior, + deleteoldrdn, NULL, NULL /* returned controls */); + } else { + rval = windows_conn_send_rename(prp->conn, remote_dn, + newrdn, (const char *)newsuperior, + deleteoldrdn, NULL, NULL /* returned controls */); + } +bail: + slapi_ch_free_string(&norm_newparent); + slapi_ch_free_string(&remote_rdn_val); + slapi_ch_free_string(&remote_rdn); + slapi_ch_free_string(&remote_dn); + slapi_ch_free_string(&local_pndn); + slapi_ch_free_string(&newsuperior); + return rval; +} + /* * Given a changelog entry, construct the appropriate LDAP operations to sync * the operation to AD. @@ -1200,6 +1330,7 @@ windows_replay_update(Private_Repl_Protocol *prp, slapi_operation_parameters *op int rc = 0; char *password = NULL; int is_ours = 0; + int is_ours_force = 0; /* force to operate for RENAME/MODRDN */ int is_user = 0; int is_group = 0; Slapi_DN *remote_dn = NULL; @@ -1217,21 +1348,42 @@ windows_replay_update(Private_Repl_Protocol *prp, slapi_operation_parameters *op * inefficient as the tombstones build up. */ if (op->operation_type != SLAPI_OPERATION_DELETE) { - rc = windows_get_local_entry_by_uniqueid(prp, op->target_address.uniqueid, &local_entry); + rc = windows_get_local_entry_by_uniqueid(prp, op->target_address.uniqueid, &local_entry, 0); } else { rc = windows_get_local_tombstone_by_uniqueid(prp, op->target_address.uniqueid, &local_entry); } if (rc) { - slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, - "%s: windows_replay_update: failed to fetch local entry for %s operation dn=\"%s\"\n", - agmt_get_long_name(prp->agmt), - op2string(op->operation_type), op->target_address.dn); - goto error; + if (SLAPI_OPERATION_MODRDN == op->operation_type) { + /* Local entry was moved out of the subtree */ + /* We need to remove the entry on AD. */ + rc = windows_get_local_entry_by_uniqueid(prp, + op->target_address.uniqueid, &local_entry, 1 /* is_global */); + if (rc) { + slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, + "%s: windows_replay_update: failed to fetch local entry " + "for %s operation dn=\"%s\"\n", + agmt_get_long_name(prp->agmt), + op2string(op->operation_type), op->target_address.dn); + goto error; + } + op->operation_type = SLAPI_OPERATION_DELETE; + is_ours_force = 1; + } else { + slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, + "%s: windows_replay_update: failed to fetch local entry for %s operation dn=\"%s\"\n", + agmt_get_long_name(prp->agmt), + op2string(op->operation_type), op->target_address.dn); + goto error; + } } - is_ours = is_subject_of_agreement_local(local_entry, prp->agmt); + if (is_ours_force) { + is_ours = is_ours_force; + } else { + is_ours = is_subject_of_agreement_local(local_entry, prp->agmt); + } windows_is_local_entry_user_or_group(local_entry,&is_user,&is_group); slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, @@ -1359,12 +1511,28 @@ windows_replay_update(Private_Repl_Protocol *prp, slapi_operation_parameters *op } break; case SLAPI_OPERATION_MODRDN: - return_value = windows_conn_send_rename(prp->conn, op->target_address.dn, - op->p.p_modrdn.modrdn_newrdn, - op->p.p_modrdn.modrdn_newsuperior_address.dn, - op->p.p_modrdn.modrdn_deloldrdn, - NULL, NULL /* returned controls */); + /* only move case (newsuperior: ...) comse here since local leaf RDN is + * not identical to the remote leaf RDN. */ + { + return_value = process_replay_rename(prp, local_entry, local_dn, + op->p.p_modrdn.modrdn_newrdn, + op->p.p_modrdn.modrdn_newsuperior_address.dn, + op->p.p_modrdn.modrdn_deloldrdn, + is_user, is_group); + if (CONN_OPERATION_FAILED == return_value) { + int operation = 0; + int error = 0; + conn_get_error(prp->conn, &operation, &error); + /* The remote entry is missing. Let's add the renamed entry. */ + if (LDAP_NO_SUCH_OBJECT == error) { + return_value = process_replay_add(prp, + local_entry /* target_entry */, + local_entry, local_dn, remote_dn, + is_user, missing_entry, &password); + } + } break; + } default: slapi_log_error(SLAPI_LOG_FATAL, windows_repl_plugin_name, "%s: replay_update: Unknown " "operation type %lu found in changelog - skipping change.\n", @@ -1897,6 +2065,106 @@ mod_already_made(Private_Repl_Protocol *prp, Slapi_Mod *smod) return retval; } +/* + * Comparing the local_dn and the remote_dn, return the newsuperior. + * If to_windows is non-zero, the newsuperior is for the entry on AD. + * If to_windows is 0, the newsuperior is on DS. + * + * Caller must be responsible to free newsuperior. + * + * Return value: 0 if successful + * non zero (and *newsuperior is NULL) if failed + */ +static int +windows_get_superior_change(Private_Repl_Protocol *prp, + Slapi_DN *local_dn, Slapi_DN *remote_dn, + char **newsuperior, int to_windows) +{ + const Repl_Agmt *winrepl_agmt; + const char *remote_ndn = NULL; /* Normalized dn of the remote entry */ + const char *local_ndn = NULL; /* Normalized dn of the local entry */ + char *remote_pndn = NULL; /* Normalized parent dn of the remote entry */ + char *local_pndn = NULL; /* Normalized parent dn of the local entry */ + const char *remote_subtree = NULL; /* Normalized subtree of the remote entry */ + const char *local_subtree = NULL; /* Normalized subtree of the local entry */ + char *ptr = NULL; + int rc = -1; + + if (NULL == newsuperior) { + slapi_log_error(SLAPI_LOG_FATAL, windows_repl_plugin_name, + "windows_get_superior_change: newsuperior is NULL\n"); + goto bail; + } + /* Check if modrdn with superior has happened on AD */ + winrepl_agmt = prp->agmt; + remote_subtree = + slapi_sdn_get_ndn(windows_private_get_windows_subtree(winrepl_agmt)); + local_subtree = + slapi_sdn_get_ndn(windows_private_get_directory_subtree(winrepl_agmt)); + if (NULL == remote_subtree || NULL == local_subtree || + '\0' == *remote_subtree || '\0' == *local_subtree) { + slapi_log_error(SLAPI_LOG_FATAL, windows_repl_plugin_name, + "windows_get_superior_change: local subtree \"%s\" or " + "remote subtree \"%s\" is empty\n", + local_subtree?local_subtree:"empty", + remote_subtree?remote_subtree:"empty"); + goto bail; + } + remote_ndn = slapi_sdn_get_ndn(remote_dn); + local_ndn = slapi_sdn_get_ndn(local_dn); + if (NULL == remote_ndn || NULL == local_ndn || + '\0' == *remote_ndn || '\0' == *local_ndn) { + slapi_log_error(SLAPI_LOG_FATAL, windows_repl_plugin_name, + "windows_get_superior_change: local dn \"%s\" or " + "remote dn \"%s\" is empty\n", + local_ndn?local_ndn:"empty", remote_ndn?remote_ndn:"empty"); + goto bail; + } + remote_pndn = slapi_dn_parent((const char *)remote_ndn); /* strdup'ed */ + local_pndn = slapi_dn_parent((const char *)local_ndn); /* strdup'ed */ + if (NULL == remote_pndn || NULL == local_pndn || + '\0' == *remote_pndn || '\0' == *local_pndn) { + slapi_log_error(SLAPI_LOG_FATAL, windows_repl_plugin_name, + "windows_get_superior_change: local parent dn \"%s\" or " + "remote parent dn \"%s\" is empty\n", + local_pndn?local_pndn:"empty", + remote_pndn?remote_pndn:"empty"); + goto bail; + } + ptr = strstr(remote_pndn, remote_subtree); + if (ptr) { + *ptr = '\0'; /* if ptr != remote_pndn, remote_pndn ends with ',' */ + ptr = strstr(local_pndn, local_subtree); + if (ptr) { + *ptr = '\0'; /* if ptr != local_pndn, local_pndn ends with ',' */ + if (0 != strcmp(remote_pndn, local_pndn)) { + /* the remote parent is different from the local parent */ + if (to_windows) { + *newsuperior = + PR_smprintf("%s%s", local_pndn, remote_subtree); + } else { + *newsuperior = + PR_smprintf("%s%s", remote_pndn, local_subtree); + } + rc = 0; + } + } else { + slapi_log_error(SLAPI_LOG_REPL, windows_repl_plugin_name, + "windows_get_superior_change: local parent \"%s\" is not in " + "DirectoryReplicaSubtree \"%s\"\n", local_pndn, local_subtree); + } + } else { + slapi_log_error(SLAPI_LOG_REPL, windows_repl_plugin_name, + "windows_get_superior_change: remote parent \"%s\" is not in " + "WindowsReplicaSubtree \"%s\"\n", remote_pndn, remote_subtree); + } +bail: + slapi_ch_free_string(&remote_pndn); + slapi_ch_free_string(&local_pndn); + + return rc; +} + static int windows_check_mods_for_rdn_change(Private_Repl_Protocol *prp, LDAPMod **original_mods, Slapi_Entry *local_entry, Slapi_DN *remote_dn, char **newrdn) @@ -2615,7 +2883,7 @@ extract_guid_from_tombstone_dn(const char *dn) "CN=WDel Userdb1\\\nDEL:551706bc-ecf2-4b38-9284-9a8554171d69,CN=Deleted Objects,DC=magpie,DC=com" */ /* First find the 'DEL:' */ - if (colon_offset = strchr(dn,':')) { + if ((colon_offset = strchr(dn,':'))) { /* Then scan forward to the next ',' */ comma_offset = strchr(colon_offset,','); } @@ -2906,6 +3174,13 @@ map_entry_dn_outbound(Slapi_Entry *e, Slapi_DN **dn, Private_Repl_Protocol *prp, slapi_sdn_get_dn(new_dn), remote_entry ? slapi_entry_get_dn_const(remote_entry) : "(null)"); if (0 == rc && remote_entry) { + if (!is_subject_of_agreement_remote(remote_entry,prp->agmt)) { + /* The remote entry is our of scope of the agreement. + * Thus, we don't map the entry_dn. + * This occurs when the remote entry is moved out. */ + slapi_sdn_free(&new_dn); + retval = -1; + } slapi_entry_free(remote_entry); } else { slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, @@ -2943,7 +3218,7 @@ map_entry_dn_outbound(Slapi_Entry *e, Slapi_DN **dn, Private_Repl_Protocol *prp, slapi_ch_free_string(&cn_string); slapi_ch_free_string(&container_str); - } + } } } } else @@ -3945,6 +4220,56 @@ windows_update_local_entry(Private_Repl_Protocol *prp,Slapi_Entry *remote_entry, int retval = 0; Slapi_PBlock *pb = NULL; int do_modify = 0; + char *newsuperior = NULL; + const char *newrdn = NULL; + int is_user = 0, is_group = 0; + const char *newdn = NULL; + Slapi_RDN rdn = {0}; + + windows_is_local_entry_user_or_group(local_entry, &is_user, &is_group); + /* Compare the local and remote RDNs if it is a group */ + /* If they don't match, set it to newrdn. */ + if (is_group && strcmp(slapi_sdn_get_ndn(slapi_entry_get_sdn(local_entry)), + slapi_sdn_get_ndn(slapi_entry_get_sdn(remote_entry)))) { + newdn = slapi_sdn_get_dn(slapi_entry_get_sdn(remote_entry)); + slapi_rdn_set_dn(&rdn, newdn); + newrdn = slapi_rdn_get_rdn(&rdn); + } + + /* compare the parents */ + retval = windows_get_superior_change(prp, + slapi_entry_get_sdn(local_entry), + slapi_entry_get_sdn(remote_entry), + &newsuperior, 0 /* to_windows */); + + if (newsuperior || newrdn) { + /* remote parent is different from the local parent */ + Slapi_PBlock *pb = slapi_pblock_new (); + + if (NULL == newrdn) { + newdn = slapi_entry_get_dn_const(local_entry); + slapi_rdn_set_dn(&rdn, newdn); + newrdn = slapi_rdn_get_rdn(&rdn); + } + + /* rename entry */ + slapi_rename_internal_set_pb (pb, + slapi_sdn_get_dn(slapi_entry_get_sdn(local_entry)), + newrdn, newsuperior, 1 /* delete old RDNS */, + NULL /* controls */, NULL /* uniqueid */, + repl_get_plugin_identity(PLUGIN_MULTIMASTER_REPLICATION), 0); + slapi_modrdn_internal_pb (pb); + slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &retval); + slapi_pblock_destroy (pb); + slapi_ch_free_string(&newsuperior); + slapi_rdn_done(&rdn); + if (LDAP_SUCCESS != retval) { + slapi_log_error(SLAPI_LOG_FATAL, windows_repl_plugin_name, + "failed to rename entry (%s); " + "LDAP error - %d\n", newdn, retval); + return retval; + } + } slapi_mods_init (&smods, 0); @@ -4097,7 +4422,7 @@ error: } static int -windows_search_local_entry_by_uniqueid(Private_Repl_Protocol *prp, const char *uniqueid, char ** attrs, Slapi_Entry **ret_entry, int tombstone, void * component_identity) +windows_search_local_entry_by_uniqueid(Private_Repl_Protocol *prp, const char *uniqueid, char ** attrs, Slapi_Entry **ret_entry, int tombstone, void * component_identity, int is_global) { Slapi_Entry **entries = NULL; Slapi_PBlock *int_search_pb = NULL; @@ -4106,7 +4431,11 @@ windows_search_local_entry_by_uniqueid(Private_Repl_Protocol *prp, const char *u const Slapi_DN *local_subtree = NULL; *ret_entry = NULL; - local_subtree = windows_private_get_directory_subtree(prp->agmt); + if (is_global) { /* Search from the suffix (rename case) */ + local_subtree = agmt_get_replarea(prp->agmt); + } else { + local_subtree = windows_private_get_directory_subtree(prp->agmt); + } /* Searching for tombstones can be expensive, so the caller needs to specify if * we should search for a tombstone entry, or a normal entry. */ @@ -4146,12 +4475,12 @@ windows_search_local_entry_by_uniqueid(Private_Repl_Protocol *prp, const char *u } static int -windows_get_local_entry_by_uniqueid(Private_Repl_Protocol *prp,const char* uniqueid,Slapi_Entry **local_entry) +windows_get_local_entry_by_uniqueid(Private_Repl_Protocol *prp,const char* uniqueid,Slapi_Entry **local_entry, int is_global) { int retval = ENTRY_NOTFOUND; Slapi_Entry *new_entry = NULL; windows_search_local_entry_by_uniqueid( prp, uniqueid, NULL, &new_entry, 0, /* Don't search tombstones */ - repl_get_plugin_identity (PLUGIN_MULTIMASTER_REPLICATION)); + repl_get_plugin_identity (PLUGIN_MULTIMASTER_REPLICATION), is_global); if (new_entry) { *local_entry = new_entry; @@ -4166,7 +4495,7 @@ windows_get_local_tombstone_by_uniqueid(Private_Repl_Protocol *prp,const char* u int retval = ENTRY_NOTFOUND; Slapi_Entry *new_entry = NULL; windows_search_local_entry_by_uniqueid( prp, uniqueid, NULL, &new_entry, 1, /* Search for tombstones */ - repl_get_plugin_identity (PLUGIN_MULTIMASTER_REPLICATION)); + repl_get_plugin_identity (PLUGIN_MULTIMASTER_REPLICATION), 0); if (new_entry) { *local_entry = new_entry; @@ -4195,6 +4524,8 @@ windows_process_dirsync_entry(Private_Repl_Protocol *prp,Slapi_Entry *e, int is_ { Slapi_DN* local_sdn = NULL; int rc = 0; + int retried = 0; + Slapi_Entry *found_entry = NULL; /* deleted users are outside the 'correct container'. They live in cn=deleted objects, windows_private_get_directory_subtree( prp->agmt) */ @@ -4216,6 +4547,7 @@ windows_process_dirsync_entry(Private_Repl_Protocol *prp,Slapi_Entry *e, int is_ /* Is this entry one we should be interested in ? */ if (is_subject_of_agreement_remote(e,prp->agmt)) { +retry: /* First make its local DN */ rc = map_entry_dn_inbound(e, &local_sdn, prp->agmt); if ((0 == rc) && local_sdn) @@ -4275,8 +4607,32 @@ windows_process_dirsync_entry(Private_Repl_Protocol *prp,Slapi_Entry *e, int is_ } } slapi_sdn_free(&local_sdn); - } else - { + } else if (0 == retried) { + /* We should try one more thing. */ + /* In case a remote entry is moved from the outside of scope of + * the agreement into the inside, the entry e only has + * attributes: parentguid, objectguid, instancetype, name. + * We search Windows with the dn and retry using the found + * entry. + */ + ConnResult cres = 0; + const char *searchbase = slapi_entry_get_dn_const(e); + char *filter = "(objectclass=*)"; + + retried = 1; + cres = windows_search_entry(prp->conn, (char*)searchbase, + filter, &found_entry); + if (0 == cres && found_entry) { + /* + * Entry e originally allocated in windows_dirsync_inc_run + * is freed in windows_dirsync_inc_run. Assigning + * found_entry to e does not break the logic. + * "found_entry" is freed at the end of this function. + */ + e = found_entry; + goto retry; + } + } else { /* We should have been able to map the DN, so this is an error */ slapi_log_error(SLAPI_LOG_REPL, windows_repl_plugin_name, "%s: windows_process_dirsync_entry: failed to map " @@ -4287,7 +4643,28 @@ windows_process_dirsync_entry(Private_Repl_Protocol *prp,Slapi_Entry *e, int is_ local_sdn ? slapi_sdn_get_dn(local_sdn) : "null"); } } /* subject of agreement */ + else { /* The remote entry might be moved out of scope of agreement. */ + /* First make its local DN */ + rc = map_entry_dn_inbound(e, &local_sdn, prp->agmt); + if ((0 == rc) && local_sdn) + { + Slapi_Entry *local_entry = NULL; + /* Get the local entry if it exists */ + rc = windows_get_local_entry(local_sdn, &local_entry); + if ((0 == rc) && local_entry) + { + /* Need to delete the local entry since the remote counter + * part is now moved out of scope of the agreement. */ + /* Since map_Entry_dn_oubound returned local_sdn, + * the entry is either user or group. */ + rc = windows_delete_local_entry(local_sdn); + slapi_entry_free(local_entry); + } + slapi_sdn_free(&local_sdn); + } + } } /* is tombstone */ + slapi_entry_free(found_entry); return rc; } |