Login
[x]
Log in using an account from:
Fedora Account System
Red Hat Associate
Red Hat Customer
Or login using a Red Hat Bugzilla account
Forgot Password
Login:
Hide Forgot
Create an Account
Red Hat Bugzilla – Attachment 193691 Details for
Bug 243227
rhds71 Windows Sync Agreement deletes users from RHDS when they are moved between OUs
[?]
New
Simple Search
Advanced Search
My Links
Browse
Requests
Reports
Current State
Search
Tabular reports
Graphical reports
Duplicates
Other Reports
User Changes
Plotly Reports
Bug Status
Bug Severity
Non-Defaults
|
Product Dashboard
Help
Page Help!
Bug Writing Guidelines
What's new
Browser Support Policy
5.0.4.rh83 Release notes
FAQ
Guides index
User guide
Web Services
Contact
Legal
This site requires JavaScript to be enabled to function correctly, please enable it.
[patch]
CVS Diffs
diffs.txt (text/plain), 45.89 KB, created by
Nathan Kinder
on 2007-09-12 17:23:45 UTC
(
hide
)
Description:
CVS Diffs
Filename:
MIME Type:
Creator:
Nathan Kinder
Created:
2007-09-12 17:23:45 UTC
Size:
45.89 KB
patch
obsolete
>Index: repl5.h >=================================================================== >RCS file: /cvs/dirsec/ldapserver/ldap/servers/plugins/replication/repl5.h,v >retrieving revision 1.9 >diff -u -5 -t -r1.9 repl5.h >--- repl5.h 10 Nov 2006 23:45:17 -0000 1.9 >+++ repl5.h 12 Sep 2007 16:44:38 -0000 >@@ -61,12 +61,12 @@ > #include "cl4.h" > > #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" > #define REPL_END_NSDS50_REPLICATION_REQUEST_OID "2.16.840.1.113730.3.5.5" > #define REPL_NSDS50_REPLICATION_ENTRY_REQUEST_OID "2.16.840.1.113730.3.5.6" >@@ -356,11 +356,15 @@ > CONN_SSL_NOT_ENABLED, > CONN_TIMEOUT, > 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); > void conn_disconnect(Repl_Connection *conn); > void conn_delete(Repl_Connection *conn); >Index: windows_connection.c >=================================================================== >RCS file: /cvs/dirsec/ldapserver/ldap/servers/plugins/replication/windows_connection.c,v >retrieving revision 1.15 >diff -u -5 -t -r1.15 windows_connection.c >--- windows_connection.c 10 Nov 2006 23:45:17 -0000 1.15 >+++ windows_connection.c 12 Sep 2007 16:44:38 -0000 >@@ -81,10 +81,11 @@ > const Repl_Agmt *agmt; > PRLock *lock; > 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 */ > #define DEFAULT_LINGER_TIME (60) > >@@ -165,10 +166,11 @@ > rpc->last_ldap_errmsg = NULL; > rpc->supports_ldapv3 = -1; > 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; > rpc->linger_time = DEFAULT_LINGER_TIME; > rpc->status = STATUS_DISCONNECTED; >@@ -289,25 +291,22 @@ > * before retrying > */ > 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; > > conn->last_operation = optype; >@@ -586,13 +585,21 @@ > ldap_ber_free( ber, 0 ); > } > 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; > int not_unique = 0; > int nummessages = 0; >@@ -605,11 +612,11 @@ > > if (windows_conn_connected(conn)) > { > 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) > { > LDAPMessage *message = ldap_first_entry(conn->ld, res); > >@@ -682,13 +689,11 @@ > if (conn->supports_dirsync == 0) > { > 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; > conn->last_operation = CONN_SEARCH; > conn->status = STATUS_SEARCHING; >@@ -744,16 +749,16 @@ > /* > * Send an LDAP add operation. > */ > 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 ); > return res; > } >@@ -762,48 +767,48 @@ > /* > * Send an LDAP delete operation. > */ > 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); > } > > > /* > * Send an LDAP modify operation. > */ > 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); > } > > /* > * Send an LDAP moddn operation. > */ > 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); > } > > /* >@@ -876,17 +881,17 @@ > * Send an LDAP extended operation. > */ > 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); > } > > > /* >@@ -1262,10 +1267,20 @@ > LDAPDebug( LDAP_DEBUG_REPL, "windows_conn_connect : detected NT4 peer\n", 0, 0, 0 ); > } else > { > 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); > creds = NULL; > >@@ -1470,10 +1485,75 @@ > LDAPDebug( LDAP_DEBUG_TRACE, "<= windows_conn_replica_supports_dirsync\n", 0, 0, 0 ); > return return_value; > } > > >+/* 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". > * Otherwise, return 0. > */ >Index: windows_private.c >=================================================================== >RCS file: /cvs/dirsec/ldapserver/ldap/servers/plugins/replication/windows_private.c,v >retrieving revision 1.14 >diff -u -5 -t -r1.14 windows_private.c >--- windows_private.c 10 Nov 2006 23:45:17 -0000 1.14 >+++ windows_private.c 12 Sep 2007 16:44:38 -0000 >@@ -63,10 +63,11 @@ > PRBool dirsync_cookie_has_more; > PRBool create_users_from_dirsync; > PRBool create_groups_from_dirsync; > char *windows_domain; > int isnt4; >+ int iswin2k3; > }; > > static int > true_value_from_string(char *val) > { >@@ -243,10 +244,42 @@ > dp->isnt4 = isit; > > 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) > { > Dirsync_Private *dp; >Index: windows_protocol_util.c >=================================================================== >RCS file: /cvs/dirsec/ldapserver/ldap/servers/plugins/replication/windows_protocol_util.c,v >retrieving revision 1.31 >diff -u -5 -t -r1.31 windows_protocol_util.c >--- windows_protocol_util.c 4 Sep 2007 15:45:57 -0000 1.31 >+++ windows_protocol_util.c 12 Sep 2007 16:44:38 -0000 >@@ -69,15 +69,20 @@ > 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 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 */ > typedef enum mapping_types { > bidirectional, >@@ -951,15 +956,89 @@ > int remote_add_allowed = add_remote_entry_allowed(local_entry); > ConnResult return_value = 0; > 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((void**)&cn_string); >+ slapi_ch_free((void**)&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; > /* First map the entry */ > rc = windows_create_remote_entry(prp,op->p.p_add.target_entry, remote_dn, &mapped_entry, password); >@@ -969,36 +1048,46 @@ > (void)slapi_entry2mods (mapped_entry , NULL /* &entrydn : We don't need it */, &entryattrs); > slapi_entry_free(mapped_entry); > 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; > } > } 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) { > return_value = windows_update_remote_entry(prp,remote_entry,local_entry); > } >@@ -1016,11 +1105,10 @@ > */ > 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; > int is_user = 0; > int is_group = 0; >@@ -1095,11 +1183,11 @@ > for(i=0;mapped_mods[i];i++) > { > 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) > { > ldap_mods_free(mapped_mods,1); > mapped_mods = NULL; >@@ -1107,11 +1195,11 @@ > } > break; > 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); > } else > { >@@ -1123,11 +1211,11 @@ > 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, >- 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 " > "operation type %d found in changelog - skipping change.\n", > agmt_get_long_name(prp->agmt), op->operation_type); >@@ -1830,10 +1918,74 @@ > } > } > 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) > { > Slapi_PBlock *pb = slapi_pblock_new(); > Slapi_Entry **entries = NULL, **ep = NULL; >@@ -1904,13 +2056,13 @@ > 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'; > > while (c = *p) >@@ -1928,14 +2080,45 @@ > } > p++; > } > } > >+/* 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}; > > char *p = guid; >@@ -1969,12 +2152,12 @@ > if (comma_offset && colon_offset && comma_offset > colon_offset) { > guid = slapi_ch_malloc(comma_offset - colon_offset); > 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; > } > > static char * >@@ -2002,10 +2185,86 @@ > } > } > 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) > { > char *guid = NULL; > Slapi_Value *val = NULL; >@@ -2149,12 +2408,58 @@ > *missing_entry = 0; > > 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); >+ /* 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((void**)&cn_string); >+ slapi_ch_free((void**)&container_str); >+ } >+ } >+ } > } else > { > /* No GUID found, try ntUserDomainId */ > Slapi_Entry *remote_entry = NULL; > char *username = slapi_entry_attr_get_charptr(e,"ntUserDomainId"); >Index: windowsrepl.h >=================================================================== >RCS file: /cvs/dirsec/ldapserver/ldap/servers/plugins/replication/windowsrepl.h,v >retrieving revision 1.11 >diff -u -5 -t -r1.11 windowsrepl.h >--- windowsrepl.h 27 Aug 2007 17:16:48 -0000 1.11 >+++ windowsrepl.h 12 Sep 2007 16:44:38 -0000 >@@ -49,10 +49,11 @@ > void windows_private_set_directory_subtree (const Repl_Agmt *ra,const Slapi_DN* sdn ); > const Slapi_DN* windows_private_get_directory_subtree (const Repl_Agmt *ra); > 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); > void windows_private_null_dirsync_cookie(const Repl_Agmt *ra); > int windows_private_save_dirsync_cookie(const Repl_Agmt *ra); >@@ -63,34 +64,37 @@ > PRBool windows_private_create_groups(const Repl_Agmt *ra); > const char *windows_private_get_windows_domain(const Repl_Agmt *ra); > 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 */ > ConnResult windows_conn_connect(Repl_Connection *conn); > void windows_conn_disconnect(Repl_Connection *conn); > 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); > void windows_conn_set_timeout(Repl_Connection *conn, long timeout); > void windows_conn_set_agmt_changed(Repl_Connection *conn); >@@ -100,5 +104,8 @@ > /* Used to work around contrained attribute legth for initials on AD */ > #define AD_INITIALS_LENGTH 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
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 243227
:
193691
|
193941