|
|
@@ -71,11 +71,16 @@ static int windows_get_local_entry(const Slapi_DN* local_dn,Slapi_Entry **local_
|
|
|
static int windows_get_local_entry_by_uniqueid(Private_Repl_Protocol *prp,const char* uniqueid,Slapi_Entry **local_entry);
|
|
|
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);
|
|
|
static int windows_get_remote_entry (Private_Repl_Protocol *prp, const Slapi_DN* remote_dn,Slapi_Entry **remote_entry);
|
|
|
+static int windows_get_remote_tombstone(Private_Repl_Protocol *prp, const Slapi_DN* remote_dn,Slapi_Entry **remote_entry);
|
|
|
+static int windows_reanimate_tombstone(Private_Repl_Protocol *prp, const Slapi_DN* tombstone_dn, const char* new_dn);
|
|
|
static const char* op2string (int op);
|
|
|
static int is_subject_of_agreemeent_remote(Slapi_Entry *e, const Repl_Agmt *ra);
|
|
|
static int map_entry_dn_inbound(Slapi_Entry *e, Slapi_DN **dn, const Repl_Agmt *ra);
|
|
|
static int windows_update_remote_entry(Private_Repl_Protocol *prp,Slapi_Entry *remote_entry,Slapi_Entry *local_entry);
|
|
|
+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);
|
|
|
|
|
|
|
|
|
/* Controls the direction of flow for mapped attributes */
|
|
|
@@ -363,7 +368,7 @@ windows_dump_entry(const char *string, Slapi_Entry *e)
|
|
|
slapi_log_error(SLAPI_LOG_REPL, NULL, "Windows sync entry: %s %s\n", string, buffer);
|
|
|
if (buffer)
|
|
|
{
|
|
|
- slapi_ch_free((void**)&buffer);
|
|
|
+ slapi_ch_free_string(&buffer);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
@@ -953,11 +958,85 @@ process_replay_add(Private_Repl_Protocol *prp, slapi_operation_parameters *op, S
|
|
|
int rc = 0;
|
|
|
|
|
|
slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
|
|
|
- "%s: process_replay_add: dn=\"%s\" (%s,%s)\n",
|
|
|
- agmt_get_long_name(prp->agmt), slapi_sdn_get_dn(remote_dn), missing_entry ? "not present" : "already present" , remote_add_allowed ? "add allowed" : "add not allowed");
|
|
|
+ "%s: process_replay_add: dn=\"%s\" (%s,%s)\n", agmt_get_long_name(prp->agmt),
|
|
|
+ slapi_sdn_get_dn(remote_dn), missing_entry ? "not present" : "already present",
|
|
|
+ remote_add_allowed ? "add allowed" : "add not allowed");
|
|
|
|
|
|
if (missing_entry)
|
|
|
{
|
|
|
+ /* If DN is a GUID, we need to attempt to reanimate the tombstone */
|
|
|
+ if (is_guid_dn(remote_dn)) {
|
|
|
+ int tstone_exists = 0;
|
|
|
+ int reanimate_rc = -1;
|
|
|
+ char *new_dn_string = NULL;
|
|
|
+ char *cn_string = NULL;
|
|
|
+ Slapi_DN *tombstone_dn = NULL;
|
|
|
+
|
|
|
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
|
|
|
+ "%s: process_replay_add: dn=\"%s\" appears to have been"
|
|
|
+ " deleted on remote side. Searching for tombstone.\n",
|
|
|
+ agmt_get_long_name(prp->agmt), slapi_sdn_get_dn(remote_dn));
|
|
|
+
|
|
|
+ /* Map local entry to tombstone DN and verify that it exists on
|
|
|
+ * AD side */
|
|
|
+ map_windows_tombstone_dn(local_entry, &tombstone_dn, prp, &tstone_exists);
|
|
|
+
|
|
|
+ /* We can't use a GUID DN, so rewrite to the new mapped DN. */
|
|
|
+ cn_string = slapi_entry_attr_get_charptr(local_entry,"cn");
|
|
|
+ if (!cn_string) {
|
|
|
+ cn_string = slapi_entry_attr_get_charptr(local_entry,"ntuserdomainid");
|
|
|
+ }
|
|
|
+
|
|
|
+ if (cn_string) {
|
|
|
+ char *rdnstr = NULL;
|
|
|
+ char *container_str = NULL;
|
|
|
+ const char *suffix = slapi_sdn_get_dn(windows_private_get_windows_subtree(prp->agmt));
|
|
|
+
|
|
|
+ container_str = extract_container(slapi_entry_get_sdn_const(local_entry),
|
|
|
+ windows_private_get_directory_subtree(prp->agmt));
|
|
|
+ new_dn_string = PR_smprintf("cn=%s,%s%s", cn_string, container_str, suffix);
|
|
|
+
|
|
|
+ if (new_dn_string) {
|
|
|
+ /* If the tombstone exists, reanimate it. If the tombstone
|
|
|
+ * does not exist, we'll create a new entry in AD, which
|
|
|
+ * will end up getting a new GUID generated by AD. */
|
|
|
+ if (tstone_exists) {
|
|
|
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
|
|
|
+ "%s: process_replay_add: Reanimating tombstone (dn=\"%s\") to"
|
|
|
+ " normal entry (dn=\"%s\").\n", agmt_get_long_name(prp->agmt),
|
|
|
+ slapi_sdn_get_dn(tombstone_dn), new_dn_string);
|
|
|
+ reanimate_rc = windows_reanimate_tombstone(prp, tombstone_dn, (const char *)new_dn_string);
|
|
|
+ if (reanimate_rc != 0) {
|
|
|
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
|
|
|
+ "%s: process_replay_add: Reanimation of tombstone"
|
|
|
+ " (dn=\"%s\") failed. A new entry (dn=\"%s\")"
|
|
|
+ " will be added instead.\n", agmt_get_long_name(prp->agmt),
|
|
|
+ slapi_sdn_get_dn(tombstone_dn), new_dn_string);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Clear out the old GUID DN and use the new one. We hand off the memory
|
|
|
+ * for new_dn_string into the remote_dn. */
|
|
|
+ slapi_sdn_done(remote_dn);
|
|
|
+ slapi_sdn_set_dn_passin(remote_dn, new_dn_string);
|
|
|
+ }
|
|
|
+
|
|
|
+ slapi_ch_free_string(&cn_string);
|
|
|
+ slapi_ch_free_string(&container_str);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (tombstone_dn) {
|
|
|
+ slapi_sdn_free(&tombstone_dn);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (reanimate_rc == 0) {
|
|
|
+ /* We reanimated a tombstone, so an add won't work. We
|
|
|
+ * fallback to doing a modify of the newly reanimated
|
|
|
+ * entry. */
|
|
|
+ goto modify_fallback;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
if (remote_add_allowed) {
|
|
|
LDAPMod **entryattrs = NULL;
|
|
|
Slapi_Entry *mapped_entry = NULL;
|
|
|
@@ -971,17 +1050,26 @@ process_replay_add(Private_Repl_Protocol *prp, slapi_operation_parameters *op, S
|
|
|
mapped_entry = NULL;
|
|
|
if (NULL == entryattrs)
|
|
|
{
|
|
|
- slapi_log_error(SLAPI_LOG_FATAL, windows_repl_plugin_name,"%s: windows_replay_update: Cannot convert entry to LDAPMods.\n",agmt_get_long_name(prp->agmt));
|
|
|
+ slapi_log_error(SLAPI_LOG_FATAL, windows_repl_plugin_name,
|
|
|
+ "%s: windows_replay_update: Cannot convert entry to LDAPMods.\n",
|
|
|
+ agmt_get_long_name(prp->agmt));
|
|
|
return_value = CONN_LOCAL_ERROR;
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
windows_log_add_entry_remote(local_dn, remote_dn);
|
|
|
- return_value = windows_conn_send_add(prp->conn, slapi_sdn_get_dn(remote_dn), entryattrs, NULL, NULL);
|
|
|
- /* It's possible that the entry already exists in AD, in which case we fall back to modify it */
|
|
|
+ return_value = windows_conn_send_add(prp->conn, slapi_sdn_get_dn(remote_dn),
|
|
|
+ entryattrs, NULL, NULL);
|
|
|
+ /* It's possible that the entry already exists in AD, in which
|
|
|
+ * case we fall back to modify it */
|
|
|
+ /* NGK - This fallback doesn't seem to happen, at least not at this point
|
|
|
+ * in the code. The only chance to fallback to doing a modify is if
|
|
|
+ * missing_entry is set to 0 at the top of this function. */
|
|
|
if (return_value)
|
|
|
{
|
|
|
- slapi_log_error(SLAPI_LOG_FATAL, windows_repl_plugin_name,"%s: windows_replay_update: Cannot replay add operation.\n",agmt_get_long_name(prp->agmt));
|
|
|
+ slapi_log_error(SLAPI_LOG_FATAL, windows_repl_plugin_name,
|
|
|
+ "%s: windows_replay_update: Cannot replay add operation.\n",
|
|
|
+ agmt_get_long_name(prp->agmt));
|
|
|
}
|
|
|
ldap_mods_free(entryattrs, 1);
|
|
|
entryattrs = NULL;
|
|
|
@@ -989,14 +1077,15 @@ process_replay_add(Private_Repl_Protocol *prp, slapi_operation_parameters *op, S
|
|
|
} else
|
|
|
{
|
|
|
slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
|
|
|
- "%s: process_replay_add: failed to create mapped entry dn=\"%s\"\n",agmt_get_long_name(prp->agmt), slapi_sdn_get_dn(remote_dn));
|
|
|
+ "%s: process_replay_add: failed to create mapped entry dn=\"%s\"\n",
|
|
|
+ agmt_get_long_name(prp->agmt), slapi_sdn_get_dn(remote_dn));
|
|
|
}
|
|
|
}
|
|
|
} else
|
|
|
{
|
|
|
-
|
|
|
Slapi_Entry *remote_entry = NULL;
|
|
|
|
|
|
+modify_fallback:
|
|
|
/* Fetch the remote entry */
|
|
|
rc = windows_get_remote_entry(prp, remote_dn,&remote_entry);
|
|
|
if (0 == rc && remote_entry) {
|
|
|
@@ -1018,7 +1107,6 @@ ConnResult
|
|
|
windows_replay_update(Private_Repl_Protocol *prp, slapi_operation_parameters *op)
|
|
|
{
|
|
|
ConnResult return_value = 0;
|
|
|
- LDAPControl *update_control = NULL; /* No controls used for AD */
|
|
|
int rc = 0;
|
|
|
char *password = NULL;
|
|
|
int is_ours = 0;
|
|
|
@@ -1097,7 +1185,7 @@ windows_replay_update(Private_Repl_Protocol *prp, slapi_operation_parameters *op
|
|
|
slapi_mod_dump(mapped_mods[i],i);
|
|
|
}
|
|
|
}
|
|
|
- return_value = windows_conn_send_modify(prp->conn, slapi_sdn_get_dn(remote_dn), mapped_mods, update_control,NULL /* returned controls */);
|
|
|
+ return_value = windows_conn_send_modify(prp->conn, slapi_sdn_get_dn(remote_dn), mapped_mods, NULL, NULL /* returned controls */);
|
|
|
}
|
|
|
if (mapped_mods)
|
|
|
{
|
|
|
@@ -1109,7 +1197,7 @@ windows_replay_update(Private_Repl_Protocol *prp, slapi_operation_parameters *op
|
|
|
case SLAPI_OPERATION_DELETE:
|
|
|
if (delete_remote_entry_allowed(local_entry))
|
|
|
{
|
|
|
- return_value = windows_conn_send_delete(prp->conn, slapi_sdn_get_dn(remote_dn), update_control, NULL /* returned controls */);
|
|
|
+ return_value = windows_conn_send_delete(prp->conn, slapi_sdn_get_dn(remote_dn), NULL, NULL /* returned controls */);
|
|
|
slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
|
|
|
"%s: windows_replay_update: deleted remote entry, dn=\"%s\", result=%d\n",
|
|
|
agmt_get_long_name(prp->agmt), slapi_sdn_get_dn(remote_dn), return_value);
|
|
|
@@ -1125,7 +1213,7 @@ windows_replay_update(Private_Repl_Protocol *prp, slapi_operation_parameters *op
|
|
|
op->p.p_modrdn.modrdn_newrdn,
|
|
|
op->p.p_modrdn.modrdn_newsuperior_address.dn,
|
|
|
op->p.p_modrdn.modrdn_deloldrdn,
|
|
|
- update_control, NULL /* returned controls */);
|
|
|
+ NULL, NULL /* returned controls */);
|
|
|
break;
|
|
|
default:
|
|
|
slapi_log_error(SLAPI_LOG_FATAL, windows_repl_plugin_name, "%s: replay_update: Unknown "
|
|
|
@@ -1296,7 +1384,7 @@ windows_create_remote_entry(Private_Repl_Protocol *prp,Slapi_Entry *original_ent
|
|
|
goto error;
|
|
|
}
|
|
|
new_entry = slapi_str2entry(entry_string, 0);
|
|
|
- slapi_ch_free((void**)&entry_string);
|
|
|
+ slapi_ch_free_string(&entry_string);
|
|
|
if (NULL == new_entry)
|
|
|
{
|
|
|
goto error;
|
|
|
@@ -1399,7 +1487,7 @@ windows_create_remote_entry(Private_Repl_Protocol *prp,Slapi_Entry *original_ent
|
|
|
slapi_attr_set_type(new_attr, new_type);
|
|
|
}
|
|
|
}
|
|
|
- slapi_ch_free((void**)&new_type);
|
|
|
+ slapi_ch_free_string(&new_type);
|
|
|
}
|
|
|
/* password mods are treated specially */
|
|
|
if (0 == slapi_attr_type_cmp(type, PSEUDO_ATTR_UNHASHEDUSERPASSWORD, SLAPI_TYPE_CMP_SUBTYPE) )
|
|
|
@@ -1469,7 +1557,7 @@ windows_create_remote_entry(Private_Repl_Protocol *prp,Slapi_Entry *original_ent
|
|
|
error:
|
|
|
if (username)
|
|
|
{
|
|
|
- slapi_ch_free((void**)&username);
|
|
|
+ slapi_ch_free_string(&username);
|
|
|
}
|
|
|
if (new_entry)
|
|
|
{
|
|
|
@@ -1633,7 +1721,7 @@ windows_map_mods_for_replay(Private_Repl_Protocol *prp,LDAPMod **original_mods,
|
|
|
|
|
|
slapi_mods_add_modbvps(&mapped_smods,mod->mod_op,mapped_type,mod->mod_bvalues);
|
|
|
}
|
|
|
- slapi_ch_free((void**)&mapped_type);
|
|
|
+ slapi_ch_free_string(&mapped_type);
|
|
|
} else
|
|
|
{
|
|
|
/* password mods are treated specially */
|
|
|
@@ -1832,6 +1920,70 @@ windows_get_remote_entry (Private_Repl_Protocol *prp, const Slapi_DN* remote_dn,
|
|
|
return retval;
|
|
|
}
|
|
|
|
|
|
+/* Search for a tombstone entry in AD by DN */
|
|
|
+static int
|
|
|
+windows_get_remote_tombstone (Private_Repl_Protocol *prp, const Slapi_DN* remote_dn,Slapi_Entry **remote_entry)
|
|
|
+{
|
|
|
+ int retval = 0;
|
|
|
+ ConnResult cres = 0;
|
|
|
+ char *filter = "(objectclass=*)";
|
|
|
+ const char *searchbase = NULL;
|
|
|
+ Slapi_Entry *found_entry = NULL;
|
|
|
+ LDAPControl *server_controls[2];
|
|
|
+
|
|
|
+ /* We need to send the "Return Deleted Objects" control to search
|
|
|
+ * for tombstones. */
|
|
|
+ slapi_build_control(REPL_RETURN_DELETED_OBJS_CONTROL_OID, NULL, PR_TRUE,
|
|
|
+ &server_controls[0]);
|
|
|
+ server_controls[1] = NULL;
|
|
|
+
|
|
|
+ searchbase = slapi_sdn_get_dn(remote_dn);
|
|
|
+ cres = windows_search_entry_ext(prp->conn, (char*)searchbase, filter,
|
|
|
+ &found_entry, server_controls);
|
|
|
+ if (cres) {
|
|
|
+ retval = -1;
|
|
|
+ } else {
|
|
|
+ if (found_entry) {
|
|
|
+ *remote_entry = found_entry;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ ldap_control_free(server_controls[0]);
|
|
|
+ return retval;
|
|
|
+}
|
|
|
+
|
|
|
+/* Reanimate a tombstone in AD. Returns 0 on success, otherwise you get the
|
|
|
+ * LDAP return code from the modify operation. */
|
|
|
+static int
|
|
|
+windows_reanimate_tombstone(Private_Repl_Protocol *prp, const Slapi_DN* tombstone_dn, const char* new_dn)
|
|
|
+{
|
|
|
+ int retval = 0;
|
|
|
+ LDAPControl *server_controls[2];
|
|
|
+ Slapi_Mods smods = {0};
|
|
|
+
|
|
|
+ /* We need to send the "Return Deleted Objects" control to modify
|
|
|
+ * tombstone entries. */
|
|
|
+ slapi_build_control(REPL_RETURN_DELETED_OBJS_CONTROL_OID, NULL, PR_TRUE,
|
|
|
+ &server_controls[0]);
|
|
|
+ server_controls[1] = NULL;
|
|
|
+
|
|
|
+ /* To reanimate a tombstone in AD, you need to send a modify
|
|
|
+ * operation that does two things. It must remove the isDeleted
|
|
|
+ * attribute from the entry and it must modify the DN. This DN
|
|
|
+ * does not have to be the same place in the tree that the entry
|
|
|
+ * previously existed. */
|
|
|
+ slapi_mods_init (&smods, 0);
|
|
|
+ slapi_mods_add_mod_values(&smods, LDAP_MOD_DELETE, "isDeleted", NULL);
|
|
|
+ slapi_mods_add_string(&smods, LDAP_MOD_REPLACE, "distinguishedName", new_dn);
|
|
|
+
|
|
|
+ retval = windows_conn_send_modify(prp->conn, slapi_sdn_get_dn(tombstone_dn),
|
|
|
+ slapi_mods_get_ldapmods_byref(&smods), server_controls, NULL );
|
|
|
+
|
|
|
+ slapi_mods_done(&smods);
|
|
|
+ ldap_control_free(server_controls[0]);
|
|
|
+ return retval;
|
|
|
+}
|
|
|
+
|
|
|
static int
|
|
|
find_entry_by_attr_value(const char *attribute, const char *value, Slapi_Entry **e, const Repl_Agmt *ra)
|
|
|
{
|
|
|
@@ -1858,7 +2010,7 @@ find_entry_by_attr_value(const char *attribute, const char *value, Slapi_Entry *
|
|
|
LDAP_SCOPE_SUBTREE, query, NULL, 0, NULL, NULL,
|
|
|
(void *)plugin_get_default_component_id(), 0);
|
|
|
slapi_search_internal_pb(pb);
|
|
|
- slapi_ch_free((void **)&query);
|
|
|
+ slapi_ch_free_string(&query);
|
|
|
|
|
|
slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &rval);
|
|
|
if (rval != LDAP_SUCCESS)
|
|
|
@@ -1906,9 +2058,9 @@ find_entry_by_guid(const char *guid, Slapi_Entry **e, const Repl_Agmt *ra)
|
|
|
return find_entry_by_attr_value("ntUniqueId",guid,e,ra);
|
|
|
}
|
|
|
|
|
|
-/* Remove dashes from a GUID string */
|
|
|
+/* Remove dashes from a GUID string. */
|
|
|
static void
|
|
|
-dedash(char *str)
|
|
|
+dedash_guid(char *str)
|
|
|
{
|
|
|
char *p = str;
|
|
|
char c = '\0';
|
|
|
@@ -1930,10 +2082,41 @@ dedash(char *str)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+/* Add dashes into a GUID string. If the guid is not formatted properly,
|
|
|
+ * we will free it and set the pointer to NULL. */
|
|
|
+static void
|
|
|
+dash_guid(char **str)
|
|
|
+{
|
|
|
+ if (strlen(*str) == NTUNIQUEID_LENGTH) {
|
|
|
+ char *p = NULL;
|
|
|
+ /* Add extra room for the dashes */
|
|
|
+ *str = slapi_ch_realloc(*str, AD_GUID_LENGTH + 1);
|
|
|
+
|
|
|
+ /* GUID needs to be in 8-4-4-4-12 format */
|
|
|
+ p = *str + 23;
|
|
|
+ memmove(p + 1, *str + 20, 12);
|
|
|
+ *p = '-';
|
|
|
+ p = *str + 18;
|
|
|
+ memmove(p + 1, *str + 16, 4);
|
|
|
+ *p = '-';
|
|
|
+ p = *str + 13;
|
|
|
+ memmove(p + 1, *str + 12, 4);
|
|
|
+ *p = '-';
|
|
|
+ p = *str + 8;
|
|
|
+ memmove(p + 1, *str + 8, 4);
|
|
|
+ *p = '-';
|
|
|
+ p = *str + 36;
|
|
|
+ *p = '\0';
|
|
|
+ } else {
|
|
|
+ /* This GUID does not appear to be valid */
|
|
|
+ slapi_ch_free_string(str);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
/* For reasons not clear, the GUID returned in the tombstone DN is all
|
|
|
* messed up, like the guy in the movie 'the fly' after he want in the tranporter device */
|
|
|
static void
|
|
|
-decrypt(char *guid)
|
|
|
+decrypt_guid(char *guid)
|
|
|
{
|
|
|
static int decrypt_offsets[] = {6,7,4,5,2,3,0,1,10,11,8,9,14,15,12,13,16,17,18,19,
|
|
|
20,21,22,23,24,25,26,27,28,29,30,31};
|
|
|
@@ -1948,7 +2131,7 @@ decrypt(char *guid)
|
|
|
p++;
|
|
|
i++;
|
|
|
}
|
|
|
- slapi_ch_free((void**)&cpy);
|
|
|
+ slapi_ch_free_string(&cpy);
|
|
|
}
|
|
|
|
|
|
static char*
|
|
|
@@ -1971,8 +2154,8 @@ extract_guid_from_tombstone_dn(const char *dn)
|
|
|
strncpy(guid,colon_offset+1,(comma_offset-colon_offset)-1);
|
|
|
guid[comma_offset-colon_offset-1] = '\0';
|
|
|
/* Finally remove the dashes since we don't store them on our side */
|
|
|
- dedash(guid);
|
|
|
- decrypt(guid);
|
|
|
+ dedash_guid(guid);
|
|
|
+ decrypt_guid(guid);
|
|
|
}
|
|
|
return guid;
|
|
|
}
|
|
|
@@ -2004,6 +2187,82 @@ convert_to_hex(Slapi_Value *val)
|
|
|
return result;
|
|
|
}
|
|
|
|
|
|
+/* Given a local entry, map it to it's AD tombstone DN. An AD
|
|
|
+ * tombstone DN is formatted like:
|
|
|
+ *
|
|
|
+ * cn=<cn>\0ADEL:<guid>,cn=Deleted Objects,<suffix>
|
|
|
+ *
|
|
|
+ * This function will allocate a new Slapi_DN. It is up to the
|
|
|
+ * caller to free it when they are finished with it. */
|
|
|
+static int
|
|
|
+map_windows_tombstone_dn(Slapi_Entry *e, Slapi_DN **dn, Private_Repl_Protocol *prp, int *exists)
|
|
|
+{
|
|
|
+ int rc = 0;
|
|
|
+ char *cn = NULL;
|
|
|
+ char *guid = NULL;
|
|
|
+ const char *suffix = NULL;
|
|
|
+ char *tombstone_dn = NULL;
|
|
|
+ Slapi_Entry *tombstone = NULL;
|
|
|
+
|
|
|
+ /* Initialize the output values */
|
|
|
+ *dn = NULL;
|
|
|
+ *exists = 0;
|
|
|
+
|
|
|
+ cn = slapi_entry_attr_get_charptr(e,"cn");
|
|
|
+ if (!cn) {
|
|
|
+ cn = slapi_entry_attr_get_charptr(e,"ntuserdomainid");
|
|
|
+ }
|
|
|
+
|
|
|
+ guid = slapi_entry_attr_get_charptr(e,"ntUniqueId");
|
|
|
+ if (guid) {
|
|
|
+ /* the GUID is in a different form in the tombstone DN, so
|
|
|
+ * we need to transform it from the way we store it. */
|
|
|
+ decrypt_guid(guid);
|
|
|
+ dash_guid(&guid);
|
|
|
+ }
|
|
|
+
|
|
|
+ /* The tombstone suffix discards any containers, so we need
|
|
|
+ * to trim the DN to only dc components. */
|
|
|
+ if (suffix = slapi_sdn_get_dn(windows_private_get_windows_subtree(prp->agmt))) {
|
|
|
+ /* If this isn't found, it is treated as an error below. */
|
|
|
+ suffix = (const char *) strcasestr(suffix,"dc=");
|
|
|
+ }
|
|
|
+
|
|
|
+ if (cn && guid && suffix) {
|
|
|
+ tombstone_dn = PR_smprintf("cn=%s\\0ADEL:%s,cn=Deleted Objects,%s",
|
|
|
+ cn, guid, suffix);
|
|
|
+
|
|
|
+ /* Hand off the memory to the Slapi_DN */
|
|
|
+ *dn = slapi_sdn_new_dn_passin(tombstone_dn);
|
|
|
+
|
|
|
+ windows_get_remote_tombstone(prp, *dn, &tombstone);
|
|
|
+ if (tombstone) {
|
|
|
+ *exists = 1;
|
|
|
+ slapi_entry_free(tombstone);
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
|
|
|
+ "%s: map_windows_tombstone_dn: Failed to map dn=\"%s\" "
|
|
|
+ "to windows tombstone dn.\n", agmt_get_long_name(prp->agmt),
|
|
|
+ slapi_entry_get_dn(e));
|
|
|
+ rc = 1;
|
|
|
+ }
|
|
|
+
|
|
|
+ slapi_ch_free_string(&cn);
|
|
|
+ slapi_ch_free_string(&guid);
|
|
|
+ return rc;
|
|
|
+}
|
|
|
+
|
|
|
+static int is_guid_dn(Slapi_DN *remote_dn)
|
|
|
+{
|
|
|
+ if ((remote_dn != NULL) && (strncasecmp("<GUID=",
|
|
|
+ slapi_sdn_get_dn(remote_dn), 6) == 0)) {
|
|
|
+ return 1;
|
|
|
+ } else {
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
static char*
|
|
|
extract_guid_from_entry(Slapi_Entry *e, int is_nt4)
|
|
|
{
|
|
|
@@ -2151,8 +2410,54 @@ map_entry_dn_outbound(Slapi_Entry *e, Slapi_DN **dn, Private_Repl_Protocol *prp,
|
|
|
guid = slapi_entry_attr_get_charptr(e,"ntUniqueId");
|
|
|
if (guid && guid_form)
|
|
|
{
|
|
|
+ int rc = 0;
|
|
|
+ Slapi_Entry *remote_entry = NULL;
|
|
|
new_dn = make_dn_from_guid(guid, is_nt4, suffix);
|
|
|
- slapi_ch_free((void**)&guid);
|
|
|
+ slapi_ch_free_string(&guid);
|
|
|
+ /* There are certain cases where we will have a GUID, but the entry does not exist in
|
|
|
+ * AD. This happens when you delete an entry, then add it back elsewhere in the tree
|
|
|
+ * without removing the ntUniqueID attribute. We should verify that the entry really
|
|
|
+ * exists in AD. */
|
|
|
+ rc = windows_get_remote_entry(prp, new_dn, &remote_entry);
|
|
|
+ if (0 == rc && remote_entry) {
|
|
|
+ slapi_entry_free(remote_entry);
|
|
|
+ } else {
|
|
|
+ /* We need to re-write the DN to a non-GUID DN if we're syncing to a
|
|
|
+ * Windows 2000 Server since tombstone reanimation is not supported.
|
|
|
+ * If we're syncing with Windows 2003 Server, we'll just use the GUID
|
|
|
+ * to reanimate the tombstone when processing the add operation. */
|
|
|
+ *missing_entry = 1;
|
|
|
+ if (!windows_private_get_iswin2k3(prp->agmt)) {
|
|
|
+ char *new_dn_string = NULL;
|
|
|
+ char *cn_string = NULL;
|
|
|
+
|
|
|
+ /* We can't use a GUID DN, so rewrite to the mapped DN. */
|
|
|
+ cn_string = slapi_entry_attr_get_charptr(e,"cn");
|
|
|
+ if (!cn_string) {
|
|
|
+ cn_string = slapi_entry_attr_get_charptr(e,"ntuserdomainid");
|
|
|
+ }
|
|
|
+
|
|
|
+ if (cn_string) {
|
|
|
+ char *rdnstr = NULL;
|
|
|
+ char *container_str = NULL;
|
|
|
+
|
|
|
+ container_str = extract_container(slapi_entry_get_sdn_const(e),
|
|
|
+ windows_private_get_directory_subtree(prp->agmt));
|
|
|
+ new_dn_string = PR_smprintf("cn=%s,%s%s", cn_string, container_str, suffix);
|
|
|
+
|
|
|
+ if (new_dn_string) {
|
|
|
+ if (new_dn) {
|
|
|
+ slapi_sdn_free(&new_dn);
|
|
|
+ }
|
|
|
+ new_dn = slapi_sdn_new_dn_byval(new_dn_string);
|
|
|
+ PR_smprintf_free(new_dn_string);
|
|
|
+ }
|
|
|
+
|
|
|
+ slapi_ch_free_string(&cn_string);
|
|
|
+ slapi_ch_free_string(&container_str);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
} else
|
|
|
{
|
|
|
/* No GUID found, try ntUserDomainId */
|
|
|
@@ -2204,8 +2509,8 @@ map_entry_dn_outbound(Slapi_Entry *e, Slapi_DN **dn, Private_Repl_Protocol *prp,
|
|
|
new_dn = slapi_sdn_new_dn_byval(new_dn_string);
|
|
|
PR_smprintf_free(new_dn_string);
|
|
|
}
|
|
|
- slapi_ch_free((void**)&cn_string);
|
|
|
- slapi_ch_free((void**)&container_str);
|
|
|
+ slapi_ch_free_string(&cn_string);
|
|
|
+ slapi_ch_free_string(&container_str);
|
|
|
}
|
|
|
} else
|
|
|
{
|
|
|
@@ -2217,7 +2522,7 @@ map_entry_dn_outbound(Slapi_Entry *e, Slapi_DN **dn, Private_Repl_Protocol *prp,
|
|
|
retval = -1;
|
|
|
}
|
|
|
}
|
|
|
- slapi_ch_free((void**)&username);
|
|
|
+ slapi_ch_free_string(&username);
|
|
|
}
|
|
|
if (remote_entry)
|
|
|
{
|
|
|
@@ -2280,7 +2585,7 @@ map_tombstone_dn_inbound(Slapi_Entry *e, Slapi_DN **dn, const Repl_Agmt *ra)
|
|
|
|
|
|
if (guid)
|
|
|
{
|
|
|
- slapi_ch_free((void**)&guid);
|
|
|
+ slapi_ch_free_string(&guid);
|
|
|
}
|
|
|
if (matching_entry)
|
|
|
{
|
|
|
@@ -2387,7 +2692,7 @@ map_entry_dn_inbound(Slapi_Entry *e, Slapi_DN **dn, const Repl_Agmt *ra)
|
|
|
}
|
|
|
new_dn = slapi_sdn_new_dn_byval(new_dn_string);
|
|
|
PR_smprintf_free(new_dn_string);
|
|
|
- slapi_ch_free((void**)&container_str);
|
|
|
+ slapi_ch_free_string(&container_str);
|
|
|
/* Clear any earlier error */
|
|
|
retval = 0;
|
|
|
} else
|
|
|
@@ -2410,7 +2715,7 @@ error:
|
|
|
}
|
|
|
if (username)
|
|
|
{
|
|
|
- slapi_ch_free((void **) &username);
|
|
|
+ slapi_ch_free_string(&username);
|
|
|
}
|
|
|
return retval;
|
|
|
}
|
|
|
@@ -2542,7 +2847,7 @@ windows_create_local_entry(Private_Repl_Protocol *prp,Slapi_Entry *remote_entry,
|
|
|
goto error;
|
|
|
}
|
|
|
local_entry = slapi_str2entry(entry_string, 0);
|
|
|
- slapi_ch_free((void**)&entry_string);
|
|
|
+ slapi_ch_free_string(&entry_string);
|
|
|
if (NULL == local_entry)
|
|
|
{
|
|
|
goto error;
|
|
|
@@ -2583,7 +2888,7 @@ windows_create_local_entry(Private_Repl_Protocol *prp,Slapi_Entry *remote_entry,
|
|
|
{
|
|
|
slapi_entry_add_valueset(local_entry,new_type,vs);
|
|
|
}
|
|
|
- slapi_ch_free((void**)&new_type);
|
|
|
+ slapi_ch_free_string(&new_type);
|
|
|
}
|
|
|
}
|
|
|
if (vs)
|
|
|
@@ -2627,7 +2932,7 @@ error:
|
|
|
}
|
|
|
if (username)
|
|
|
{
|
|
|
- slapi_ch_free((void**)&username);
|
|
|
+ slapi_ch_free_string(&username);
|
|
|
}
|
|
|
LDAPDebug( LDAP_DEBUG_TRACE, "<= windows_create_local_entry\n", 0, 0, 0 );
|
|
|
return retval;
|
|
|
@@ -2812,7 +3117,7 @@ windows_generate_update_mods(Private_Repl_Protocol *prp,Slapi_Entry *remote_entr
|
|
|
if (guid)
|
|
|
{
|
|
|
slapi_mods_add_string(smods,LDAP_MOD_ADD,local_type,guid);
|
|
|
- slapi_ch_free((void**)&guid);
|
|
|
+ slapi_ch_free_string(&guid);
|
|
|
}
|
|
|
} else
|
|
|
{
|