[Fedora-directory-commits] ldapserver/ldap/servers/plugins/replication repl5.h, 1.9, 1.10 windows_connection.c, 1.15, 1.16 windows_private.c, 1.14, 1.15 windows_protocol_util.c, 1.31, 1.32 windowsrepl.h, 1.11, 1.12
Nathan Kinder (nkinder)
fedora-directory-commits at redhat.com
Wed Sep 12 23:05:27 UTC 2007
- Previous message (by thread): [Fedora-directory-commits] ldapserver aclocal.m4, 1.50, 1.51 configure, 1.63, 1.64 missing, 1.39, 1.40 install-sh, 1.39, 1.40 depcomp, 1.39, 1.40 compile, 1.38, 1.39 config.sub, 1.38, 1.39 config.guess, 1.38, 1.39 Makefile.in, 1.69, 1.70
- Next message (by thread): [Fedora-directory-commits] ldapserver/ldap/admin/src/scripts DSMigration.pm.in, 1.11, 1.12 FileConn.pm, 1.3, 1.4 Migration.pm.in, 1.5, 1.6 Util.pm.in, 1.11, 1.12
- Messages sorted by:
[ date ]
[ thread ]
[ subject ]
[ author ]
Author: nkinder
Update of /cvs/dirsec/ldapserver/ldap/servers/plugins/replication
In directory cvs-int.fedora.redhat.com:/tmp/cvs-serv9727
Modified Files:
repl5.h windows_connection.c windows_private.c
windows_protocol_util.c windowsrepl.h
Log Message:
Resolves: 243227
Summary: Handle syncing add opererations that have a ntuniqueid present.
Index: repl5.h
===================================================================
RCS file: /cvs/dirsec/ldapserver/ldap/servers/plugins/replication/repl5.h,v
retrieving revision 1.9
retrieving revision 1.10
diff -u -r1.9 -r1.10
--- repl5.h 10 Nov 2006 23:45:17 -0000 1.9
+++ repl5.h 12 Sep 2007 23:05:24 -0000 1.10
@@ -63,8 +63,8 @@
#define REPLICA_TYPE_WINDOWS 1
#define REPLICA_TYPE_MULTIMASTER 0
#define REPL_DIRSYNC_CONTROL_OID "1.2.840.113556.1.4.841"
-#define CONN_SUPPORTS_DIRSYNC 12
-#define CONN_DOES_NOT_SUPPORT_DIRSYNC 13
+#define REPL_RETURN_DELETED_OBJS_CONTROL_OID "1.2.840.113556.1.4.417"
+#define REPL_WIN2K3_AD_OID "1.2.840.113556.1.4.1670"
/* DS 5.0 replication protocol OIDs */
#define REPL_START_NSDS50_REPLICATION_REQUEST_OID "2.16.840.1.113730.3.5.3"
@@ -358,7 +358,11 @@
CONN_SUPPORTS_DS71_REPL,
CONN_DOES_NOT_SUPPORT_DS71_REPL,
CONN_IS_READONLY,
- CONN_IS_NOT_READONLY
+ CONN_IS_NOT_READONLY,
+ CONN_SUPPORTS_DIRSYNC,
+ CONN_DOES_NOT_SUPPORT_DIRSYNC,
+ CONN_IS_WIN2K3,
+ CONN_NOT_WIN2K3
} ConnResult;
Repl_Connection *conn_new(Repl_Agmt *agmt);
ConnResult conn_connect(Repl_Connection *conn);
Index: windows_connection.c
===================================================================
RCS file: /cvs/dirsec/ldapserver/ldap/servers/plugins/replication/windows_connection.c,v
retrieving revision 1.15
retrieving revision 1.16
diff -u -r1.15 -r1.16
--- windows_connection.c 10 Nov 2006 23:45:17 -0000 1.15
+++ windows_connection.c 12 Sep 2007 23:05:24 -0000 1.16
@@ -83,6 +83,7 @@
struct timeval timeout;
int flag_agmt_changed;
char *plain;
+ int is_win2k3; /* 1 if it is win2k3 or later, 0 if not, -1 if not determined */
} repl_connection;
/* #define DEFAULT_LINGER_TIME (5 * 60) */ /* 5 minutes */
@@ -167,6 +168,7 @@
rpc->supports_ds40_repl = -1;
rpc->supports_ds50_repl = -1;
rpc->supports_dirsync = -1;
+ rpc->is_win2k3 = -1;
rpc->linger_active = PR_FALSE;
rpc->delete_after_linger = PR_FALSE;
rpc->linger_event = NULL;
@@ -291,21 +293,18 @@
static ConnResult
windows_perform_operation(Repl_Connection *conn, int optype, const char *dn,
LDAPMod **attrs, const char *newrdn, const char *newparent,
- int deleteoldrdn, LDAPControl *update_control,
+ int deleteoldrdn, LDAPControl **server_controls,
const char *extop_oid, struct berval *extop_payload, char **retoidp,
struct berval **retdatap, LDAPControl ***returned_controls)
{
int rc;
ConnResult return_value;
- LDAPControl *server_controls[1];
LDAPControl **loc_returned_controls;
const char *op_string = NULL;
const char *extra_op_string = NULL;
LDAPDebug( LDAP_DEBUG_TRACE, "=> windows_perform_operation\n", 0, 0, 0 );
- server_controls[0] = NULL;
-
if (windows_conn_connected(conn))
{
int msgid;
@@ -588,9 +587,17 @@
return e;
}
+/* Perform a simple search against Windows with no controls */
ConnResult
windows_search_entry(Repl_Connection *conn, char* searchbase, char *filter, Slapi_Entry **entry)
{
+ return windows_search_entry_ext(conn, searchbase, filter, entry, NULL);
+}
+
+/* Perform a simple search against Windows with optional controls */
+ConnResult
+windows_search_entry_ext(Repl_Connection *conn, char* searchbase, char *filter, Slapi_Entry **entry, LDAPControl **serverctrls)
+{
ConnResult return_value = 0;
int ldap_rc = 0;
LDAPMessage *res = NULL;
@@ -607,7 +614,7 @@
{
ldap_rc = ldap_search_ext_s(conn->ld, searchbase, LDAP_SCOPE_SUBTREE,
filter, NULL, 0 /* attrsonly */,
- NULL , NULL /* client controls */,
+ serverctrls , NULL /* client controls */,
&conn->timeout, 0 /* sizelimit */, &res);
if (LDAP_SUCCESS == ldap_rc)
{
@@ -684,9 +691,7 @@
server_controls[0] = NULL; /* unsupported */
} else
{
- /* DBDB: I'm pretty sure that the control is leaked from here */
- /* Purify agrees */
- server_controls[0] = windows_private_dirsync_control(conn->agmt); /* yes, or don't know */
+ server_controls[0] = windows_private_dirsync_control(conn->agmt);
}
server_controls[1] = NULL;
@@ -746,12 +751,12 @@
*/
ConnResult
windows_conn_send_add(Repl_Connection *conn, const char *dn, LDAPMod **attrs,
- LDAPControl *update_control, LDAPControl ***returned_controls)
+ LDAPControl **server_controls, LDAPControl ***returned_controls)
{
ConnResult res = 0;
LDAPDebug( LDAP_DEBUG_TRACE, "=> windows_conn_send_add\n", 0, 0, 0 );
res = windows_perform_operation(conn, CONN_ADD, dn, attrs, NULL /* newrdn */,
- NULL /* newparent */, 0 /* deleteoldrdn */, update_control,
+ NULL /* newparent */, 0 /* deleteoldrdn */, server_controls,
NULL /* extop OID */, NULL /* extop payload */, NULL /* retoidp */,
NULL /* retdatap */, returned_controls);
LDAPDebug( LDAP_DEBUG_TRACE, "<= windows_conn_send_add\n", 0, 0, 0 );
@@ -764,13 +769,13 @@
*/
ConnResult
windows_conn_send_delete(Repl_Connection *conn, const char *dn,
- LDAPControl *update_control, LDAPControl ***returned_controls)
+ LDAPControl **server_controls, LDAPControl ***returned_controls)
{
LDAPDebug( LDAP_DEBUG_TRACE, "=> windows_conn_send_delete\n", 0, 0, 0 );
LDAPDebug( LDAP_DEBUG_TRACE, "<= windows_conn_send_delete\n", 0, 0, 0 );
return windows_perform_operation(conn, CONN_DELETE, dn, NULL /* attrs */,
NULL /* newrdn */, NULL /* newparent */, 0 /* deleteoldrdn */,
- update_control, NULL /* extop OID */, NULL /* extop payload */,
+ server_controls, NULL /* extop OID */, NULL /* extop payload */,
NULL /* retoidp */, NULL /* retdatap */, returned_controls);
}
@@ -780,12 +785,12 @@
*/
ConnResult
windows_conn_send_modify(Repl_Connection *conn, const char *dn, LDAPMod **mods,
- LDAPControl *update_control, LDAPControl ***returned_controls)
+ LDAPControl **server_controls, LDAPControl ***returned_controls)
{
LDAPDebug( LDAP_DEBUG_TRACE, "=> windows_conn_send_modify\n", 0, 0, 0 );
LDAPDebug( LDAP_DEBUG_TRACE, "<= windows_conn_send_modify\n", 0, 0, 0 );
return windows_perform_operation(conn, CONN_MODIFY, dn, mods, NULL /* newrdn */,
- NULL /* newparent */, 0 /* deleteoldrdn */, update_control,
+ NULL /* newparent */, 0 /* deleteoldrdn */, server_controls,
NULL /* extop OID */, NULL /* extop payload */, NULL /* retoidp */,
NULL /* retdatap */, returned_controls);
}
@@ -796,12 +801,12 @@
ConnResult
windows_conn_send_rename(Repl_Connection *conn, const char *dn,
const char *newrdn, const char *newparent, int deleteoldrdn,
- LDAPControl *update_control, LDAPControl ***returned_controls)
+ LDAPControl **server_controls, LDAPControl ***returned_controls)
{
LDAPDebug( LDAP_DEBUG_TRACE, "=> windows_conn_send_rename\n", 0, 0, 0 );
LDAPDebug( LDAP_DEBUG_TRACE, "<= windows_conn_send_rename\n", 0, 0, 0 );
return windows_perform_operation(conn, CONN_RENAME, dn, NULL /* attrs */,
- newrdn, newparent, deleteoldrdn, update_control,
+ newrdn, newparent, deleteoldrdn, server_controls,
NULL /* extop OID */, NULL /* extop payload */, NULL /* retoidp */,
NULL /* retdatap */, returned_controls);
}
@@ -878,13 +883,13 @@
ConnResult
windows_conn_send_extended_operation(Repl_Connection *conn, const char *extop_oid,
struct berval *payload, char **retoidp, struct berval **retdatap,
- LDAPControl *update_control, LDAPControl ***returned_controls)
+ LDAPControl **server_controls, LDAPControl ***returned_controls)
{
LDAPDebug( LDAP_DEBUG_TRACE, "=> windows_conn_send_extended_operation\n", 0, 0, 0 );
LDAPDebug( LDAP_DEBUG_TRACE, "<= windows_conn_send_extended_operation\n", 0, 0, 0 );
return windows_perform_operation(conn, CONN_EXTENDED_OPERATION, NULL /* dn */, NULL /* attrs */,
NULL /* newrdn */, NULL /* newparent */, 0 /* deleteoldrdn */,
- update_control, extop_oid, payload, retoidp, retdatap,
+ server_controls, extop_oid, payload, retoidp, retdatap,
returned_controls);
}
@@ -1264,6 +1269,16 @@
{
windows_private_set_isnt4(conn->agmt,0);
}
+
+ supports = windows_conn_replica_is_win2k3(conn);
+ if (CONN_IS_WIN2K3 == supports)
+ {
+ windows_private_set_iswin2k3(conn->agmt,1);
+ LDAPDebug( LDAP_DEBUG_REPL, "windows_conn_connect : detected Win2k3 peer\n", 0, 0, 0 );
+ } else
+ {
+ windows_private_set_iswin2k3(conn->agmt,0);
+ }
}
ber_bvfree(creds);
@@ -1472,6 +1487,71 @@
}
+/* Checks if the AD server is running win2k3 (or later) */
+ConnResult
+windows_conn_replica_is_win2k3(Repl_Connection *conn)
+{
+ ConnResult return_value;
+ int ldap_rc;
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "=> windows_conn_replica_is_win2k3\n", 0, 0, 0 );
+
+ if (windows_conn_connected(conn))
+ {
+ if (conn->is_win2k3 == -1) {
+ LDAPMessage *res = NULL;
+ LDAPMessage *entry = NULL;
+ char *attrs[] = {"supportedCapabilities", NULL};
+
+ conn->status = STATUS_SEARCHING;
+ ldap_rc = ldap_search_ext_s(conn->ld, "", LDAP_SCOPE_BASE,
+ "(objectclass=*)", attrs, 0 /* attrsonly */,
+ NULL /* server controls */, NULL /* client controls */,
+ &conn->timeout, LDAP_NO_LIMIT, &res);
+ if (LDAP_SUCCESS == ldap_rc)
+ {
+ conn->is_win2k3 = 0;
+ entry = ldap_first_entry(conn->ld, res);
+ if (!attribute_string_value_present(conn->ld, entry, "supportedCapabilities", REPL_WIN2K3_AD_OID))
+ {
+ return_value = CONN_NOT_WIN2K3;
+ }
+ else
+ {
+
+ conn->is_win2k3 =1;
+ return_value = CONN_IS_WIN2K3;
+ }
+ }
+ else
+ {
+ if (IS_DISCONNECT_ERROR(ldap_rc))
+ {
+ conn->last_ldap_error = ldap_rc; /* specific reason */
+ windows_conn_disconnect(conn);
+ return_value = CONN_NOT_CONNECTED;
+ }
+ else
+ {
+ return_value = CONN_OPERATION_FAILED;
+ }
+ }
+ if (NULL != res)
+ ldap_msgfree(res);
+ }
+ else {
+ return_value = conn->is_win2k3 ? CONN_IS_WIN2K3 : CONN_NOT_WIN2K3;
+ }
+ }
+ else
+ {
+ /* Not connected */
+ return_value = CONN_NOT_CONNECTED;
+ }
+ LDAPDebug( LDAP_DEBUG_TRACE, "<= windows_conn_replica_is_win2k3\n", 0, 0, 0 );
+ return return_value;
+}
+
/*
* Return 1 if "value" is a value of attribute type "type" in entry "entry".
Index: windows_private.c
===================================================================
RCS file: /cvs/dirsec/ldapserver/ldap/servers/plugins/replication/windows_private.c,v
retrieving revision 1.14
retrieving revision 1.15
diff -u -r1.14 -r1.15
--- windows_private.c 10 Nov 2006 23:45:17 -0000 1.14
+++ windows_private.c 12 Sep 2007 23:05:24 -0000 1.15
@@ -65,6 +65,7 @@
PRBool create_groups_from_dirsync;
char *windows_domain;
int isnt4;
+ int iswin2k3;
};
static int
@@ -245,6 +246,38 @@
LDAPDebug( LDAP_DEBUG_TRACE, "<= windows_private_set_isnt4\n", 0, 0, 0 );
}
+int windows_private_get_iswin2k3(const Repl_Agmt *ra)
+{
+ Dirsync_Private *dp;
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "=> windows_private_get_iswin2k3\n", 0, 0, 0 );
+
+ PR_ASSERT(ra);
+
+ dp = (Dirsync_Private *) agmt_get_priv(ra);
+ PR_ASSERT (dp);
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "<= windows_private_get_iswin2k3\n", 0, 0, 0 );
+
+ return dp->iswin2k3;
+}
+
+void windows_private_set_iswin2k3(const Repl_Agmt *ra, int isit)
+{
+ Dirsync_Private *dp;
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "=> windows_private_set_iswin2k3\n", 0, 0, 0 );
+
+ PR_ASSERT(ra);
+
+ dp = (Dirsync_Private *) agmt_get_priv(ra);
+ PR_ASSERT (dp);
+
+ dp->iswin2k3 = isit;
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "<= windows_private_set_iswin2k3\n", 0, 0, 0 );
+}
+
/* Returns a copy of the Slapi_DN pointer, no need to free it */
const Slapi_DN* windows_private_get_windows_subtree (const Repl_Agmt *ra)
Index: windows_protocol_util.c
===================================================================
RCS file: /cvs/dirsec/ldapserver/ldap/servers/plugins/replication/windows_protocol_util.c,v
retrieving revision 1.31
retrieving revision 1.32
diff -u -r1.31 -r1.32
--- windows_protocol_util.c 4 Sep 2007 15:45:57 -0000 1.31
+++ windows_protocol_util.c 12 Sep 2007 23:05:25 -0000 1.32
@@ -71,11 +71,16 @@
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 @@
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 @@
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 @@
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 @@
} 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
error:
if (username)
{
- slapi_ch_free((void**)&username);
+ slapi_ch_free_string(&username);
}
if (new_entry)
{
@@ -1633,7 +1721,7 @@
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 @@
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 @@
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 @@
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 @@
}
}
+/* 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 @@
p++;
i++;
}
- slapi_ch_free((void**)&cpy);
+ slapi_ch_free_string(&cpy);
}
static char*
@@ -1971,8 +2154,8 @@
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 @@
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 @@
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 @@
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 @@
retval = -1;
}
}
- slapi_ch_free((void**)&username);
+ slapi_ch_free_string(&username);
}
if (remote_entry)
{
@@ -2280,7 +2585,7 @@
if (guid)
{
- slapi_ch_free((void**)&guid);
+ slapi_ch_free_string(&guid);
}
if (matching_entry)
{
@@ -2387,7 +2692,7 @@
}
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 @@
}
if (username)
{
- slapi_ch_free((void **) &username);
+ slapi_ch_free_string(&username);
}
return retval;
}
@@ -2542,7 +2847,7 @@
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 @@
{
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 @@
}
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 @@
if (guid)
{
slapi_mods_add_string(smods,LDAP_MOD_ADD,local_type,guid);
- slapi_ch_free((void**)&guid);
+ slapi_ch_free_string(&guid);
}
} else
{
Index: windowsrepl.h
===================================================================
RCS file: /cvs/dirsec/ldapserver/ldap/servers/plugins/replication/windowsrepl.h,v
retrieving revision 1.11
retrieving revision 1.12
diff -u -r1.11 -r1.12
--- windowsrepl.h 27 Aug 2007 17:16:48 -0000 1.11
+++ windowsrepl.h 12 Sep 2007 23:05:25 -0000 1.12
@@ -51,6 +51,7 @@
LDAPControl* windows_private_dirsync_control(const Repl_Agmt *ra);
ConnResult send_dirsync_search(Repl_Connection *conn);
ConnResult windows_search_entry(Repl_Connection *conn, char* searchbase, char *filter, Slapi_Entry **entry);
+ConnResult windows_search_entry_ext(Repl_Connection *conn, char* searchbase, char *filter, Slapi_Entry **entry, LDAPControl **serverctrls);
Slapi_Entry *windows_conn_get_search_result(Repl_Connection *conn );
void windows_private_update_dirsync_control(const Repl_Agmt *ra,LDAPControl **controls );
PRBool windows_private_dirsync_has_more(const Repl_Agmt *ra);
@@ -65,6 +66,8 @@
static void windows_private_set_windows_domain(const Repl_Agmt *ra, char *domain);
int windows_private_get_isnt4(const Repl_Agmt *ra);
void windows_private_set_isnt4(const Repl_Agmt *ra, int isit);
+int windows_private_get_iswin2k3(const Repl_Agmt *ra);
+void windows_private_set_iswin2k3(const Repl_Agmt *ra, int isit);
const char* windows_private_get_purl(const Repl_Agmt *ra);
/* in windows_connection.c */
@@ -73,22 +76,23 @@
void windows_conn_delete(Repl_Connection *conn);
void windows_conn_get_error(Repl_Connection *conn, int *operation, int *error);
ConnResult windows_conn_send_add(Repl_Connection *conn, const char *dn, LDAPMod **attrs,
- LDAPControl *update_control, LDAPControl ***returned_controls);
+ LDAPControl **server_controls, LDAPControl ***returned_controls);
ConnResult windows_conn_send_delete(Repl_Connection *conn, const char *dn,
- LDAPControl *update_control, LDAPControl ***returned_controls);
+ LDAPControl **server_controls, LDAPControl ***returned_controls);
ConnResult windows_conn_send_modify(Repl_Connection *conn, const char *dn, LDAPMod **mods,
- LDAPControl *update_control, LDAPControl ***returned_controls);
+ LDAPControl **server_controls, LDAPControl ***returned_controls);
ConnResult windows_conn_send_rename(Repl_Connection *conn, const char *dn,
const char *newrdn, const char *newparent, int deleteoldrdn,
- LDAPControl *update_control, LDAPControl ***returned_controls);
+ LDAPControl **server_controls, LDAPControl ***returned_controls);
ConnResult windows_conn_send_extended_operation(Repl_Connection *conn, const char *extop_oid,
struct berval *payload, char **retoidp, struct berval **retdatap,
- LDAPControl *update_control, LDAPControl ***returned_controls);
+ LDAPControl **server_controls, LDAPControl ***returned_controls);
const char *windows_conn_get_status(Repl_Connection *conn);
void windows_conn_start_linger(Repl_Connection *conn);
void windows_conn_cancel_linger(Repl_Connection *conn);
ConnResult windows_conn_replica_supports_ds5_repl(Repl_Connection *conn);
ConnResult windows_conn_replica_supports_dirsync(Repl_Connection *conn);
+ConnResult windows_conn_replica_is_win2k3(Repl_Connection *conn);
ConnResult windows_conn_read_entry_attribute(Repl_Connection *conn, const char *dn, char *type,
struct berval ***returned_bvals);
ConnResult windows_conn_push_schema(Repl_Connection *conn, CSN **remotecsn);
@@ -102,3 +106,6 @@
/* Used to check for pre-hashed passwords when syncing */
#define PASSWD_CLEAR_PREFIX "{clear}"
#define PASSWD_CLEAR_PREFIX_LEN 7
+/* Used for GUID format conversion */
+#define NTUNIQUEID_LENGTH 32
+#define AD_GUID_LENGTH 36
- Previous message (by thread): [Fedora-directory-commits] ldapserver aclocal.m4, 1.50, 1.51 configure, 1.63, 1.64 missing, 1.39, 1.40 install-sh, 1.39, 1.40 depcomp, 1.39, 1.40 compile, 1.38, 1.39 config.sub, 1.38, 1.39 config.guess, 1.38, 1.39 Makefile.in, 1.69, 1.70
- Next message (by thread): [Fedora-directory-commits] ldapserver/ldap/admin/src/scripts DSMigration.pm.in, 1.11, 1.12 FileConn.pm, 1.3, 1.4 Migration.pm.in, 1.5, 1.6 Util.pm.in, 1.11, 1.12
- Messages sorted by:
[ date ]
[ thread ]
[ subject ]
[ author ]
More information about the Fedora-directory-commits
mailing list