diff options
author | David Boreham <dboreham@redhat.com> | 2005-03-31 22:00:46 +0000 |
---|---|---|
committer | David Boreham <dboreham@redhat.com> | 2005-03-31 22:00:46 +0000 |
commit | ff2e6525088908ba32f727d92f0ea861b1cfa0b4 (patch) | |
tree | eb2f3fa50a44bf4b9e24fa9ed6221827c7efdf41 /ldap/servers | |
parent | 3e4f39cde6b1e1fa0395c2f7bce0e13eaa0ead88 (diff) | |
download | ds-ff2e6525088908ba32f727d92f0ea861b1cfa0b4.tar.gz ds-ff2e6525088908ba32f727d92f0ea861b1cfa0b4.tar.xz ds-ff2e6525088908ba32f727d92f0ea861b1cfa0b4.zip |
New windows sync code
Diffstat (limited to 'ldap/servers')
17 files changed, 3534 insertions, 3208 deletions
diff --git a/ldap/servers/plugins/replication/Makefile b/ldap/servers/plugins/replication/Makefile index 8d874b1e..85866a82 100644 --- a/ldap/servers/plugins/replication/Makefile +++ b/ldap/servers/plugins/replication/Makefile @@ -130,6 +130,10 @@ EXTRA_LIBS += $(DLL_EXTRA_LIBS) LD=ld endif +# ICU used by Windows Sync code +INCLUDES+= $(ICU_INCLUDE) +EXTRA_LIBS+=$(ICULINK) + clientSDK: all: $(OBJDEST) $(LIBDIR) $(LIBREPLICATION) diff --git a/ldap/servers/plugins/replication/repl5.h b/ldap/servers/plugins/replication/repl5.h index 3527f56f..19cafa41 100644 --- a/ldap/servers/plugins/replication/repl5.h +++ b/ldap/servers/plugins/replication/repl5.h @@ -109,7 +109,9 @@ extern const char *type_nsds5ReplicaSessionPauseTime; extern const char *type_nsds7WindowsReplicaArea; extern const char *type_nsds7DirectoryReplicaArea; extern const char *type_nsds7CreateNewUsers; - +extern const char *type_nsds7CreateNewGroups; +extern const char *type_nsds7DirsyncCookie; +extern const char *type_nsds7WindowsDomain; /* To Allow Consumer Initialisation when adding an agreement - */ extern const char *type_nsds5BeginReplicaRefresh; @@ -274,6 +276,8 @@ int agmt_set_replicated_attributes_from_entry(Repl_Agmt *ra, const Slapi_Entry * int agmt_set_replicated_attributes_from_attr(Repl_Agmt *ra, Slapi_Attr *sattr); char **agmt_get_fractional_attrs(const Repl_Agmt *ra); char **agmt_validate_replicated_attributes(Repl_Agmt *ra); +void* agmt_get_priv (const Repl_Agmt *agmt); +void agmt_set_priv (Repl_Agmt *agmt, void* priv); int get_agmt_agreement_type ( Repl_Agmt *agmt); @@ -527,20 +531,10 @@ void repl5_set_debug_timeout(const char *val); /* temp hack XXX */ ReplicaId agmt_get_consumerRID(Repl_Agmt *ra); -/* windows_private.c */ -typedef struct windowsprivate Dirsync_Private; -void windows_private_delete(Dirsync_Private **dp); -void* get_priv_from_agmt (const Repl_Agmt *agmt); -Dirsync_Private* windows_private_new(); -void windows_private_set_windows_replarea (const Repl_Agmt *ra,const Slapi_DN* sdn ); -const Slapi_DN* windows_private_get_windows_replarea (const Repl_Agmt *ra); -void windows_private_set_directory_replarea (const Repl_Agmt *ra,const Slapi_DN* sdn ); -const Slapi_DN* windows_private_get_directory_replarea (const Repl_Agmt *ra); -LDAPControl* windows_private_dirsync_control(const Repl_Agmt *ra); -ConnResult perform_search(Repl_Connection *conn); -Slapi_Entry *windows_conn_get_search_result(Repl_Connection *conn ); -void windows_private_update_dirsync_control(const Repl_Agmt *ra,LDAPControl **controls ); -void windows_private_null_dirsync_control(const Repl_Agmt *ra); -void windows_private_set_create_users(const Repl_Agmt *ra, PRBool value); -PRBool windows_private_create_users(const Repl_Agmt *ra); + +void windows_init_agreement_from_entry(Repl_Agmt *ra, Slapi_Entry *e); +void windows_agreement_delete(Repl_Agmt *ra); +Repl_Connection *windows_conn_new(Repl_Agmt *agmt); + + #endif /* _REPL5_H_ */ diff --git a/ldap/servers/plugins/replication/repl5_agmt.c b/ldap/servers/plugins/replication/repl5_agmt.c index a52df287..afc0b15e 100644 --- a/ldap/servers/plugins/replication/repl5_agmt.c +++ b/ldap/servers/plugins/replication/repl5_agmt.c @@ -45,7 +45,6 @@ */ #include "repl5.h" -#include "windowsrepl.h" #include "repl5_prot_private.h" #include "cl5_api.h" #include "slapi-plugin.h" @@ -98,7 +97,7 @@ typedef struct repl5agmt { to allow another supplier to send its updates - should be greater than busywaittime - if set to 0, this means do not pause */ - void *priv; /* private data, used for cookie, and windows domain name */ + void *priv; /* private data, used for windows-specific agreement data */ int agreement_type; } repl5agmt; @@ -326,27 +325,7 @@ agmt_new_from_entry(Slapi_Entry *e) if (slapi_entry_attr_hasvalue(e, "objectclass", "nsDSWindowsReplicationAgreement")) { ra->agreement_type = REPLICA_TYPE_WINDOWS; - ra->priv = windows_private_new(); - - /* DN of entry at root of replicated area */ - tmpstr = slapi_entry_attr_get_charptr(e, type_nsds7WindowsReplicaArea); - if (NULL != tmpstr) - { - windows_private_set_windows_replarea(ra, slapi_sdn_new_dn_passin(tmpstr) ); - } - - tmpstr = slapi_entry_attr_get_charptr(e, type_nsds7DirectoryReplicaArea); - if (NULL != tmpstr) - { - windows_private_set_directory_replarea(ra, slapi_sdn_new_dn_passin(tmpstr) ); - } - - tmpstr = slapi_entry_attr_get_charptr(e, type_nsds7CreateNewUsers); - if (NULL != tmpstr) - windows_private_set_create_users(ra, PR_TRUE); - else - windows_private_set_create_users(ra, PR_FALSE); - + windows_init_agreement_from_entry(ra,e); } else { @@ -481,7 +460,7 @@ agmt_delete(void **rap) if (ra->agreement_type == REPLICA_TYPE_WINDOWS) { - windows_private_delete(ra->priv); + windows_agreement_delete(ra); } schedule_destroy(ra->schedule); @@ -2120,11 +2099,16 @@ get_agmt_agreement_type( Repl_Agmt *agmt) return agmt->agreement_type; } -void* get_priv_from_agmt (const Repl_Agmt *agmt) +void* agmt_get_priv (const Repl_Agmt *agmt) { PR_ASSERT (agmt); return agmt->priv; +} +void agmt_set_priv (Repl_Agmt *agmt, void* priv) +{ + PR_ASSERT (agmt); + agmt->priv = priv; } ReplicaId agmt_get_consumerRID(Repl_Agmt *ra) diff --git a/ldap/servers/plugins/replication/repl5_agmtlist.c b/ldap/servers/plugins/replication/repl5_agmtlist.c index 178a22b0..cb775dae 100644 --- a/ldap/servers/plugins/replication/repl5_agmtlist.c +++ b/ldap/servers/plugins/replication/repl5_agmtlist.c @@ -530,13 +530,13 @@ agmtlist_config_init() /* Register callbacks so we're informed about updates */ slapi_config_register_callback(SLAPI_OPERATION_ADD, DSE_FLAG_PREOP, AGMT_CONFIG_BASE, - LDAP_SCOPE_SUBTREE, CONFIG_FILTER, agmtlist_add_callback, NULL); + LDAP_SCOPE_SUBTREE, GLOBAL_CONFIG_FILTER, agmtlist_add_callback, NULL); slapi_config_register_callback(SLAPI_OPERATION_MODIFY, DSE_FLAG_PREOP, AGMT_CONFIG_BASE, - LDAP_SCOPE_SUBTREE, CONFIG_FILTER, agmtlist_modify_callback, NULL); + LDAP_SCOPE_SUBTREE, GLOBAL_CONFIG_FILTER, agmtlist_modify_callback, NULL); slapi_config_register_callback(SLAPI_OPERATION_DELETE, DSE_FLAG_PREOP, AGMT_CONFIG_BASE, - LDAP_SCOPE_SUBTREE, CONFIG_FILTER, agmtlist_delete_callback, NULL); + LDAP_SCOPE_SUBTREE, GLOBAL_CONFIG_FILTER, agmtlist_delete_callback, NULL); slapi_config_register_callback(SLAPI_OPERATION_MODRDN, DSE_FLAG_PREOP, AGMT_CONFIG_BASE, - LDAP_SCOPE_SUBTREE, CONFIG_FILTER, agmtlist_rename_callback, NULL); + LDAP_SCOPE_SUBTREE, GLOBAL_CONFIG_FILTER, agmtlist_rename_callback, NULL); /* Search the DIT and find all the replication agreements */ pb = slapi_pblock_new(); diff --git a/ldap/servers/plugins/replication/repl5_prot_private.h b/ldap/servers/plugins/replication/repl5_prot_private.h index f4ede144..e7efb705 100644 --- a/ldap/servers/plugins/replication/repl5_prot_private.h +++ b/ldap/servers/plugins/replication/repl5_prot_private.h @@ -67,6 +67,6 @@ CSN *get_current_csn(Slapi_DN *replarea_sdn); char* protocol_response2string (int response); int repl5_strip_fractional_mods(Repl_Agmt *agmt, LDAPMod **); void windows_release_replica(Private_Repl_Protocol *prp); -int windows_acquire_replica(Private_Repl_Protocol *prp, RUV **ruv); +int windows_acquire_replica(Private_Repl_Protocol *prp, RUV **ruv, int check_ruv); #endif /* _REPL5_PROT_PRIVATE_H_ */ diff --git a/ldap/servers/plugins/replication/repl5_protocol.c b/ldap/servers/plugins/replication/repl5_protocol.c index 4d8dc3a9..fcb9b2a8 100644 --- a/ldap/servers/plugins/replication/repl5_protocol.c +++ b/ldap/servers/plugins/replication/repl5_protocol.c @@ -15,7 +15,6 @@ */ #include "repl5.h" -#include "windowsrepl.h" #include "repl5_prot_private.h" #define PROTOCOL_5_INCREMENTAL 1 diff --git a/ldap/servers/plugins/replication/repl_globals.c b/ldap/servers/plugins/replication/repl_globals.c index bfabf777..d69e35ae 100644 --- a/ldap/servers/plugins/replication/repl_globals.c +++ b/ldap/servers/plugins/replication/repl_globals.c @@ -93,7 +93,9 @@ const char *type_nsds5ReplicaSessionPauseTime = "nsds5ReplicaSessionPauseTime"; const char *type_nsds7WindowsReplicaArea = "nsds7WindowsReplicaSubtree"; const char *type_nsds7DirectoryReplicaArea = "nsds7DirectoryReplicaSubtree"; const char *type_nsds7CreateNewUsers = "nsds7NewWinUserSyncEnabled"; - +const char *type_nsds7CreateNewGroups = "nsds7NewWinGroupSyncEnabled"; +const char *type_nsds7WindowsDomain = "nsds7WindowsDomain"; +const char *type_nsds7DirsyncCookie = "nsds7DirsyncCookie"; /* To Allow Consumer Initialisation when adding an agreement - */ const char *type_nsds5BeginReplicaRefresh = "nsds5BeginReplicaRefresh"; diff --git a/ldap/servers/plugins/replication/repl_shared.h b/ldap/servers/plugins/replication/repl_shared.h index 3e65ddff..df14a70f 100644 --- a/ldap/servers/plugins/replication/repl_shared.h +++ b/ldap/servers/plugins/replication/repl_shared.h @@ -98,6 +98,7 @@ #define CHANGELOG_DB_VERSION_PREV "3.0" #define CHANGELOG_DB_VERSION "4.0" extern char *repl_plugin_name; +extern char *windows_repl_plugin_name; extern char *repl_plugin_name_cl; /* repl_monitor.c */ diff --git a/ldap/servers/plugins/replication/windows_connection.c b/ldap/servers/plugins/replication/windows_connection.c index d0651f51..96593e84 100644 --- a/ldap/servers/plugins/replication/windows_connection.c +++ b/ldap/servers/plugins/replication/windows_connection.c @@ -15,8 +15,9 @@ replica locked. Seems like right thing to do. */ #include "repl5.h" -#include "ldappr.h" #include "windowsrepl.h" +#include "ldappr.h" +#include "slap.h" typedef struct repl_connection { @@ -108,6 +109,8 @@ windows_conn_new(Repl_Agmt *agmt) { Repl_Connection *rpc; + LDAPDebug( LDAP_DEBUG_TRACE, "=> windows_conn_new\n", 0, 0, 0 ); + rpc = (Repl_Connection *)slapi_ch_malloc(sizeof(repl_connection)); if ((rpc->lock = PR_NewLock()) == NULL) { @@ -138,9 +141,11 @@ windows_conn_new(Repl_Agmt *agmt) rpc->timeout.tv_usec = 0; rpc->flag_agmt_changed = 0; rpc->plain = NULL; + LDAPDebug( LDAP_DEBUG_TRACE, "<= windows_conn_new\n", 0, 0, 0 ); return rpc; loser: windows_conn_delete(rpc); + LDAPDebug( LDAP_DEBUG_TRACE, "<= windows_conn_new - loser\n", 0, 0, 0 ); return NULL; } @@ -152,9 +157,11 @@ static PRBool windows_conn_connected(Repl_Connection *conn) { PRBool return_value; + LDAPDebug( LDAP_DEBUG_TRACE, "=> windows_conn_connected\n", 0, 0, 0 ); PR_Lock(conn->lock); return_value = STATE_CONNECTED == conn->state; PR_Unlock(conn->lock); + LDAPDebug( LDAP_DEBUG_TRACE, "<= windows_conn_connected\n", 0, 0, 0 ); return return_value; } @@ -165,12 +172,14 @@ windows_conn_connected(Repl_Connection *conn) static void windows_conn_delete_internal(Repl_Connection *conn) { + LDAPDebug( LDAP_DEBUG_TRACE, "=> windows_conn_delete_internal\n", 0, 0, 0 ); PR_ASSERT(NULL != conn); close_connection_internal(conn); /* slapi_ch_free accepts NULL pointer */ slapi_ch_free((void **)&conn->hostname); slapi_ch_free((void **)&conn->binddn); slapi_ch_free((void **)&conn->plain); + LDAPDebug( LDAP_DEBUG_TRACE, "<= windows_conn_delete_internal\n", 0, 0, 0 ); } /* @@ -182,6 +191,8 @@ windows_conn_delete(Repl_Connection *conn) { PRBool destroy_it = PR_FALSE; + LDAPDebug( LDAP_DEBUG_TRACE, "=> windows_conn_delete\n", 0, 0, 0 ); + PR_ASSERT(NULL != conn); PR_Lock(conn->lock); if (conn->linger_active) @@ -207,6 +218,7 @@ windows_conn_delete(Repl_Connection *conn) { windows_conn_delete_internal(conn); } + LDAPDebug( LDAP_DEBUG_TRACE, "<= windows_conn_delete\n", 0, 0, 0 ); } @@ -217,10 +229,12 @@ windows_conn_delete(Repl_Connection *conn) void windows_conn_get_error(Repl_Connection *conn, int *operation, int *error) { + LDAPDebug( LDAP_DEBUG_TRACE, "=> windows_conn_get_error\n", 0, 0, 0 ); PR_Lock(conn->lock); *operation = conn->last_operation; *error = conn->last_ldap_error; PR_Unlock(conn->lock); + LDAPDebug( LDAP_DEBUG_TRACE, "<= windows_conn_get_error\n", 0, 0, 0 ); } @@ -251,6 +265,8 @@ windows_perform_operation(Repl_Connection *conn, int optype, const char *dn, 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)) @@ -432,11 +448,111 @@ windows_perform_operation(Repl_Connection *conn, int optype, const char *dn, */ return_value = CONN_NOT_CONNECTED; } + LDAPDebug( LDAP_DEBUG_TRACE, "<= windows_perform_operation\n", 0, 0, 0 ); return return_value; } +/* Copied from the chaining backend*/ +static Slapi_Entry * +windows_LDAPMessage2Entry(LDAP * ld, LDAPMessage * msg, int attrsonly) { + + Slapi_Entry * e = slapi_entry_alloc(); + char * a=NULL; + BerElement * ber=NULL; + + if ( e == NULL ) return NULL; + if (msg == NULL) { + slapi_entry_free(e); + return NULL; + } + + /* + * dn not allocated by slapi + * attribute type and values ARE allocated + */ + + slapi_entry_set_dn( e, ldap_get_dn( ld, msg ) ); + + for ( a = ldap_first_attribute( ld, msg, &ber ); a!=NULL; + a=ldap_next_attribute( ld, msg, ber ) ) { + if(attrsonly) { + slapi_entry_add_value(e, a, (Slapi_Value *)NULL); + ldap_memfree(a); + } else { + struct berval ** aVal = ldap_get_values_len( ld, msg, a); + slapi_entry_add_values( e, a, aVal); + + ldap_memfree(a); + ldap_value_free_len(aVal); + } + } + if ( NULL != ber ) + ldap_ber_free( ber, 0 ); + + return e; +} + ConnResult -perform_search(Repl_Connection *conn) +windows_search_entry(Repl_Connection *conn, char* searchbase, char *filter, Slapi_Entry **entry) +{ + ConnResult return_value = 0; + int ldap_rc = 0; + LDAPMessage *res = NULL; + int not_unique = 0; + + LDAPDebug( LDAP_DEBUG_TRACE, "=> windows_search_entry\n", 0, 0, 0 ); + + *entry = NULL; + + 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 */, + &conn->timeout, 0 /* sizelimit */, &res); + if (LDAP_SUCCESS == ldap_rc) + { + LDAPMessage *message = ldap_first_entry(conn->ld, res); + LDAPMessage *next_entry = NULL; + if (NULL != entry) + { + *entry = windows_LDAPMessage2Entry(conn->ld,message,0); + } + /* See if there are any more entries : if so then that's an error + * but we still need to get them to avoid gumming up the connection + */ + while (NULL != ( next_entry = ldap_next_entry(conn->ld,res))) + { + not_unique = 1; + } + return_value = CONN_OPERATION_SUCCESS; + } + else if (IS_DISCONNECT_ERROR(ldap_rc)) + { + windows_conn_disconnect(conn); + return_value = CONN_NOT_CONNECTED; + } + else + { + return_value = CONN_OPERATION_FAILED; + } + conn->last_ldap_error = ldap_rc; + if (NULL != res) + { + ldap_msgfree(res); + res = NULL; + } + } + else + { + return_value = CONN_NOT_CONNECTED; + } + LDAPDebug( LDAP_DEBUG_TRACE, "<= windows_search_entry\n", 0, 0, 0 ); + return return_value; +} + +ConnResult +send_dirsync_search(Repl_Connection *conn) { int rc; ConnResult return_value; @@ -449,33 +565,38 @@ perform_search(Repl_Connection *conn) char* dn = NULL; int i=0; int num_comp=0; + + LDAPDebug( LDAP_DEBUG_TRACE, "=> send_dirsync_search\n", 0, 0, 0 ); /* need to strip the dn down to dc= */ - /* XXX: this is not the most elegant way of doing this */ - old_dn = slapi_sdn_get_ndn( windows_private_get_windows_replarea(conn->agmt) ); + old_dn = slapi_sdn_get_ndn( windows_private_get_windows_subtree(conn->agmt) ); dn = strstr(old_dn, "dc="); if (windows_conn_connected(conn)) { if (conn->supports_dirsync == 0) + { server_controls[0] = NULL; /* unsupported */ - else + } 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[1] = NULL; conn->last_operation = CONN_SEARCH; conn->status = STATUS_SEARCHING; op_string = "search"; + LDAPDebug( LDAP_DEBUG_REPL, "Sending dirsync search request\n", 0, 0, 0 ); + rc = ldap_search_ext( conn->ld, dn, LDAP_SCOPE_SUBTREE, "(objectclass=*)", /* filter */ NULL /*attrs */, PR_FALSE, server_controls, NULL, /* ClientControls */ 0,0, &msgid); if (LDAP_SUCCESS == rc) { - - int setlevel = 0; - int finished = 0; return_value = 0; } else @@ -496,6 +617,11 @@ perform_search(Repl_Connection *conn) return_value = CONN_OPERATION_FAILED; } } + if (server_controls[0]) + { + ldap_control_free(server_controls[0]); + } + } else { @@ -505,6 +631,7 @@ perform_search(Repl_Connection *conn) */ return_value = CONN_NOT_CONNECTED; } + LDAPDebug( LDAP_DEBUG_TRACE, "<= send_dirsync_search\n", 0, 0, 0 ); return return_value; } @@ -516,10 +643,14 @@ ConnResult windows_conn_send_add(Repl_Connection *conn, const char *dn, LDAPMod **attrs, LDAPControl *update_control, LDAPControl ***returned_controls) { - return windows_perform_operation(conn, CONN_ADD, dn, attrs, NULL /* newrdn */, + 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 /* 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; } @@ -530,6 +661,8 @@ ConnResult windows_conn_send_delete(Repl_Connection *conn, const char *dn, LDAPControl *update_control, 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 */, @@ -544,6 +677,8 @@ ConnResult windows_conn_send_modify(Repl_Connection *conn, const char *dn, LDAPMod **mods, LDAPControl *update_control, 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 /* extop OID */, NULL /* extop payload */, NULL /* retoidp */, @@ -558,6 +693,8 @@ windows_conn_send_rename(Repl_Connection *conn, const char *dn, const char *newrdn, const char *newparent, int deleteoldrdn, LDAPControl *update_control, 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, NULL /* extop OID */, NULL /* extop payload */, NULL /* retoidp */, @@ -578,6 +715,9 @@ Slapi_Entry * windows_conn_get_search_result(Repl_Connection *conn) char *a = ""; char *dn = ""; BerElement *ber = NULL; + + LDAPDebug( LDAP_DEBUG_TRACE, "=> windows_conn_get_search_result\n", 0, 0, 0 ); + if (windows_conn_connected(conn)) { rc = ldap_result( conn->ld, LDAP_RES_ANY, 0, &conn->timeout, &res ); @@ -585,49 +725,48 @@ Slapi_Entry * windows_conn_get_search_result(Repl_Connection *conn) case 0: case -1: case LDAP_RES_SEARCH_REFERENCE: - slapi_log_error(SLAPI_LOG_FATAL, windows_repl_plugin_name, "error, rc=%d\n", rc); - ldap_msgfree( res ); + slapi_log_error(SLAPI_LOG_FATAL, windows_repl_plugin_name, "error in windows_conn_get_search_result, rc=%d\n", rc); break; case LDAP_RES_SEARCH_RESULT: { - LDAPControl **returned_controls; - int code=0; - int parse_rc; - parse_rc = ldap_parse_result( conn->ld, res, &code, NULL, NULL, NULL, &returned_controls, 1 ); - windows_private_update_dirsync_control(conn->agmt, returned_controls); + LDAPControl **returned_controls = NULL; + int code = 0; + int parse_rc = 0; + /* Purify says this is a leak : */ + parse_rc = ldap_parse_result( conn->ld, res, &code, NULL, NULL, NULL, &returned_controls, 0 ); + if (returned_controls) + { + windows_private_update_dirsync_control(conn->agmt, returned_controls); + ldap_controls_free(returned_controls); + } + if (windows_private_dirsync_has_more(conn->agmt)) { + slapi_log_error(SLAPI_LOG_REPL, windows_repl_plugin_name,"received hasmore from dirsync\n", 0); + } } break; case LDAP_RES_SEARCH_ENTRY: { if (( dn = ldap_get_dn( conn->ld, res )) != NULL ) { - slapi_log_error(SLAPI_LOG_FATAL, windows_repl_plugin_name,"found an entry %s\n", dn); + slapi_log_error(SLAPI_LOG_REPL, windows_repl_plugin_name,"received entry from dirsync: %s\n", dn); lm = ldap_first_entry( conn->ld, res ); - e = slapi_entry_alloc(); - slapi_entry_init(e, dn, NULL); - for ( a = ldap_first_attribute( conn->ld, lm, &ber ); a != NULL; a = ldap_next_attribute( conn->ld, lm, ber ) ) - { - int i =0; - char **vals; - - if ((vals = ldap_get_values( conn->ld, lm, a)) != NULL ) - { - for ( i = 0; vals[i] != NULL; i++ ) - { - slapi_entry_add_string (e, a, vals[i]); - } - ldap_value_free( vals ); - } - } + e = windows_LDAPMessage2Entry(conn->ld,lm,0); + ldap_memfree(dn); } } break; - } // switch - } //if + } /* switch */ + } /* if */ - return e; + if (res) + { + ldap_msgfree( res ); + res = NULL; + } + LDAPDebug( LDAP_DEBUG_TRACE, "<= windows_conn_get_search_result\n", 0, 0, 0 ); + return e; } @@ -639,6 +778,8 @@ windows_conn_send_extended_operation(Repl_Connection *conn, const char *extop_oi struct berval *payload, char **retoidp, struct berval **retdatap, LDAPControl *update_control, 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, @@ -665,6 +806,8 @@ windows_conn_read_entry_attribute(Repl_Connection *conn, const char *dn, LDAPMessage *res = NULL; char *attrs[2]; + LDAPDebug( LDAP_DEBUG_TRACE, "=> windows_conn_read_entry_attribute\n", 0, 0, 0 ); + PR_ASSERT(NULL != type); if (windows_conn_connected(conn)) { @@ -705,6 +848,7 @@ windows_conn_read_entry_attribute(Repl_Connection *conn, const char *dn, { return_value = CONN_NOT_CONNECTED; } + LDAPDebug( LDAP_DEBUG_TRACE, "<= windows_conn_read_entry_attribute\n", 0, 0, 0 ); return return_value; } @@ -716,6 +860,8 @@ windows_conn_read_entry_attribute(Repl_Connection *conn, const char *dn, const char * windows_conn_get_status(Repl_Connection *conn) { + LDAPDebug( LDAP_DEBUG_TRACE, "=> windows_conn_get_status\n", 0, 0, 0 ); + LDAPDebug( LDAP_DEBUG_TRACE, "<= windows_conn_get_status\n", 0, 0, 0 ); return conn->status; } @@ -728,6 +874,7 @@ windows_conn_get_status(Repl_Connection *conn) void windows_conn_cancel_linger(Repl_Connection *conn) { + LDAPDebug( LDAP_DEBUG_TRACE, "=> windows_conn_cancel_linger\n", 0, 0, 0 ); PR_ASSERT(NULL != conn); PR_Lock(conn->lock); if (conn->linger_active) @@ -750,6 +897,7 @@ windows_conn_cancel_linger(Repl_Connection *conn) agmt_get_long_name(conn->agmt)); } PR_Unlock(conn->lock); + LDAPDebug( LDAP_DEBUG_TRACE, "<= windows_conn_cancel_linger\n", 0, 0, 0 ); } @@ -765,6 +913,8 @@ linger_timeout(time_t event_time, void *arg) PRBool delete_now; Repl_Connection *conn = (Repl_Connection *)arg; + LDAPDebug( LDAP_DEBUG_TRACE, "=> linger_timeout\n", 0, 0, 0 ); + PR_ASSERT(NULL != conn); slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "%s: Linger timeout has expired on the connection\n", @@ -782,6 +932,7 @@ linger_timeout(time_t event_time, void *arg) { windows_conn_delete_internal(conn); } + LDAPDebug( LDAP_DEBUG_TRACE, "<= linger_timeout\n", 0, 0, 0 ); } @@ -794,6 +945,8 @@ windows_conn_start_linger(Repl_Connection *conn) { time_t now; + LDAPDebug( LDAP_DEBUG_TRACE, "=> windows_conn_start_linger\n", 0, 0, 0 ); + PR_ASSERT(NULL != conn); slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "%s: Beginning linger on the connection\n", @@ -820,6 +973,7 @@ windows_conn_start_linger(Repl_Connection *conn) conn->status = STATUS_LINGERING; } PR_Unlock(conn->lock); + LDAPDebug( LDAP_DEBUG_TRACE, "<= windows_conn_start_linger\n", 0, 0, 0 ); } @@ -843,8 +997,13 @@ windows_conn_connect(Repl_Connection *conn) ConnResult return_value = CONN_OPERATION_SUCCESS; int pw_ret = 1; + LDAPDebug( LDAP_DEBUG_TRACE, "=> windows_conn_connect\n", 0, 0, 0 ); + /** Connection already open just return SUCCESS **/ - if(conn->state == STATE_CONNECTED) return return_value; + if(conn->state == STATE_CONNECTED) { + LDAPDebug( LDAP_DEBUG_TRACE, "<= windows_conn_connect\n", 0, 0, 0 ); + return return_value; + } PR_Lock(conn->lock); if (conn->flag_agmt_changed) { @@ -882,6 +1041,7 @@ windows_conn_connect(Repl_Connection *conn) return_value = CONN_OPERATION_FAILED; conn->last_ldap_error = LDAP_INVALID_CREDENTIALS; conn->state = STATE_DISCONNECTED; + LDAPDebug( LDAP_DEBUG_TRACE, "<= windows_conn_connect\n", 0, 0, 0 ); return (return_value); } /* Else, does not mean that the plain is correct, only means the we had no internal decoding pb */ @@ -915,6 +1075,7 @@ windows_conn_connect(Repl_Connection *conn) conn->last_operation = CONN_INIT; ber_bvfree(creds); creds = NULL; + LDAPDebug( LDAP_DEBUG_TRACE, "<= windows_conn_connect\n", 0, 0, 0 ); return CONN_SSL_NOT_ENABLED; } else { @@ -944,6 +1105,7 @@ windows_conn_connect(Repl_Connection *conn) secure ? "secure " : ""); ber_bvfree(creds); creds = NULL; + LDAPDebug( LDAP_DEBUG_TRACE, "<= windows_conn_connect\n", 0, 0, 0 ); return return_value; } @@ -1004,6 +1166,7 @@ windows_conn_connect(Repl_Connection *conn) conn->state = STATE_CONNECTED; } + LDAPDebug( LDAP_DEBUG_TRACE, "<= windows_conn_connect\n", 0, 0, 0 ); return return_value; } @@ -1011,6 +1174,8 @@ windows_conn_connect(Repl_Connection *conn) static void close_connection_internal(Repl_Connection *conn) { + LDAPDebug( LDAP_DEBUG_TRACE, "=> close_connection_internal\n", 0, 0, 0 ); + if (NULL != conn->ld) { /* Since we call slapi_ldap_init, @@ -1023,15 +1188,18 @@ close_connection_internal(Repl_Connection *conn) conn->supports_ds50_repl = -1; slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "%s: Disconnected from the consumer\n", agmt_get_long_name(conn->agmt)); + LDAPDebug( LDAP_DEBUG_TRACE, "<= close_connection_internal\n", 0, 0, 0 ); } void windows_conn_disconnect(Repl_Connection *conn) { + LDAPDebug( LDAP_DEBUG_TRACE, "=> windows_conn_disconnect\n", 0, 0, 0 ); PR_ASSERT(NULL != conn); PR_Lock(conn->lock); close_connection_internal(conn); PR_Unlock(conn->lock); + LDAPDebug( LDAP_DEBUG_TRACE, "<= windows_conn_disconnect\n", 0, 0, 0 ); } @@ -1051,6 +1219,8 @@ windows_conn_replica_supports_ds5_repl(Repl_Connection *conn) ConnResult return_value; int ldap_rc; + LDAPDebug( LDAP_DEBUG_TRACE, "=> windows_conn_replica_supports_ds5_repl\n", 0, 0, 0 ); + if (windows_conn_connected(conn)) { if (conn->supports_ds50_repl == -1) { @@ -1118,6 +1288,7 @@ windows_conn_replica_supports_ds5_repl(Repl_Connection *conn) /* Not connected */ return_value = CONN_NOT_CONNECTED; } + LDAPDebug( LDAP_DEBUG_TRACE, "<= windows_conn_replica_supports_ds5_repl\n", 0, 0, 0 ); return return_value; } @@ -1128,6 +1299,8 @@ windows_conn_replica_supports_dirsync(Repl_Connection *conn) ConnResult return_value; int ldap_rc; + LDAPDebug( LDAP_DEBUG_TRACE, "=> windows_conn_replica_supports_dirsync\n", 0, 0, 0 ); + if (windows_conn_connected(conn)) { if (conn->supports_dirsync == -1) { @@ -1180,6 +1353,7 @@ windows_conn_replica_supports_dirsync(Repl_Connection *conn) /* Not connected */ return_value = CONN_NOT_CONNECTED; } + LDAPDebug( LDAP_DEBUG_TRACE, "<= windows_conn_replica_supports_dirsync\n", 0, 0, 0 ); return return_value; } @@ -1195,6 +1369,8 @@ attribute_string_value_present(LDAP *ld, LDAPMessage *entry, const char *type, { int return_value = 0; + LDAPDebug( LDAP_DEBUG_TRACE, "=> attribute_string_value_present\n", 0, 0, 0 ); + if (NULL != entry) { char *atype = NULL; @@ -1228,6 +1404,7 @@ attribute_string_value_present(LDAP *ld, LDAPMessage *entry, const char *type, if (NULL != atype) ldap_memfree(atype); } + LDAPDebug( LDAP_DEBUG_TRACE, "<= attribute_string_value_present\n", 0, 0, 0 ); return return_value; } @@ -1251,20 +1428,24 @@ attribute_string_value_present(LDAP *ld, LDAPMessage *entry, const char *type, void windows_conn_set_timeout(Repl_Connection *conn, long timeout) { + LDAPDebug( LDAP_DEBUG_TRACE, "=> windows_conn_set_timeout\n", 0, 0, 0 ); PR_ASSERT(NULL != conn); PR_ASSERT(timeout >= 0); PR_Lock(conn->lock); conn->timeout.tv_sec = timeout; PR_Unlock(conn->lock); + LDAPDebug( LDAP_DEBUG_TRACE, "<= windows_conn_set_timeout\n", 0, 0, 0 ); } void windows_conn_set_agmt_changed(Repl_Connection *conn) { + LDAPDebug( LDAP_DEBUG_TRACE, "=> windows_conn_set_agmt_changed\n", 0, 0, 0 ); PR_ASSERT(NULL != conn); PR_Lock(conn->lock); if (NULL != conn->agmt) conn->flag_agmt_changed = 1; PR_Unlock(conn->lock); + LDAPDebug( LDAP_DEBUG_TRACE, "<= windows_conn_set_agmt_changed\n", 0, 0, 0 ); } /* @@ -1287,6 +1468,8 @@ bind_and_check_pwp(Repl_Connection *conn, char * binddn, char *password) char * optype; /* ldap_simple_bind or slapd_SSL_client_bind */ + LDAPDebug( LDAP_DEBUG_TRACE, "=> windows_conn_set_agmt_changed\n", 0, 0, 0 ); + if ( conn->transport_flags == TRANSPORT_FLAG_SSL ) { char *auth; @@ -1319,6 +1502,8 @@ bind_and_check_pwp(Repl_Connection *conn, char * binddn, char *password) ldap_err2string(rc)); } + LDAPDebug( LDAP_DEBUG_TRACE, "<= windows_conn_set_agmt_changed - CONN_OPERATION_FAILED\n", 0, 0, 0 ); + return (CONN_OPERATION_FAILED); } } @@ -1326,6 +1511,7 @@ bind_and_check_pwp(Repl_Connection *conn, char * binddn, char *password) { if( ( msgid = do_simple_bind( conn, ld, binddn, password ) ) == -1 ) { + LDAPDebug( LDAP_DEBUG_TRACE, "<= windows_conn_set_agmt_changed - CONN_OPERATION_FAILED\n", 0, 0, 0 ); return (CONN_OPERATION_FAILED); } } @@ -1335,6 +1521,7 @@ bind_and_check_pwp(Repl_Connection *conn, char * binddn, char *password) optype = "ldap_simple_bind"; if( ( msgid = do_simple_bind( conn, ld, binddn, password ) ) == -1 ) { + LDAPDebug( LDAP_DEBUG_TRACE, "<= windows_conn_set_agmt_changed - CONN_OPERATION_FAILED\n", 0, 0, 0 ); return (CONN_OPERATION_FAILED); } } @@ -1344,7 +1531,9 @@ bind_and_check_pwp(Repl_Connection *conn, char * binddn, char *password) { slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "%s: Received error from consumer for %s operation\n", + agmt_get_long_name(conn->agmt), optype); + LDAPDebug( LDAP_DEBUG_TRACE, "<= windows_conn_set_agmt_changed - CONN_OPERATION_FAILED\n", 0, 0, 0 ); return (CONN_OPERATION_FAILED); } @@ -1358,6 +1547,8 @@ bind_and_check_pwp(Repl_Connection *conn, char * binddn, char *password) "%s: Received error from consumer for %s operation\n", agmt_get_long_name(conn->agmt), optype); + LDAPDebug( LDAP_DEBUG_TRACE, "<= windows_conn_set_agmt_changed - CONN_OPERATION_FAILED\n", 0, 0, 0 ); + return (CONN_OPERATION_FAILED); } @@ -1393,6 +1584,8 @@ bind_and_check_pwp(Repl_Connection *conn, char * binddn, char *password) ldap_controls_free( ctrls ); } + LDAPDebug( LDAP_DEBUG_TRACE, "<= windows_conn_set_agmt_changed - CONN_OPERATION_SUCCESS\n", 0, 0, 0 ); + return (CONN_OPERATION_SUCCESS); } else @@ -1404,6 +1597,7 @@ bind_and_check_pwp(Repl_Connection *conn, char * binddn, char *password) agmt_get_long_name(conn->agmt), binddn, rc, errmsg); conn->last_ldap_error = rc; /* specific error */ + LDAPDebug( LDAP_DEBUG_TRACE, "<= windows_conn_set_agmt_changed - CONN_OPERATION_FAILED\n", 0, 0, 0 ); return (CONN_OPERATION_FAILED); } } @@ -1413,6 +1607,8 @@ do_simple_bind (Repl_Connection *conn, LDAP *ld, char * binddn, char *password) { int msgid; + LDAPDebug( LDAP_DEBUG_TRACE, "=> do_simple_bind\n", 0, 0, 0 ); + if( ( msgid = ldap_simple_bind( ld, binddn, password ) ) == -1 ) { char *ldaperrtext = NULL; @@ -1440,6 +1636,7 @@ do_simple_bind (Repl_Connection *conn, LDAP *ld, char * binddn, char *password) "%s: Simple bind resumed\n", agmt_get_long_name(conn->agmt)); } + LDAPDebug( LDAP_DEBUG_TRACE, "<= do_simple_bind\n", 0, 0, 0 ); return msgid; } @@ -1449,10 +1646,14 @@ PRTime2time_t (PRTime tm) { PRInt64 rt; + LDAPDebug( LDAP_DEBUG_TRACE, "=> PRTime2time_t\n", 0, 0, 0 ); + PR_ASSERT (tm); LL_DIV(rt, tm, PR_USEC_PER_SEC); + LDAPDebug( LDAP_DEBUG_TRACE, "<= PRTime2time_t\n", 0, 0, 0 ); + return (time_t)rt; } @@ -1460,11 +1661,15 @@ static Slapi_Eq_Context repl5_start_debug_timeout(int *setlevel) { Slapi_Eq_Context eqctx = 0; + + LDAPDebug( LDAP_DEBUG_TRACE, "=> repl5_start_debug_timeout\n", 0, 0, 0 ); + if (s_debug_timeout && s_debug_level) { time_t now = time(NULL); eqctx = slapi_eq_once(repl5_debug_timeout_callback, setlevel, s_debug_timeout + now); } + LDAPDebug( LDAP_DEBUG_TRACE, "<= repl5_start_debug_timeout\n", 0, 0, 0 ); return eqctx; } @@ -1474,25 +1679,31 @@ repl5_stop_debug_timeout(Slapi_Eq_Context eqctx, int *setlevel) char buf[20]; char msg[SLAPI_DSE_RETURNTEXT_SIZE]; + LDAPDebug( LDAP_DEBUG_TRACE, "=> repl5_stop_debug_timeout\n", 0, 0, 0 ); + if (eqctx && !*setlevel) { int found = slapi_eq_cancel(eqctx); } if (s_debug_timeout && s_debug_level && *setlevel) { - void config_set_errorlog_level(const char *type, char *buf, char *msg, int apply); + /* No longer needed as we are including the one in slap.h */ sprintf(buf, "%d", 0); config_set_errorlog_level("nsslapd-errorlog-level", buf, msg, 1); } + + LDAPDebug( LDAP_DEBUG_TRACE, "<= repl5_stop_debug_timeout\n", 0, 0, 0 ); } static void repl5_debug_timeout_callback(time_t when, void *arg) { int *setlevel = (int *)arg; - void config_set_errorlog_level(const char *type, char *buf, char *msg, int apply); + /* No longer needed as we are including the one in slap.h */ char buf[20]; char msg[SLAPI_DSE_RETURNTEXT_SIZE]; + LDAPDebug( LDAP_DEBUG_TRACE, "=> repl5_debug_timeout_callback\n", 0, 0, 0 ); + *setlevel = 1; sprintf(buf, "%d", s_debug_level); config_set_errorlog_level("nsslapd-errorlog-level", buf, msg, 1); @@ -1500,4 +1711,6 @@ repl5_debug_timeout_callback(time_t when, void *arg) slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "repl5_debug_timeout_callback: set debug level to %d at %d\n", s_debug_level, when); + + LDAPDebug( LDAP_DEBUG_TRACE, "<= repl5_debug_timeout_callback\n", 0, 0, 0 ); } diff --git a/ldap/servers/plugins/replication/windows_inc_protocol.c b/ldap/servers/plugins/replication/windows_inc_protocol.c index 1de3fb2a..f588d6ba 100644 --- a/ldap/servers/plugins/replication/windows_inc_protocol.c +++ b/ldap/servers/plugins/replication/windows_inc_protocol.c @@ -32,59 +32,6 @@ Perhaps these events should be properties of the main protocol. #include "slapi-plugin.h" extern int slapi_log_urp; -typedef struct attribute_map -{ - char *old_name; - char *new_name; - int map_to; - -} attribute_map; - -static attribute_map mapping[] = -{ /* map the attribute from , to, which platform we going to? */ - { "ntUserDomainId", "sAMAccountName", REPLICA_TYPE_WINDOWS}, - { "ntUserHomeDir", "homeDirectory", REPLICA_TYPE_WINDOWS}, - { "ntUserScriptPath", "scriptPath", REPLICA_TYPE_WINDOWS}, - { "ntUserLastLogon", "lastLogon", REPLICA_TYPE_WINDOWS}, - { "ntUserLastLogoff", "lastLogoff", REPLICA_TYPE_WINDOWS}, - { "cn", "description", REPLICA_TYPE_WINDOWS}, /* temporary */ - { "uid", "cn", REPLICA_TYPE_WINDOWS}, - { "dn", "dn", REPLICA_TYPE_WINDOWS}, - { "sn", "sn", REPLICA_TYPE_WINDOWS}, - - { "sAMAccountName", "ntUserDomainId", REPLICA_TYPE_MULTIMASTER}, - { "homeDirectory", "ntUserHomeDir", REPLICA_TYPE_MULTIMASTER}, - { "scriptPath", "ntUserScriptPath", REPLICA_TYPE_MULTIMASTER}, - { "lastLogon", "ntUserLastLogon", REPLICA_TYPE_MULTIMASTER}, - { "lastLogoff", "ntUserLastLogoff", REPLICA_TYPE_MULTIMASTER}, - { "sAMAccountName", "uid", REPLICA_TYPE_MULTIMASTER}, - { "dn", "dn", REPLICA_TYPE_MULTIMASTER}, - { "sAMAccountName", "sn", REPLICA_TYPE_MULTIMASTER}, - { "sAMAccountName", "cn", REPLICA_TYPE_MULTIMASTER}, - - {NULL, NULL, -1} -}; - -static attribute_map group_map[] = -{ - { "ntGroupDomainId ", "name", REPLICA_TYPE_WINDOWS}, - { "ntGroupDomainId ", "sAMAccountName", REPLICA_TYPE_WINDOWS}, - { "ntGroupType", "groupType", REPLICA_TYPE_WINDOWS}, - - { "sAMAccountName", "ntGroupDomainId ", REPLICA_TYPE_MULTIMASTER}, - { "groupType", "ntGroupType", REPLICA_TYPE_MULTIMASTER}, - - {NULL, NULL, -1} - -}; - -void map_entry_user(Slapi_Entry **e, int map_to, char** password); -static Slapi_Entry* windows_entry_already_exists(Slapi_Entry *e); - -static Slapi_DN* map_dn_user(Slapi_DN *sdn, int map_to, const Slapi_DN *root); -static Slapi_DN* map_dn_group(Slapi_DN *sdn, int map_to, const Slapi_DN *root); -static void make_mods_from_entries(Slapi_Entry *new_entry, Slapi_Entry *existing_entry, LDAPMod ***attrs); -static void alter_mods(LDAPMod ***m, char** password); /*** from proto-slap.h ***/ void ava_done(struct ava *ava); @@ -119,6 +66,7 @@ typedef struct windows_inc_private #define EVENT_REPLICATE_NOW 16 #define EVENT_PROTOCOL_SHUTDOWN 32 #define EVENT_AGMT_CHANGED 64 +#define EVENT_RUN_DIRSYNC 128 #define UPDATE_NO_MORE_UPDATES 201 #define UPDATE_TRANSIENT_ERROR 202 @@ -142,7 +90,11 @@ typedef struct windows_inc_private * we go ahead and start a replication session, just to be safe */ #define MAX_WAIT_BETWEEN_SESSIONS PR_SecondsToInterval(60 * 5) /* 5 minutes */ - +/* + * Periodic synchronization interval. This is used for scheduling the periodic_dirsync event. + * The time is in milliseconds. + */ +#define PERIODIC_DIRSYNC_INTERVAL 5 * 60 * 1000 /* DBDB this should probably be configurable. 5 mins fixed for now */ /* * tests if the protocol has been shutdown and we need to quit * event_occurred resets the bits in the bit flag, so whoever tests for shutdown @@ -161,8 +113,10 @@ static int windows_examine_update_vector(Private_Repl_Protocol *prp, RUV *ruv); static PRBool ignore_error_and_keep_going(int error); static const char* state2name (int state); static const char* event2name (int event); -static const char* op2string (int op); +static const char* acquire2name (int code); +static void periodic_dirsync(time_t when, void *arg); +static Slapi_Eq_Context dirsync; /* * It's specifically ok to delete a protocol instance that * is currently running. The instance will be shut down, and @@ -172,14 +126,18 @@ static const char* op2string (int op); static void windows_inc_delete(Private_Repl_Protocol **prpp) { + LDAPDebug( LDAP_DEBUG_TRACE, "=> windows_inc_delete\n", 0, 0, 0 ); /* First, stop the protocol if it isn't already stopped */ /* Then, delete all resources used by the protocol */ + slapi_eq_cancel(dirsync); + LDAPDebug( LDAP_DEBUG_TRACE, "<= windows_inc_delete\n", 0, 0, 0 ); } /* helper function */ void w_set_pause_and_busy_time(long *pausetime, long *busywaittime) { + LDAPDebug( LDAP_DEBUG_TRACE, "=> w_set_pause_and_busy_time\n", 0, 0, 0 ); /* If neither are set, set busy time to its default */ if (!*pausetime && !*busywaittime) { @@ -216,6 +174,7 @@ w_set_pause_and_busy_time(long *pausetime, long *busywaittime) */ *pausetime = *busywaittime + 1; } + LDAPDebug( LDAP_DEBUG_TRACE, "<= w_set_pause_and_busy_time\n", 0, 0, 0 ); } /* @@ -267,435 +226,472 @@ w_set_pause_and_busy_time(long *pausetime, long *busywaittime) static void windows_inc_run(Private_Repl_Protocol *prp) { - int current_state = STATE_START; - int next_state = STATE_START; - windows_inc_private *prp_priv = (windows_inc_private *)prp->private; - int done; - int e1; - RUV *ruv = NULL; - CSN *cons_schema_csn; - Replica *replica; - int wait_change_timer_set = 0; - time_t last_start_time; - PRUint32 num_changes_sent; - char *hostname = NULL; - int portnum = 0; - /* use a different backoff timer strategy for ACQUIRE_REPLICA_BUSY errors */ - PRBool use_busy_backoff_timer = PR_FALSE; - long pausetime = 0; - long busywaittime = 0; - - prp->stopped = 0; - prp->terminate = 0; - hostname = agmt_get_hostname(prp->agmt); - portnum = agmt_get_port(prp->agmt); - - /* establish_protocol_callbacks(prp); */ - done = 0; - do { - int rc; - - /* Take action, based on current state, and compute new state. */ - switch (current_state) - { - case STATE_START: - - dev_debug("windows_inc_run(STATE_START)"); - if (PROTOCOL_IS_SHUTDOWN(prp)) - { - done = 1; - break; - } + int current_state = STATE_START; + int next_state = STATE_START; + windows_inc_private *prp_priv = (windows_inc_private *)prp->private; + int done = 0; + int e1 = 0; + RUV *ruv = NULL; + Replica *replica = NULL; + int wait_change_timer_set = 0; + time_t last_start_time = 0; + PRUint32 num_changes_sent = 0; + char *hostname = NULL; + int portnum = 0; + /* use a different backoff timer strategy for ACQUIRE_REPLICA_BUSY errors */ + PRBool use_busy_backoff_timer = PR_FALSE; + long pausetime = 0; + long busywaittime = 0; + // Some operations should only be done the first time STATE_START is true. + static PRBool is_first_start = PR_TRUE; + + PRBool run_dirsync = PR_FALSE; + + LDAPDebug( LDAP_DEBUG_TRACE, "=> windows_inc_run\n", 0, 0, 0 ); - /* - * Our initial state. See if we're in a schedule window. If - * so, then we're ready to acquire the replica and see if it - * needs any updates from us. If not, then wait for the window - * to open. - */ - if (agmt_schedule_in_window_now(prp->agmt)) - { - next_state = STATE_READY_TO_ACQUIRE; - } - else - { - next_state = STATE_WAIT_WINDOW_OPEN; - } + prp->stopped = 0; + prp->terminate = 0; + hostname = agmt_get_hostname(prp->agmt); + portnum = agmt_get_port(prp->agmt); - /* we can get here from other states because some events happened and were - not cleared. For instance when we wake up in STATE_WAIT_CHANGES state. - Since this is a fresh start state, we should clear all events */ - /* ONREPL - this does not feel right - we should take another look - at this state machine */ - reset_events (prp); - - /* Cancel any linger timer that might be in effect... */ - windows_conn_cancel_linger(prp->conn); - /* ... and disconnect, if currently connected */ - windows_conn_disconnect(prp->conn); - /* get the new pause time, if any */ - pausetime = agmt_get_pausetime(prp->agmt); - /* get the new busy wait time, if any */ - busywaittime = agmt_get_busywaittime(prp->agmt); - if (pausetime || busywaittime) - { - /* helper function to make sure they are set correctly */ - w_set_pause_and_busy_time(&pausetime, &busywaittime); - } - break; - case STATE_WAIT_WINDOW_OPEN: - /* - * We're waiting for a schedule window to open. If one did, - * or we receive a "replicate now" event, then start a protocol - * session immediately. If the replication schedule changed, go - * back to start. Otherwise, go back to sleep. - */ - dev_debug("windows_inc_run(STATE_WAIT_WINDOW_OPEN)"); - if (PROTOCOL_IS_SHUTDOWN(prp)) - { - done = 1; - break; - } - else if (event_occurred(prp, EVENT_WINDOW_OPENED)) - { - next_state = STATE_READY_TO_ACQUIRE; - } - else if (event_occurred(prp, EVENT_REPLICATE_NOW)) - { - next_state = STATE_READY_TO_ACQUIRE; - } - else if (event_occurred(prp, EVENT_AGMT_CHANGED)) - { - next_state = STATE_START; - windows_conn_set_agmt_changed(prp->conn); - } - else if (event_occurred(prp, EVENT_TRIGGERING_CRITERIA_MET)) /* change available */ - { - /* just ignore it and go to sleep */ - protocol_sleep(prp, PR_INTERVAL_NO_TIMEOUT); - } - else if (e1 = event_occurred(prp, EVENT_WINDOW_CLOSED) || - event_occurred(prp, EVENT_BACKOFF_EXPIRED)) - { - /* this events - should not occur - log a warning and go to sleep */ - slapi_log_error(SLAPI_LOG_FATAL, windows_repl_plugin_name, - "%s: Incremental protocol: " - "event %s should not occur in state %s; going to sleep\n", - agmt_get_long_name(prp->agmt), - e1 ? event2name(EVENT_WINDOW_CLOSED) : event2name(EVENT_BACKOFF_EXPIRED), - state2name(current_state)); - protocol_sleep(prp, PR_INTERVAL_NO_TIMEOUT); - } - else - { - /* wait until window opens or an event occurs */ - slapi_log_error(SLAPI_LOG_REPL, windows_repl_plugin_name, - "%s: Incremental protocol: " - "waiting for update window to open\n", agmt_get_long_name(prp->agmt)); - protocol_sleep(prp, PR_INTERVAL_NO_TIMEOUT); - } - break; - case STATE_WAIT_CHANGES: - /* - * We're in a replication window, but we're waiting for more - * changes to accumulate before we actually hook up and send - * them. - */ - dev_debug("windows_inc_run(STATE_WAIT_CHANGES)"); - if (PROTOCOL_IS_SHUTDOWN(prp)) - { - dev_debug("windows_inc_run(STATE_WAIT_CHANGES): PROTOCOL_IS_SHUTING_DOWN -> end windows_inc_run\n"); - done = 1; - break; - } - else if (event_occurred(prp, EVENT_REPLICATE_NOW)) - { - dev_debug("windows_inc_run(STATE_WAIT_CHANGES): EVENT_REPLICATE_NOW received -> STATE_READY_TO_ACQUIRE\n"); - next_state = STATE_READY_TO_ACQUIRE; - wait_change_timer_set = 0; - } - else if (event_occurred(prp, EVENT_AGMT_CHANGED)) - { - dev_debug("windows_inc_run(STATE_WAIT_CHANGES): EVENT_AGMT_CHANGED received -> STATE_START\n"); - next_state = STATE_START; - windows_conn_set_agmt_changed(prp->conn); - wait_change_timer_set = 0; - } - else if (event_occurred(prp, EVENT_WINDOW_CLOSED)) - { - dev_debug("windows_inc_run(STATE_WAIT_CHANGES): EVENT_WINDOW_CLOSED received -> STATE_WAIT_WINDOW_OPEN\n"); - next_state = STATE_WAIT_WINDOW_OPEN; - wait_change_timer_set = 0; - } - else if (event_occurred(prp, EVENT_TRIGGERING_CRITERIA_MET)) - { - dev_debug("windows_inc_run(STATE_WAIT_CHANGES): EVENT_TRIGGERING_CRITERIA_MET received -> STATE_READY_TO_ACQUIRE\n"); - next_state = STATE_READY_TO_ACQUIRE; - wait_change_timer_set = 0; - } - else if (e1 = event_occurred(prp, EVENT_WINDOW_OPENED) || - event_occurred(prp, EVENT_BACKOFF_EXPIRED)) - { - /* this events - should not occur - log a warning and clear the event */ - slapi_log_error(SLAPI_LOG_FATAL, windows_repl_plugin_name, "%s: Incremental protocol: " - "event %s should not occur in state %s\n", - agmt_get_long_name(prp->agmt), - e1 ? event2name(EVENT_WINDOW_OPENED) : event2name(EVENT_BACKOFF_EXPIRED), - state2name(current_state)); - wait_change_timer_set = 0; - } - else - { - if (wait_change_timer_set) - { - /* We are here because our timer expired */ - dev_debug("windows_inc_run(STATE_WAIT_CHANGES): wait_change_timer_set expired -> STATE_START\n"); - next_state = STATE_START; - wait_change_timer_set = 0; - } - else + windows_private_load_dirsync_cookie(prp->agmt); + + do { + int rc = 0; + + /* Take action, based on current state, and compute new state. */ + switch (current_state) { - /* We are here because the last replication session - * finished or aborted. - */ - wait_change_timer_set = 1; - protocol_sleep(prp, MAX_WAIT_BETWEEN_SESSIONS); - } - } - break; - case STATE_READY_TO_ACQUIRE: - - dev_debug("windows_inc_run(STATE_READY_TO_ACQUIRE)"); - if (PROTOCOL_IS_SHUTDOWN(prp)) - { - done = 1; - break; - } + case STATE_START: - /* ONREPL - at this state we unconditionally acquire the replica - ignoring all events. Not sure if this is good */ - object_acquire(prp->replica_object); - replica = object_get_data(prp->replica_object); - - rc = windows_acquire_replica(prp, &ruv); + dev_debug("windows_inc_run(STATE_START)"); + if (PROTOCOL_IS_SHUTDOWN(prp)) + { + done = 1; + break; + } - slapi_log_error(SLAPI_LOG_REPL, windows_repl_plugin_name, - "windows_acquire_replica returned %s (%d)\n", - state2name(rc), - rc); + /* + * Our initial state. See if we're in a schedule window. If + * so, then we're ready to acquire the replica and see if it + * needs any updates from us. If not, then wait for the window + * to open. + */ + if (agmt_schedule_in_window_now(prp->agmt)) + { + next_state = STATE_READY_TO_ACQUIRE; + } else + { + next_state = STATE_WAIT_WINDOW_OPEN; + } - use_busy_backoff_timer = PR_FALSE; /* default */ - if (rc == ACQUIRE_SUCCESS) - { - next_state = STATE_SENDING_UPDATES; - } - else if (rc == ACQUIRE_REPLICA_BUSY) - { - next_state = STATE_BACKOFF_START; - use_busy_backoff_timer = PR_TRUE; - } - else if (rc == ACQUIRE_CONSUMER_WAS_UPTODATE) - { - next_state = STATE_WAIT_CHANGES; - } - else if (rc == ACQUIRE_TRANSIENT_ERROR) - { - next_state = STATE_BACKOFF_START; - } - else if (rc == ACQUIRE_FATAL_ERROR) - { - next_state = STATE_STOP_FATAL_ERROR; - } - if (rc != ACQUIRE_SUCCESS) - { - int optype, ldaprc; - windows_conn_get_error(prp->conn, &optype, &ldaprc); - agmt_set_last_update_status(prp->agmt, ldaprc, - prp->last_acquire_response_code, NULL); - } - - object_release(prp->replica_object); replica = NULL; - break; - case STATE_BACKOFF_START: - dev_debug("windows_inc_run(STATE_BACKOFF_START)"); - if (PROTOCOL_IS_SHUTDOWN(prp)) - { - done = 1; - break; - } - if (event_occurred(prp, EVENT_REPLICATE_NOW)) - { - next_state = STATE_READY_TO_ACQUIRE; - } - else if (event_occurred(prp, EVENT_AGMT_CHANGED)) - { - next_state = STATE_START; - windows_conn_set_agmt_changed(prp->conn); - } - else if (event_occurred (prp, EVENT_WINDOW_CLOSED)) - { - next_state = STATE_WAIT_WINDOW_OPEN; - } - else if (event_occurred (prp, EVENT_TRIGGERING_CRITERIA_MET)) - { - /* consume and ignore */ - } - else if (e1 = event_occurred (prp, EVENT_WINDOW_OPENED) || - event_occurred (prp, EVENT_BACKOFF_EXPIRED)) - { - /* This should never happen */ - /* this events - should not occur - log a warning and go to sleep */ - slapi_log_error(SLAPI_LOG_FATAL, windows_repl_plugin_name, - "%s: Incremental protocol: event %s should not occur in state %s\n", - agmt_get_long_name(prp->agmt), - e1 ? event2name(EVENT_WINDOW_OPENED) : event2name(EVENT_BACKOFF_EXPIRED), - state2name(current_state)); - } - else - { - /* Set up the backoff timer to wake us up at the appropriate time */ - if (use_busy_backoff_timer) - { - /* we received a busy signal from the consumer, wait for a while */ - if (!busywaittime) - { - busywaittime = PROTOCOL_BUSY_BACKOFF_MINIMUM; - } - prp_priv->backoff = backoff_new(BACKOFF_FIXED, busywaittime, - busywaittime); - } - else - { - prp_priv->backoff = backoff_new(BACKOFF_EXPONENTIAL, PROTOCOL_BACKOFF_MINIMUM, - PROTOCOL_BACKOFF_MAXIMUM); - } - next_state = STATE_BACKOFF; - backoff_reset(prp_priv->backoff, windows_inc_backoff_expired, (void *)prp); - protocol_sleep(prp, PR_INTERVAL_NO_TIMEOUT); - use_busy_backoff_timer = PR_FALSE; - } - break; - case STATE_BACKOFF: - /* - * We're in a backoff state. - */ - dev_debug("windows_inc_run(STATE_BACKOFF)"); - if (PROTOCOL_IS_SHUTDOWN(prp)) - { - if (prp_priv->backoff) - backoff_delete(&prp_priv->backoff); - done = 1; - break; - } - else if (event_occurred(prp, EVENT_REPLICATE_NOW)) - { - next_state = STATE_READY_TO_ACQUIRE; - } - else if (event_occurred(prp, EVENT_AGMT_CHANGED)) - { - next_state = STATE_START; + /* we can get here from other states because some events happened and were + not cleared. For instance when we wake up in STATE_WAIT_CHANGES state. + Since this is a fresh start state, we should clear all events */ + /* ONREPL - this does not feel right - we should take another look + at this state machine */ + reset_events (prp); + + /* Cancel any linger timer that might be in effect... */ + windows_conn_cancel_linger(prp->conn); + /* ... and disconnect, if currently connected */ + windows_conn_disconnect(prp->conn); + /* get the new pause time, if any */ + pausetime = agmt_get_pausetime(prp->agmt); + /* get the new busy wait time, if any */ + busywaittime = agmt_get_busywaittime(prp->agmt); + if (pausetime || busywaittime) + { + /* helper function to make sure they are set correctly */ + w_set_pause_and_busy_time(&pausetime, &busywaittime); + } - windows_conn_set_agmt_changed(prp->conn); - /* Destroy the backoff timer, since we won't need it anymore */ - if (prp_priv->backoff) - backoff_delete(&prp_priv->backoff); - } - else if (event_occurred(prp, EVENT_WINDOW_CLOSED)) - { - next_state = STATE_WAIT_WINDOW_OPEN; - /* Destroy the backoff timer, since we won't need it anymore */ - if (prp_priv->backoff) - backoff_delete(&prp_priv->backoff); - } - else if (event_occurred(prp, EVENT_BACKOFF_EXPIRED)) - { - rc = windows_acquire_replica(prp, &ruv); - use_busy_backoff_timer = PR_FALSE; - if (rc == ACQUIRE_SUCCESS) - { - next_state = STATE_SENDING_UPDATES; - } - else if (rc == ACQUIRE_REPLICA_BUSY) - { - next_state = STATE_BACKOFF; - use_busy_backoff_timer = PR_TRUE; - } - else if (rc == ACQUIRE_CONSUMER_WAS_UPTODATE) - { - next_state = STATE_WAIT_CHANGES; - } - else if (rc == ACQUIRE_TRANSIENT_ERROR) - { - next_state = STATE_BACKOFF; - } - else if (rc == ACQUIRE_FATAL_ERROR) - { - next_state = STATE_STOP_FATAL_ERROR; - } - if (rc != ACQUIRE_SUCCESS) - { - int optype, ldaprc; - windows_conn_get_error(prp->conn, &optype, &ldaprc); - agmt_set_last_update_status(prp->agmt, ldaprc, - prp->last_acquire_response_code, NULL); - } + + if (is_first_start) { + /* + * The function, the arguments, the time (hence) when it is first to be called, + * and the repeat interval. + */ + /* DBDB: we should probably make this polling interval configurable */ + dirsync = slapi_eq_repeat(periodic_dirsync, (void*) prp, (time_t)0 , PERIODIC_DIRSYNC_INTERVAL); + is_first_start = PR_FALSE; + } + break; + + case STATE_WAIT_WINDOW_OPEN: /* - * We either need to step the backoff timer, or - * destroy it if we don't need it anymore. + * We're waiting for a schedule window to open. If one did, + * or we receive a "replicate now" event, then start a protocol + * session immediately. If the replication schedule changed, go + * back to start. Otherwise, go back to sleep. */ - if (STATE_BACKOFF == next_state) - { - time_t next_fire_time; - time_t now; - /* Step the backoff timer */ - time(&now); - next_fire_time = backoff_step(prp_priv->backoff); - /* And go back to sleep */ - slapi_log_error(SLAPI_LOG_REPL, windows_repl_plugin_name, - "%s: Replication session backing off for %d seconds\n", - agmt_get_long_name(prp->agmt), - next_fire_time - now); + dev_debug("windows_inc_run(STATE_WAIT_WINDOW_OPEN)"); + if (PROTOCOL_IS_SHUTDOWN(prp)) + { + done = 1; + break; + } + else if (event_occurred(prp, EVENT_WINDOW_OPENED)) + { + next_state = STATE_READY_TO_ACQUIRE; + } + else if (event_occurred(prp, EVENT_REPLICATE_NOW)) + { + next_state = STATE_READY_TO_ACQUIRE; + } + else if (event_occurred(prp, EVENT_AGMT_CHANGED)) + { + next_state = STATE_START; + run_dirsync = PR_TRUE; + windows_conn_set_agmt_changed(prp->conn); + } + else if (event_occurred(prp, EVENT_TRIGGERING_CRITERIA_MET)) /* change available */ + { + /* just ignore it and go to sleep */ + protocol_sleep(prp, PR_INTERVAL_NO_TIMEOUT); + } + else if (e1 = event_occurred(prp, EVENT_WINDOW_CLOSED) || + event_occurred(prp, EVENT_BACKOFF_EXPIRED)) + { + /* this events - should not occur - log a warning and go to sleep */ + slapi_log_error(SLAPI_LOG_FATAL, windows_repl_plugin_name, + "%s: Incremental protocol: " + "event %s should not occur in state %s; going to sleep\n", + agmt_get_long_name(prp->agmt), + e1 ? event2name(EVENT_WINDOW_CLOSED) : event2name(EVENT_BACKOFF_EXPIRED), + state2name(current_state)); + protocol_sleep(prp, PR_INTERVAL_NO_TIMEOUT); + } + else + { + /* wait until window opens or an event occurs */ + slapi_log_error(SLAPI_LOG_REPL, windows_repl_plugin_name, + "%s: Incremental protocol: " + "waiting for update window to open\n", agmt_get_long_name(prp->agmt)); + protocol_sleep(prp, PR_INTERVAL_NO_TIMEOUT); + } + break; - protocol_sleep(prp, PR_INTERVAL_NO_TIMEOUT); - } - else - { - /* Destroy the backoff timer, since we won't need it anymore */ - backoff_delete(&prp_priv->backoff); - } - use_busy_backoff_timer = PR_FALSE; - } - else if (event_occurred(prp, EVENT_TRIGGERING_CRITERIA_MET)) - { - /* changes are available */ - if ( prp_priv->backoff == NULL || backoff_expired (prp_priv->backoff, 60) ) - { - /* - * Have seen cases that the agmt stuck here forever since - * somehow the backoff timer was not in event queue anymore. - * If the backoff timer has expired more than 60 seconds, - * destroy it. - */ - if ( prp_priv->backoff ) - backoff_delete(&prp_priv->backoff); - next_state = STATE_READY_TO_ACQUIRE; - } - else - { - /* ignore changes and go to sleep */ - protocol_sleep(prp, PR_INTERVAL_NO_TIMEOUT); - } - } - else if (event_occurred(prp, EVENT_WINDOW_OPENED)) - { - /* this should never happen - log an error and go to sleep */ - slapi_log_error(SLAPI_LOG_FATAL, windows_repl_plugin_name, "%s: Incremental protocol: " - "event %s should not occur in state %s; going to sleep\n", - agmt_get_long_name(prp->agmt), - event2name(EVENT_WINDOW_OPENED), state2name(current_state)); - protocol_sleep(prp, PR_INTERVAL_NO_TIMEOUT); - } - break; + case STATE_WAIT_CHANGES: + /* + * We're in a replication window, but we're waiting for more + * changes to accumulate before we actually hook up and send + * them. + */ + dev_debug("windows_inc_run(STATE_WAIT_CHANGES)"); + if (PROTOCOL_IS_SHUTDOWN(prp)) + { + dev_debug("windows_inc_run(STATE_WAIT_CHANGES): PROTOCOL_IS_SHUTING_DOWN -> end windows_inc_run\n"); + done = 1; + break; + } + else if (event_occurred(prp, EVENT_REPLICATE_NOW)) + { + dev_debug("windows_inc_run(STATE_WAIT_CHANGES): EVENT_REPLICATE_NOW received -> STATE_READY_TO_ACQUIRE\n"); + next_state = STATE_READY_TO_ACQUIRE; + wait_change_timer_set = 0; + /* We also want to run dirsync on a 'replicate now' event */ + run_dirsync = PR_TRUE; + } + else if ( event_occurred(prp, EVENT_RUN_DIRSYNC)) + { + dev_debug("windows_inc_run(STATE_WAIT_CHANGES): EVENT_REPLICATE_NOW received -> STATE_READY_TO_ACQUIRE\n"); + next_state = STATE_READY_TO_ACQUIRE; + wait_change_timer_set = 0; + run_dirsync = PR_TRUE; + + } + else if (event_occurred(prp, EVENT_AGMT_CHANGED)) + { + dev_debug("windows_inc_run(STATE_WAIT_CHANGES): EVENT_AGMT_CHANGED received -> STATE_START\n"); + next_state = STATE_START; + windows_conn_set_agmt_changed(prp->conn); + wait_change_timer_set = 0; + /* We also want to run dirsync on a 'agreement changed' event, because that's how we receive 'send updates now' */ + run_dirsync = PR_TRUE; + } + else if (event_occurred(prp, EVENT_WINDOW_CLOSED)) + { + dev_debug("windows_inc_run(STATE_WAIT_CHANGES): EVENT_WINDOW_CLOSED received -> STATE_WAIT_WINDOW_OPEN\n"); + next_state = STATE_WAIT_WINDOW_OPEN; + wait_change_timer_set = 0; + } + else if (event_occurred(prp, EVENT_TRIGGERING_CRITERIA_MET) ) + { + dev_debug("windows_inc_run(STATE_WAIT_CHANGES): EVENT_TRIGGERING_CRITERIA_MET received -> STATE_READY_TO_ACQUIRE\n"); + next_state = STATE_READY_TO_ACQUIRE; + wait_change_timer_set = 0; + } + else if (e1 = event_occurred(prp, EVENT_WINDOW_OPENED) || + event_occurred(prp, EVENT_BACKOFF_EXPIRED)) + { + /* this events - should not occur - log a warning and clear the event */ + slapi_log_error(SLAPI_LOG_FATAL, windows_repl_plugin_name, "%s: Incremental protocol: " + "event %s should not occur in state %s\n", + agmt_get_long_name(prp->agmt), + e1 ? event2name(EVENT_WINDOW_OPENED) : event2name(EVENT_BACKOFF_EXPIRED), + state2name(current_state)); + wait_change_timer_set = 0; + } + else + { + if (wait_change_timer_set) + { + /* We are here because our timer expired */ + dev_debug("windows_inc_run(STATE_WAIT_CHANGES): wait_change_timer_set expired -> STATE_START\n"); + next_state = STATE_START; + run_dirsync = PR_TRUE; + wait_change_timer_set = 0; + } + else + { + /* We are here because the last replication session + * finished or aborted. + */ + wait_change_timer_set = 1; + protocol_sleep(prp, MAX_WAIT_BETWEEN_SESSIONS); + } + } + break; + + case STATE_READY_TO_ACQUIRE: + + dev_debug("windows_inc_run(STATE_READY_TO_ACQUIRE)"); + if (PROTOCOL_IS_SHUTDOWN(prp)) + { + done = 1; + break; + } + + /* ONREPL - at this state we unconditionally acquire the replica + ignoring all events. Not sure if this is good */ + object_acquire(prp->replica_object); + replica = object_get_data(prp->replica_object); + + rc = windows_acquire_replica(prp, &ruv , 1 /* yes, check the consumer RUV for incremental */); + + slapi_log_error(SLAPI_LOG_REPL, windows_repl_plugin_name, + "windows_acquire_replica returned %s (%d)\n", + acquire2name(rc), + rc); + + use_busy_backoff_timer = PR_FALSE; /* default */ + if (rc == ACQUIRE_SUCCESS) + { + next_state = STATE_SENDING_UPDATES; + } + else if (rc == ACQUIRE_REPLICA_BUSY) + { + next_state = STATE_BACKOFF_START; + use_busy_backoff_timer = PR_TRUE; + } + else if (rc == ACQUIRE_CONSUMER_WAS_UPTODATE) + { + next_state = STATE_WAIT_CHANGES; + + } + else if (rc == ACQUIRE_TRANSIENT_ERROR) + { + next_state = STATE_BACKOFF_START; + } + else if (rc == ACQUIRE_FATAL_ERROR) + { + next_state = STATE_STOP_FATAL_ERROR; + } + if (rc != ACQUIRE_SUCCESS) + { + int optype, ldaprc; + windows_conn_get_error(prp->conn, &optype, &ldaprc); + agmt_set_last_update_status(prp->agmt, ldaprc, + prp->last_acquire_response_code, NULL); + } + + object_release(prp->replica_object); replica = NULL; + break; + + case STATE_BACKOFF_START: + dev_debug("windows_inc_run(STATE_BACKOFF_START)"); + if (PROTOCOL_IS_SHUTDOWN(prp)) + { + done = 1; + break; + } + if (event_occurred(prp, EVENT_REPLICATE_NOW) || event_occurred(prp, EVENT_RUN_DIRSYNC)) + { + next_state = STATE_READY_TO_ACQUIRE; + } + else if (event_occurred(prp, EVENT_AGMT_CHANGED)) + { + next_state = STATE_START; + run_dirsync = PR_TRUE; /* Also trigger dirsync for the 'send updates now' feature */ + windows_conn_set_agmt_changed(prp->conn); + } + else if (event_occurred (prp, EVENT_WINDOW_CLOSED)) + { + next_state = STATE_WAIT_WINDOW_OPEN; + } + else if (event_occurred (prp, EVENT_TRIGGERING_CRITERIA_MET)) + { + /* consume and ignore */ + } + else if (e1 = event_occurred (prp, EVENT_WINDOW_OPENED) || + event_occurred (prp, EVENT_BACKOFF_EXPIRED)) + { + /* This should never happen */ + /* this events - should not occur - log a warning and go to sleep */ + slapi_log_error(SLAPI_LOG_FATAL, windows_repl_plugin_name, + "%s: Incremental protocol: event %s should not occur in state %s\n", + agmt_get_long_name(prp->agmt), + e1 ? event2name(EVENT_WINDOW_OPENED) : event2name(EVENT_BACKOFF_EXPIRED), + state2name(current_state)); + } + else + { + /* Set up the backoff timer to wake us up at the appropriate time */ + if (use_busy_backoff_timer) + { + /* we received a busy signal from the consumer, wait for a while */ + if (!busywaittime) + { + busywaittime = PROTOCOL_BUSY_BACKOFF_MINIMUM; + } + prp_priv->backoff = backoff_new(BACKOFF_FIXED, busywaittime, + busywaittime); + } + else + { + prp_priv->backoff = backoff_new(BACKOFF_EXPONENTIAL, PROTOCOL_BACKOFF_MINIMUM, + PROTOCOL_BACKOFF_MAXIMUM); + } + next_state = STATE_BACKOFF; + backoff_reset(prp_priv->backoff, windows_inc_backoff_expired, (void *)prp); + protocol_sleep(prp, PR_INTERVAL_NO_TIMEOUT); + use_busy_backoff_timer = PR_FALSE; + } + break; + + case STATE_BACKOFF: + /* + * We're in a backoff state. + */ + dev_debug("windows_inc_run(STATE_BACKOFF)"); + if (PROTOCOL_IS_SHUTDOWN(prp)) + { + if (prp_priv->backoff) + backoff_delete(&prp_priv->backoff); + done = 1; + break; + } + else if (event_occurred(prp, EVENT_REPLICATE_NOW) || event_occurred(prp, EVENT_RUN_DIRSYNC)) + { + next_state = STATE_READY_TO_ACQUIRE; + } + else if (event_occurred(prp, EVENT_AGMT_CHANGED)) + { + next_state = STATE_START; + run_dirsync = PR_TRUE; + + windows_conn_set_agmt_changed(prp->conn); + /* Destroy the backoff timer, since we won't need it anymore */ + if (prp_priv->backoff) + backoff_delete(&prp_priv->backoff); + } + else if (event_occurred(prp, EVENT_WINDOW_CLOSED)) + { + next_state = STATE_WAIT_WINDOW_OPEN; + /* Destroy the backoff timer, since we won't need it anymore */ + if (prp_priv->backoff) + backoff_delete(&prp_priv->backoff); + } + else if (event_occurred(prp, EVENT_BACKOFF_EXPIRED)) + { + rc = windows_acquire_replica(prp, &ruv, 1 /* check RUV for incremental */); + use_busy_backoff_timer = PR_FALSE; + if (rc == ACQUIRE_SUCCESS) + { + next_state = STATE_SENDING_UPDATES; + } + else if (rc == ACQUIRE_REPLICA_BUSY) + { + next_state = STATE_BACKOFF; + use_busy_backoff_timer = PR_TRUE; + } + else if (rc == ACQUIRE_CONSUMER_WAS_UPTODATE) + { + next_state = STATE_WAIT_CHANGES; + } + else if (rc == ACQUIRE_TRANSIENT_ERROR) + { + next_state = STATE_BACKOFF; + } + else if (rc == ACQUIRE_FATAL_ERROR) + { + next_state = STATE_STOP_FATAL_ERROR; + } + if (rc != ACQUIRE_SUCCESS) + { + int optype, ldaprc; + windows_conn_get_error(prp->conn, &optype, &ldaprc); + agmt_set_last_update_status(prp->agmt, ldaprc, + prp->last_acquire_response_code, NULL); + } + /* + * We either need to step the backoff timer, or + * destroy it if we don't need it anymore. + */ + if (STATE_BACKOFF == next_state) + { + time_t next_fire_time; + time_t now; + /* Step the backoff timer */ + time(&now); + next_fire_time = backoff_step(prp_priv->backoff); + /* And go back to sleep */ + slapi_log_error(SLAPI_LOG_REPL, windows_repl_plugin_name, + "%s: Replication session backing off for %d seconds\n", + agmt_get_long_name(prp->agmt), + next_fire_time - now); + + protocol_sleep(prp, PR_INTERVAL_NO_TIMEOUT); + } + else + { + /* Destroy the backoff timer, since we won't need it anymore */ + backoff_delete(&prp_priv->backoff); + } + use_busy_backoff_timer = PR_FALSE; + } + else if (event_occurred(prp, EVENT_TRIGGERING_CRITERIA_MET)) + { + /* changes are available */ + if ( prp_priv->backoff == NULL || backoff_expired (prp_priv->backoff, 60) ) + { + /* + * Have seen cases that the agmt stuck here forever since + * somehow the backoff timer was not in event queue anymore. + * If the backoff timer has expired more than 60 seconds, + * destroy it. + */ + if ( prp_priv->backoff ) + backoff_delete(&prp_priv->backoff); + next_state = STATE_READY_TO_ACQUIRE; + } + else + { + /* ignore changes and go to sleep */ + protocol_sleep(prp, PR_INTERVAL_NO_TIMEOUT); + } + } + else if (event_occurred(prp, EVENT_WINDOW_OPENED)) + { + /* this should never happen - log an error and go to sleep */ + slapi_log_error(SLAPI_LOG_FATAL, windows_repl_plugin_name, "%s: Incremental protocol: " + "event %s should not occur in state %s; going to sleep\n", + agmt_get_long_name(prp->agmt), + event2name(EVENT_WINDOW_OPENED), state2name(current_state)); + protocol_sleep(prp, PR_INTERVAL_NO_TIMEOUT); + } + break; case STATE_SENDING_UPDATES: dev_debug("windows_inc_run(STATE_SENDING_UPDATES)"); agmt_set_update_in_progress(prp->agmt, PR_TRUE); @@ -724,29 +720,6 @@ windows_inc_run(Private_Repl_Protocol *prp) agmt_set_last_update_status(prp->agmt, 0, 0, "Incremental update started"); - /* ONREPL - in this state we send changes no matter what other events occur. - This is because we can get because of the REPLICATE_NOW event which - has high priority. Is this ok? */ - /* First, push new schema to the consumer if needed */ - /* ONREPL - should we push schema after we examine the RUV? */ - /* - * GGOOREPL - I don't see why we should wait until we've - * examined the RUV. The schema entry has its own CSN that is - * used to decide if the remote schema needs to be updated. - */ - cons_schema_csn = agmt_get_consumer_schema_csn ( prp->agmt ); - // rc = windows_conn_push_schema(prp->conn, &cons_schema_csn); XXX - if ( cons_schema_csn != agmt_get_consumer_schema_csn ( prp->agmt )) - { - agmt_set_consumer_schema_csn ( prp->agmt, cons_schema_csn ); - } - if (CONN_SCHEMA_UPDATED != rc && CONN_SCHEMA_NO_UPDATE_NEEDED != rc) - { - slapi_log_error(SLAPI_LOG_FATAL, windows_repl_plugin_name, - "%s: Warning: unable to replicate schema: rc=%d\n", - agmt_get_long_name(prp->agmt), rc); - /* But keep going */ - } dev_debug("windows_inc_run(STATE_SENDING_UPDATES) -> windows_examine_update_vector"); rc = windows_examine_update_vector(prp, ruv); /* @@ -842,10 +815,14 @@ windows_inc_run(Private_Repl_Protocol *prp) last_start_time = 0UL; break; } -/* if (NULL != ruv) - { - ruv_destroy(&ruv); ruv = NULL; - } XXX elliot commented this out */ + + if ( run_dirsync ) + { + windows_dirsync_inc_run(prp); + windows_private_save_dirsync_cookie(prp->agmt); + run_dirsync = PR_FALSE; + } + agmt_set_last_update_end(prp->agmt, current_time()); agmt_set_update_in_progress(prp->agmt, PR_FALSE); /* If timed out, close the connection after released the replica */ @@ -882,7 +859,6 @@ windows_inc_run(Private_Repl_Protocol *prp) /* DS_Sleep ( PR_SecondsToInterval(1) ); */ } } - windows_dirsync_inc_run(prp); break; case STATE_STOP_FATAL_ERROR: @@ -960,6 +936,7 @@ windows_inc_run(Private_Repl_Protocol *prp) conn_cancel_linger(prp->conn); /* ... and disconnect, if currently connected */ conn_disconnect(prp->conn); + LDAPDebug( LDAP_DEBUG_TRACE, "<= windows_inc_run\n", 0, 0, 0 ); } @@ -970,6 +947,7 @@ windows_inc_run(Private_Repl_Protocol *prp) static void protocol_sleep(Private_Repl_Protocol *prp, PRIntervalTime duration) { + LDAPDebug( LDAP_DEBUG_TRACE, "=> protocol_sleep\n", 0, 0, 0 ); PR_ASSERT(NULL != prp); PR_Lock(prp->lock); /* we should not go to sleep if there are events available to be processed. @@ -983,6 +961,7 @@ protocol_sleep(Private_Repl_Protocol *prp, PRIntervalTime duration) agmt_get_long_name(prp->agmt), prp->eventbits); } PR_Unlock(prp->lock); + LDAPDebug( LDAP_DEBUG_TRACE, "<= protocol_sleep\n", 0, 0, 0 ); } @@ -995,11 +974,13 @@ protocol_sleep(Private_Repl_Protocol *prp, PRIntervalTime duration) static void event_notify(Private_Repl_Protocol *prp, PRUint32 event) { + LDAPDebug( LDAP_DEBUG_TRACE, "=> event_notify\n", 0, 0, 0 ); PR_ASSERT(NULL != prp); PR_Lock(prp->lock); prp->eventbits |= event; PR_NotifyCondVar(prp->cvar); PR_Unlock(prp->lock); + LDAPDebug( LDAP_DEBUG_TRACE, "<= event_notify\n", 0, 0, 0 ); } @@ -1011,187 +992,36 @@ static PRUint32 event_occurred(Private_Repl_Protocol *prp, PRUint32 event) { PRUint32 return_value; + + LDAPDebug( LDAP_DEBUG_TRACE, "=> event_occurred\n", 0, 0, 0 ); + PR_ASSERT(NULL != prp); PR_Lock(prp->lock); return_value = (prp->eventbits & event); prp->eventbits &= ~event; /* Clear event */ PR_Unlock(prp->lock); + LDAPDebug( LDAP_DEBUG_TRACE, "<= event_occurred\n", 0, 0, 0 ); return return_value; } static void reset_events (Private_Repl_Protocol *prp) { + LDAPDebug( LDAP_DEBUG_TRACE, "=> reset_events\n", 0, 0, 0 ); PR_ASSERT(NULL != prp); PR_Lock(prp->lock); prp->eventbits = 0; PR_Unlock(prp->lock); + LDAPDebug( LDAP_DEBUG_TRACE, "<= reset_events\n", 0, 0, 0 ); } -/* - * Replay the actual update to the consumer. Construct an appropriate LDAP - * operation, attach the baggage LDAPv3 control that contains the CSN, etc., - * and send the operation to the consumer. - */ -ConnResult -w_replay_update(Private_Repl_Protocol *prp, slapi_operation_parameters *op) -{ - ConnResult return_value; - LDAPControl *update_control = NULL; - char csn_str[CSN_STRSIZE]; /* For logging only */ - char *old_dn; - char *password = NULL; - - old_dn = slapi_ch_strdup(op->target_address.dn); - - csn_as_string(op->csn, PR_FALSE, csn_str); - - if ( windows_private_get_windows_replarea(prp->agmt) && windows_private_get_directory_replarea(prp->agmt) ) - { - Slapi_DN *sdn; - - sdn = slapi_sdn_new_dn_passin( op->target_address.dn ); - sdn = map_dn_user(sdn, REPLICA_TYPE_WINDOWS, windows_private_get_windows_replarea( prp->agmt) ); - - op->target_address.dn = slapi_ch_strdup(slapi_sdn_get_ndn(sdn)); - - } - - /* Construct the replication info control that accompanies the operation */ - if (SLAPI_OPERATION_ADD == op->operation_type) - { - - map_entry_user(&(op->p.p_add.target_entry), REPLICA_TYPE_WINDOWS, &password); - - - } - else if (SLAPI_OPERATION_MODRDN == op->operation_type) - { - /* op->p.p_modrdn.modrdn_newrdn needs to change from - uid=fbar to cn=fbar */ - - - } - else if (SLAPI_OPERATION_MODIFY == op->operation_type) - { - alter_mods(& op->p.p_modify.modify_mods, &password) ; - /* if the entry already exists, modify_mods will be null. - attempting to modifiy null will return LDAP_PARAM_ERROR. - The password still might be set. bail */ - if ( op->p.p_modify.modify_mods == NULL) - { - return_value = CONN_OPERATION_SUCCESS; - goto skipchange; - } - - } - - slapi_log_error(SLAPI_LOG_REPL, windows_repl_plugin_name, - "%s: replay_update: Sending %s operation (dn=\"%s\" csn=%s)\n", - agmt_get_long_name(prp->agmt), - op2string(op->operation_type), op->target_address.dn, csn_str); - /* What type of operation is it? */ - switch (op->operation_type) - { - case SLAPI_OPERATION_ADD: - { - LDAPMod **entryattrs; - /* Convert entry to mods */ - (void)slapi_entry2mods (op->p.p_add.target_entry, - NULL /* &entrydn : We don't need it */, - &entryattrs); - if (NULL == entryattrs) - { - slapi_log_error(SLAPI_LOG_FATAL, windows_repl_plugin_name, - "%s: replay_update: Cannot convert entry to LDAPMods.\n", - agmt_get_long_name(prp->agmt)); - return_value = CONN_LOCAL_ERROR; - } - else - { - return_value = windows_conn_send_add(prp->conn, op->target_address.dn, - entryattrs, update_control, NULL /* returned controls */); - ldap_mods_free(entryattrs, 1); - } - break; - } - case SLAPI_OPERATION_MODIFY: - return_value = windows_conn_send_modify(prp->conn, op->target_address.dn, - op->p.p_modify.modify_mods, update_control, - NULL /* returned controls */); - break; - case SLAPI_OPERATION_DELETE: - return_value = windows_conn_send_delete(prp->conn, op->target_address.dn, - update_control, NULL /* returned controls */); - break; - case SLAPI_OPERATION_MODRDN: - /* XXXggood need to pass modrdn mods in update control! */ - 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 */); - 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); - } - -skipchange: - if (NULL != password) - { /* this entry had a password, handle it seperately */ - /* http://support.microsoft.com/?kbid=269190 */ - - int pw_return; - LDAPMod *pw_mods[2]; - LDAPMod pw_mod; - - char *pw[2]; - pw[0] = password; - pw[1] = NULL; - - pw_mod.mod_type = "UnicodePwd"; - pw_mod.mod_op = LDAP_MOD_REPLACE; - pw_mod.mod_values = pw; - - pw_mods[0] = &pw_mod; - pw_mods[1] = NULL; - - - pw_return = windows_conn_send_modify(prp->conn, op->target_address.dn, - pw_mods, NULL, NULL ); - slapi_log_error(SLAPI_LOG_REPL, windows_repl_plugin_name, - "%s: replay_update: update password returned %d\n", - agmt_get_long_name(prp->agmt), pw_return ); - - - // slapi_ch_free((void**) &password); - - } - - /* XXX - what else should be 'ignored' here?. and in which cases? - Or should this go in a different part of the file? */ - if ( CONN_OPERATION_SUCCESS == return_value ) - { - slapi_log_error(SLAPI_LOG_REPL, windows_repl_plugin_name, - "%s: replay_update: Consumer successfully replayed operation with csn %s\n", - agmt_get_long_name(prp->agmt), csn_str); - } - else - { - slapi_log_error(SLAPI_LOG_REPL, windows_repl_plugin_name, - "%s: replay_update: Consumer could not replay operation with csn %s\n", - agmt_get_long_name(prp->agmt), csn_str); - } - return return_value; -} static PRBool is_dummy_operation (const slapi_operation_parameters *op) { + LDAPDebug( LDAP_DEBUG_TRACE, "=> is_dummy_operation\n", 0, 0, 0 ); + LDAPDebug( LDAP_DEBUG_TRACE, "<= is_dummy_operation\n", 0, 0, 0 ); return (strcmp (op->target_address.uniqueid, START_ITERATION_ENTRY_UNIQUEID) == 0); } @@ -1200,6 +1030,7 @@ is_dummy_operation (const slapi_operation_parameters *op) void w_cl5_operation_parameters_done (struct slapi_operation_parameters *sop) { + LDAPDebug( LDAP_DEBUG_TRACE, "=> w_cl5_operation_parameters_done\n", 0, 0, 0 ); if(sop!=NULL) { switch(sop->operation_type) { @@ -1234,7 +1065,7 @@ w_cl5_operation_parameters_done (struct slapi_operation_parameters *sop) } } operation_parameters_done(sop); - + LDAPDebug( LDAP_DEBUG_TRACE, "<= w_cl5_operation_parameters_done\n", 0, 0, 0 ); } @@ -1258,6 +1089,8 @@ send_updates(Private_Repl_Protocol *prp, RUV *remote_update_vector, PRUint32 *nu int rc; CL5ReplayIterator *changelog_iterator = NULL; + LDAPDebug( LDAP_DEBUG_TRACE, "=> send_updates\n", 0, 0, 0 ); + *num_changes_sent = 0; /* * Iterate over the changelog. Retrieve each update, @@ -1265,8 +1098,8 @@ send_updates(Private_Repl_Protocol *prp, RUV *remote_update_vector, PRUint32 *nu * attaching the CSN, and send the change. */ - //rc = cl5CreateReplayIterator( prp, remote_update_vector, &changelog_iterator); // XXX fixme - rc = cl5CreateReplayIteratorEx( prp, remote_update_vector, &changelog_iterator, agmt_get_consumerRID(prp->agmt)); // XXX fixme + + rc = cl5CreateReplayIteratorEx( prp, remote_update_vector, &changelog_iterator, agmt_get_consumerRID(prp->agmt)); if (CL5_SUCCESS != rc) { switch (rc) @@ -1388,7 +1221,8 @@ send_updates(Private_Repl_Protocol *prp, RUV *remote_update_vector, PRUint32 *nu agmt_get_long_name(prp->agmt), csn_as_string(entry.op->csn, PR_FALSE, csn_str)); continue; } - replay_crc = w_replay_update(prp, entry.op); + /* This is where the work actually happens: */ + replay_crc = windows_replay_update(prp, entry.op); if (CONN_OPERATION_SUCCESS != replay_crc) { int operation, error; @@ -1459,6 +1293,9 @@ send_updates(Private_Repl_Protocol *prp, RUV *remote_update_vector, PRUint32 *nu /* Positive response received */ (*num_changes_sent)++; agmt_inc_last_update_changecount (prp->agmt, csn_get_replicaid(entry.op->csn), 0 /*replayed*/); + + /* bring the consumers (AD) RUV up to date */ + /* DBDB removed because it breaks server startup ruv_set_max_csn(remote_update_vector,entry.op->csn, NULL ); */ } break; case CL5_BAD_DATA: @@ -1515,6 +1352,7 @@ send_updates(Private_Repl_Protocol *prp, RUV *remote_update_vector, PRUint32 *nu w_cl5_operation_parameters_done ( entry.op ); cl5DestroyReplayIterator(&changelog_iterator); } + LDAPDebug( LDAP_DEBUG_TRACE, "<= send_updates\n", 0, 0, 0 ); return return_value; } @@ -1531,6 +1369,8 @@ windows_inc_stop(Private_Repl_Protocol *prp) PRIntervalTime start, maxwait, now; int seconds = 1200; + LDAPDebug( LDAP_DEBUG_TRACE, "=> windows_inc_stop\n", 0, 0, 0 ); + maxwait = PR_SecondsToInterval(seconds); prp->terminate = 1; event_notify(prp, EVENT_PROTOCOL_SHUTDOWN); @@ -1557,6 +1397,7 @@ windows_inc_stop(Private_Repl_Protocol *prp) agmt_get_long_name(prp->agmt), PR_IntervalToSeconds(now-start)); } + LDAPDebug( LDAP_DEBUG_TRACE, "<= windows_inc_stop\n", 0, 0, 0 ); return return_value; } @@ -1567,6 +1408,10 @@ windows_inc_status(Private_Repl_Protocol *prp) { int return_value = 0; + LDAPDebug( LDAP_DEBUG_TRACE, "=> windows_inc_status\n", 0, 0, 0 ); + + LDAPDebug( LDAP_DEBUG_TRACE, "<= windows_inc_status\n", 0, 0, 0 ); + return return_value; } @@ -1575,40 +1420,54 @@ windows_inc_status(Private_Repl_Protocol *prp) static void windows_inc_notify_update(Private_Repl_Protocol *prp) { + LDAPDebug( LDAP_DEBUG_TRACE, "=> windows_inc_notify_update\n", 0, 0, 0 ); event_notify(prp, EVENT_TRIGGERING_CRITERIA_MET); + LDAPDebug( LDAP_DEBUG_TRACE, "<= windows_inc_notify_update\n", 0, 0, 0 ); } static void windows_inc_update_now(Private_Repl_Protocol *prp) { + LDAPDebug( LDAP_DEBUG_TRACE, "=> windows_inc_update_now\n", 0, 0, 0 ); event_notify(prp, EVENT_REPLICATE_NOW); + LDAPDebug( LDAP_DEBUG_TRACE, "<= windows_inc_update_now\n", 0, 0, 0 ); } static void windows_inc_notify_agmt_changed(Private_Repl_Protocol *prp) { + LDAPDebug( LDAP_DEBUG_TRACE, "=> windows_inc_notify_agmt_changed\n", 0, 0, 0 ); event_notify(prp, EVENT_AGMT_CHANGED); + LDAPDebug( LDAP_DEBUG_TRACE, "<= windows_inc_notify_agmt_changed\n", 0, 0, 0 ); } static void windows_inc_notify_window_opened (Private_Repl_Protocol *prp) { + LDAPDebug( LDAP_DEBUG_TRACE, "=> windows_inc_notify_window_opened\n", 0, 0, 0 ); event_notify(prp, EVENT_WINDOW_OPENED); + LDAPDebug( LDAP_DEBUG_TRACE, "<= windows_inc_notify_window_opened\n", 0, 0, 0 ); } static void windows_inc_notify_window_closed (Private_Repl_Protocol *prp) { + LDAPDebug( LDAP_DEBUG_TRACE, "=> windows_inc_notify_window_closed\n", 0, 0, 0 ); event_notify(prp, EVENT_WINDOW_CLOSED); + LDAPDebug( LDAP_DEBUG_TRACE, "<= windows_inc_notify_window_closed\n", 0, 0, 0 ); } + Private_Repl_Protocol * Windows_Inc_Protocol_new(Repl_Protocol *rp) { windows_inc_private *rip = NULL; Private_Repl_Protocol *prp = (Private_Repl_Protocol *)slapi_ch_malloc(sizeof(Private_Repl_Protocol)); + + LDAPDebug( LDAP_DEBUG_TRACE, "=> Windows_Inc_Protocol_new\n", 0, 0, 0 ); + prp->delete = windows_inc_delete; prp->run = windows_inc_run; prp->stop = windows_inc_stop; @@ -1639,9 +1498,14 @@ Windows_Inc_Protocol_new(Repl_Protocol *rp) rip->rp = rp; prp->private = (void *)rip; prp->replica_acquired = PR_FALSE; + + LDAPDebug( LDAP_DEBUG_TRACE, "<= Windows_Inc_Protocol_new\n", 0, 0, 0 ); + return prp; + loser: windows_inc_delete(&prp); + LDAPDebug( LDAP_DEBUG_TRACE, "<= Windows_Inc_Protocol_new (loser)\n", 0, 0, 0 ); return NULL; } @@ -1652,8 +1516,13 @@ static void windows_inc_backoff_expired(time_t timer_fire_time, void *arg) { Private_Repl_Protocol *prp = (Private_Repl_Protocol *)arg; + + LDAPDebug( LDAP_DEBUG_TRACE, "=> windows_inc_backoff_expired\n", 0, 0, 0 ); + PR_ASSERT(NULL != prp); event_notify(prp, EVENT_BACKOFF_EXPIRED); + + LDAPDebug( LDAP_DEBUG_TRACE, "<= windows_inc_backoff_expired\n", 0, 0, 0 ); } @@ -1679,6 +1548,8 @@ windows_examine_update_vector(Private_Repl_Protocol *prp, RUV *remote_ruv) { int return_value; + LDAPDebug( LDAP_DEBUG_TRACE, "=> windows_examine_update_vector\n", 0, 0, 0 ); + PR_ASSERT(NULL != prp); if (NULL == prp) { @@ -1718,6 +1589,7 @@ windows_examine_update_vector(Private_Repl_Protocol *prp, RUV *remote_ruv) slapi_ch_free((void**)&remote_gen); slapi_ch_free((void**)&local_gen); } + LDAPDebug( LDAP_DEBUG_TRACE, "<= windows_examine_update_vector\n", 0, 0, 0 ); return return_value; } @@ -1742,6 +1614,8 @@ ignore_error_and_keep_going(int error) { int return_value; + LDAPDebug( LDAP_DEBUG_TRACE, "=> ignore_error_and_keep_going\n", 0, 0, 0 ); + switch (error) { /* Cases where we keep going */ @@ -1811,13 +1685,32 @@ ignore_error_and_keep_going(int error) return_value = PR_FALSE; break; } + LDAPDebug( LDAP_DEBUG_TRACE, "<= ignore_error_and_keep_going\n", 0, 0, 0 ); return return_value; } +/* this function converts an aquisition code to a string - for debug output */ +static const char* +acquire2name (int code) +{ + switch (code) + { + case ACQUIRE_SUCCESS: return "success"; + case ACQUIRE_REPLICA_BUSY: return "replica_busy"; + case ACQUIRE_FATAL_ERROR: return "fatal_error"; + case ACQUIRE_CONSUMER_WAS_UPTODATE: return "consumer_was_uptodate"; + case ACQUIRE_TRANSIENT_ERROR: return "transient_error"; + default: return "invalid_code"; + } +} + + /* this function converts a state to its name - for debug output */ static const char* state2name (int state) { + LDAPDebug( LDAP_DEBUG_TRACE, "=> state2name\n", 0, 0, 0 ); + LDAPDebug( LDAP_DEBUG_TRACE, "<= state2name\n", 0, 0, 0 ); switch (state) { case STATE_START: return "start"; @@ -1838,6 +1731,8 @@ state2name (int state) static const char* event2name (int event) { + LDAPDebug( LDAP_DEBUG_TRACE, "=> event2name\n", 0, 0, 0 ); + LDAPDebug( LDAP_DEBUG_TRACE, "<= event2name\n", 0, 0, 0 ); switch (event) { case EVENT_WINDOW_OPENED: return "update_window_opened"; @@ -1847,763 +1742,20 @@ event2name (int event) case EVENT_REPLICATE_NOW: return "replicate_now"; case EVENT_PROTOCOL_SHUTDOWN: return "protocol_shutdown"; case EVENT_AGMT_CHANGED: return "agreement_changed"; + case EVENT_RUN_DIRSYNC: return "run_dirsync"; default: return "invalid_event"; } } -static const char* -op2string(int op) -{ - switch (op) { - case SLAPI_OPERATION_ADD: - return "add"; - case SLAPI_OPERATION_MODIFY: - return "modify"; - case SLAPI_OPERATION_DELETE: - return "delete"; - case SLAPI_OPERATION_MODRDN: - return "rename"; - case SLAPI_OPERATION_EXTENDED: - return "extended"; - } - - return "unknown"; -} - - - -void map_entry_user(Slapi_Entry **e, int map_to, char** password) { - /* do schema changes */ - - Slapi_Entry *new_entry; - Slapi_Attr *a; - Slapi_Attr **attr = &a; - Slapi_Attr *prevattr = NULL; - int rc; - char* ldif = ""; /* for debugging only */ - int ldif_len=0; /* for debugging only */ - - a = slapi_attr_new(); - - new_entry = slapi_entry_alloc(); - - - rc =slapi_entry_first_attr( *e, attr ); - - while (rc == 0) - { - char* attr_type; - Slapi_Value *old_value; - int i=-1; - int ret = 0; - slapi_attr_get_type(*attr, &attr_type); - - - while ( mapping[++i].old_name != NULL) - { - - - if ((mapping[i].map_to == map_to) && strcasecmp(attr_type, mapping[i].old_name) == 0 ) - { - - slapi_attr_first_value( *attr, &old_value); - slapi_entry_add_value (new_entry, mapping[i].new_name, old_value); - - slapi_log_error(SLAPI_LOG_REPL, windows_repl_plugin_name, - "translate_attrib \n\t%s\n\t%s\n", mapping[i].old_name, mapping[i].new_name); - - } - - } - - if ((map_to == REPLICA_TYPE_WINDOWS) && ( - slapi_attr_type_cmp(attr_type, PSEUDO_ATTR_UNHASHEDUSERPASSWORD , 1) == 0)) - { - int b; - const char* pw; - pw = slapi_value_get_string(old_value); - - *password = (char*) slapi_ch_malloc(strlen( pw ) + 3); /* "%s"\0 */ - b = sprintf(*password, "\"%s\"", pw); - - } - - - if (mapping[i].old_name != NULL) { - slapi_attr_first_value( *attr, &old_value); - ret = slapi_entry_add_value (new_entry, mapping[i].new_name, old_value); - } - - prevattr = *attr; - rc = slapi_entry_next_attr( *e, prevattr, attr ); - - } - /* replace the existing entry with our duplicate */ - { - char *ad_objectclass[] = {"top", "person", "organizationalperson", "user", NULL}; - char *ds_objectclass[] = {"top", "person", "organizationalperson", "inetorgperson", "ntuser", NULL}; - - Slapi_ValueSet *vs = slapi_valueset_new(); - Slapi_Value * addval; - int j = -1; - - if (map_to == REPLICA_TYPE_WINDOWS) { - - while (ad_objectclass[++j]!= NULL) - { - addval = slapi_value_new_string(ad_objectclass[j]); - slapi_valueset_add_value(vs,addval); - slapi_value_free(&addval); - } - } - else - { - while (ds_objectclass[++j]!= NULL) - { - addval = slapi_value_new_string(ds_objectclass[j]); - slapi_valueset_add_value(vs,addval); - slapi_value_free(&addval); - } - } - - slapi_entry_add_valueset(new_entry,"objectclass", vs); - slapi_valueset_free(vs); - - } - - /* - ldif = slapi_entry2str( *e, &ldif_len ); - slapi_log_error(SLAPI_LOG_REPL, windows_repl_plugin_name, - "found entry %s from windows:\n%s\n", slapi_entry_get_ndn(*e), ldif); - ldif = slapi_entry2str( new_entry, &ldif_len ); - slapi_log_error(SLAPI_LOG_REPL, windows_repl_plugin_name, - "found entry %s from windows:\n%s\n", slapi_entry_get_ndn(new_entry), ldif); - slapi_ch_free_string(&ldif); -*/ - - - *e = slapi_entry_dup( new_entry ); - -} - - -void map_entry_group(Slapi_Entry **e, int map_to) { - /* do schema changes */ - - Slapi_Entry *new_entry; - Slapi_Attr *a; - Slapi_Attr **attr = &a; - Slapi_Attr *prevattr = NULL; - int rc; - char* ldif = ""; /* for debugging only */ - int ldif_len=0; /* for debugging only */ - - a = slapi_attr_new(); - - new_entry = slapi_entry_alloc(); - - - rc =slapi_entry_first_attr( *e, attr ); - - while (rc == 0) - { - char* attr_type; - Slapi_Value *old_value; - int i=-1; - int ret = 0; - slapi_attr_get_type(*attr, &attr_type); - - - while ( group_map[++i].old_name != NULL) - { - - - if ((group_map[i].map_to == map_to) && strcasecmp(attr_type, group_map[i].old_name) == 0 ) - { - - slapi_attr_first_value( *attr, &old_value); - slapi_entry_add_value (new_entry, group_map[i].new_name, old_value); - - slapi_log_error(SLAPI_LOG_REPL, windows_repl_plugin_name, - "translate_attrib \n\t%s\n\t%s\n", group_map[i].old_name, group_map[i].new_name); - - } - - } - - if (group_map[i].old_name != NULL) { - slapi_attr_first_value( *attr, &old_value); - ret = slapi_entry_add_value (new_entry, group_map[i].new_name, old_value); - } - - prevattr = *attr; - rc = slapi_entry_next_attr( *e, prevattr, attr ); - - } - /* replace the existing entry with our duplicate */ - { - char *ad_objectclass[] = {"top", "group", NULL}; - char *ds_objectclass[] = {"top", "ntGroup", NULL}; - - Slapi_ValueSet *vs = slapi_valueset_new(); - Slapi_Value * addval; - int j = -1; - - if (map_to == REPLICA_TYPE_WINDOWS) { - - while (ad_objectclass[++j]!= NULL) - { - addval = slapi_value_new_string(ad_objectclass[j]); - slapi_valueset_add_value(vs,addval); - slapi_value_free(&addval); - } - } - else - { - while (ds_objectclass[++j]!= NULL) - { - addval = slapi_value_new_string(ds_objectclass[j]); - slapi_valueset_add_value(vs,addval); - slapi_value_free(&addval); - } - } - - slapi_entry_add_valueset(new_entry,"objectclass", vs); - slapi_valueset_free(vs); - - } - - - ldif = slapi_entry2str( *e, &ldif_len ); - slapi_log_error(SLAPI_LOG_REPL, windows_repl_plugin_name, - "found entry %s from windows:\n%s\n", slapi_entry_get_ndn(*e), ldif); - ldif = slapi_entry2str( new_entry, &ldif_len ); - slapi_log_error(SLAPI_LOG_REPL, windows_repl_plugin_name, - "found entry %s from windows:\n%s\n", slapi_entry_get_ndn(new_entry), ldif); - slapi_ch_free_string(&ldif); - - - - *e = slapi_entry_dup( new_entry ); - -} - -static Slapi_DN* map_dn_user(Slapi_DN *sdn, int map_to, const Slapi_DN *root) -{ - /* function operation - convert to rdn - pop off naming attribute of sdn "{ cn | uid }" - replace with other naming attribute "{ uid | cn }" - append root - return sdn by reference - */ - Slapi_RDN *old_rdn = NULL; - Slapi_RDN *new_rdn = NULL; - char* naming_type = ""; - char* naming_value= ""; - Slapi_DN *return_sdn = NULL; - int rc = 0; - char* tempdn; - - PR_ASSERT(sdn); - PR_ASSERT(root); - - old_rdn = slapi_rdn_new_sdn(sdn); /* cn=administrator */ - - new_rdn = slapi_rdn_new(); - - rc = slapi_rdn_get_first(old_rdn, &naming_type, &naming_value); /* cn administrator */ - - if (map_to == REPLICA_TYPE_MULTIMASTER) - naming_type = slapi_ch_strdup("uid"); /* uid administrator */ - else if (map_to == REPLICA_TYPE_WINDOWS) - naming_type = slapi_ch_strdup("cn"); - - - rc = slapi_rdn_add(new_rdn, naming_type, naming_value); /* uid=administrator */ - - /* XXX this should be done with SDN and not char* */ - - tempdn = (char*) slapi_ch_malloc( strlen (naming_type) + strlen(naming_value) + - slapi_sdn_get_ndn_len(root) + 4); - - sprintf(tempdn, "%s=%s, %s", naming_type, naming_value, slapi_sdn_get_ndn(root) ); - - - return_sdn = slapi_sdn_new_dn_byref(tempdn); - - - return return_sdn; - -} - -static Slapi_DN* map_dn_group(Slapi_DN *sdn, int map_to, const Slapi_DN *root) -{ - /* function operation - convert to rdn - append root - return sdn by reference - */ - Slapi_RDN *old_rdn = NULL; - Slapi_RDN *new_rdn = NULL; - char* naming_type = ""; - char* naming_value= ""; - Slapi_DN *return_sdn = NULL; - int rc = 0; - char* tempdn; - - PR_ASSERT(sdn); - PR_ASSERT(root); - - old_rdn = slapi_rdn_new_sdn(sdn); /* cn=administrator */ - - new_rdn = slapi_rdn_new(); - - rc = slapi_rdn_get_first(old_rdn, &naming_type, &naming_value); /* cn administrator */ - - rc = slapi_rdn_add(new_rdn, naming_type, naming_value); - - /* XXX this should be done with SDN and not char* */ - - tempdn = (char*) slapi_ch_malloc( strlen (naming_type) + strlen(naming_value) + - slapi_sdn_get_ndn_len(root) + 4); - - sprintf(tempdn, "%s=%s, %s", naming_type, naming_value, slapi_sdn_get_ndn(root) ); - - - return_sdn = slapi_sdn_new_dn_passin(tempdn); - - - return return_sdn; - -} - -static void alter_mods(LDAPMod ***m, char** password) +static void +periodic_dirsync(time_t when, void *arg) { - LDAPMod **mods = *m; - int i=0; - - while (NULL != mods && NULL != mods[i]) - { - int j=-1; /* index of the attribute mapping array */ - char* attr_type; - attr_type = slapi_ch_strdup(mods[i]->mod_type); - while ( mapping[++j].old_name != NULL) - { - - if ( (mapping[j].map_to == REPLICA_TYPE_WINDOWS) && - (slapi_attr_type_cmp(attr_type, mapping[j].old_name, 1) == 0 ) ) - { - mods[i]->mod_type = slapi_ch_strdup(mapping[j].new_name); - - slapi_log_error(SLAPI_LOG_REPL, windows_repl_plugin_name, - "alter_mods \n\t%s\n\t%s\n", mapping[j].old_name, mapping[j].new_name); - break; - - } - } - - if (slapi_attr_type_cmp(attr_type, PSEUDO_ATTR_UNHASHEDUSERPASSWORD , 1) == 0) - { - int b; - char *pw; - if (mods[i]->mod_op | LDAP_MOD_BVALUES) - { - *password = (char*) slapi_ch_malloc(strlen( mods[i]->mod_bvalues[0]->bv_val) + 3); /* "%s"\0 */ - pw = mods[i]->mod_bvalues[0]->bv_val; - } - else - { - *password = (char*) slapi_ch_malloc(strlen( mods[i]->mod_values[0]) + 3); /* "%s"\0 */ - pw = mods[i]->mod_values[0]; - } - - b = sprintf(*password, "\"%s\"", pw); - - - } - - if (mapping[j].old_name == NULL) - { - LDAPMod *this_mod = mods[i]; - - /* Move down all subsequent mods */ - int k = 0; - for (k = i; mods[k+1] ; k++) - { - mods[k] = mods[k+1]; - } - /* Zero the end of the array */ - mods[k] = NULL; - /* Adjust value of j, implicit in not incrementing it */ - /* Free this mod */ - ber_bvecfree(this_mod->mod_bvalues); - slapi_ch_free((void **)&(this_mod->mod_type)); - slapi_ch_free((void **)&this_mod); - } - else - i++; - } -} - - -/* the entry has already been translated, so be sure to search for ntuserid - and not samaccountname or anything else. */ - -static Slapi_Entry* windows_entry_already_exists(Slapi_Entry *e){ - - int rc = 0; - Slapi_DN *sdn = NULL; - Slapi_Entry *entry = NULL; - - sdn = slapi_entry_get_sdn(e); - rc = slapi_search_internal_get_entry( sdn, NULL, &entry, repl_get_plugin_identity (PLUGIN_MULTIMASTER_REPLICATION)); - - if (rc == LDAP_SUCCESS) - { - return entry; - } - else - { - return NULL; - } - -} - -static PRBool entry_is_tombstone(Slapi_Entry *e){ - return PR_FALSE; -} - -static int delete_user(Slapi_Entry *e){ - const char* dn; - const char* new_dn; - Slapi_PBlock *pb = NULL; - Slapi_DN *sdn = NULL; - int return_value = 0; - - PR_ASSERT(e); - - dn = slapi_ch_strdup( slapi_entry_get_ndn(e) ); - new_dn = slapi_ch_strdup(dn); - - /* XXX dn parsing in this if block could use some improvement */ - if ( strstr(new_dn, "\ndel:") != NULL ) - { - char* comma; - const char* c = ","; - pb = slapi_pblock_new(); - - comma = strstr(dn, c); - - strcpy( strstr(new_dn, "\ndel:"), comma); - - slapi_delete_internal_set_pb(pb, new_dn, NULL, NULL, repl_get_plugin_identity(PLUGIN_MULTIMASTER_REPLICATION), 0); - slapi_delete_internal_pb(pb); - - slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &return_value); - slapi_pblock_destroy(pb); - - - } - else - { - return_value = -1; - } - - slapi_log_error(SLAPI_LOG_REPL, windows_repl_plugin_name, - "delete operation of entry %s returned: %d\n", new_dn, return_value); - - slapi_ch_free((void**) &dn); - slapi_ch_free((void**) &new_dn); - - return return_value; -} - - -static void make_mods_from_entries(Slapi_Entry *new_entry, Slapi_Entry *existing_entry, LDAPMod ***attrs){ - Slapi_Attr *attr; - int rc = 0; - Slapi_Mods smods; - - PR_ASSERT (new_entry && attrs && existing_entry); - - slapi_mods_init (&smods, 0); - - rc =slapi_entry_first_attr( new_entry, &attr ); - - while (rc == 0) - { - char* attr_type; - Slapi_Attr *existing_attr; - int i=-1; - Slapi_Value *v1 = NULL; - Slapi_Value *v2 = NULL; - - slapi_attr_get_type(attr, &attr_type); - - slapi_attr_first_value( attr, &v1); - - if (slapi_entry_attr_find(existing_entry, attr_type, &existing_attr) == 0) - { - /* found */ - slapi_attr_first_value( existing_attr, &v2); - - if (slapi_value_compare(existing_attr, v1, v2) == 0) - { - /* same, do nothing */ - /* slapi_log_error(SLAPI_LOG_REPL, windows_repl_plugin_name, - "make_mods_from_entries: %s has same value (%s) on both sides\n", attr_type, slapi_value_get_string(v1)); */ - - } - else - { - /* attributes different -- create CHANGE */ - /* slapi_log_error(SLAPI_LOG_REPL, windows_repl_plugin_name, - "make_mods_from_entries: %s has different value (%s, %s)\n", - attr_type, slapi_value_get_string(v1),slapi_value_get_string(v2)); */ - - slapi_mods_add_mod_values(&smods, LDAP_MOD_REPLACE, attr_type, &v1 ); - } - - - } - else - { - /* not found -- create ADD */ - /*slapi_log_error(SLAPI_LOG_REPL, windows_repl_plugin_name, - "make_mods_from_entries: %s has no value ( will be %s)\n", - attr_type, slapi_value_get_string(v1)); */ - - - slapi_mods_add_mod_values(&smods, LDAP_MOD_ADD, attr_type, &v1 ); - - } - - /* XXX TODO: - delete an attribute */ - - rc = slapi_entry_next_attr(new_entry, attr, &attr); - - - } - *attrs = slapi_mods_get_ldapmods_passout (&smods); - slapi_mods_done (&smods); - - -} - -int add_or_modify_user(Slapi_Entry *e){ - Slapi_PBlock *pb = NULL; - int return_value = 0; - char *dn; - Slapi_Entry *existing = NULL; - - pb = slapi_pblock_new(); - dn = slapi_ch_strdup( slapi_entry_get_ndn(e) ); - - existing = windows_entry_already_exists(e); - if ( existing == NULL) - { - slapi_add_entry_internal_set_pb(pb, e, NULL, - repl_get_plugin_identity(PLUGIN_MULTIMASTER_REPLICATION), - 0); - slapi_add_internal_pb(pb); - - } - else - { - LDAPMod **mods; - make_mods_from_entries(e, existing, &mods); - if (NULL == mods) - { /* also get null if there are no differences, so this is ok. */ - slapi_log_error(SLAPI_LOG_FATAL, windows_repl_plugin_name, - "add_or_modify_user: Cannot convert entry %s to LDAPMods.\n", dn ); - return_value = 0; - goto bail; - } - - slapi_modify_internal_set_pb (pb, slapi_entry_get_ndn(e), mods, NULL, NULL, - repl_get_plugin_identity (PLUGIN_MULTIMASTER_REPLICATION), 0); - slapi_modify_internal_pb (pb); - ldap_mods_free(mods, 1); - } - - - - slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &return_value); + LDAPDebug( LDAP_DEBUG_TRACE, "=> periodic_dirsync\n", 0, 0, 0 ); slapi_log_error(SLAPI_LOG_REPL, windows_repl_plugin_name, - "operation of entry %s returned: %d\n", dn, return_value); - -bail: - - if (pb) - slapi_pblock_destroy(pb); + "Running Dirsync \n"); - return return_value; + event_notify( (Private_Repl_Protocol*) arg, EVENT_RUN_DIRSYNC); + LDAPDebug( LDAP_DEBUG_TRACE, "<= periodic_dirsync\n", 0, 0, 0 ); } - - -int add_or_modify_group(Slapi_Entry *e){ - Slapi_PBlock *pb = NULL; - int return_value = 0; - char *dn; - Slapi_Entry *existing = NULL; - - pb = slapi_pblock_new(); - dn = slapi_ch_strdup( slapi_entry_get_ndn(e) ); - - existing = windows_entry_already_exists(e); - if ( existing == NULL) - { - slapi_add_entry_internal_set_pb(pb, e, NULL, - repl_get_plugin_identity(PLUGIN_MULTIMASTER_REPLICATION), - 0); - slapi_add_internal_pb(pb); - - } - else - { - LDAPMod **mods; - make_mods_from_entries(e, existing, &mods); - if (NULL == mods) - { /* also get null if there are no differences, so this is ok. */ - slapi_log_error(SLAPI_LOG_FATAL, windows_repl_plugin_name, - "add_or_modify_user: Cannot convert entry %s to LDAPMods.\n", dn ); - return_value = 0; - goto bail; - } - - slapi_modify_internal_set_pb (pb, slapi_entry_get_ndn(e), mods, NULL, NULL, - repl_get_plugin_identity (PLUGIN_MULTIMASTER_REPLICATION), 0); - slapi_modify_internal_pb (pb); - ldap_mods_free(mods, 1); - } - - - - slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &return_value); - - slapi_log_error(SLAPI_LOG_REPL, windows_repl_plugin_name, - "operation of entry %s returned: %d\n", dn, return_value); - -bail: - - if (pb) - slapi_pblock_destroy(pb); - - return return_value; -} - - - -void windows_dirsync_inc_run(Private_Repl_Protocol *prp) - { - - int rc; - int msgid=0; - Slapi_PBlock *pb = NULL; - Slapi_Filter *filter_user = NULL; - Slapi_Filter *filter_user_deleted = NULL; - Slapi_Filter *filter_group = NULL; - Slapi_Filter *filter_group_deleted = NULL; - - rc = perform_search(prp->conn); - if (rc == CONN_OPERATION_SUCCESS) - { - - Slapi_Entry *e; - int filter_ret = 0; - - -#define FILTER_USER "(objectclass=user)" -#define FILTER_GROUP "(objectclass=group)" -#define FILTER_USER_DELETED "(&(isdeleted=*)(objectclass=user))" -#define FILTER_GROUP_DELETED "(&(isdeleted=*)(objectclass=group))" - - filter_user = slapi_str2filter( slapi_ch_strdup( FILTER_USER ) ); - filter_user_deleted = slapi_str2filter( slapi_ch_strdup( FILTER_USER_DELETED ) ); - filter_group = slapi_str2filter( slapi_ch_strdup( FILTER_GROUP ) ); - filter_group_deleted = slapi_str2filter( slapi_ch_strdup( FILTER_GROUP_DELETED ) ); - - - - while ((e = windows_conn_get_search_result(prp->conn)) != NULL) - { - const Slapi_DN* sdn = NULL; - /* deleted users are outside the 'correct container'. - They live in cn=deleted objects, windows_private_get_directory_replarea( prp->agmt) */ - - if ( slapi_filter_test( pb, e, filter_user_deleted, 0 ) == 0 ) - { - slapi_log_error(SLAPI_LOG_REPL, windows_repl_plugin_name, - "entry %s marked for deletion\n", slapi_entry_get_ndn(e)); - - sdn = map_dn_user(slapi_entry_get_sdn(e),REPLICA_TYPE_MULTIMASTER, windows_private_get_directory_replarea( prp->agmt) ); - slapi_entry_set_sdn(e, sdn); - - slapi_log_error(SLAPI_LOG_REPL, windows_repl_plugin_name, - "entry %s marked for deletion\n", slapi_entry_get_ndn(e)); - - - delete_user(e); /* CN is "garbled" if the entry is deleted */ - } - else if ( slapi_filter_test( pb, e, filter_group_deleted, 0 ) == 0 ) - { - slapi_log_error(SLAPI_LOG_REPL, windows_repl_plugin_name, - "group %s marked for deletion\n", slapi_entry_get_ndn(e)); - - sdn = map_dn_group(slapi_entry_get_sdn(e),REPLICA_TYPE_MULTIMASTER, windows_private_get_directory_replarea( prp->agmt) ); - slapi_entry_set_sdn(e, sdn); - - slapi_log_error(SLAPI_LOG_REPL, windows_repl_plugin_name, - "entry %s marked for deletion\n", slapi_entry_get_ndn(e)); - - delete_user(e); /* CN is "garbled" if the entry is deleted */ - - - } - /* must be in the previously specified container to be replicated, lest it is ignored */ - else if (slapi_sdn_isparent(windows_private_get_windows_replarea( prp->agmt ), slapi_entry_get_sdn(e)) ) - { - if (0 == slapi_filter_test( pb, e, filter_user, 0)) - { - sdn = map_dn_user(slapi_entry_get_sdn(e),REPLICA_TYPE_MULTIMASTER, windows_private_get_directory_replarea( prp->agmt) ); - map_entry_user(&e, REPLICA_TYPE_MULTIMASTER, NULL); - - slapi_entry_set_sdn(e, sdn); - /* if (windows_private_create_users(prp->ra)) */ - add_or_modify_user(e); - } - else if (0 == slapi_filter_test( pb, e, filter_group, 0)) - { - slapi_log_error(SLAPI_LOG_REPL, windows_repl_plugin_name, - "group %s marked for addition\n", slapi_entry_get_ndn(e)); - - sdn = map_dn_group(slapi_entry_get_sdn(e),REPLICA_TYPE_MULTIMASTER, windows_private_get_directory_replarea( prp->agmt) ); - slapi_entry_set_sdn(e, sdn); - - map_entry_group(&e, REPLICA_TYPE_MULTIMASTER); - - slapi_log_error(SLAPI_LOG_REPL, windows_repl_plugin_name, - "group %s marked for addition\n", slapi_entry_get_ndn(e)); - - add_or_modify_group(e); - } - else - { - slapi_log_error(SLAPI_LOG_REPL, windows_repl_plugin_name, - "entry %s in %s ignored\n", slapi_entry_get_ndn(e), slapi_sdn_get_dn(windows_private_get_directory_replarea( prp->agmt)) ); - } - /* inside container */ - } - else - { - slapi_log_error(SLAPI_LOG_REPL, windows_repl_plugin_name, - "entry %s ignored\n", slapi_entry_get_ndn(e)); - } - } - } -} - diff --git a/ldap/servers/plugins/replication/windows_private.c b/ldap/servers/plugins/replication/windows_private.c index 63a30fe5..001e57bb 100644 --- a/ldap/servers/plugins/replication/windows_private.c +++ b/ldap/servers/plugins/replication/windows_private.c @@ -8,121 +8,213 @@ #include "repl.h" #include "repl5.h" - +#include "slap.h" +#include "slapi-plugin.h" +#include "windowsrepl.h" struct windowsprivate { - Slapi_DN *windows_replarea; /* DN of replicated area (on the windows side) */ - Slapi_DN *directory_replarea; /* DN of replicated area on directory side */ + Slapi_DN *windows_subtree; /* DN of synchronized subtree (on the windows side) */ + Slapi_DN *directory_subtree; /* DN of synchronized subtree on directory side */ /* this simplifies the mapping as it's simply from the former to the latter container, or vice versa */ - int dirsync_flags; int dirsync_maxattributecount; char *dirsync_cookie; int dirsync_cookie_len; PRBool dirsync_cookie_has_more; - PRBool create_users_from_dirsync; + PRBool create_groups_from_dirsync; + char *windows_domain; }; +void +windows_init_agreement_from_entry(Repl_Agmt *ra, Slapi_Entry *e) +{ + char *tmpstr = NULL; + agmt_set_priv(ra,windows_private_new()); + + /* DN of entry at root of replicated area */ + tmpstr = slapi_entry_attr_get_charptr(e, type_nsds7WindowsReplicaArea); + if (NULL != tmpstr) + { + windows_private_set_windows_subtree(ra, slapi_sdn_new_dn_passin(tmpstr) ); + } + tmpstr = slapi_entry_attr_get_charptr(e, type_nsds7DirectoryReplicaArea); + if (NULL != tmpstr) + { + windows_private_set_directory_subtree(ra, slapi_sdn_new_dn_passin(tmpstr) ); + } - + tmpstr = slapi_entry_attr_get_charptr(e, type_nsds7CreateNewUsers); + if (NULL != tmpstr) + { + windows_private_set_create_users(ra, PR_TRUE); + slapi_ch_free((void**)&tmpstr); + } + else + { + windows_private_set_create_users(ra, PR_FALSE); + } + tmpstr = slapi_entry_attr_get_charptr(e, type_nsds7WindowsDomain); + if (NULL != tmpstr) + { + windows_private_set_windows_domain(ra,tmpstr); + } +} Dirsync_Private* windows_private_new() { Dirsync_Private *dp; - dp = (Dirsync_Private *)slapi_ch_malloc(sizeof(Dirsync_Private)); - dp->windows_replarea = NULL; - dp->dirsync_flags = 0; + LDAPDebug( LDAP_DEBUG_TRACE, "=> windows_private_new\n", 0, 0, 0 ); + + dp = (Dirsync_Private *)slapi_ch_calloc(sizeof(Dirsync_Private),1); + dp->dirsync_maxattributecount = -1; - dp->dirsync_cookie = NULL; - dp->dirsync_cookie_len = 0; - dp->dirsync_cookie_has_more = 0; dp->create_users_from_dirsync = PR_TRUE; + + LDAPDebug( LDAP_DEBUG_TRACE, "<= windows_private_new\n", 0, 0, 0 ); return dp; } -void windows_private_delete(Dirsync_Private **dp) +void windows_agreement_delete(Repl_Agmt *ra) { + Dirsync_Private *dp = (Dirsync_Private *) agmt_get_priv(ra); + LDAPDebug( LDAP_DEBUG_TRACE, "=> windows_private_delete\n", 0, 0, 0 ); + PR_ASSERT(dp != NULL); - PR_ASSERT(*dp != NULL); - /* TODO: free cookie */ + /* DBDB: need to free payoad here */ - /* slapi_sdn_done((**dp).windows_replarea); */ slapi_ch_free((void **)dp); -} + LDAPDebug( LDAP_DEBUG_TRACE, "<= windows_private_delete\n", 0, 0, 0 ); +} -const Slapi_DN* windows_private_get_windows_replarea (const Repl_Agmt *ra) +/* 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; + + LDAPDebug( LDAP_DEBUG_TRACE, "=> windows_private_get_windows_subtree\n", 0, 0, 0 ); + PR_ASSERT(ra); - dp = (Dirsync_Private *) get_priv_from_agmt(ra); + dp = (Dirsync_Private *) agmt_get_priv(ra); PR_ASSERT (dp); + + LDAPDebug( LDAP_DEBUG_TRACE, "<= windows_private_get_windows_subtree\n", 0, 0, 0 ); - if(dp->windows_replarea) - return slapi_sdn_dup (dp->windows_replarea); - else - return NULL; + return dp->windows_subtree; } -const Slapi_DN* windows_private_get_directory_replarea (const Repl_Agmt *ra) +const char * +windows_private_get_windows_domain(const Repl_Agmt *ra) { Dirsync_Private *dp; + + LDAPDebug( LDAP_DEBUG_TRACE, "=> windows_private_get_windows_domain\n", 0, 0, 0 ); + PR_ASSERT(ra); - dp = (Dirsync_Private *) get_priv_from_agmt(ra); + dp = (Dirsync_Private *) agmt_get_priv(ra); PR_ASSERT (dp); + + LDAPDebug( LDAP_DEBUG_TRACE, "<= windows_private_get_windows_domain\n", 0, 0, 0 ); - if(dp->directory_replarea) - return slapi_sdn_dup (dp->directory_replarea); - else - return NULL; + return dp->windows_domain; } +static void +windows_private_set_windows_domain(const Repl_Agmt *ra, char *domain) +{ + Dirsync_Private *dp; + + LDAPDebug( LDAP_DEBUG_TRACE, "=> windows_private_set_windows_domain\n", 0, 0, 0 ); -void windows_private_set_windows_replarea (const Repl_Agmt *ra,const Slapi_DN* sdn ) + PR_ASSERT(ra); + + dp = (Dirsync_Private *) agmt_get_priv(ra); + PR_ASSERT (dp); + + dp->windows_domain = domain; + + LDAPDebug( LDAP_DEBUG_TRACE, "<= windows_private_set_windows_domain\n", 0, 0, 0 ); + } + +/* Returns a copy of the Slapi_DN pointer, no need to free it */ +const Slapi_DN* windows_private_get_directory_subtree (const Repl_Agmt *ra) +{ + Dirsync_Private *dp; + + LDAPDebug( LDAP_DEBUG_TRACE, "=> windows_private_get_directory_replarea\n", 0, 0, 0 ); + + PR_ASSERT(ra); + + dp = (Dirsync_Private *) agmt_get_priv(ra); + PR_ASSERT (dp); + + LDAPDebug( LDAP_DEBUG_TRACE, "<= windows_private_get_directory_replarea\n", 0, 0, 0 ); + + return dp->directory_subtree; +} + +/* Takes a copy of the sdn passed in */ +void windows_private_set_windows_subtree (const Repl_Agmt *ra,const Slapi_DN* sdn ) { Dirsync_Private *dp; + + LDAPDebug( LDAP_DEBUG_TRACE, "=> windows_private_set_windows_replarea\n", 0, 0, 0 ); + PR_ASSERT(ra); PR_ASSERT(sdn); - dp = (Dirsync_Private *) get_priv_from_agmt(ra); + dp = (Dirsync_Private *) agmt_get_priv(ra); PR_ASSERT (dp); - dp->windows_replarea = slapi_sdn_dup(sdn); + dp->windows_subtree = slapi_sdn_dup(sdn); + + LDAPDebug( LDAP_DEBUG_TRACE, "<= windows_private_set_windows_replarea\n", 0, 0, 0 ); } -void windows_private_set_directory_replarea (const Repl_Agmt *ra,const Slapi_DN* sdn ) +/* Takes a copy of the sdn passed in */ +void windows_private_set_directory_subtree (const Repl_Agmt *ra,const Slapi_DN* sdn ) { Dirsync_Private *dp; + + LDAPDebug( LDAP_DEBUG_TRACE, "=> windows_private_set_directory_replarea\n", 0, 0, 0 ); + PR_ASSERT(ra); PR_ASSERT(sdn); - dp = (Dirsync_Private *) get_priv_from_agmt(ra); + dp = (Dirsync_Private *) agmt_get_priv(ra); PR_ASSERT (dp); - dp->directory_replarea = slapi_sdn_dup(sdn); + dp->directory_subtree = slapi_sdn_dup(sdn); + + LDAPDebug( LDAP_DEBUG_TRACE, "<= windows_private_set_directory_replarea\n", 0, 0, 0 ); } PRBool windows_private_create_users(const Repl_Agmt *ra) { Dirsync_Private *dp; + + LDAPDebug( LDAP_DEBUG_TRACE, "=> windows_private_create_users\n", 0, 0, 0 ); + PR_ASSERT(ra); - dp = (Dirsync_Private *) get_priv_from_agmt(ra); + dp = (Dirsync_Private *) agmt_get_priv(ra); PR_ASSERT (dp); + LDAPDebug( LDAP_DEBUG_TRACE, "<= windows_private_create_users\n", 0, 0, 0 ); + return dp->create_users_from_dirsync; } @@ -131,12 +223,17 @@ PRBool windows_private_create_users(const Repl_Agmt *ra) void windows_private_set_create_users(const Repl_Agmt *ra, PRBool value) { Dirsync_Private *dp; + + LDAPDebug( LDAP_DEBUG_TRACE, "=> windows_private_set_create_users\n", 0, 0, 0 ); + PR_ASSERT(ra); - dp = (Dirsync_Private *) get_priv_from_agmt(ra); + dp = (Dirsync_Private *) agmt_get_priv(ra); PR_ASSERT (dp); dp->create_users_from_dirsync = value; + LDAPDebug( LDAP_DEBUG_TRACE, "<= windows_private_set_create_users\n", 0, 0, 0 ); + } @@ -145,16 +242,19 @@ void windows_private_set_create_users(const Repl_Agmt *ra, PRBool value) Repl_Agmt ra as a ldap control. */ -LDAPControl* windows_private_dirsync_control(const Repl_Agmt *ra){ +LDAPControl* windows_private_dirsync_control(const Repl_Agmt *ra) +{ LDAPControl *control = NULL; LDAPControl **lc = &control ; BerElement *ber; Dirsync_Private *dp; + + LDAPDebug( LDAP_DEBUG_TRACE, "=> windows_private_dirsync_control\n", 0, 0, 0 ); PR_ASSERT(ra); - dp = (Dirsync_Private *) get_priv_from_agmt(ra); + dp = (Dirsync_Private *) agmt_get_priv(ra); PR_ASSERT (dp); ber = ber_alloc(); @@ -162,6 +262,10 @@ LDAPControl* windows_private_dirsync_control(const Repl_Agmt *ra){ slapi_build_control( REPL_DIRSYNC_CONTROL_OID, ber, PR_TRUE, &control); + ber_free(ber,1); + + LDAPDebug( LDAP_DEBUG_TRACE, "<= windows_private_dirsync_control\n", 0, 0, 0 ); + return control; @@ -172,7 +276,8 @@ LDAPControl* windows_private_dirsync_control(const Repl_Agmt *ra){ Dirsync_Private if the dirsync control is found. */ -void windows_private_update_dirsync_control(const Repl_Agmt *ra,LDAPControl **controls ){ +void windows_private_update_dirsync_control(const Repl_Agmt *ra,LDAPControl **controls ) +{ Dirsync_Private *dp; int foundDirsyncControl; @@ -181,13 +286,14 @@ void windows_private_update_dirsync_control(const Repl_Agmt *ra,LDAPControl **co BerElement *ber; int hasMoreData; int maxAttributeCount; - - - BerValue *serverCookie; + BerValue *serverCookie; + int return_value = LDAP_SUCCESS; + + LDAPDebug( LDAP_DEBUG_TRACE, "=> windows_private_update_dirsync_control\n", 0, 0, 0 ); PR_ASSERT(ra); - dp = (Dirsync_Private *) get_priv_from_agmt(ra); + dp = (Dirsync_Private *) agmt_get_priv(ra); PR_ASSERT (dp); if (NULL != controls ) @@ -198,13 +304,22 @@ void windows_private_update_dirsync_control(const Repl_Agmt *ra,LDAPControl **co } if ( !foundDirsyncControl ) - return; + { + return_value = LDAP_CONTROL_NOT_FOUND; + goto choke; + } else + { dirsync = slapi_dup_control( controls[i-1]); + } ber = ber_init( &dirsync->ldctl_value ) ; - ber_scanf( ber, "{iiO}", &hasMoreData, &maxAttributeCount, &serverCookie); + if (ber_scanf( ber, "{iiO}", &hasMoreData, &maxAttributeCount, &serverCookie) == LBER_ERROR) + { + return_value = LDAP_CONTROL_NOT_FOUND; + goto choke; + } slapi_ch_free(&dp->dirsync_cookie); dp->dirsync_cookie = ( char* ) slapi_ch_malloc(serverCookie->bv_len + 1); @@ -212,34 +327,187 @@ void windows_private_update_dirsync_control(const Repl_Agmt *ra,LDAPControl **co memcpy(dp->dirsync_cookie, serverCookie->bv_val, serverCookie->bv_len); dp->dirsync_cookie_len = (int) serverCookie->bv_len; /* XXX shouldn't cast? */ - dp->dirsync_maxattributecount = maxAttributeCount; + /* dp->dirsync_maxattributecount = maxAttributeCount; We don't need to keep this */ dp->dirsync_cookie_has_more = hasMoreData; +choke: ber_bvfree(serverCookie); ber_free(ber,1); } + else + { + return_value = LDAP_CONTROL_NOT_FOUND; + } + + LDAPDebug( LDAP_DEBUG_TRACE, "<= windows_private_update_dirsync_control\n", 0, 0, 0 ); + /* return return_value; */ } PRBool windows_private_dirsync_has_more(const Repl_Agmt *ra) { - Dirsync_Private *dp; + Dirsync_Private *dp; + + LDAPDebug( LDAP_DEBUG_TRACE, "=> windows_private_dirsync_has_more\n", 0, 0, 0 ); + PR_ASSERT(ra); - dp = (Dirsync_Private *) get_priv_from_agmt(ra); + dp = (Dirsync_Private *) agmt_get_priv(ra); PR_ASSERT (dp); + LDAPDebug( LDAP_DEBUG_TRACE, "<= windows_private_dirsync_has_more\n", 0, 0, 0 ); + return dp->dirsync_cookie_has_more; } -void windows_private_null_dirsync_control(const Repl_Agmt *ra){ - +void windows_private_null_dirsync_cookie(const Repl_Agmt *ra) +{ Dirsync_Private *dp; - dp = (Dirsync_Private *) get_priv_from_agmt(ra); + + LDAPDebug( LDAP_DEBUG_TRACE, "=> windows_private_null_dirsync_control\n", 0, 0, 0 ); + + dp = (Dirsync_Private *) agmt_get_priv(ra); PR_ASSERT (dp); dp->dirsync_cookie_len = 0; - /* XXX should this value be free'd? */ + slapi_ch_free(&dp->dirsync_cookie); dp->dirsync_cookie = NULL; -}
\ No newline at end of file + + LDAPDebug( LDAP_DEBUG_TRACE, "<= windows_private_null_dirsync_control\n", 0, 0, 0 ); +} + +static +Slapi_Mods *windows_private_get_cookie_mod(Dirsync_Private *dp, int modtype) +{ + Slapi_Mods *smods = NULL; + smods = slapi_mods_new(); + + slapi_mods_add( smods, modtype, + "nsds7DirsyncCookie", dp->dirsync_cookie_len , dp->dirsync_cookie); + + return smods; + +} + + +/* writes the current cookie into dse.ldif under the replication agreement entry + returns: ldap result code of the operation. */ +int +windows_private_save_dirsync_cookie(const Repl_Agmt *ra) +{ + Dirsync_Private *dp = NULL; + Slapi_PBlock *pb = NULL; + const char* dn = NULL; + Slapi_DN* sdn = NULL; + int rc = 0; + Slapi_Mods *mods = NULL; + + + + LDAPDebug( LDAP_DEBUG_TRACE, "=> windows_private_save_dirsync_cookie\n", 0, 0, 0 ); + PR_ASSERT(ra); + + dp = (Dirsync_Private *) agmt_get_priv(ra); + PR_ASSERT (dp); + + + pb = slapi_pblock_new (); + + mods = windows_private_get_cookie_mod(dp, LDAP_MOD_REPLACE); + sdn = slapi_sdn_dup( agmt_get_dn_byref(ra) ); + dn = slapi_sdn_get_dn(sdn); + + slapi_modify_internal_set_pb (pb, dn, slapi_mods_get_ldapmods_byref(mods), NULL, NULL, + repl_get_plugin_identity(PLUGIN_MULTIMASTER_REPLICATION), 0); + slapi_modify_internal_pb (pb); + + slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &rc); + + if (rc == LDAP_NO_SUCH_ATTRIBUTE) + { /* try again, but as an add instead */ + mods = windows_private_get_cookie_mod(dp, LDAP_MOD_ADD); + slapi_modify_internal_set_pb (pb, dn, slapi_mods_get_ldapmods_byref(mods), NULL, NULL, + repl_get_plugin_identity(PLUGIN_MULTIMASTER_REPLICATION), 0); + slapi_modify_internal_pb (pb); + + slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &rc); + } + + slapi_pblock_destroy (pb); + slapi_mods_free(&mods); + slapi_sdn_free(&sdn); + + LDAPDebug( LDAP_DEBUG_TRACE, "<= windows_private_save_dirsync_cookie\n", 0, 0, 0 ); + return rc; +} + +/* reads the cookie in dse.ldif to the replication agreement entry + returns: ldap result code of ldap operation, or + LDAP_NO_SUCH_ATTRIBUTE. (this is the equilivent of a null cookie) */ +int windows_private_load_dirsync_cookie(const Repl_Agmt *ra) +{ + Dirsync_Private *dp = NULL; + Slapi_PBlock *pb = NULL; + + Slapi_DN* sdn = NULL; + int rc = 0; + Slapi_Entry *entry = NULL; + char* cookie = NULL; + Slapi_Attr *attr = NULL; + + LDAPDebug( LDAP_DEBUG_TRACE, "=> windows_private_load_dirsync_cookie\n", 0, 0, 0 ); + PR_ASSERT(ra); + + dp = (Dirsync_Private *) agmt_get_priv(ra); + PR_ASSERT (dp); + + + pb = slapi_pblock_new (); + sdn = slapi_sdn_dup( agmt_get_dn_byref(ra) ); + + + rc = slapi_search_internal_get_entry(sdn, NULL, &entry, + repl_get_plugin_identity (PLUGIN_MULTIMASTER_REPLICATION)); + + if (rc == 0) + { + rc= slapi_entry_attr_find( entry, type_nsds7DirsyncCookie, &attr ); + if (attr) + { + struct berval **vals; + rc = slapi_attr_get_bervals_copy(attr, &vals ); + + if (vals) + { + dp->dirsync_cookie_len = (int) (vals[0])->bv_len; + slapi_ch_free(&dp->dirsync_cookie); + + dp->dirsync_cookie = ( char* ) slapi_ch_malloc(dp->dirsync_cookie_len + 1); + memcpy(dp->dirsync_cookie,(vals[0]->bv_val), (vals[0])->bv_len+1); + + } + + ber_bvecfree(vals); + /* we do not free attr */ + + } + else + { + rc = LDAP_NO_SUCH_ATTRIBUTE; + } + } + + if (entry) + { + slapi_entry_free(entry); + } + + slapi_sdn_free( &sdn); + slapi_pblock_destroy (pb); + + LDAPDebug( LDAP_DEBUG_TRACE, "<= windows_private_load_dirsync_cookie\n", 0, 0, 0 ); + + return rc; +} + diff --git a/ldap/servers/plugins/replication/windows_prot_private.h b/ldap/servers/plugins/replication/windows_prot_private.h index d9832cb3..424f52e8 100644 --- a/ldap/servers/plugins/replication/windows_prot_private.h +++ b/ldap/servers/plugins/replication/windows_prot_private.h @@ -66,5 +66,7 @@ CSN *get_current_csn(Slapi_DN *replarea_sdn); char* protocol_response2string (int response); void windows_dirsync_inc_run(Private_Repl_Protocol *prp); +ConnResult windows_replay_update(Private_Repl_Protocol *prp, slapi_operation_parameters *op); +int windows_process_total_entry(Private_Repl_Protocol *prp,Slapi_Entry *e); #endif /* _REPL5_PROT_PRIVATE_H_ */ diff --git a/ldap/servers/plugins/replication/windows_protocol_util.c b/ldap/servers/plugins/replication/windows_protocol_util.c index bb09c05d..4f37af87 100644 --- a/ldap/servers/plugins/replication/windows_protocol_util.c +++ b/ldap/servers/plugins/replication/windows_protocol_util.c @@ -12,13 +12,297 @@ Code common to both incremental and total protocols. */ #include "repl5.h" -// #include "windows_prot_private.h" #include "repl5_prot_private.h" #include "windowsrepl.h" +#include "slap.h" + +#include <unicode/ustring.h> /* UTF8 conversion */ int ruv_private_new( RUV **ruv, RUV *clone ); + +static Slapi_Entry* windows_entry_already_exists(Slapi_Entry *e); +static void windows_dirsync_now (Private_Repl_Protocol *prp); +static Slapi_DN* map_dn_user(Slapi_DN *sdn, int map_to, const Slapi_DN *root); +static Slapi_DN* map_dn_group(Slapi_DN *sdn, int map_to, const Slapi_DN *root); +static void make_mods_from_entries(Slapi_Entry *new_entry, Slapi_Entry *existing_entry, LDAPMod ***attrs); +static void windows_map_mods_for_replay(Private_Repl_Protocol *prp,LDAPMod **original_mods, LDAPMod ***returned_mods, int is_user, char** password); +static int is_subject_of_agreemeent_local(const Slapi_Entry *local_entry,const Repl_Agmt *ra); +static int windows_create_remote_entry(Private_Repl_Protocol *prp,Slapi_Entry *original_entry, Slapi_DN *remote_sdn, Slapi_Entry **remote_entry, char** password); +static int windows_get_local_entry(const Slapi_DN* local_dn,Slapi_Entry **local_entry); +static int windows_get_local_entry_by_uniqueid(Private_Repl_Protocol *prp,const char* uniqueid,Slapi_Entry **local_entry); +static int map_entry_dn_outbound(Slapi_Entry *e, const Slapi_DN **dn, Private_Repl_Protocol *prp, int *missing_entry); +static char* extract_ntuserdomainid_from_entry(Slapi_Entry *e); +static int windows_get_remote_entry (Private_Repl_Protocol *prp, Slapi_DN* remote_dn,Slapi_Entry **remote_entry); +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, const Slapi_DN **dn, const Repl_Agmt *ra); + + +/* Controls the direction of flow for mapped attributes */ +typedef enum mapping_types { + bidirectional, + fromwindowsonly, + towindowsonly, + disabled +} mapping_types; + +/* Controls if we sync the attibute always, or only when we're creating new entries */ +/* Used for attributes like samaccountname, where we want to fill it in on a new entry, but + * we never want to change it on an existing entry */ +typedef enum creation_types { + always, + createonly +} creation_types; + +typedef enum attr_types { + normal, + dnmap +} attr_types; + +typedef struct _windows_attribute_map +{ + char *windows_attribute_name; + char *ldap_attribute_name; + mapping_types map_type; + creation_types create_type; + attr_types attr_type; +} windows_attribute_map; + +/* List of attributes that are common to AD and LDAP, so we simply copy them over in both directions */ +static char* windows_user_matching_attributes[] = +{ + "destinationIndicator", + "facsimileTelephoneNumber", + "givenName", + "homePhone", + "homePostalAddress", + "initials", + "l", + "mail", + "manager", + "mobile", + "o", + "ou", + "pager", + "physicalDeliveryOfficeName", + "postOfficeBox", + "postalAddress", + "postalCode", + "preferredDeliveryMethod", + "registeredAddress", + "seeAlso", + "sn", + "st", + "street", + "telephoneNumber", + "teletexTerminalIdentifier", + "telexNumber", + "title", + "userCertificate", + "x121Address", + NULL +}; + +static char* windows_group_matching_attributes[] = +{ + "description", + "destinationIndicator", + "facsimileTelephoneNumber", + "givenName", + "homePhone", + "homePostalAddress", + "initials", + "l", + "mail", + "manager", + "mobile", + "o", + "ou", + "pager", + "physicalDeliveryOfficeName", + "postOfficeBox", + "postalAddress", + "postalCode", + "preferredDeliveryMethod", + "registeredAddress", + "seeAlso", + "sn", + "st", + "street", + "telephoneNumber", + "teletexTerminalIdentifier", + "telexNumber", + "title", + "userCertificate", + "x121Address", + NULL +}; + +static windows_attribute_map user_attribute_map[] = +{ + { "homeDirectory", "ntUserHomeDir", bidirectional, always, normal}, + { "scriptPath", "ntUserScriptPath", bidirectional, always, normal}, + { "lastLogon", "ntUserLastLogon", bidirectional, always, normal}, + { "lastLogoff", "ntUserLastLogoff", bidirectional, always, normal}, + { "sAMAccountName", "ntUserDomainId", bidirectional, createonly, normal}, + /* cn is a naming attribute in AD, so we don't want to change it after entry creation */ + { "cn", "cn", towindowsonly, createonly, normal}, + /* However, it isn't a naming attribute in DS (we use uid) so it's safe to accept changes inbound */ + { "name", "cn", fromwindowsonly, always, normal}, + { "manager", "manager", bidirectional, always, dnmap}, + { "secretary", "secretary", bidirectional, always, dnmap}, + {NULL, NULL, -1} +}; + +static windows_attribute_map group_attribute_map[] = +{ + { "ntGroupType", "groupType", bidirectional, createonly, normal}, + { "sAMAccountName", "ntUserDomainId", bidirectional, createonly, normal}, + { "member", "uniquemember", bidirectional, always, dnmap}, + {NULL, NULL, -1} +}; + +static const char* +op2string(int op) +{ + LDAPDebug( LDAP_DEBUG_TRACE, "=> op2string\n", 0, 0, 0 ); + LDAPDebug( LDAP_DEBUG_TRACE, "<= op2string\n", 0, 0, 0 ); + switch (op) { + case SLAPI_OPERATION_ADD: + return "add"; + case SLAPI_OPERATION_MODIFY: + return "modify"; + case SLAPI_OPERATION_DELETE: + return "delete"; + case SLAPI_OPERATION_MODRDN: + return "rename"; + case SLAPI_OPERATION_EXTENDED: + return "extended"; + } + + return "unknown"; +} + + +static void +windows_dump_entry(const char *string, Slapi_Entry *e) +{ + int length = 0; + char *buffer = NULL; + buffer = slapi_entry2str(e,&length); + slapi_log_error(SLAPI_LOG_REPL, NULL, "Windows sync entry: %s %s\n", string, buffer); + if (buffer) + { + slapi_ch_free((void**)&buffer); + } +} + +static void +map_dn_values(Private_Repl_Protocol *prp,Slapi_ValueSet *original_values, Slapi_ValueSet **mapped_values, int to_windows) +{ + Slapi_ValueSet *new_vs = NULL; + Slapi_Value *original_value = NULL; + int retval = 0; + int i = 0; + /* For each value: */ + i= slapi_valueset_first_value(original_values,&original_value); + while ( i != -1 ) { + + int is_ours = 0; + char *new_dn_string = NULL; + const char *original_dn_string = NULL; + int original_dn_string_length = 0; + Slapi_DN *original_dn = NULL; + + original_dn_string = slapi_value_get_string(original_value); + /* Sanity check the data was a valid string */ + original_dn_string_length = slapi_value_get_length(original_value); + /* Make a sdn from the string */ + original_dn = slapi_sdn_new_dn_byref(original_dn_string); + if (to_windows) + { + Slapi_Entry *local_entry = NULL; + /* Try to get the local entry */ + retval = windows_get_local_entry(original_dn,&local_entry); + if (0 == retval && local_entry) + { + int missing_entry = 0; + Slapi_DN *remote_dn = NULL; + /* Now map the DN */ + is_ours = is_subject_of_agreemeent_local(local_entry,prp->agmt); + if (is_ours) + { + map_entry_dn_outbound(local_entry,&remote_dn,prp,&missing_entry); + if (remote_dn) + { + if (!missing_entry) + { + /* Success */ + new_dn_string = slapi_ch_strdup(slapi_sdn_get_dn(remote_dn)); + } + slapi_sdn_free(&remote_dn); + } + } + } else { + slapi_log_error(SLAPI_LOG_REPL, NULL, "map_dn_values: no local entry found for %s\n", original_dn_string); + } + if (local_entry) + { + slapi_entry_free(local_entry); + local_entry = NULL; + } + } else + { + Slapi_Entry *remote_entry = NULL; + Slapi_DN *local_dn = NULL; + /* Try to get the remote entry */ + retval = windows_get_remote_entry(prp,original_dn,&remote_entry); + is_ours = is_subject_of_agreemeent_remote(remote_entry,prp->agmt); + if (is_ours) + { + retval = map_entry_dn_inbound(remote_entry,&local_dn,prp->agmt); + if (0 == retval && local_dn) + { + new_dn_string = slapi_ch_strdup(slapi_sdn_get_dn(local_dn)); + slapi_sdn_free(&local_dn); + } else + { + slapi_log_error(SLAPI_LOG_REPL, NULL, "map_dn_values: no remote entry found for %s\n", original_dn_string); + } + } + if (remote_entry) + { + slapi_entry_free(remote_entry); + remote_entry = NULL; + } + } + /* Extract the dn string and store in the new value */ + if (new_dn_string) + { + Slapi_Value *new_value = NULL; + if (NULL == new_vs) + { + new_vs = slapi_valueset_new(); + } + new_value = slapi_value_new_string_passin(new_dn_string); + slapi_valueset_add_value(new_vs,new_value); + slapi_value_free(&new_value); + } + /* If not then we skip it */ + i = slapi_valueset_next_value(original_values,i,&original_value); + if (original_dn) + { + slapi_sdn_free(&original_dn); + } + }/* while */ + if (new_vs) + { + *mapped_values = new_vs; + } +} + /* * Acquire exclusive access to a replica. Send a start replication extended * operation to the replica. The response will contain a success code, and @@ -36,13 +320,15 @@ int ruv_private_new( RUV **ruv, RUV *clone ); * an error). */ int -windows_acquire_replica(Private_Repl_Protocol *prp, RUV **ruv) +windows_acquire_replica(Private_Repl_Protocol *prp, RUV **ruv, int check_ruv) { - char * prot_oid = REPL_NSDS50_INCREMENTAL_PROTOCOL_OID; //xXX get rid of this + int return_value = ACQUIRE_SUCCESS; ConnResult crc; Repl_Connection *conn; + LDAPDebug( LDAP_DEBUG_TRACE, "=> windows_acquire_replica\n", 0, 0, 0 ); + PR_ASSERT(prp); if (prp->replica_acquired) /* we already acquire replica */ @@ -51,12 +337,10 @@ windows_acquire_replica(Private_Repl_Protocol *prp, RUV **ruv) "%s: Remote replica already acquired\n", agmt_get_long_name(prp->agmt)); return_value = ACQUIRE_FATAL_ERROR; + LDAPDebug( LDAP_DEBUG_TRACE, "<= windows_acquire_replica\n", 0, 0, 0 ); return ACQUIRE_SUCCESS; } - //if (NULL != ruv) - //{ ruv_destroy ( ruv ); } - { Replica *replica; Object *supl_ruv_obj, *cons_ruv_obj; @@ -90,22 +374,23 @@ windows_acquire_replica(Private_Repl_Protocol *prp, RUV **ruv) slapi_log_error(SLAPI_LOG_REPL, NULL, "acquire_replica, consumer RUV:\n"); - if (cons_ruv_obj) { + if (cons_ruv_obj) + { RUV* con; object_acquire(cons_ruv_obj); con = (RUV*) object_get_data ( cons_ruv_obj ); ruv_dump (con,"consumer", NULL); object_release( cons_ruv_obj ); - }else + } else { slapi_log_error(SLAPI_LOG_REPL, NULL, "acquire_replica, consumer RUV = null\n"); - + } is_newer = ruv_is_newer ( supl_ruv_obj, cons_ruv_obj ); /* This follows ruv_is_newer, since it's always newer if it's null */ if (cons_ruv_obj == NULL) { - RUV *s; // int rc; + RUV *s; s = (RUV*) object_get_data ( replica_get_ruv ( replica ) ); agmt_set_consumer_ruv(prp->agmt, s ); @@ -123,8 +408,9 @@ windows_acquire_replica(Private_Repl_Protocol *prp, RUV **ruv) object_release (prp->replica_object); replica = NULL; - if (is_newer == PR_FALSE) { - prp->last_acquire_response_code = NSDS50_REPL_UPTODATE; + if (is_newer == PR_FALSE && check_ruv) { + prp->last_acquire_response_code = NSDS50_REPL_UPTODATE; + LDAPDebug( LDAP_DEBUG_TRACE, "<= windows_acquire_replica - ACQUIRE_CONSUMER_WAS_UPTODATE\n", 0, 0, 0 ); return ACQUIRE_CONSUMER_WAS_UPTODATE; } } @@ -166,15 +452,7 @@ windows_acquire_replica(Private_Repl_Protocol *prp, RUV **ruv) current_csn = get_current_csn(replarea_sdn); if (NULL != current_csn) { - - /* Save consumer's RUV in the replication agreement. - It is used by the changelog trimming code */ - // if (ruv && *ruv) agmt_set_consumer_ruv (prp->agmt, *ruv); XXX deadlock? -// XXX return_value = ACQUIRE_SUCCESS; - - - } else { @@ -201,6 +479,8 @@ windows_acquire_replica(Private_Repl_Protocol *prp, RUV **ruv) prp->replica_acquired = PR_TRUE; } + LDAPDebug( LDAP_DEBUG_TRACE, "<= windows_acquire_replica\n", 0, 0, 0 ); + return return_value; } @@ -213,6 +493,8 @@ windows_release_replica(Private_Repl_Protocol *prp) struct berval *payload = NULL; Slapi_DN *replarea_sdn = NULL; + LDAPDebug( LDAP_DEBUG_TRACE, "=> windows_release_replica\n", 0, 0, 0 ); + PR_ASSERT(NULL != prp); PR_ASSERT(NULL != prp->conn); @@ -223,4 +505,1972 @@ windows_release_replica(Private_Repl_Protocol *prp) prp->replica_acquired = PR_FALSE; + LDAPDebug( LDAP_DEBUG_TRACE, "<= windows_release_replica\n", 0, 0, 0 ); + +} + +/* this entry had a password, handle it seperately */ +/* http://support.microsoft.com/?kbid=269190 */ +static int +send_password_modify(Slapi_DN *sdn, char *password, Private_Repl_Protocol *prp) +{ + ConnResult pw_return = 0; + LDAPMod *pw_mods[2]; + LDAPMod pw_mod; + struct berval bv = {0}; + UChar *unicode_password = NULL; + int32_t unicode_password_length = 0; /* Length in _characters_ */ + int32_t buffer_size = 0; /* Size in _characters_ */ + UErrorCode error = 0; + char *quoted_password = NULL; + struct berval *bvals[2]; + + /* AD wants the password in quotes ! */ + quoted_password = PR_smprintf("\"%s\"",password); + if (quoted_password) + { + /* Need to UNICODE encode the password here */ + /* It's one of those 'ask me first and I will tell you the buffer size' functions */ + u_strFromUTF8(NULL, 0, &unicode_password_length, quoted_password, strlen(quoted_password), &error); + buffer_size = unicode_password_length; + unicode_password = (UChar *)slapi_ch_malloc(unicode_password_length * sizeof(UChar)); + if (unicode_password) { + u_strFromUTF8(unicode_password, buffer_size, &unicode_password_length, quoted_password, strlen(quoted_password), &error); + + bv.bv_len = unicode_password_length * sizeof(UChar); + bv.bv_val = (char*)unicode_password; + + bvals[0] = &bv; + bvals[1] = NULL; + + pw_mod.mod_type = "UnicodePwd"; + pw_mod.mod_op = LDAP_MOD_REPLACE | LDAP_MOD_BVALUES; + pw_mod.mod_bvalues = bvals; + + pw_mods[0] = &pw_mod; + pw_mods[1] = NULL; + + pw_return = windows_conn_send_modify(prp->conn, slapi_sdn_get_dn(sdn), pw_mods, NULL, NULL ); + + slapi_ch_free((void**)&unicode_password); + } + PR_smprintf_free(quoted_password); + } + + return pw_return; +} + +static int +windows_entry_has_attr_and_value(Slapi_Entry *e, const char *attrname, char *value) +{ + int retval = 0; + Slapi_Attr *attr = 0; + if (!e || !attrname) + return retval; + + /* see if the entry has the specified attribute name */ + if (!slapi_entry_attr_find(e, attrname, &attr) && attr) + { + /* if value is not null, see if the attribute has that + value */ + if (!value) + { + retval = 1; + } + else + { + Slapi_Value *v = 0; + int index = 0; + for (index = slapi_attr_first_value(attr, &v); + v && (index != -1); + index = slapi_attr_next_value(attr, index, &v)) + { + const char *s = slapi_value_get_string(v); + if (!s) + continue; + + if (!strcasecmp(s, value)) + { + retval = 1; + break; + } + } + } + } + return retval; +} + +static void +windows_is_local_entry_user_or_group(Slapi_Entry *e, int *is_user, int *is_group) +{ + *is_user = windows_entry_has_attr_and_value(e,"objectclass","ntuser"); + *is_group = windows_entry_has_attr_and_value(e,"objectclass","ntgroup"); +} + +static void +windows_is_remote_entry_user_or_group(Slapi_Entry *e, int *is_user, int *is_group) +{ + *is_user = windows_entry_has_attr_and_value(e,"objectclass","person"); + *is_group = windows_entry_has_attr_and_value(e,"objectclass","group"); +} + +static int +add_remote_entry_allowed(Slapi_Entry *e) +{ + /* We say yes if the entry has the ntUserCreateNewAccount attribute set in the case of a user, or the ntGroupDeleteGroup + * attribute set in the case of a group + */ + /* Is this a user or a group ? */ + int is_user = 0; + int is_group = 0; + char *delete_attr = NULL; + + windows_is_local_entry_user_or_group(e,&is_user,&is_group); + if (!is_user && !is_group) + { + /* Neither fish nor foul.. */ + return -1; + } + if (is_user && is_group) + { + /* Now that's just really strange... */ + return -1; + } + if (is_user) + { + delete_attr = "ntUserCreateNewAccount"; + } else + { + delete_attr = "ntGroupCreateNewGroup"; + } + /* Now test if the attribute value is set */ + return windows_entry_has_attr_and_value(e,delete_attr,"true"); +} + +static int +delete_remote_entry_allowed(Slapi_Entry *e) +{ + /* We say yes if the entry has the ntUserDeleteAccount attribute set in the case of a user, or the ntGroupDeleteGroup + * attribute set in the case of a group + */ + /* Is this a user or a group ? */ + int is_user = 0; + int is_group = 0; + char *delete_attr = NULL; + + windows_is_local_entry_user_or_group(e,&is_user,&is_group); + if (!is_user && !is_group) + { + /* Neither fish nor foul.. */ + return -1; + } + if (is_user && is_group) + { + /* Now that's just really strange... */ + return -1; + } + if (is_user) + { + delete_attr = "ntUserDeleteAccount"; + } else + { + delete_attr = "ntGroupDeleteGroup"; + } + /* Now test if the attribute value is set */ + return windows_entry_has_attr_and_value(e,delete_attr,"true"); +} + +static void +windows_make_mods_for_add_retry(Slapi_Entry *local_entry, Slapi_Entry *remote_entry, LDAPMod ***result_mods, int is_user) +{ +} + +static void +windows_log_add_entry_remote(const Slapi_DN *local_dn,const Slapi_DN *remote_dn) +{ + const char* local_dn_string = slapi_sdn_get_dn(local_dn); + const char* remote_dn_string = slapi_sdn_get_dn(remote_dn); + slapi_log_error(SLAPI_LOG_REPL, NULL, "Attempting to add entry %s to AD for local entry %s\n",remote_dn_string,local_dn_string); +} + +static ConnResult +process_replay_add(Private_Repl_Protocol *prp, slapi_operation_parameters *op, Slapi_Entry *local_entry, Slapi_DN *local_dn, Slapi_DN *remote_dn, int is_user, int missing_entry, char **password) +{ + 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"); + + if (missing_entry) + { + 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); + /* Convert entry to mods */ + if (0 == rc && mapped_entry) + { + (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)); + 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 */ + 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)); + } + 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)); + } + } + } else + { + /* Need to re-play this as a mod */ + LDAPMod **mapped_mods = NULL; + Slapi_Entry *remote_entry = NULL; + + /* Fetch the remote entry */ + rc = windows_get_remote_entry(prp, remote_dn,&remote_entry); + if (0 == rc && remote_entry) { + windows_make_mods_for_add_retry(op->p.p_add.target_entry, remote_entry, &mapped_mods, is_user); + /* It's possible that the mapping process results in an empty mod list, in which case we don't bother with the replay */ + if ( mapped_mods == NULL || *(mapped_mods)== NULL ) + { + return_value = CONN_OPERATION_SUCCESS; + } else + { + return_value = windows_conn_send_modify(prp->conn, slapi_sdn_get_dn(remote_dn),mapped_mods, NULL,NULL); + } + if (mapped_mods) + { + ldap_mods_free(mapped_mods,1); + mapped_mods = NULL; + } + slapi_entry_free(remote_entry); + } + } + return return_value; +} + +/* + * Given a changelog entry, construct the appropriate LDAP operations to sync + * the operation to AD. + */ +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; + Slapi_DN *remote_dn = NULL; + Slapi_DN *local_dn = NULL; + Slapi_Entry *local_entry = NULL; + + LDAPDebug( LDAP_DEBUG_TRACE, "=> windows_replay_update\n", 0, 0, 0 ); + + local_dn = slapi_sdn_new_dn_byref( op->target_address.dn ); + + /* Since we have the target uniqueid in the op structure, let's + * fetch the local entry here using it. + */ + + rc = windows_get_local_entry_by_uniqueid(prp, op->target_address.uniqueid, &local_entry); + + if (rc) + { + slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, + "%s: windows_replay_update: failed to fetch local entry for %s operation dn=\"%s\"\n", + agmt_get_long_name(prp->agmt), + op2string(op->operation_type), op->target_address.dn); + goto error; + } + + is_ours = is_subject_of_agreemeent_local(local_entry, prp->agmt); + windows_is_local_entry_user_or_group(local_entry,&is_user,&is_group); + + slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, + "%s: windows_replay_update: Looking at %s operation dn=\"%s\" (%s,%s,%s)\n", + agmt_get_long_name(prp->agmt), + op2string(op->operation_type), op->target_address.dn, is_ours ? "ours" : "not ours", + is_user ? "user" : "not user", is_group ? "group" : "not group"); + + if (is_ours && (is_user || is_group) ) { + int missing_entry = 0; + /* Make the entry's DN */ + rc = map_entry_dn_outbound(local_entry,&remote_dn,prp,&missing_entry); + if (rc || NULL == remote_dn) + { + slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, + "%s: windows_replay_update: failed map dn for %s operation dn=\"%s\"\n", + agmt_get_long_name(prp->agmt), + op2string(op->operation_type), op->target_address.dn); + goto error; + } + switch (op->operation_type) { + /* For an ADD operation, we map the entry and then send the operation, which may fail if the peer entry already existed */ + case SLAPI_OPERATION_ADD: + return_value = process_replay_add(prp,op,local_entry,local_dn,remote_dn,is_user,missing_entry,&password); + break; + case SLAPI_OPERATION_MODIFY: + { + LDAPMod **mapped_mods = NULL; + + windows_map_mods_for_replay(prp,op->p.p_modify.modify_mods, &mapped_mods, is_user, &password); + /* It's possible that the mapping process results in an empty mod list, in which case we don't bother with the replay */ + if ( mapped_mods == NULL || *(mapped_mods)== NULL ) + { + return_value = CONN_OPERATION_SUCCESS; + } else + { + return_value = windows_conn_send_modify(prp->conn, slapi_sdn_get_dn(remote_dn), mapped_mods, update_control,NULL /* returned controls */); + } + if (mapped_mods) + { + ldap_mods_free(mapped_mods,1); + mapped_mods = NULL; + } + } + 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 */); + 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 + { + slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, + "%s: windows_replay_update: delete not allowed on remote entry, dn=\"%s\"\n", + agmt_get_long_name(prp->agmt), slapi_sdn_get_dn(remote_dn)); + } + break; + case SLAPI_OPERATION_MODRDN: + return_value = windows_conn_send_rename(prp->conn, op->target_address.dn, + op->p.p_modrdn.modrdn_newrdn, + op->p.p_modrdn.modrdn_newsuperior_address.dn, + op->p.p_modrdn.modrdn_deloldrdn, + update_control, 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); + } + if (password) + { + return_value = send_password_modify(remote_dn, password, prp); + if (return_value) + { + slapi_log_error(SLAPI_LOG_REPL, windows_repl_plugin_name, "%s: windows_replay_update: update password returned %d\n", + agmt_get_long_name(prp->agmt), return_value ); + } + } + } else { + /* We ignore operations that target entries outside of our sync'ed subtree, or which are not Windows users or groups */ + } +error: + if (local_entry) + { + slapi_entry_free(local_entry); + } + if (local_dn) + { + slapi_sdn_free (&local_dn); + } + if (remote_dn) + { + slapi_sdn_free(&remote_dn); + } + return return_value; +} + +static int +is_straight_mapped_attr(const char *type, int is_user /* or group */) +{ + int found = 0; + size_t offset = 0; + char *this_attr = NULL; + char **list = is_user ? windows_user_matching_attributes : windows_group_matching_attributes; + /* Look for the type in the list of straight mapped attrs for the appropriate object type */ + while (this_attr = list[offset]) + { + if (0 == slapi_attr_type_cmp(this_attr, type, SLAPI_TYPE_CMP_SUBTYPE)) + { + found = 1; + break; + } + offset++; + } + return found; +} + +static void +windows_map_attr_name(const char *original_type , int to_windows, int is_user, int is_create, char **mapped_type, int *map_dn) +{ + char *new_type = NULL; + windows_attribute_map *our_map = is_user ? user_attribute_map : group_attribute_map; + windows_attribute_map *this_map = NULL; + size_t offset = 0; + + *mapped_type = NULL; + + /* Iterate over the map entries looking for the type we have */ + while(this_map = &(our_map[offset])) + { + char *their_name = to_windows ? this_map->windows_attribute_name : this_map->ldap_attribute_name; + char *our_name = to_windows ? this_map->ldap_attribute_name : this_map->windows_attribute_name; + + if (NULL == their_name) + { + /* End of the list */ + break; + } + if (0 == slapi_attr_type_cmp(original_type, our_name, SLAPI_TYPE_CMP_SUBTYPE)) + { + if (!is_create && (this_map->create_type == createonly)) + { + /* Skip create-only entries if we're not creating */ + } else + { + if ( (this_map->map_type == towindowsonly && to_windows) || (this_map->map_type == fromwindowsonly && !to_windows) + || (this_map->map_type == bidirectional) ) + { + new_type = slapi_ch_strdup(their_name); + *map_dn = (this_map->attr_type == dnmap); + break; + } + } + } + offset++; + } + + if (new_type) + { + *mapped_type = new_type; + } +} + +/* + * Make a new entry suitable for the sync destination (indicated by the to_windows argument). + * Returns the new entry ready to be passed to an LDAP ADD operation, either remote or local. + * Also returns the plaintext value of any password contained in the original entry (only for the + * to_windows direction). This is because passwords must be added to entries after they are added in AD. + * Caller must free the new entry and any password returned. + */ +static int +windows_create_remote_entry(Private_Repl_Protocol *prp,Slapi_Entry *original_entry, Slapi_DN *remote_sdn, Slapi_Entry **remote_entry, char** password) +{ + int retval = 0; + char *entry_string = NULL; + Slapi_Entry *new_entry = NULL; + Slapi_PBlock* pb = NULL; + int rc = 0; + int is_user = 1; /* DBDB need to add code to test for group here */ + Slapi_Attr *attr = NULL; + char *username = NULL; + const char *dn_string = NULL; + char *remote_entry_template = NULL; + char *fqusername = NULL; + const char *domain_name = windows_private_get_windows_domain(prp->agmt); + + char *remote_user_entry_template = + "dn: %s\n" + "objectclass:top\n" + "objectclass:person\n" + "objectclass:organizationalperson\n" + "objectclass:user\n" + "userPrincipalName:%s\n" + "userAccountControl:512\n"; + + char *remote_group_entry_template = + "dn: %s\n" + "objectclass:top\n" + "objectclass:group\n"; + + LDAPDebug( LDAP_DEBUG_TRACE, "=> windows_create_remote_entry\n", 0, 0, 0 ); + + remote_entry_template = is_user ? remote_user_entry_template : remote_group_entry_template; + + /* Create a new entry */ + /* Give it its DN and samaccountname */ + username = extract_ntuserdomainid_from_entry(original_entry); + if (NULL == username) + { + goto error; + } + fqusername = PR_smprintf("%s@%s",username,domain_name); + dn_string = slapi_sdn_get_dn(remote_sdn); + entry_string = slapi_ch_smprintf(remote_entry_template, dn_string, fqusername); + PR_smprintf_free(fqusername); + if (NULL == entry_string) + { + goto error; + } + new_entry = slapi_str2entry(entry_string, 0); + slapi_ch_free((void**)&entry_string); + if (NULL == new_entry) + { + goto error; + } + /* Map the appropriate attributes sourced from the remote entry */ + /* Iterate over the local entry's attributes */ + for (rc = slapi_entry_first_attr(original_entry, &attr); rc == 0; + rc = slapi_entry_next_attr(original_entry, attr, &attr)) + { + Slapi_Value *value = NULL; + char *type = NULL; + Slapi_ValueSet *vs = NULL; + int mapdn = 0; + + slapi_attr_get_type( attr, &type ); + slapi_attr_get_valueset(attr,&vs); + + if ( is_straight_mapped_attr(type,is_user) ) + { + /* copy over the attr values */ + slapi_entry_add_valueset(new_entry,type,vs); + } else + { + char *new_type = NULL; + + windows_map_attr_name(type , 1 /* to windows */, is_user, 1 /* create */, &new_type, &mapdn); + if (new_type) + { + if (mapdn) + { + Slapi_ValueSet *mapped_values = NULL; + map_dn_values(prp,vs,&mapped_values, 1 /* to windows */); + if (mapped_values) + { + slapi_entry_add_valueset(new_entry,new_type,mapped_values); + slapi_valueset_free(mapped_values); + mapped_values = NULL; + } + } else + { + slapi_entry_add_valueset(new_entry,new_type,vs); + } + slapi_ch_free((void**)&new_type); + } + /* password mods are treated specially */ + if (0 == slapi_attr_type_cmp(type, PSEUDO_ATTR_UNHASHEDUSERPASSWORD, SLAPI_TYPE_CMP_SUBTYPE) ) + { + const char *password_value = NULL; + Slapi_Value *value = NULL; + + slapi_valueset_first_value(vs,&value); + password_value = slapi_value_get_string(value); + *password = slapi_ch_strdup(password_value); + } + + } + if (vs) + { + slapi_valueset_free(vs); + vs = NULL; + } + } + if (remote_entry) + { + *remote_entry = new_entry; + } +error: + if (username) + { + slapi_ch_free((void**)&username); + } + windows_dump_entry("Created new remote entry:\n",new_entry); + LDAPDebug( LDAP_DEBUG_TRACE, "<= windows_create_remote_entry: %d\n", retval, 0, 0 ); + return retval; +} + +/* the entry has already been translated, so be sure to search for ntuserid + and not samaccountname or anything else. */ + +static Slapi_Entry* +windows_entry_already_exists(Slapi_Entry *e){ + + int rc = 0; + Slapi_DN *sdn = NULL; + Slapi_Entry *entry = NULL; + + LDAPDebug( LDAP_DEBUG_TRACE, "=> windows_entry_already_exists\n", 0, 0, 0 ); + + sdn = slapi_entry_get_sdn(e); + rc = slapi_search_internal_get_entry( sdn, NULL, &entry, repl_get_plugin_identity (PLUGIN_MULTIMASTER_REPLICATION)); + + LDAPDebug( LDAP_DEBUG_TRACE, "<= windows_entry_already_exists\n", 0, 0, 0 ); + + if (rc == LDAP_SUCCESS) + { + return entry; + } + else + { + return NULL; + } + +} + +static int +windows_delete_local_entry(Slapi_DN *sdn){ + + Slapi_PBlock *pb = NULL; + int return_value = 0; + + LDAPDebug( LDAP_DEBUG_TRACE, "=> windows_delete_local_entry\n", 0, 0, 0 ); + + pb = slapi_pblock_new(); + slapi_delete_internal_set_pb(pb, slapi_sdn_get_dn(sdn), NULL, NULL, repl_get_plugin_identity(PLUGIN_MULTIMASTER_REPLICATION), 0); + slapi_delete_internal_pb(pb); + slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &return_value); + slapi_pblock_destroy(pb); + + if (return_value) { + slapi_log_error(SLAPI_LOG_REPL, windows_repl_plugin_name, + "delete operation on local entry %s returned: %d\n", slapi_sdn_get_dn(sdn), return_value); + } + LDAPDebug( LDAP_DEBUG_TRACE, "<= windows_delete_local_entry: %d\n", return_value, 0, 0 ); + + return return_value; +} + +static void +windows_map_mods_for_replay(Private_Repl_Protocol *prp,LDAPMod **original_mods, LDAPMod ***returned_mods, int is_user, char** password) +{ + Slapi_Mods smods = {0}; + Slapi_Mods mapped_smods = {0}; + LDAPMod *mod = NULL; + int i=0; + + LDAPDebug( LDAP_DEBUG_TRACE, "=> windows_map_mods_for_replay\n", 0, 0, 0 ); + + /* Iterate through the original mods, looking each attribute type up in the maps for either user or group */ + + slapi_mods_init_byref(&smods, original_mods); + slapi_mods_init(&mapped_smods,10); + mod = slapi_mods_get_first_mod(&smods); + while(mod) + { + char *attr_type = mod->mod_type; + int mapdn = 0; + + /* Check to see if this attribute is passed through */ + if (is_straight_mapped_attr(attr_type,is_user)) { + /* If so then just copy over the mod */ + slapi_mods_add_modbvps(&mapped_smods,mod->mod_op,attr_type,mod->mod_bvalues); + } else + { + char *mapped_type = NULL; + /* Check if this mod has its attribute type mapped */ + windows_map_attr_name(attr_type,1,is_user,0,&mapped_type, &mapdn); + if (mapped_type) + { + /* If so copy over the mod with new type name */ + if (mapdn) + { + Slapi_ValueSet *mapped_values = NULL; + Slapi_ValueSet *vs = NULL; + Slapi_Mod smod; + + vs = slapi_valueset_new(); + slapi_mod_init_byref(&smod,mod); + slapi_valueset_set_from_smod(vs, &smod); + map_dn_values(prp,vs,&mapped_values, 1 /* to windows */); + if (mapped_values) + { + slapi_mods_add_mod_values(&mapped_smods,mod->mod_op,mapped_type,valueset_get_valuearray(mapped_values)); + slapi_valueset_free(mapped_values); + mapped_values = NULL; + } + slapi_mod_done(&smod); + slapi_valueset_free(vs); + } else + { + slapi_mods_add_modbvps(&mapped_smods,mod->mod_op,mapped_type,mod->mod_bvalues); + } + slapi_ch_free((void**)&mapped_type); + } else + { + /* password mods are treated specially */ + if (0 == slapi_attr_type_cmp(attr_type, PSEUDO_ATTR_UNHASHEDUSERPASSWORD, SLAPI_TYPE_CMP_SUBTYPE) ) + { + char *password_value = NULL; + password_value = mod->mod_bvalues[0]->bv_val; + *password = slapi_ch_strdup(password_value); + } + } + } + /* Otherwise we do not copy this mod at all */ + mod = slapi_mods_get_next_mod(&smods); + } + slapi_mods_done (&smods); + /* Extract the mods for the caller */ + *returned_mods = slapi_mods_get_ldapmods_passout(&mapped_smods); + LDAPDebug( LDAP_DEBUG_TRACE, "<= windows_map_mods_for_replay\n", 0, 0, 0 ); +} + +/* Returns non-zero if the attribute value sets are identical */ +static int +attr_compare_equal(Slapi_Attr *a, Slapi_Attr *b) +{ + /* For now only handle single values */ + Slapi_Value *va = NULL; + Slapi_Value *vb = NULL; + int num_a = 0; + int num_b = 0; + int match = 1; + + slapi_attr_get_numvalues(a,&num_a); + slapi_attr_get_numvalues(b,&num_b); + + if (num_a == num_b) + { + slapi_attr_first_value(a, &va); + slapi_attr_first_value(b, &vb); + + if (va->bv.bv_len == va->bv.bv_len) + { + if (0 != memcmp(va->bv.bv_val,vb->bv.bv_val,va->bv.bv_len)) + { + match = 0; + } + } else + { + match = 0; + } + } else + { + match = 0; + } + return match; +} + +/* Helper functions for dirsync result processing */ + +/* Is this entry a tombstone ? */ +static int +is_tombstone(Slapi_Entry *e) +{ + int retval = 0; + + char *string_deleted = "(isdeleted=*)"; + + /* DBDB: we should allocate these filters once and keep them around for better performance */ + Slapi_Filter *filter_deleted = slapi_str2filter( string_deleted ); + + /* DBDB: this should be one filter, the code originally tested separately and hasn't been fixed yet */ + if ( (slapi_filter_test_simple( e, filter_deleted ) == 0) ) + { + retval = 1; + } + + slapi_filter_free(filter_deleted,1); + filter_deleted = NULL; + + return retval; +} + +#define ENTRY_NOTFOUND -1 +#define ENTRY_NOT_UNIQUE -2 + +/* Search for an entry in AD */ +static int +find_entry_by_attr_value_remote(const char *attribute, const char *value, Slapi_Entry **e, Private_Repl_Protocol *prp) +{ + int retval = 0; + ConnResult cres = 0; + char *filter = NULL; + const char *searchbase = NULL; + Slapi_Entry *found_entry = NULL; + + filter = PR_smprintf("(%s=%s)",attribute,value); + searchbase = slapi_sdn_get_dn(windows_private_get_windows_subtree(prp->agmt)); + cres = windows_search_entry(prp->conn, (char*)searchbase, filter, &found_entry); + if (cres) + { + retval = -1; + } else + { + if (found_entry) + { + *e = found_entry; + } + } + if (filter) + { + PR_smprintf_free(filter); + filter = NULL; + } + return retval; +} + +/* Search for an entry in AD by DN */ +static int +windows_get_remote_entry (Private_Repl_Protocol *prp, 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; + + searchbase = slapi_sdn_get_dn(remote_dn); + cres = windows_search_entry(prp->conn, (char*)searchbase, filter, &found_entry); + if (cres) + { + retval = -1; + } else + { + if (found_entry) + { + *remote_entry = found_entry; + } + } + 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; + Slapi_Entry *entry_found = NULL; + char *query = NULL; + int found_or_not = ENTRY_NOTFOUND; + int rval = 0; + const char *subtree_dn = NULL; + int not_unique = 0; + + if (pb == NULL) + goto done; + + query = slapi_ch_smprintf("(%s=%s)", attribute, value); + + if (query == NULL) + goto done; + + subtree_dn = slapi_sdn_get_dn(windows_private_get_directory_subtree(ra)); + + slapi_search_internal_set_pb(pb, subtree_dn, + 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_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &rval); + if (rval != LDAP_SUCCESS) + { + goto done; + } + + slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &entries); + if ((entries == NULL) || (entries[0] == NULL)) + { + goto done; + } + entry_found = entries[0]; + for (ep = entries; *ep; ep++) { + if (not_unique) + { + found_or_not = ENTRY_NOT_UNIQUE; + } + not_unique = 1; + } +done: + if (entry_found && (found_or_not != ENTRY_NOT_UNIQUE)) + { + found_or_not = 0; + *e = slapi_entry_dup(entry_found); + } + if (pb) + { + slapi_free_search_results_internal(pb); + slapi_pblock_destroy(pb); + } + return found_or_not; +} + +static int +find_entry_by_username(const char *username, Slapi_Entry **e, const Repl_Agmt *ra) +{ + return find_entry_by_attr_value("ntUserDomainId",username,e,ra); +} + +/* Find an entry in the local server given its GUID, or return ENTRY_NOTFOUND */ +static int +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 */ +static void +dedash(char *str) +{ + char *p = str; + char c = '\0'; + + while (c = *p) + { + if ('-' == c) + { + /* Move on down please */ + char *q = p; + char *r = q + 1; + while (*r) + { + *q++ = *r++; + } + *q = '\0'; + } + p++; + } +} + +/* 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) +{ + 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; + int i = 0; + char *cpy = slapi_ch_strdup(guid); + + while (*p && i < (sizeof(decrypt_offsets)/sizeof(int))) + { + *p = cpy[decrypt_offsets[i]]; + p++; + i++; + } + slapi_ch_free((void**)&cpy); +} + +static char* +extract_guid_from_tombstone_dn(const char *dn) +{ + char *guid = NULL; + char *colon_offset = NULL; + char *comma_offset = NULL; + + /* example DN of tombstone: + "CN=WDel Userdb1\\\nDEL:551706bc-ecf2-4b38-9284-9a8554171d69,CN=Deleted Objects,DC=magpie,DC=com" */ + + /* First find the 'DEL:' */ + colon_offset = strchr(dn,':'); + /* Then scan forward to the next ',' */ + comma_offset = strchr(dn,','); + /* The characters inbetween are the GUID, copy them to a new string and return to the caller */ + 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); + } + return guid; +} + +static char * +convert_to_hex(Slapi_Value *val) +{ + int offset = 0; + const struct berval *bvp = NULL; + int length = 0; + char *result = NULL; + + bvp = slapi_value_get_berval(val); + if (bvp) + { + char *new_buffer = NULL; + length = bvp->bv_len; + + for (offset = 0; offset < length; offset++) + { + unsigned char byte = ((unsigned char*)(bvp->bv_val))[offset]; + new_buffer = PR_sprintf_append(new_buffer, "%02x", byte ); + } + if (new_buffer) + { + result = new_buffer; + } + } + return result; +} + +static char* +extract_guid_from_entry(Slapi_Entry *e) +{ + char *guid = NULL; + Slapi_Value *val = NULL; + Slapi_Attr *attr = NULL; + + slapi_entry_attr_find(e, "objectGUID", &attr); + if (attr) + { + slapi_attr_first_value(attr, &val); + if (val) { + guid = convert_to_hex(val); + } + } + return guid; +} + +static void +extract_guid_from_entry_bv(Slapi_Entry *e, const struct berval **bv) +{ + Slapi_Value *val = NULL; + Slapi_Attr *attr = NULL; + + slapi_entry_attr_find(e, "objectGUID", &attr); + if (attr) + { + slapi_attr_first_value(attr, &val); + if (val) { + *bv = slapi_value_get_berval(val); + } + } +} + +static char* +extract_username_from_entry(Slapi_Entry *e) +{ + char *uid = NULL; + uid = slapi_entry_attr_get_charptr(e,"samAccountName"); + return uid; +} + +static char* +extract_ntuserdomainid_from_entry(Slapi_Entry *e) +{ + char *uid = NULL; + uid = slapi_entry_attr_get_charptr(e,"ntuserdomainid"); + return uid; +} + +static Slapi_DN *make_dn_from_guid(char *guid) +{ + Slapi_DN *new_dn = NULL; + char *dn_string = NULL; + if (guid) + { + new_dn = slapi_sdn_new(); + dn_string = PR_smprintf("<GUID=%s>",guid); + slapi_sdn_init_dn_byval(new_dn,dn_string); + PR_smprintf_free(dn_string); + } + /* dn string is now inside the Slapi_DN, and will be freed by its owner */ + return new_dn; } + +/* Given a non-tombstone entry, return the DN of its peer in AD (whether present or not) */ +static int +map_entry_dn_outbound(Slapi_Entry *e, const Slapi_DN **dn, Private_Repl_Protocol *prp, int *missing_entry) +{ + int retval = 0; + char *guid = NULL; + Slapi_DN *new_dn = NULL; + /* To find the DN of the peer entry we first look for an ntUniqueId attribute + * on the local entry. If that's present, we generate a GUID-form DN. + * If there's no GUID, then we look for an ntUserDomainId attribute + * on the entry. If that's present we attempt to search for an entry with + * that samaccountName attribute value in AD. If we don't find any matching + * entry we generate a new DN using the entry's cn. If later, we find that + * this entry already exists, we handle that problem at the time. We don't + * check here. + */ + + *missing_entry = 0; + + guid = slapi_entry_attr_get_charptr(e,"ntUniqueId"); + if (guid) + { + new_dn = make_dn_from_guid(guid); + slapi_ch_free((void**)&guid); + } else + { + /* No GUID found, try ntUserDomainId */ + Slapi_Entry *remote_entry = NULL; + char *username = slapi_entry_attr_get_charptr(e,"ntUserDomainId"); + if (username) { + retval = find_entry_by_attr_value_remote("samAccountName",username,&remote_entry,prp); + if (0 == retval && remote_entry) + { + /* Get the entry's DN */ + new_dn = slapi_sdn_new(); + slapi_sdn_copy(slapi_entry_get_sdn_const(remote_entry), new_dn); + } else { + if (0 == retval) + { + const char *suffix = slapi_sdn_get_dn(windows_private_get_windows_subtree(prp->agmt)); + char *new_dn_string = NULL; + char *cn_string = NULL; + + *missing_entry = 1; + /* This means that we failed to find a peer entry */ + /* In that case we need to generate the DN that we want to use */ + /* Generated DN's take the form : + cn=<cn from local entry>, ... in the case that the local entry has a cn, OR + cn=<ntuserdomainid attribute value>, ... in the case that the local entry doesn't have a CN + */ + cn_string = slapi_entry_attr_get_charptr(e,"cn"); + if (!cn_string) + { + cn_string = slapi_entry_attr_get_charptr(e,"ntuserdomainid"); + } + if (cn_string) + { + new_dn_string = PR_smprintf("cn=%s,%s",cn_string,suffix); + if (new_dn_string) + { + new_dn = slapi_sdn_new_dn_byval(new_dn_string); + PR_smprintf_free(new_dn_string); + } + slapi_ch_free((void**)&cn_string); + } + } else + { + /* This means that we failed to talk to the AD for some reason, the operation should be re-tried */ + slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, + "%s: map_entry_dn_outbound: failed to fetch entry from AD: dn=\"%s\", err=%d\n", + agmt_get_long_name(prp->agmt), slapi_sdn_get_dn(slapi_entry_get_sdn_const(e)), retval); + + retval = -1; + } + } + slapi_ch_free((void**)&username); + } + if (remote_entry) + { + slapi_entry_free(remote_entry); + } + } + if (new_dn) + { + *dn = new_dn; + } + return retval; +} + +/* Given a tombstone entry, return the DN of its peer in this server (if present) */ +static int +map_tombstone_dn_inbound(Slapi_Entry *e, const Slapi_DN **dn, const Repl_Agmt *ra) +{ + int retval = 0; + Slapi_DN *new_dn = NULL; + char *guid = NULL; + const char *dn_string = NULL; + Slapi_Entry *matching_entry = NULL; + + /* To map a tombstone's DN we need to first extract the entry's objectGUID from the DN + * CN=vpdxtAD_07\ + DEL:d4ca4e16-e35b-400d-834a-f02db600f3fa,CN=Deleted Objects,DC=magpie,DC=com + */ + *dn = NULL; + + dn_string = slapi_sdn_get_dn(slapi_entry_get_sdn_const(e)); /* This is a pointer from inside the sdn, no need to free */ + guid = extract_guid_from_tombstone_dn(dn_string); + + if (guid) + { + retval = find_entry_by_guid(guid,&matching_entry,ra); + if (retval) + { + if (ENTRY_NOTFOUND == retval) + { + } else + { + if (ENTRY_NOT_UNIQUE == retval) + { + } else + { + /* A real error */ + } + } + } else + { + /* We found the matching entry : get its DN */ + new_dn = slapi_sdn_dup(slapi_entry_get_sdn_const(matching_entry)); + } + } + + if (new_dn) + { + *dn = new_dn; + } + + if (guid) + { + slapi_ch_free((void**)&guid); + } + if (matching_entry) + { + slapi_entry_free(matching_entry); + } + return retval; +} + +/* Given a non-tombstone entry, return the DN of its peer in this server (whether present or not) */ +static int +map_entry_dn_inbound(Slapi_Entry *e, const Slapi_DN **dn, const Repl_Agmt *ra) +{ + int retval = 0; + Slapi_DN *new_dn = NULL; + char *guid = NULL; + char *username = NULL; + Slapi_Entry *matching_entry = NULL; + int is_user = 0; + int is_group = 0; + + /* To map a non-tombstone's DN we need to first try to look it up by GUID. + * If we do not find it, then we need to generate the DN that it would have if added as a new entry. + */ + *dn = NULL; + + windows_is_remote_entry_user_or_group(e,&is_user,&is_group); + + guid = extract_guid_from_entry(e); + if (guid) + { + retval = find_entry_by_guid(guid,&matching_entry,ra); + if (retval) + { + if (ENTRY_NOTFOUND == retval) + { + } else + { + if (ENTRY_NOT_UNIQUE == retval) + { + } else + { + /* A real error */ + goto error; + } + } + } else + { + /* We found the matching entry : get its DN */ + new_dn = slapi_sdn_dup(slapi_entry_get_sdn_const(matching_entry)); + } + } + /* If we failed to lookup by guid, try samaccountname */ + if (NULL == new_dn) + { + username = extract_username_from_entry(e); + if (username) { + retval = find_entry_by_username(username,&matching_entry,ra); + if (retval) + { + if (ENTRY_NOTFOUND == retval) + { + } else + { + if (ENTRY_NOT_UNIQUE == retval) + { + } else + { + /* A real error */ + goto error; + } + } + } else + { + /* We found the matching entry : get its DN */ + new_dn = slapi_sdn_dup(slapi_entry_get_sdn_const(matching_entry)); + } + } + } + /* If we couldn't find a matching entry by either method, then we need to invent a new DN */ + if (NULL == new_dn) + { + /* The new DN has the form: uid=<samaccountname>,<sync'ed subtree> */ + /* If an entry with this DN already exists, we fail and return no DN + * this is because we don't want to second-guess what the admin wants here: + * they may want to associate this existing entry with the peer AD entry, + * but if they intend that we say they must add the ntDomainUserId attribute to + * that entry. + */ + char *new_dn_string = NULL; + if (username) + { + const char *suffix = slapi_sdn_get_dn(windows_private_get_directory_subtree(ra)); + /* Local DNs for users and groups are different */ + if (is_user) + { + new_dn_string = PR_smprintf("uid=%s,%s",username,suffix); + } else + { + new_dn_string = PR_smprintf("cn=%s,%s",username,suffix); + } + new_dn = slapi_sdn_new_dn_byval(new_dn_string); + PR_smprintf_free(new_dn_string); + /* Clear any earlier error */ + retval = 0; + } else + { + /* Error, no username */ + } + } + if (new_dn) + { + *dn = new_dn; + } +error: + if (guid) + { + PR_smprintf_free(guid); + } + if (matching_entry) + { + slapi_entry_free(matching_entry); + } + if (username) + { + slapi_ch_free((void **) &username); + } + return retval; +} + +/* Tests if the entry is subject to our agreement (i.e. is it in the sync'ed subtree in this server, and is it the right objectclass + * and does it have the right attribute values for sync ?) + */ +static int +is_subject_of_agreemeent_local(const Slapi_Entry *local_entry, const Repl_Agmt *ra) +{ + int retval = 0; + int is_in_subtree = 0; + const Slapi_DN *agreement_subtree = NULL; + + /* First test for the sync'ed subtree */ + agreement_subtree = windows_private_get_directory_subtree(ra); + if (NULL == agreement_subtree) + { + goto error; + } + is_in_subtree = slapi_sdn_scope_test(slapi_entry_get_sdn_const(local_entry), agreement_subtree, LDAP_SCOPE_SUBTREE); + if (is_in_subtree) + { + /* Next test for the correct kind of entry */ + if (local_entry) { + /* DBDB: we should allocate these filters once and keep them around for better performance */ + char *string_filter = "(&(|(objectclass=ntuser)(objectclass=ntgroup))(ntUserDomainId=*))"; + Slapi_Filter *filter = slapi_str2filter( string_filter ); + + if (slapi_filter_test_simple( (Slapi_Entry*)local_entry, filter ) == 0) + { + retval = 1; + } + + slapi_filter_free(filter,1); + filter = NULL; + } else + { + /* Error: couldn't find the entry */ + slapi_log_error(SLAPI_LOG_FATAL, windows_repl_plugin_name, + "failed to find entry in is_subject_of_agreemeent_local: %d\n", retval); + retval = 0; + } + } +error: + return retval; +} + +/* Tests if the entry is subject to our agreement (i.e. is it in the sync'ed subtree in AD and either a user or a group ?) */ +static int +is_subject_of_agreemeent_remote(Slapi_Entry *e, const Repl_Agmt *ra) +{ + int retval = 0; + int is_in_subtree = 0; + const Slapi_DN *agreement_subtree = NULL; + + /* First test for the sync'ed subtree */ + agreement_subtree = windows_private_get_windows_subtree(ra); + if (NULL == agreement_subtree) + { + goto error; + } + is_in_subtree = slapi_sdn_scope_test(slapi_entry_get_sdn_const(e), agreement_subtree, LDAP_SCOPE_SUBTREE); + if (is_in_subtree) + { + retval = 1; + } +error: + return retval; +} + +static int +windows_create_local_entry(Private_Repl_Protocol *prp,Slapi_Entry *remote_entry,const Slapi_DN* local_sdn) +{ + int retval = 0; + char *entry_string = NULL; + Slapi_Entry *local_entry = NULL; + Slapi_PBlock* pb = NULL; + int is_user = 0; + int is_group = 0; + char *local_entry_template = NULL; + char *username = extract_username_from_entry(remote_entry); + Slapi_Attr *attr = NULL; + int rc = 0; + char *guid_str = NULL; + + char *local_user_entry_template = + "dn: %s\n" + "objectclass:top\n" + "objectclass:organizationalperson\n" + "objectclass:inetOrgPerson\n" + "objectclass:ntUser\n" + "ntUserDeleteAccount:true\n" + "uid:%s\n"; + + char *local_group_entry_template = + "dn: %s\n" + "objectclass:top\n" + "objectclass:groupofuniquenames\n" + "objectclass:ntGroup\n" + "objectclass:mailGroup\n" + "ntGroupDeleteGroup:true\n" + "cn:%s\n"; + + LDAPDebug( LDAP_DEBUG_TRACE, "=> windows_create_local_entry\n", 0, 0, 0 ); + + windows_is_remote_entry_user_or_group(remote_entry,&is_user,&is_group); + local_entry_template = is_user ? local_user_entry_template : local_group_entry_template; + /* Create a new entry */ + /* Give it its DN and username */ + entry_string = slapi_ch_smprintf(local_entry_template,slapi_sdn_get_dn(local_sdn),username, username); + if (NULL == entry_string) + { + goto error; + } + local_entry = slapi_str2entry(entry_string, 0); + slapi_ch_free((void**)&entry_string); + if (NULL == local_entry) + { + goto error; + } + /* Map the appropriate attributes sourced from the remote entry */ + for (rc = slapi_entry_first_attr(remote_entry, &attr); rc == 0; + rc = slapi_entry_next_attr(remote_entry, attr, &attr)) + { + Slapi_Value *value = NULL; + char *type = NULL; + Slapi_ValueSet *vs = NULL; + int mapdn = 0; + + slapi_attr_get_type( attr, &type ); + slapi_attr_get_valueset(attr,&vs); + + if ( is_straight_mapped_attr(type,is_user) ) + { + /* copy over the attr values */ + slapi_entry_add_valueset(local_entry,type,vs); + } else + { + char *new_type = NULL; + + windows_map_attr_name(type , 0 /* from windows */, is_user, 1 /* create */, &new_type, &mapdn); + if (new_type) + { + if (mapdn) + { + Slapi_ValueSet *mapped_values = NULL; + map_dn_values(prp,vs,&mapped_values, 0 /* from windows */); + if (mapped_values) + { + slapi_entry_add_valueset(local_entry,new_type,mapped_values); + slapi_valueset_free(mapped_values); + mapped_values = NULL; + } + } else + { + slapi_entry_add_valueset(local_entry,new_type,vs); + } + slapi_ch_free((void**)&new_type); + } + } + if (vs) + { + slapi_valueset_free(vs); + vs = NULL; + } + } + /* Copy over the GUID */ + guid_str = extract_guid_from_entry(remote_entry); + if (guid_str) + { + slapi_entry_add_string(local_entry,"ntUniqueId",guid_str); + } else + { + slapi_log_error(SLAPI_LOG_REPL, windows_repl_plugin_name, + "extract_guid_from_entry entry %s failed to extract the guid\n", slapi_sdn_get_dn(local_sdn)); + /* Fatal error : need the guid */ + goto error; + } + /* Store it */ + windows_dump_entry("Adding new local entry",local_entry); + pb = slapi_pblock_new(); + slapi_add_entry_internal_set_pb(pb, local_entry, NULL,repl_get_plugin_identity(PLUGIN_MULTIMASTER_REPLICATION),0); + slapi_add_internal_pb(pb); + slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &retval); + + if (retval) { + slapi_log_error(SLAPI_LOG_REPL, windows_repl_plugin_name, + "add operation of entry %s returned: %d\n", slapi_sdn_get_dn(local_sdn), retval); + } +error: + if (pb) + { + slapi_pblock_destroy(pb); + } + if (username) + { + slapi_ch_free((void**)&username); + } + LDAPDebug( LDAP_DEBUG_TRACE, "<= windows_create_local_entry\n", 0, 0, 0 ); + return retval; +} + +static int +windows_update_local_entry(Private_Repl_Protocol *prp,Slapi_Entry *remote_entry,Slapi_Entry *local_entry) +{ + int retval = 0; + Slapi_Mods smods = {0}; + Slapi_Attr *attr = NULL; + int do_modify = 0; + int is_user = 0; + int is_group = 0; + int rc = 0; + Slapi_PBlock *pb = NULL; + /* Iterate over the attributes on the remote entry, updating the local entry where appropriate */ + LDAPDebug( LDAP_DEBUG_TRACE, "=> windows_update_local_entry\n", 0, 0, 0 ); + + windows_is_remote_entry_user_or_group(remote_entry,&is_user,&is_group); + + slapi_mods_init (&smods, 0); + for (rc = slapi_entry_first_attr(remote_entry, &attr); rc == 0; + rc = slapi_entry_next_attr(remote_entry, attr, &attr)) + { + int is_present_local = 0; + Slapi_Value *value = NULL; + char *type = NULL; + Slapi_ValueSet *vs = NULL; + char *local_type = NULL; + Slapi_Attr *local_attr = NULL; + int is_guid = 0; + int mapdn = 0; + + + slapi_attr_get_type( attr, &type ); + slapi_attr_get_valueset(attr,&vs); + + /* First determine what we will do with this attr */ + /* If it's a GUID, we need to take special action */ + if (0 == slapi_attr_type_cmp(type,"objectGuid",SLAPI_TYPE_CMP_SUBTYPE)) + { + is_guid = 1; + local_type = slapi_ch_strdup("ntUniqueId"); + } else + { + if ( is_straight_mapped_attr(type,is_user) ) { + local_type = slapi_ch_strdup(type); + } else { + windows_map_attr_name(type , 0 /* from windows */, is_user, 0 /* not create */, &local_type, &mapdn); + } + is_guid = 0; + } + if (NULL == local_type) + { + /* Means we do not map this attribute */ + if (vs) + { + slapi_valueset_free(vs); + vs = NULL; + } + continue; + } + slapi_entry_attr_find(local_entry,local_type,&local_attr); + is_present_local = (NULL == local_attr) ? 0 : 1; + /* Is the attribute present on the local entry ? */ + if (is_present_local && !is_guid) + { + int values_equal = attr_compare_equal(attr,local_attr); + /* If it is then we need to replace the local values with the remote values if they are different */ + if (!values_equal) + { + if (mapdn) + { + Slapi_ValueSet *mapped_values = NULL; + map_dn_values(prp,vs,&mapped_values, 1 /* to windows */); + if (mapped_values) + { + slapi_mods_add_mod_values(&smods,LDAP_MOD_REPLACE,local_type,valueset_get_valuearray(mapped_values)); + slapi_valueset_free(mapped_values); + mapped_values = NULL; + } + } else + { + slapi_mods_add_mod_values(&smods,LDAP_MOD_REPLACE,local_type,valueset_get_valuearray(vs)); + } + do_modify = 1; + } else + { + slapi_log_error(SLAPI_LOG_REPL, windows_repl_plugin_name, + "windows_update_local_entry: %s, %s : values are equal\n", slapi_sdn_get_dn(slapi_entry_get_sdn_const(local_entry)), local_type); + } + } else + { + if (!is_present_local) + { + /* If it is currently absent, then we add the value from the remote entry */ + if (is_guid) + { + /* Translate the guid value */ + char *guid = extract_guid_from_entry(remote_entry); + if (guid) + { + slapi_mods_add_string(&smods,LDAP_MOD_ADD,local_type,guid); + slapi_ch_free((void**)&guid); + } + } else + { + slapi_mods_add_mod_values(&smods,LDAP_MOD_ADD,local_type,valueset_get_valuearray(vs)); + } + do_modify = 1; + } + } + if (vs) + { + slapi_valueset_free(vs); + vs = NULL; + } + if (local_type) + { + slapi_ch_free((void**)&local_type); + local_type = NULL; + } + } + /* Now perform the modify if we need to */ + if (do_modify) + { + int rc = 0; + pb = slapi_pblock_new(); + if (pb) + { + slapi_log_error(SLAPI_LOG_REPL, windows_repl_plugin_name, + "modifying entry: %s\n", slapi_sdn_get_dn(slapi_entry_get_sdn_const(local_entry))); + slapi_modify_internal_set_pb (pb, slapi_entry_get_ndn(local_entry), slapi_mods_get_ldapmods_byref(&smods), NULL, NULL, + repl_get_plugin_identity (PLUGIN_MULTIMASTER_REPLICATION), 0); + slapi_modify_internal_pb (pb); + slapi_pblock_get (pb, SLAPI_PLUGIN_INTOP_RESULT, &rc); + if (rc) + { + slapi_log_error(SLAPI_LOG_FATAL, windows_repl_plugin_name, + "windows_update_local_entry: failed to modify entry %s\n", slapi_sdn_get_dn(slapi_entry_get_sdn_const(local_entry))); + } + slapi_pblock_destroy(pb); + } else + { + slapi_log_error(SLAPI_LOG_FATAL, windows_repl_plugin_name, + "failed to make pb in windows_update_local_entry\n"); + } + + } else + { + slapi_log_error(SLAPI_LOG_REPL, windows_repl_plugin_name, + "no mods generated for entry: %s\n", slapi_sdn_get_dn(slapi_entry_get_sdn_const(remote_entry))); + } + slapi_mods_done(&smods); + LDAPDebug( LDAP_DEBUG_TRACE, "<= windows_update_local_entry: %d\n", retval, 0, 0 ); + return retval; +} + +static int +windows_process_total_add(Private_Repl_Protocol *prp,Slapi_Entry *e, Slapi_DN* remote_dn) +{ + int retval = 0; + LDAPMod **entryattrs = NULL; + Slapi_Entry *mapped_entry = NULL; + char *password = NULL; + const Slapi_DN* local_dn = NULL; + /* First map the entry */ + local_dn = slapi_entry_get_sdn_const(e); + retval = windows_create_remote_entry(prp, e, remote_dn, &mapped_entry, &password); + /* Convert entry to mods */ + if (0 == retval && mapped_entry) + { + (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)); + retval = CONN_LOCAL_ERROR; + } + else + { + windows_log_add_entry_remote(local_dn, remote_dn); + retval = windows_conn_send_add(prp->conn, slapi_sdn_get_dn(remote_dn), entryattrs, NULL, NULL /* returned controls */); + /* It's possible that the entry already exists in AD, in which case we fall back to modify it */ + if (retval) + { + 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; + } + } + return retval; +} + +static int +windows_process_total_delete(Private_Repl_Protocol *prp,Slapi_Entry *e, Slapi_DN* remote_dn) +{ + int retval = 0; + if (delete_remote_entry_allowed(e)) + { + retval = windows_conn_send_delete(prp->conn, slapi_sdn_get_dn(remote_dn), NULL, NULL /* returned controls */); + } + return retval; +} + +/* Entry point for the total protocol */ +int windows_process_total_entry(Private_Repl_Protocol *prp,Slapi_Entry *e) +{ + int retval = 0; + int is_ours = 0; + int is_tombstone = 0; + Slapi_DN *remote_dn = NULL; + int missing_entry = 0; + const Slapi_DN *local_dn = slapi_entry_get_sdn_const(e); + /* First check if the entry is for us */ + is_ours = is_subject_of_agreemeent_local(e, prp->agmt); + slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, + "%s: windows_process_total_entry: Looking dn=\"%s\" (%s)\n", + agmt_get_long_name(prp->agmt), slapi_sdn_get_dn(slapi_entry_get_sdn_const(e)), is_ours ? "ours" : "not ours"); + if (is_ours) + { + retval = map_entry_dn_outbound(e,&remote_dn,prp,&missing_entry); + if (retval || NULL == remote_dn) + { + slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, + "%s: windows_replay_update: failed map dn for total update dn=\"%s\"\n", + agmt_get_long_name(prp->agmt), slapi_sdn_get_dn(local_dn)); + goto error; + } + /* Either the entry is a tombstone, or not a tombstone */ + if (is_tombstone) + { + retval = windows_process_total_delete(prp,e,remote_dn); + } else + { + retval = windows_process_total_add(prp,e,remote_dn); + } + } + if (remote_dn) + { + slapi_sdn_free(&remote_dn); + } +error: + return retval; +} + +int +windows_search_local_entry_by_uniqueid(Private_Repl_Protocol *prp, const char *uniqueid, char ** attrs, Slapi_Entry **ret_entry , void * component_identity) +{ + Slapi_Entry **entries = NULL; + Slapi_PBlock *int_search_pb = NULL; + int rc = 0; + char *filter_string = NULL; + const Slapi_DN *local_subtree = NULL; + + *ret_entry = NULL; + local_subtree = windows_private_get_directory_subtree(prp->agmt); + filter_string = PR_smprintf("(&(|(objectclass=*)(objectclass=ldapsubentry)(objectclass=nsTombstone))(nsUniqueid=%s))",uniqueid); + int_search_pb = slapi_pblock_new (); + slapi_search_internal_set_pb ( int_search_pb, slapi_sdn_get_dn(local_subtree), LDAP_SCOPE_SUBTREE, filter_string, + attrs , + 0 /* attrsonly */, NULL /* controls */, + NULL /* uniqueid */, + component_identity, 0 /* actions */ ); + slapi_search_internal_pb ( int_search_pb ); + slapi_pblock_get( int_search_pb, SLAPI_PLUGIN_INTOP_RESULT, &rc ); + if ( LDAP_SUCCESS == rc ) { + slapi_pblock_get( int_search_pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &entries ); + if ( NULL != entries && NULL != entries[ 0 ]) { + Slapi_Entry *temp_entry = NULL; + temp_entry = entries[ 0 ]; + *ret_entry = slapi_entry_dup(temp_entry); + } else { + /* No entry there */ + rc = LDAP_NO_SUCH_OBJECT; + } + } + slapi_free_search_results_internal(int_search_pb); + slapi_pblock_destroy(int_search_pb); + int_search_pb = NULL; + if (filter_string) + { + PR_smprintf_free(filter_string); + } + return rc; +} + +static int +windows_get_local_entry_by_uniqueid(Private_Repl_Protocol *prp,const char* uniqueid,Slapi_Entry **local_entry) +{ + int retval = ENTRY_NOTFOUND; + Slapi_Entry *new_entry = NULL; + windows_search_local_entry_by_uniqueid( prp, uniqueid, NULL, &new_entry, + repl_get_plugin_identity (PLUGIN_MULTIMASTER_REPLICATION)); + if (new_entry) + { + *local_entry = new_entry; + retval = 0; + } + return retval; +} + +static int +windows_get_local_entry(const Slapi_DN* local_dn,Slapi_Entry **local_entry) +{ + int retval = ENTRY_NOTFOUND; + Slapi_Entry *new_entry = NULL; + slapi_search_internal_get_entry( (Slapi_DN*)local_dn, NULL, &new_entry, + repl_get_plugin_identity (PLUGIN_MULTIMASTER_REPLICATION)); + if (new_entry) + { + *local_entry = new_entry; + retval = 0; + } + return retval; +} + +static int +windows_process_dirsync_entry(Private_Repl_Protocol *prp,Slapi_Entry *e, int is_total) +{ + Slapi_DN* local_sdn = NULL; + int rc = 0; + + /* deleted users are outside the 'correct container'. + They live in cn=deleted objects, windows_private_get_directory_subtree( prp->agmt) */ + + if (is_tombstone(e)) + { + rc = map_tombstone_dn_inbound(e, &local_sdn, prp->agmt); + if ((0 == rc) && local_sdn) + { + /* Go ahead and delte the local peer */ + rc = windows_delete_local_entry(local_sdn); + slapi_sdn_free(&local_sdn); + } else + { + slapi_log_error(SLAPI_LOG_FATAL, windows_repl_plugin_name,"%s: windows_process_dirsync_entry: failed to map tombstone dn.\n",agmt_get_long_name(prp->agmt)); + } + } else + { + /* Is this entry one we should be interested in ? */ + if (is_subject_of_agreemeent_remote(e,prp->agmt)) + { + /* First make its local DN */ + rc = map_entry_dn_inbound(e, &local_sdn, prp->agmt); + if ((0 == rc) && local_sdn) + { + Slapi_Entry *local_entry = NULL; + /* Get the local entry if it exists */ + rc = windows_get_local_entry(local_sdn,&local_entry); + if ((0 == rc) && local_entry) + { + /* Since the entry exists we should now make it match the entry we received from AD */ + rc = windows_update_local_entry(prp, e, local_entry); + slapi_entry_free(local_entry); + if (rc) { + /* Something bad happened */ + slapi_log_error(SLAPI_LOG_REPL, windows_repl_plugin_name,"%s: windows_process_dirsync_entry: failed to update inbound entry.\n",agmt_get_long_name(prp->agmt)); + } + } else + { + /* If it doesn't exist, try to make it */ + windows_create_local_entry(prp,e,local_sdn); + } + slapi_sdn_free(&local_sdn); + } else + { + /* We should have been able to map the DN, so this is an error */ + slapi_log_error(SLAPI_LOG_REPL, windows_repl_plugin_name,"%s: windows_process_dirsync_entry: failed to map inbound entry.\n",agmt_get_long_name(prp->agmt)); + } + } /* subject of agreement */ + } /* is tombstone */ + return rc; +} + +void +windows_dirsync_inc_run(Private_Repl_Protocol *prp) + { + + int rc = 0; + int msgid=0; + Slapi_PBlock *pb = NULL; + Slapi_Filter *filter_user = NULL; + Slapi_Filter *filter_user_deleted = NULL; + Slapi_Filter *filter_group = NULL; + Slapi_Filter *filter_group_deleted = NULL; + int done = 0; + + LDAPDebug( LDAP_DEBUG_TRACE, "=> windows_dirsync_inc_run\n", 0, 0, 0 ); + while (!done) { + + Slapi_Entry *e = NULL; + int filter_ret = 0; + PRBool create_users_from_dirsync = windows_private_create_users(prp->agmt); + + rc = send_dirsync_search(prp->conn); + if (rc != CONN_OPERATION_SUCCESS) + { + slapi_log_error(SLAPI_LOG_FATAL, windows_repl_plugin_name, + "failed to send dirsync search request: %d\n", rc); + goto error; + } + + while ( (e = windows_conn_get_search_result(prp->conn) ) != NULL) + { + rc = windows_process_dirsync_entry(prp,e,0); + if (e) + { + slapi_entry_free(e); + } + } /* While entry != NULL */ + if (!windows_private_dirsync_has_more(prp->agmt)) + { + done = 1; + } + } /* While !done */ +error: + LDAPDebug( LDAP_DEBUG_TRACE, "<= windows_dirsync_inc_run\n", 0, 0, 0 ); +} + diff --git a/ldap/servers/plugins/replication/windows_replica.c b/ldap/servers/plugins/replication/windows_replica.c deleted file mode 100644 index fc86cbdd..00000000 --- a/ldap/servers/plugins/replication/windows_replica.c +++ /dev/null @@ -1,1213 +0,0 @@ -/** BEGIN COPYRIGHT BLOCK - * Copyright (C) 2001 Sun Microsystems, Inc. Used by permission. - * Copyright (C) 2005 Red Hat, Inc. - * All rights reserved. - * END COPYRIGHT BLOCK **/ -/* repl5_replica.c */ - -#include "slapi-plugin.h" -#include "repl.h" /* ONREPL - this is bad */ -#include "repl5.h" -#include "windowsrepl.h" -#include "repl_shared.h" -#include "csnpl.h" -#include "cl5_api.h" - -/* from proto-slap.h */ -int g_get_shutdown(); - -#define RUV_SAVE_INTERVAL (30 * 1000) /* 30 seconds */ -#define START_UPDATE_DELAY 2 /* 2 second */ -#define START_REAP_DELAY 3600 /* 1 hour */ - -#define REPLICA_RDN "cn=windowsreplica" -#define CHANGELOG_RDN "cn=legacy changelog" - -/* - * A replica is a locally-held copy of a portion of the DIT. - */ -struct replica { - Slapi_DN *repl_root; /* top of the replicated area */ - char *repl_name; /* unique replica name */ - PRBool new_name; /* new name was generated - need to be saved */ - ReplicaUpdateDNList updatedn_list; /* list of dns with which a supplier should bind - to update this replica */ - ReplicaType repl_type; /* is this replica read-only ? */ - PRBool legacy_consumer; /* if true, this replica is supplied by 4.0 consumer */ - char* legacy_purl; /* partial url of the legacy supplier */ - ReplicaId repl_rid; /* replicaID */ - Object *repl_ruv; /* replica update vector */ - PRBool repl_ruv_dirty; /* Dirty flag for ruv */ - CSNPL *min_csn_pl; /* Pending list for minimal CSN */ - void *csn_pl_reg_id; /* registration assignment for csn callbacks */ - unsigned long repl_state_flags; /* state flags */ - PRUint32 repl_flags; /* persistent, externally visible flags */ - PRLock *repl_lock; /* protects entire structure */ - Slapi_Eq_Context repl_eqcxt_rs; /* context to cancel event that saves ruv */ - Slapi_Eq_Context repl_eqcxt_tr; /* context to cancel event that reaps tombstones */ - Object *repl_csngen; /* CSN generator for this replica */ - PRBool repl_csn_assigned; /* Flag set when new csn is assigned. */ - PRUint32 repl_purge_delay; /* When purgeable, CSNs are held on to for this many extra seconds */ - PRBool tombstone_reap_stop; /* TRUE when the tombstone reaper should stop */ - PRBool tombstone_reap_active; /* TRUE when the tombstone reaper is running */ - long tombstone_reap_interval; /* Time in seconds between tombstone reaping */ - Slapi_ValueSet *repl_referral; /* A list of administrator provided referral URLs */ - PRBool state_update_inprogress; /* replica state is being updated */ - PRLock *agmt_lock; /* protects agreement creation, start and stop */ - char *locking_purl; /* supplier who has exclusive access */ - - - Object *consumer_repl_ruv; /* tracks location in changelog for changes to send to active directoroy */ - -}; - - -typedef struct reap_callback_data -{ - int rc; - unsigned long num_entries; - unsigned long num_purged_entries; - CSN *purge_csn; - PRBool *tombstone_reap_stop; -} reap_callback_data; - - - - -/* Forward declarations of helper functions*/ -static Slapi_Entry* _windows_replica_get_config_entry (const Slapi_DN *root); -static int _windows_replica_check_validity (const Replica *r); -static int _windows_replica_init_from_config (Replica *r, Slapi_Entry *e, char *errortext); -static int __replica_update_entry (Replica *r, Slapi_Entry *e, char *errortext); -static int __replica_configure_ruv (Replica *r, PRBool isLocked); -static void _windows_replica_update_state (time_t when, void *arg); -static char * _replica_get_config_dn (const Slapi_DN *root); -static char * __replica_type_as_string (const Replica *r); -static int replica_create_ruv_tombstone(Replica *r); -static void assign_csn_callback(const CSN *csn, void *data); -static void abort_csn_callback(const CSN *csn, void *data); -static void eq_cb_reap_tombstones(time_t when, void *arg); -static CSN *_replica_get_purge_csn_nolock (const Replica *r); -static void replica_get_referrals_nolock (const Replica *r, char ***referrals); -static void replica_clear_legacy_referrals (const Slapi_DN *repl_root_sdn, char **referrals, const char *state); -static void replica_remove_legacy_attr (const Slapi_DN *repl_root_sdn, const char *attr); -static int replica_log_ruv_elements_nolock (const Replica *r); -static void replica_replace_ruv_tombstone(Replica *r); -static void start_agreements_for_replica (Replica *r, PRBool start); -void replica_consumer_set_ruv (Replica *r, RUV *ruv) ; - -/* PRBool */ -/* replica_is_state_flag_set(Replica *r, PRInt32 flag) */ -/* { */ -/* PR_ASSERT(r); */ -/* if (r) */ -/* return (r->repl_state_flags & flag); */ -/* else */ -/* return PR_FALSE; */ -/* } */ - -/* Replica * */ -/* windows_replica_new(const Slapi_DN *root) */ -/* { */ -/* Replica *r = NULL; */ -/* Slapi_Entry *e = NULL; */ -/* char errorbuf[BUFSIZ]; */ -/* char ebuf[BUFSIZ]; */ - -/* PR_ASSERT (root); */ - -/* /\* check if there is a replica associated with the tree *\/ */ -/* e = _windows_replica_get_config_entry (root); */ -/* if (e) */ -/* { */ -/* errorbuf[0] = '\0'; */ -/* r = windows_replica_new_from_entry(e, errorbuf, */ -/* PR_FALSE /\* not a newly added entry *\/); */ - -/* if (NULL == r) */ -/* { */ -/* slapi_log_error(SLAPI_LOG_FATAL, windows_repl_plugin_name, "Unable to " */ -/* "configure replica %s: %s\n", */ -/* escape_string(slapi_sdn_get_dn(root), ebuf), */ -/* errorbuf); */ -/* } */ - -/* slapi_entry_free (e); */ -/* } */ - -/* return r; */ -/* } */ - -/* -int windows_replica_start_agreement -(Replica *r, Repl_Agmt *ra) -{ - int ret = 0; - - if (r == NULL) return -1; - - PR_Lock(r->agmt_lock); - - slapi_log_error(SLAPI_LOG_FATAL, windows_repl_plugin_name, "windows_replica_start_agreement: state_flag =%d\n", - !replica_is_state_flag_set(r, REPLICA_AGREEMENTS_DISABLED)); - - - if (!replica_is_state_flag_set(r, REPLICA_AGREEMENTS_DISABLED)) { - ret = windows_agmt_start(ra); - slapi_log_error(SLAPI_LOG_FATAL, windows_repl_plugin_name, "windows_replica_start_agreement: rc=%d\n", ret); - ret = 0; - } - - PR_Unlock(r->agmt_lock); - - return ret; -} */ - - -/* - * A callback function registed as op->o_replica_attr_handler and - * called by backend ops to get replica attributes. - */ -int -__replica_get_attr ( Slapi_PBlock *pb, const char* type, void *value ) -{ - int rc = -1; - - Object *replica_obj; - replica_obj = replica_get_replica_for_op (pb); - if (NULL != replica_obj) - { - Replica *replica = (Replica*) object_get_data (replica_obj); - if ( NULL != replica ) - { - if (strcasecmp (type, type_replicaTombstonePurgeInterval) == 0) - { - *((int*)value) = replica->tombstone_reap_interval; - rc = 0; - } - else if (strcasecmp (type, type_replicaPurgeDelay) == 0) - { - *((int*)value) = replica->repl_purge_delay; - rc = 0; - } - } - object_release (replica_obj); - } - - return rc; -} - - -static Slapi_Entry* -_windows_replica_get_config_entry (const Slapi_DN *root) -{ - int rc = 0; - char *dn = NULL; - Slapi_Entry **entries; - Slapi_Entry *e = NULL; - Slapi_PBlock *pb = NULL; - - dn = _replica_get_config_dn (root); - pb = slapi_pblock_new (); - - slapi_search_internal_set_pb (pb, dn, LDAP_SCOPE_BASE, "objectclass=*", NULL, 0, NULL, - NULL, repl_get_plugin_identity (PLUGIN_WINDOWS_REPLICATION), 0); - slapi_search_internal_pb (pb); - slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &rc); - if (rc == 0) - { - slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &entries); - e = slapi_entry_dup (entries [0]); - } - - slapi_free_search_results_internal(pb); - slapi_pblock_destroy (pb); - slapi_ch_free_string(&dn); - - return e; -} - - -static char* -_replica_get_config_dn (const Slapi_DN *root) -{ - char *dn; - const char *mp_base = slapi_get_mapping_tree_config_root (); - int len; - - PR_ASSERT (root); - - len = strlen (REPLICA_RDN) + strlen (slapi_sdn_get_dn (root)) + - strlen (mp_base) + 8; /* 8 = , + cn= + \" + \" + , + \0 */ - - dn = (char*)slapi_ch_malloc (len); - sprintf (dn, "%s,cn=\"%s\",%s", REPLICA_RDN, slapi_sdn_get_dn (root), mp_base); - - return dn; -} - -Replica * -windows_replica_new_from_entry (Slapi_Entry *e, char *errortext, PRBool is_add_operation) -{ - int rc = 0; - Replica *r; - RUV *ruv; - RUV *consumer_ruv; - char *repl_name = NULL; - - if (e == NULL) - { - if (NULL != errortext) - { - sprintf (errortext, "NULL entry"); - } - return NULL; - } - - r = (Replica *)slapi_ch_calloc(1, sizeof(Replica)); - - if ((r->repl_lock = PR_NewLock()) == NULL) - { - if (NULL != errortext) - { - sprintf (errortext, "failed to create replica lock"); - } - rc = -1; - goto done; - } - - if ((r->agmt_lock = PR_NewLock()) == NULL) - { - if (NULL != errortext) - { - sprintf (errortext, "failed to create replica lock"); - } - rc = -1; - goto done; - } - - /* read parameters from the replica config entry */ - rc = _windows_replica_init_from_config (r, e, errortext); - if (rc != 0) - { - goto done; - } - - /* configure ruv */ - rc = __replica_configure_ruv (r, PR_FALSE); - if (rc != 0) - { - goto done; - } - - /* If smallest csn exists in RUV for our local replica, it's ok to begin iteration */ - ruv = (RUV*) object_get_data (r->repl_ruv); //XXX - PR_ASSERT (ruv); - - consumer_ruv = ruv_dup(ruv); - replica_consumer_set_ruv(r, consumer_ruv); - - if (is_add_operation) - { - /* - * This is called by an ldap add operation. - * Update the entry to contain information generated - * during replica initialization - */ - rc = __replica_update_entry (r, e, errortext); - } - else - { - /* - * Entry is already in dse.ldif - update it on the disk - * (done by the update state event scheduled below) - */ - } - if (rc != 0) - goto done; - - /* ONREPL - the state update can occur before the entry is added to the DIT. - In that case the updated would fail but nothing bad would happen. The next - scheduled update would save the state */ - repl_name = slapi_ch_strdup (r->repl_name); - r->repl_eqcxt_rs = slapi_eq_repeat(_windows_replica_update_state, repl_name, - current_time () + START_UPDATE_DELAY, RUV_SAVE_INTERVAL); - - if (r->tombstone_reap_interval > 0) - { - /* - * Reap Tombstone should be started some time after the plugin started. - * This will allow the server to fully start before consuming resources. - */ - repl_name = slapi_ch_strdup (r->repl_name); - // XXX r->repl_eqcxt_tr = slapi_eq_repeat(eq_cb_reap_tombstones, repl_name, current_time() + START_REAP_DELAY, 1000 * r->tombstone_reap_interval); - } - - if (r->legacy_consumer) - { - char ebuf[BUFSIZ]; - - legacy_consumer_init_referrals (r); - slapi_log_error(SLAPI_LOG_REPL, windows_repl_plugin_name, "replica_new_from_entry: " - "replica for %s was configured as legacy consumer\n", - escape_string(slapi_sdn_get_dn(r->repl_root),ebuf)); - } - -done: - if (rc != 0 && r) - { - replica_destroy ((void**)&r); - } - - return r; - - - -} - -static int -_windows_replica_init_from_config (Replica *r, Slapi_Entry *e, char *errortext) -{ - int rc; - Slapi_Attr *attr; - char *val; - CSNGen *gen; - char buf [BUFSIZ]; - char *errormsg = errortext? errortext : buf; - Slapi_Attr *a = NULL; - char dnescape[BUFSIZ]; /* for escape_string */ - - PR_ASSERT (r && e); - - /* get replica root */ - val = slapi_entry_attr_get_charptr (e, attr_replicaRoot); - if (val == NULL) - { - sprintf (errormsg, "failed to retrieve %s attribute from (%s)\n", - attr_replicaRoot, - escape_string((char*)slapi_entry_get_dn ((Slapi_Entry*)e), dnescape)); - slapi_log_error(SLAPI_LOG_FATAL, windows_repl_plugin_name, "_replica_init_from_config: %s\n", - errormsg); - - return -1; - } - - r->repl_root = slapi_sdn_new_dn_passin (val); - - /* get replica type */ - val = slapi_entry_attr_get_charptr (e, attr_replicaType); - if (val) - { - r->repl_type = atoi(val); - slapi_ch_free ((void**)&val); - } - else - { - r->repl_type = REPLICA_TYPE_READONLY; - } - - /* get legacy consumer flag */ - val = slapi_entry_attr_get_charptr (e, type_replicaLegacyConsumer); - if (val) - { - if (strcasecmp (val, "on") == 0 || strcasecmp (val, "yes") == 0 || - strcasecmp (val, "true") == 0 || strcasecmp (val, "1") == 0) - { - r->legacy_consumer = PR_TRUE; - } - else - { - r->legacy_consumer = PR_FALSE; - } - - slapi_ch_free ((void**)&val); - } - else - { - r->legacy_consumer = PR_FALSE; - } - - /* get replica flags */ - r->repl_flags = slapi_entry_attr_get_ulong(e, attr_flags); - - /* get replicaid */ - /* the replica id is ignored for read only replicas and is set to the - special value READ_ONLY_REPLICA_ID */ - if (r->repl_type == REPLICA_TYPE_READONLY) - { - r->repl_rid = READ_ONLY_REPLICA_ID; - slapi_entry_attr_set_uint(e, attr_replicaId, (unsigned int)READ_ONLY_REPLICA_ID); - } - /* a replica id is required for updatable and primary replicas */ - else if (r->repl_type == REPLICA_TYPE_UPDATABLE || - r->repl_type == REPLICA_TYPE_PRIMARY) - { - if ((val = slapi_entry_attr_get_charptr (e, attr_replicaId))) - { - int temprid = atoi (val); - slapi_ch_free ((void**)&val); - if (temprid <= 0 || temprid >= READ_ONLY_REPLICA_ID) - { -/* sprintf (errormsg, */ -/* "attribute %s must have a value greater than 0 " */ -/* "and less than %d: entry %s", */ -/* attr_replicaId, READ_ONLY_REPLICA_ID, */ -/* escape_string((char*)slapi_entry_get_dn ((Slapi_Entry*)e), */ -/* dnescape)); */ -/* slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, */ -/* "_replica_init_from_config: %s\n", */ -/* errormsg); */ -/* return -1; */ - } - else - { - r->repl_rid = (ReplicaId)temprid; - } - } - else - { - sprintf (errormsg, "failed to retrieve required %s attribute from %s", - attr_replicaId, - escape_string((char*)slapi_entry_get_dn ((Slapi_Entry*)e), - dnescape)); - slapi_log_error(SLAPI_LOG_FATAL, windows_repl_plugin_name, - "_replica_init_from_config: %s\n", - errormsg); - return -1; - } - } - - attr = NULL; - rc = slapi_entry_attr_find(e, attr_state, &attr); - gen = csngen_new (r->repl_rid, attr); - if (gen == NULL) - { - sprintf (errormsg, "failed to create csn generator for replica (%s)", - escape_string((char*)slapi_entry_get_dn ((Slapi_Entry*)e), - dnescape)); - slapi_log_error(SLAPI_LOG_FATAL, windows_repl_plugin_name, - "_replica_init_from_config: %s\n", - errormsg); - return -1; - } - r->repl_csngen = object_new((void*)gen, (FNFree)csngen_free); - - /* Hook generator so we can maintain min/max CSN info */ - r->csn_pl_reg_id = csngen_register_callbacks(gen, assign_csn_callback, r, abort_csn_callback, r); - - /* get replication bind dn */ - r->updatedn_list = replica_updatedn_list_new(e); - - /* get replica name */ - val = slapi_entry_attr_get_charptr (e, attr_replicaName); - if (val) { - r->repl_name = val; - } - else - { - rc = slapi_uniqueIDGenerateString (&r->repl_name); - if (rc != UID_SUCCESS) - { - sprintf (errormsg, "failed to assign replica name for replica (%s); " - "uuid generator error - %d ", - escape_string((char*)slapi_entry_get_dn ((Slapi_Entry*)e), dnescape), - rc); - slapi_log_error(SLAPI_LOG_FATAL, windows_repl_plugin_name, "_replica_init_from_config: %s\n", - errormsg); - return -1; - } - else - r->new_name = PR_TRUE; - } - - /* get the list of referrals */ - slapi_entry_attr_find( e, attr_replicaReferral, &attr ); - if(attr!=NULL) - { - slapi_attr_get_valueset(attr, &r->repl_referral); - } - - /* - * Set the purge offset (default 7 days). This is the extra - * time we allow purgeable CSNs to stick around, in case a - * replica regresses. Could also be useful when LCUP happens, - * since we don't know about LCUP replicas, and they can just - * turn up whenever they want to. - */ - if (slapi_entry_attr_find(e, type_replicaPurgeDelay, &a) == -1) - { - /* No purge delay provided, so use default */ - r->repl_purge_delay = 60 * 60 * 24 * 7; /* One week, in seconds */ - } - else - { - r->repl_purge_delay = slapi_entry_attr_get_uint(e, type_replicaPurgeDelay); - } - - if (slapi_entry_attr_find(e, type_replicaTombstonePurgeInterval, &a) == -1) - { - /* No reap interval provided, so use default */ - r->tombstone_reap_interval = 3600 * 24; /* One day */ - } - else - { - r->tombstone_reap_interval = slapi_entry_attr_get_int(e, type_replicaTombstonePurgeInterval); - } - - r->tombstone_reap_stop = r->tombstone_reap_active = PR_FALSE; - - return (_windows_replica_check_validity (r)); -} - - -static int -_windows_replica_check_validity (const Replica *r) -{ - PR_ASSERT (r); - - if (r->repl_root == NULL || r->repl_type == 0 || - r->repl_rid > MAX_REPLICA_ID || r->repl_name == NULL) - { - return -1; - } - else - { - return 0; - } -} - - -/* NOTE - this is the only non-api function that performs locking because - it is called by the event queue */ -static void -_windows_replica_update_state (time_t when, void *arg) -{ - int rc; - const char *replica_name = (const char *)arg; - Object *replica_object = NULL; - Replica *r; - Slapi_Mod smod; - LDAPMod *mods[3]; - Slapi_PBlock *pb = NULL; - char *dn = NULL; - - if (NULL == replica_name) - return; - - /* - * replica_get_by_name() will acquire the replica object - * and that could prevent the replica from being destroyed - * until the object_release is called. - */ - replica_object = replica_get_by_name(replica_name); - if (NULL == replica_object) - { - return; - } - - /* We have a reference, so replica won't vanish on us. */ - r = (Replica *)object_get_data(replica_object); - if (NULL == r) - { - goto done; - } - - PR_Lock(r->repl_lock); - - /* replica state is currently being updated - or no CSN was assigned - bail out */ - if (r->state_update_inprogress) - { - PR_Unlock(r->repl_lock); - goto done; - } - - /* This might be a consumer */ - if (!r->repl_csn_assigned) - { - /* EY: the consumer needs to flush ruv to disk. */ - PR_Unlock(r->repl_lock); - replica_write_ruv(r); - goto done; - } - - /* ONREPL update csn generator state of an updatable replica only */ - /* ONREPL state always changes because we update time every second and - we write state to the disk less frequently */ - rc = csngen_get_state ((CSNGen*)object_get_data (r->repl_csngen), &smod); - if (rc != 0) - { - PR_Unlock(r->repl_lock); - goto done; - } - - r->state_update_inprogress = PR_TRUE; - r->repl_csn_assigned = PR_FALSE; - - dn = _replica_get_config_dn (r->repl_root); - pb = slapi_pblock_new(); - mods[0] = (LDAPMod*)slapi_mod_get_ldapmod_byref(&smod); - - /* we don't want to held lock during operations since it causes lock contention - and sometimes deadlock. So releasing lock here */ - - PR_Unlock(r->repl_lock); - - /* replica repl_name and new_name attributes do not get changed once - the replica is configured - so it is ok that they are outside replica lock */ - - /* write replica name if it has not been written before */ - if (r->new_name) - { - struct berval *vals[2]; - struct berval val; - LDAPMod mod; - - mods[1] = &mod; - - mod.mod_op = LDAP_MOD_REPLACE; - mod.mod_type = (char*)attr_replicaName; - mod.mod_bvalues = vals; - vals [0] = &val; - vals [1] = NULL; - val.bv_val = r->repl_name; - val.bv_len = strlen (val.bv_val); - mods[2] = NULL; - } - else - { - mods[1] = NULL; - } - - slapi_modify_internal_set_pb (pb, dn, mods, NULL, NULL, - repl_get_plugin_identity (PLUGIN_WINDOWS_REPLICATION), 0); - slapi_modify_internal_pb (pb); - slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &rc); - if (rc != LDAP_SUCCESS) - { - char ebuf[BUFSIZ]; - - slapi_log_error(SLAPI_LOG_FATAL, windows_repl_plugin_name, "_replica_update_state: " - "failed to update state of csn generator for replica %s: LDAP " - "error - %d\n", escape_string(slapi_sdn_get_dn(r->repl_root),ebuf), rc); - } - else - { - r->new_name = PR_FALSE; - } - - /* update RUV - performs its own locking */ - replica_write_ruv (r); - - /* since this is the only place this value is changed and we are - guaranteed that only one thread enters the function, its ok - to change it outside replica lock */ - r->state_update_inprogress = PR_FALSE; - - slapi_ch_free ((void**)&dn); - slapi_pblock_destroy (pb); - slapi_mod_done (&smod); - -done: - if (replica_object) - object_release (replica_object); -} - - -/* this function is called during server startup for each replica - to check whether the replica's data was reloaded offline and - whether replica's changelog needs to be reinitialized */ - -/* the function does not use replica lock but all functions it calls are - thread safe. Locking replica lock while calling changelog functions - causes a deadlock because changelog calls replica functions that - that lock the same lock */ -int windows_replica_check_for_data_reload (Replica *r, void *arg) -{ - int rc = 0; - RUV *upper_bound_ruv = NULL; - RUV *r_ruv = NULL; - Object *r_obj, *ruv_obj; - int cl_cover_be, be_cover_cl; - - PR_ASSERT (r); - - /* check that we have a changelog and if this replica logs changes */ - if (cl5GetState () == CL5_STATE_OPEN && r->repl_flags & REPLICA_LOG_CHANGES) - { - /* Compare new ruv to the purge ruv. If the new contains csns which - are smaller than those in purge ruv, we need to remove old and - create new changelog file for this replica. This is because we - will not have sufficient changes to incrementally update a consumer - to the current state of the supplier. */ - - rc = cl5GetUpperBoundRUV (r, &upper_bound_ruv); - if (rc != CL5_SUCCESS && rc != CL5_NOTFOUND) - { - return -1; - } - - if (upper_bound_ruv) - { - ruv_obj = replica_get_ruv (r); - r_ruv = object_get_data (ruv_obj); - PR_ASSERT (r_ruv); - - /* Compare new ruv to the changelog's upper bound ruv. We could only keep - the existing changelog if its upper bound is the same as replica's RUV. - This is because if changelog has changes not in RUV, they will be - eventually sent to the consumer's which will cause a state mismatch - (because the supplier does not actually contain the changes in its data store. - If, on the other hand, the changelog is not as up to date as the supplier, - it is not really useful since out of sync consumer's can't be brought - up to date using this changelog and hence will need to be reinitialized */ - - /* - * Actually we can ignore the scenario that the changelog's upper - * bound ruv covers data store's ruv for two reasons: (1) a change - * is always written to the changelog after it is committed to the - * data store; (2) a change will be ignored if the server has seen - * it before - this happens frequently at the beginning of replication - * sessions. - */ - - be_cover_cl = ruv_covers_ruv (r_ruv, upper_bound_ruv); - cl_cover_be = ruv_covers_ruv (upper_bound_ruv, r_ruv); - if (!cl_cover_be) - { - /* the data was reloaded and we can no longer use existing changelog */ - char ebuf[BUFSIZ]; - - /* create a temporary replica object to conform to the interface */ - r_obj = object_new (r, NULL); - - /* We can't use existing changelog - remove existing file */ - slapi_log_error(SLAPI_LOG_FATAL, windows_repl_plugin_name, "replica_check_for_data_reload: " - "Warning: data for replica %s was reloaded and it no longer matches the data " - "in the changelog (replica data %s changelog). Recreating the changelog file. This could affect replication " - "with replica's consumers in which case the consumers should be reinitialized.\n", - escape_string(slapi_sdn_get_dn(r->repl_root),ebuf), - ((!be_cover_cl && !cl_cover_be) ? "<>" : (!be_cover_cl ? "<" : ">")) ); - - rc = cl5DeleteDBSync (r_obj); - - object_release (r_obj); - - if (rc == CL5_SUCCESS) - { - /* log changes to mark starting point for replication */ - rc = replica_log_ruv_elements (r); - } - } - - object_release (ruv_obj); - } - else /* we have no changes currently logged for this replica */ - { - /* log changes to mark starting point for replication */ - rc = replica_log_ruv_elements (r); - } - } - - if (rc == 0) - { - /* reset mapping tree referrals based on new local RUV */ - // consumer5_set_mapping_tree_state_for_replica(r, NULL); - } - - if (upper_bound_ruv) - ruv_destroy (&upper_bound_ruv); - - return rc; -} - -/* This function updates the entry to contain information generated - during replica initialization. - Returns 0 if successful and -1 otherwise */ -static int -__replica_update_entry (Replica *r, Slapi_Entry *e, char *errortext) -{ - int rc; - Slapi_Mod smod; - Slapi_Value *val; - - PR_ASSERT (r); - - /* add attribute that stores state of csn generator */ - rc = csngen_get_state ((CSNGen*)object_get_data (r->repl_csngen), &smod); - if (rc != CSN_SUCCESS) - { - sprintf (errortext, "failed to get csn generator's state; csn error - %d", rc); - slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, - "_replica_update_entry: %s\n", errortext); - return -1; - } - - val = slapi_value_new_berval(slapi_mod_get_first_value(&smod)); - - rc = slapi_entry_add_value (e, slapi_mod_get_type (&smod), val); - - slapi_value_free(&val); - slapi_mod_done (&smod); - - if (rc != 0) - { - sprintf (errortext, "failed to update replica entry"); - slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, - "_replica_update_entry: %s\n", errortext); - return -1; - } - - /* add attribute that stores replica name */ - rc = slapi_entry_add_string (e, attr_replicaName, r->repl_name); - if (rc != 0) - { - sprintf (errortext, "failed to update replica entry"); - slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, - "_replica_update_entry: %s\n", errortext); - return -1; - } - else - r->new_name = PR_FALSE; - - return 0; -} - - -/* This function retrieves RUV from the root of the replicated tree. - * The attribute can be missing if - * (1) this replica is the first supplier and replica generation has not been assigned - * or - * (2) this is a consumer that has not been yet initialized - * In either case, replica_set_ruv should be used to further initialize the replica. - * Returns 0 on success, -1 on failure. If 0 is returned, the RUV is present in the replica. - */ -static int -__replica_configure_ruv (Replica *r, PRBool isLocked) -{ - Slapi_PBlock *pb = NULL; - char *attrs[2]; - int rc; - int return_value = -1; - Slapi_Entry **entries = NULL; - Slapi_Attr *attr; - RUV *ruv = NULL; - CSN *csn = NULL; - ReplicaId rid = 0; - char ebuf[BUFSIZ]; - - /* read ruv state from the ruv tombstone entry */ - pb = slapi_pblock_new(); - attrs[0] = (char*)type_ruvElement; - attrs[1] = NULL; - slapi_search_internal_set_pb( - pb, - slapi_sdn_get_dn(r->repl_root), - LDAP_SCOPE_BASE, - "objectclass=*", - attrs, - 0, /* attrsonly */ - NULL, /* controls */ - RUV_STORAGE_ENTRY_UNIQUEID, - repl_get_plugin_identity (PLUGIN_MULTIMASTER_REPLICATION), - OP_FLAG_REPLICATED); /* flags */ - slapi_search_internal_pb (pb); - - slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &rc); - if (rc == LDAP_SUCCESS) - { - /* get RUV attributes and construct the RUV */ - slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &entries); - if (NULL == entries || NULL == entries[0]) - { - slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, - "_replica_configure_ruv: replica ruv tombstone entry for " - "replica %s not found\n", - escape_string(slapi_sdn_get_dn(r->repl_root),ebuf)); - goto done; - } - - rc = slapi_entry_attr_find(entries[0], type_ruvElement, &attr); - if (rc != 0) /* ruv attribute is missing - this not allowed */ - { - slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, - "_replica_configure_ruv: replica ruv tombstone entry for " - "replica %s does not contain %s\n", - escape_string(slapi_sdn_get_dn(r->repl_root),ebuf), type_ruvElement); - goto done; - } - - /* Check in the tombstone we have retrieved if the local purl is - already present: - rid == 0: the local purl is not present - rid != 0: the local purl is present ==> nothing to do - */ - ruv_init_from_slapi_attr_and_check_purl (attr, &ruv, &rid); - if (ruv) - { - char *generation = NULL; - generation = ruv_get_replica_generation(ruv); - if (NULL != generation) - { - r->repl_ruv = object_new((void*)ruv, (FNFree)ruv_destroy); - - /* Is the local purl in the ruv? (the port or the host could have - changed) - */ - /* A consumer only doesn't have its purl in its ruv */ - if (r->repl_type == REPLICA_TYPE_UPDATABLE) - { - int need_update = 0; - if (rid == 0) - { - /* We can not have more than 1 ruv with the same rid - so we replace it */ - const char *purl = NULL; - - purl = multimaster_get_local_purl(); - ruv_delete_replica(ruv, r->repl_rid); - ruv_add_index_replica(ruv, r->repl_rid, purl, 1); - need_update = 1; /* ruv changed, so write tombstone */ - } - else /* bug 540844: make sure the local supplier rid is first in the ruv */ - { - /* make sure local supplier is first in list */ - ReplicaId first_rid = 0; - char *first_purl = NULL; - ruv_get_first_id_and_purl(ruv, &first_rid, &first_purl); - /* if the local supplier is not first in the list . . . */ - if (rid != first_rid) - { - /* . . . move the local supplier to the beginning of the list */ - ruv_move_local_supplier_to_first(ruv, rid); - need_update = 1; /* must update tombstone also */ - } - } - - /* Update also the directory entry */ - if (need_update) { - /* richm 20010821 bug 556498 - replica_replace_ruv_tombstone acquires the repl_lock, so release - the lock then reacquire it if locked */ - if (isLocked) PR_Unlock(r->repl_lock); - replica_replace_ruv_tombstone(r); - if (isLocked) PR_Lock(r->repl_lock); - } - } - - slapi_ch_free((void **)&generation); - return_value = 0; - } - else - { - slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, - "RUV for replica %s is missing replica generation\n", - escape_string(slapi_sdn_get_dn(r->repl_root),ebuf)); - goto done; - } - } - else - { - slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, - "Unable to convert %s attribute in entry %s to a replica update vector.\n", - type_ruvElement, escape_string(slapi_sdn_get_dn(r->repl_root),ebuf)); - goto done; - } - - } - else /* search failed */ - { - if (LDAP_NO_SUCH_OBJECT == rc) - { - /* The entry doesn't exist: create it */ - rc = replica_create_ruv_tombstone(r); - if (LDAP_SUCCESS != rc) - { - /* - * XXXggood - the following error appears on startup if we try - * to initialize replica RUVs before the backend instance is up. - * It's alarming to see this error, and we should suppress it - * (or avoid trying to configure it) if the backend instance is - * not yet online. - */ - /* - * XXXrichm - you can also get this error when the backend is in - * read only mode c.f. bug 539782 - */ - slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, - "_replica_configure_ruv: failed to create replica ruv tombstone " - "entry (%s); LDAP error - %d\n", - escape_string(slapi_sdn_get_dn(r->repl_root),ebuf), rc); - goto done; - } - else - { - slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, - "_replica_configure_ruv: No ruv tombstone found for replica %s. " - "Created a new one\n", - escape_string(slapi_sdn_get_dn(r->repl_root),ebuf)); - return_value = 0; - } - } - else - { - /* see if the suffix is disabled */ - char *state = slapi_mtn_get_state(r->repl_root); - if (state && !strcasecmp(state, "disabled")) - { - slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, - "_replica_configure_ruv: replication disabled for " - "entry (%s); LDAP error - %d\n", - escape_string(slapi_sdn_get_dn(r->repl_root),ebuf), rc); - slapi_ch_free_string(&state); - goto done; - } - else if (!r->repl_ruv) /* other error */ - { - slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, - "_replica_configure_ruv: replication broken for " - "entry (%s); LDAP error - %d\n", - escape_string(slapi_sdn_get_dn(r->repl_root),ebuf), rc); - slapi_ch_free_string(&state); - goto done; - } - else /* some error but continue anyway? */ - { - slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, - "_replica_configure_ruv: Error %d reading tombstone for replica %s.\n", - rc, escape_string(slapi_sdn_get_dn(r->repl_root),ebuf)); - return_value = 0; - } - slapi_ch_free_string(&state); - } - } - - if (NULL != r->min_csn_pl) - { - csnplFree (&r->min_csn_pl); - } - - /* create pending list for min csn if necessary */ - if (ruv_get_smallest_csn_for_replica ((RUV*)object_get_data (r->repl_ruv), - r->repl_rid, &csn) == RUV_SUCCESS) - { - csn_free (&csn); - r->min_csn_pl = NULL; - } - else - { - /* - * The local replica has not generated any of its own CSNs yet. - * We need to watch CSNs being generated and note the first - * locally-generated CSN that's committed. Once that event occurs, - * the RUV is suitable for iteration over locally generated - * changes. - */ - r->min_csn_pl = csnplNew(); - } - -done: - if (NULL != pb) - { - slapi_free_search_results_internal(pb); - slapi_pblock_destroy (pb); - } - if (return_value != 0) - { - if (ruv) - ruv_destroy (&ruv); - } - - return return_value; -} - -/* Update the tombstone entry to reflect the content of the ruv */ -static void -replica_replace_ruv_tombstone(Replica *r) -{ - Slapi_PBlock *pb = NULL; - char *dn; - int rc; - - Slapi_Mod smod; - Slapi_Mod smod_last_modified; - LDAPMod *mods [3]; - - PR_ASSERT(NULL != r && NULL != r->repl_root); - - PR_Lock(r->repl_lock); - - PR_ASSERT (r->repl_ruv); - ruv_to_smod ((RUV*)object_get_data(r->repl_ruv), &smod); - ruv_last_modified_to_smod ((RUV*)object_get_data(r->repl_ruv), &smod_last_modified); - - dn = _replica_get_config_dn (r->repl_root); - mods[0] = (LDAPMod*)slapi_mod_get_ldapmod_byref(&smod); - mods[1] = (LDAPMod*)slapi_mod_get_ldapmod_byref(&smod_last_modified); - - PR_Unlock (r->repl_lock); - - mods [2] = NULL; - pb = slapi_pblock_new(); - - slapi_modify_internal_set_pb( - pb, - (char*)slapi_sdn_get_dn (r->repl_root), /* only used to select be */ - mods, - NULL, /* controls */ - RUV_STORAGE_ENTRY_UNIQUEID, - repl_get_plugin_identity (PLUGIN_MULTIMASTER_REPLICATION), - OP_FLAG_REPLICATED | OP_FLAG_REPL_FIXUP); - - slapi_modify_internal_pb (pb); - - slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &rc); - - if (rc != LDAP_SUCCESS) - { - if ((rc != LDAP_NO_SUCH_OBJECT) || !replica_is_state_flag_set(r, REPLICA_IN_USE)) - { - slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "replica_replace_ruv_tombstone: " - "failed to update replication update vector for replica %s: LDAP " - "error - %d\n", (char*)slapi_sdn_get_dn (r->repl_root), rc); - } - } - - slapi_ch_free ((void**)&dn); - slapi_pblock_destroy (pb); - slapi_mod_done (&smod); - slapi_mod_done (&smod_last_modified); -} - - -/* - * Returns refcounted object that contains RUV. The caller should release the - * object once it is no longer used. To release, call object_release - */ -Object * -replica_consumer_get_ruv (const Replica *r) -{ - Object *ruv = NULL; - - PR_ASSERT(r); - // PR_ASSERT (r->repl_ruv); - - object_acquire (r->consumer_repl_ruv); - ruv = r->consumer_repl_ruv; - - return ruv; -} - -void -replica_consumer_set_ruv (Replica *r, RUV *ruv) -{ - PR_ASSERT(r); - PR_ASSERT(ruv); - - if(NULL != r->consumer_repl_ruv) - { - object_release(r->consumer_repl_ruv); - } - - r->consumer_repl_ruv = object_new((void*)ruv, (FNFree)ruv_destroy); -} diff --git a/ldap/servers/plugins/replication/windows_tot_protocol.c b/ldap/servers/plugins/replication/windows_tot_protocol.c index d6da5a7c..f81a2bf8 100644 --- a/ldap/servers/plugins/replication/windows_tot_protocol.c +++ b/ldap/servers/plugins/replication/windows_tot_protocol.c @@ -12,11 +12,12 @@ */ -#include "windowsrepl.h" -#include "windows_prot_private.h" + #include "repl.h" #include "repl5.h" -#include "repl5_prot_private.h" +#include "windowsrepl.h" +#include "windows_prot_private.h" +#include "slap.h" /* Private data structures */ typedef struct windows_tot_private @@ -65,6 +66,8 @@ windows_tot_run(Private_Repl_Protocol *prp) CSN *remote_schema_csn = NULL; PRBool cookie_has_more = PR_TRUE; RUV *ruv = NULL; + + LDAPDebug( LDAP_DEBUG_TRACE, "=> windows_tot_run\n", 0, 0, 0 ); PR_ASSERT(NULL != prp); @@ -80,7 +83,7 @@ windows_tot_run(Private_Repl_Protocol *prp) /* acquire remote replica */ agmt_set_last_init_start(prp->agmt, current_time()); - rc = windows_acquire_replica (prp, &ruv); + rc = windows_acquire_replica (prp, &ruv, 0 /* don't check RUV for total protocol */); /* We never retry total protocol, even in case a transient error. This is because if somebody already updated the replica we don't want to do it again */ @@ -108,16 +111,17 @@ windows_tot_run(Private_Repl_Protocol *prp) slapi_log_error(SLAPI_LOG_FATAL, windows_repl_plugin_name, "Beginning total update of replica " "\"%s\".\n", agmt_get_long_name(prp->agmt)); - windows_private_null_dirsync_control(prp->agmt); + windows_private_null_dirsync_cookie(prp->agmt); /* get everything */ windows_dirsync_inc_run(prp); cookie_has_more = windows_private_dirsync_has_more(prp->agmt); + windows_private_save_dirsync_cookie(prp->agmt); /* send everything */ - dn = slapi_sdn_get_dn( windows_private_get_directory_replarea(prp->agmt)); + dn = slapi_sdn_get_dn( windows_private_get_directory_subtree(prp->agmt)); pb = slapi_pblock_new (); slapi_search_internal_set_pb (pb, dn, /* XXX modify the searchfilter and scope? */ @@ -155,6 +159,7 @@ windows_tot_run(Private_Repl_Protocol *prp) done: prp->stopped = 1; + LDAPDebug( LDAP_DEBUG_TRACE, "<= windows_tot_run\n", 0, 0, 0 ); } static int @@ -164,6 +169,8 @@ windows_tot_stop(Private_Repl_Protocol *prp) int seconds = 600; PRIntervalTime start, maxwait, now; + LDAPDebug( LDAP_DEBUG_TRACE, "=> windows_tot_stop\n", 0, 0, 0 ); + prp->terminate = 1; maxwait = PR_SecondsToInterval(seconds); start = PR_IntervalNow(); @@ -188,6 +195,8 @@ windows_tot_stop(Private_Repl_Protocol *prp) return_value = 0; } + LDAPDebug( LDAP_DEBUG_TRACE, "<= windows_tot_stop\n", 0, 0, 0 ); + return return_value; } @@ -197,6 +206,8 @@ static int windows_tot_status(Private_Repl_Protocol *prp) { int return_value = 0; + LDAPDebug( LDAP_DEBUG_TRACE, "=> windows_tot_status\n", 0, 0, 0 ); + LDAPDebug( LDAP_DEBUG_TRACE, "<= windows_tot_status\n", 0, 0, 0 ); return return_value; } @@ -205,6 +216,8 @@ windows_tot_status(Private_Repl_Protocol *prp) static void windows_tot_noop(Private_Repl_Protocol *prp) { + LDAPDebug( LDAP_DEBUG_TRACE, "=> windows_tot_noop\n", 0, 0, 0 ); + LDAPDebug( LDAP_DEBUG_TRACE, "<= windows_tot_noop\n", 0, 0, 0 ); /* noop */ } @@ -214,6 +227,9 @@ Windows_Tot_Protocol_new(Repl_Protocol *rp) { windows_tot_private *rip = NULL; Private_Repl_Protocol *prp = (Private_Repl_Protocol *)slapi_ch_malloc(sizeof(Private_Repl_Protocol)); + + LDAPDebug( LDAP_DEBUG_TRACE, "=> Windows_Tot_Protocol_new\n", 0, 0, 0 ); + prp->delete = windows_tot_delete; prp->run = windows_tot_run; prp->stop = windows_tot_stop; @@ -241,22 +257,28 @@ Windows_Tot_Protocol_new(Repl_Protocol *rp) rip->rp = rp; prp->private = (void *)rip; prp->replica_acquired = PR_FALSE; + LDAPDebug( LDAP_DEBUG_TRACE, "<= Windows_Tot_Protocol_new\n", 0, 0, 0 ); return prp; loser: windows_tot_delete(&prp); + LDAPDebug( LDAP_DEBUG_TRACE, "<= Windows_Tot_Protocol_new - loser\n", 0, 0, 0 ); return NULL; } static void windows_tot_delete(Private_Repl_Protocol **prp) { + LDAPDebug( LDAP_DEBUG_TRACE, "=> windows_tot_delete\n", 0, 0, 0 ); + LDAPDebug( LDAP_DEBUG_TRACE, "<= windows_tot_delete\n", 0, 0, 0 ); } static void get_result (int rc, void *cb_data) { + LDAPDebug( LDAP_DEBUG_TRACE, "=> get_result\n", 0, 0, 0 ); PR_ASSERT (cb_data); ((callback_data*)cb_data)->rc = rc; + LDAPDebug( LDAP_DEBUG_TRACE, "<= get_result\n", 0, 0, 0 ); } static @@ -265,11 +287,12 @@ int send_entry (Slapi_Entry *e, void *cb_data) int rc; Private_Repl_Protocol *prp; - // struct berval *bv; unsigned long *num_entriesp; time_t *sleep_on_busyp; time_t *last_busyp; + LDAPDebug( LDAP_DEBUG_TRACE, "=> send_entry\n", 0, 0, 0 ); + PR_ASSERT (cb_data); prp = ((callback_data*)cb_data)->prp; @@ -283,40 +306,23 @@ int send_entry (Slapi_Entry *e, void *cb_data) conn_disconnect(prp->conn); prp->stopped = 1; ((callback_data*)cb_data)->rc = -1; + LDAPDebug( LDAP_DEBUG_TRACE, "<= send_entry\n", 0, 0, 0 ); return -1; } - /* skip ruv tombstone - need to do this because it might be - more up to date then the data we are sending to the client. - RUV is sent separately via the protocol */ - if (is_ruv_tombstone_entry (e)) + /* skip ruv tombstone - not relvant to Active Directory */ + if (is_ruv_tombstone_entry (e)) { + LDAPDebug( LDAP_DEBUG_TRACE, "<= send_entry\n", 0, 0, 0 ); return 0; + } - do { /* push the entry to the consumer */ - rc = add_or_modify_user(e); + rc = windows_process_total_entry(prp,e); - if (rc == CONN_BUSY) { - time_t now = current_time (); - if ((now - *last_busyp) < (*sleep_on_busyp + 10)) { - *sleep_on_busyp +=5; - } - else { - *sleep_on_busyp = 5; - } - *last_busyp = now; - - slapi_log_error(SLAPI_LOG_FATAL, windows_repl_plugin_name, - "Replica \"%s\" is busy. Waiting %ds while" - " it finishes processing its current import queue\n", - agmt_get_long_name(prp->agmt), *sleep_on_busyp); - DS_Sleep(PR_SecondsToInterval(*sleep_on_busyp)); - } - } - while (rc == CONN_BUSY); - (*num_entriesp)++; + LDAPDebug( LDAP_DEBUG_TRACE, "<= send_entry\n", 0, 0, 0 ); + if (CONN_OPERATION_SUCCESS == rc) { return 0; } else { diff --git a/ldap/servers/plugins/replication/windows_total.c b/ldap/servers/plugins/replication/windows_total.c index 6af9d3f9..0c2435c2 100644 --- a/ldap/servers/plugins/replication/windows_total.c +++ b/ldap/servers/plugins/replication/windows_total.c @@ -5,42 +5,9 @@ * END COPYRIGHT BLOCK **/ -/* - repl5_total.c - code that implements a total replica update. - - The requestValue of the NSDS50ReplicationEntry looks like this: - - requestValue ::= SEQUENCE { - uniqueid OCTET STRING, - dn LDAPDN, - annotatedAttributes AnnotatedAttributeList - } - - AnnotatedAttributeList ::= SET OF SEQUENCE { - attributeType AttributeDescription, - attributeDeletionCSN OCTET STRING OPTIONAL, - attributeDeleted BOOLEAN DEFAULT FALSE, - annotatedValues SET OF AnnotatedValue - } - - AnnotatedValue ::= SEQUENCE { - value AttributeValue, - valueDeleted BOOLEAN DEFAULT FALSE, - valueCSNSet SEQUENCE OF ValueCSN, - } - - ValueCSN ::= SEQUENCE { - CSNType ENUMERATED { - valuePresenceCSN (1), - valueDeletionCSN (2), - valueDistinguishedCSN (3) - } - CSN OCTET STRING, - } -*/ #include "repl5.h" -#include "windowsrepl.h" +#include "slap.h" #define CSN_TYPE_VALUE_UPDATED_ON_WIRE 1 #define CSN_TYPE_VALUE_DELETED_ON_WIRE 2 @@ -72,6 +39,8 @@ my_ber_printf_csn(BerElement *ber, const CSN *csn, const CSNType t) int rc = -1; int csn_type_as_ber = -1; + LDAPDebug( LDAP_DEBUG_TRACE, "=> my_ber_printf_csn\n", 0, 0, 0 ); + switch (t) { case CSN_TYPE_VALUE_UPDATED: @@ -88,6 +57,7 @@ my_ber_printf_csn(BerElement *ber, const CSN *csn, const CSNType t) default: slapi_log_error(SLAPI_LOG_FATAL, windows_repl_plugin_name, "my_ber_printf_csn: unknown " "csn type %d encountered.\n", (int)t); + LDAPDebug( LDAP_DEBUG_TRACE, "<= my_ber_printf_csn\n", 0, 0, 0 ); return -1; } @@ -106,6 +76,8 @@ my_ber_printf_csn(BerElement *ber, const CSN *csn, const CSNType t) BER_DEBUG("{e(csn type)s(csn)}"); } + LDAPDebug( LDAP_DEBUG_TRACE, "<= my_ber_printf_csn\n", 0, 0, 0 ); + return rc; } @@ -123,6 +95,8 @@ my_ber_printf_value(BerElement *ber, const char *type, const Slapi_Value *value, CSN *csn; CSNType t; + LDAPDebug( LDAP_DEBUG_TRACE, "=> my_ber_printf_value\n", 0, 0, 0 ); + bval = slapi_value_get_berval(value); BER_DEBUG("{o(value)"); if (ber_printf(ber, "{o", bval->bv_val, bval->bv_len) == -1) /* Start sequence */ @@ -183,6 +157,7 @@ my_ber_printf_value(BerElement *ber, const char *type, const Slapi_Value *value, rc = 0; done: + LDAPDebug( LDAP_DEBUG_TRACE, "<= my_ber_printf_value\n", 0, 0, 0 ); return rc; } @@ -195,6 +170,8 @@ my_ber_printf_attr (BerElement *ber, Slapi_Attr *attr, PRBool deleted) char *type; int i; const CSN *csn; + + LDAPDebug( LDAP_DEBUG_TRACE, "=> my_ber_printf_attr\n", 0, 0, 0 ); /* First, send the type */ slapi_attr_get_type(attr, &type); @@ -272,8 +249,10 @@ my_ber_printf_attr (BerElement *ber, Slapi_Attr *attr, PRBool deleted) goto loser; } + LDAPDebug( LDAP_DEBUG_TRACE, "<= my_ber_printf_attr\n", 0, 0, 0 ); return 0; loser: + LDAPDebug( LDAP_DEBUG_TRACE, "<= my_ber_printf_attr - loser\n", 0, 0, 0 ); return -1; } @@ -292,6 +271,8 @@ my_ber_scanf_value(BerElement *ber, Slapi_Value **value, PRBool *deleted) CSNType csntype; char *lasti; + LDAPDebug( LDAP_DEBUG_TRACE, "=> my_ber_scanf_value\n", 0, 0, 0 ); + PR_ASSERT(ber && value && deleted); *value = NULL; @@ -377,6 +358,7 @@ my_ber_scanf_value(BerElement *ber, Slapi_Value **value, PRBool *deleted) if (attrval) ber_bvfree(attrval); + LDAPDebug( LDAP_DEBUG_TRACE, "<= my_ber_scanf_value\n", 0, 0, 0 ); return 0; loser: @@ -389,7 +371,7 @@ loser: { slapi_value_free (value); } - + LDAPDebug( LDAP_DEBUG_TRACE, "<= my_ber_scanf_value - loser\n", 0, 0, 0 ); return -1; } @@ -406,6 +388,8 @@ my_ber_scanf_attr (BerElement *ber, Slapi_Attr **attr, PRBool *deleted) int rc; Slapi_Value *value; + LDAPDebug( LDAP_DEBUG_TRACE, "=> my_ber_scanf_attr\n", 0, 0, 0 ); + PR_ASSERT (ber && attr && deleted); /* allocate the attribute */ @@ -495,6 +479,7 @@ my_ber_scanf_attr (BerElement *ber, Slapi_Attr **attr, PRBool *deleted) goto loser; } + LDAPDebug( LDAP_DEBUG_TRACE, "<= my_ber_scanf_attr\n", 0, 0, 0 ); return 0; loser: if (*attr) @@ -502,6 +487,7 @@ loser: if (value) slapi_value_free (&value); + LDAPDebug( LDAP_DEBUG_TRACE, "<= my_ber_scanf_attr - loser\n", 0, 0, 0 ); return -1; } @@ -525,6 +511,8 @@ decode_total_update_extop(Slapi_PBlock *pb, Slapi_Entry **ep) unsigned long tag; int rc; PRBool deleted; + + LDAPDebug( LDAP_DEBUG_TRACE, "=> decode_total_update_extop\n", 0, 0, 0 ); PR_ASSERT(NULL != pb); PR_ASSERT(NULL != ep); @@ -645,6 +633,7 @@ free_and_return: ber_free(tmp_bere, 1); tmp_bere = NULL; } + LDAPDebug( LDAP_DEBUG_TRACE, "<= decode_total_update_extop\n", 0, 0, 0 ); return rc; } @@ -659,6 +648,8 @@ ___multimaster_extop_NSDS50ReplicationEntry(Slapi_PBlock *pb) Slapi_Entry *e = NULL; Slapi_Connection *conn = NULL; int connid, opid; + + LDAPDebug( LDAP_DEBUG_TRACE, "=> ___multimaster_extop_NSDS50ReplicationEntry\n", 0, 0, 0 ); connid = 0; slapi_pblock_get(pb, SLAPI_CONN_ID, &connid); @@ -723,5 +714,7 @@ ___multimaster_extop_NSDS50ReplicationEntry(Slapi_PBlock *pb) } } + LDAPDebug( LDAP_DEBUG_TRACE, "<= ___multimaster_extop_NSDS50ReplicationEntry\n", 0, 0, 0 ); + return rc; } diff --git a/ldap/servers/plugins/replication/windowsrepl.h b/ldap/servers/plugins/replication/windowsrepl.h index 88ad1d41..8379dc6c 100644 --- a/ldap/servers/plugins/replication/windowsrepl.h +++ b/ldap/servers/plugins/replication/windowsrepl.h @@ -4,247 +4,28 @@ * All rights reserved. * END COPYRIGHT BLOCK **/ -/* repl5.h - 5.0 replication header */ -#include "repl.h" -#include "repl5.h" - -#ifndef _WINDOWSREPL5_H_ -#define _WINDOWSREPL5_H_ - -#include <limits.h> -#include <time.h> -#include <stdio.h> - -#undef REPL_PLUGIN_NAME -#define REPL_PLUGIN_NAME "WindowsSyncPlugin" -#define WINDOWS_REPL_PLUGIN_NAME REPL_PLUGIN_NAME - -char* get_repl_session_id (Slapi_PBlock *pb, char *id, CSN **opcsn); -#include <string.h> -#ifndef _WIN32 -#include <sys/param.h> -#endif /* _WIN32 */ - -#include "portable.h" /* GGOODREPL - is this cheating? */ -#include "repl_shared.h" -#include "llist.h" -#include "repl5_ruv.h" -#include "cl4.h" - - -/* Attribute names for replication agreement attributes */ -extern const char *type_nsdsWindowsReplicaCookie; -extern char *windows_repl_plugin_name; - -/* windows plugin points */ -int windows_preop_bind (Slapi_PBlock *pb); -int windows_preop_add (Slapi_PBlock *pb); -int windows_preop_delete (Slapi_PBlock *pb); -int windows_preop_modify (Slapi_PBlock *pb); -int windows_preop_modrdn (Slapi_PBlock *pb); -int windows_preop_search (Slapi_PBlock *pb); -int windows_preop_compare (Slapi_PBlock *pb); -int windows_bepreop_add (Slapi_PBlock *pb); -int windows_bepreop_delete (Slapi_PBlock *pb); -int windows_bepreop_modify (Slapi_PBlock *pb); -int windows_bepreop_modrdn (Slapi_PBlock *pb); -int windows_bepostop_modrdn (Slapi_PBlock *pb); -int windows_bepostop_delete (Slapi_PBlock *pb); -int windows_postop_bind (Slapi_PBlock *pb); -int windows_postop_add (Slapi_PBlock *pb); -int windows_postop_delete (Slapi_PBlock *pb); -int windows_postop_modify (Slapi_PBlock *pb); -int windows_postop_modrdn (Slapi_PBlock *pb); - -/* In repl5_init.c */ -char* get_thread_private_agmtname (); -void set_thread_private_agmtname (const char *agmtname); -void* get_thread_private_cache (); -void set_thread_private_cache (void *buf); -char* get_repl_session_id (Slapi_PBlock *pb, char *id, CSN **opcsn); - -/* In repl_extop.c */ -int windows_extop_StartNSDS50ReplicationRequest(Slapi_PBlock *pb); -int windows_extop_EndNSDS50ReplicationRequest(Slapi_PBlock *pb); -int extop_noop(Slapi_PBlock *pb); -struct berval *NSDS50StartReplicationRequest_new(const char *protocol_oid, - const char *repl_root, char **extra_referrals, CSN *csn); -struct berval *NSDS50EndReplicationRequest_new(char *repl_root); -int decode_repl_ext_response(struct berval *data, int *response_code, - struct berval ***ruv_bervals); - -/* extension construct/destructor */ -void* windows_operation_extension_constructor (void *object, void *parent); -void windows_operation_extension_destructor (void* ext,void *object, void *parent); -void* windows_consumer_operation_extension_constructor (void *object, void *parent); -void windows_consumer_operation_extension_destructor (void* ext,void *object, void *parent); -void windows_mtnode_extension_destructor (void* ext, void *object, void *parent); -void *windows_mtnode_extension_constructor (void *object, void *parent); - - - - - -typedef struct windows_operation_extension -{ - int prevent_recursive_call; - struct slapi_operation_parameters *operation_parameters; - char *repl_gen; -} windows_operation_extension; - -/* windows_ext.c */ -void windows_repl_sup_init_ext (); -void windows_repl_con_init_ext (); -int windows_repl_sup_register_ext (ext_type type); // never used? -int windows_repl_con_register_ext (ext_type type); // never used -void* windows_repl_sup_get_ext (ext_type type, void *object); -void* windows_repl_con_get_ext (ext_type type, void *object); - - - -/* In repl5_total.c */ -int windows_extop_NSDS50ReplicationEntry(Slapi_PBlock *pb); - -/* In repl_controls.c */ -int create_NSDS50ReplUpdateInfoControl(const char *uuid, - const char *superior_uuid, const CSN *csn, - LDAPMod **modify_mods, LDAPControl **ctrlp); -void destroy_NSDS50ReplUpdateInfoControl(LDAPControl **ctrlp); -int decode_NSDS50ReplUpdateInfoControl(LDAPControl **controlsp, - char **uuid, char **newsuperior_uuid, CSN **csn, LDAPMod ***modrdn_mods); - -/* In repl5_replsupplier.c */ -/* typedef struct repl_supplier Repl_Supplier; */ -Repl_Supplier *replsupplier_init(Slapi_Entry *e); -void replsupplier_configure(Repl_Supplier *rs, Slapi_PBlock *pb); -void replsupplier_start(Repl_Supplier *rs); -void replsupplier_stop(Repl_Supplier *rs); -void replsupplier_destroy(Repl_Supplier **rs); -void replsupplier_notify(Repl_Supplier *rs, PRUint32 eventmask); -PRUint32 replsupplier_get_status(Repl_Supplier *rs); - -/* In repl5_plugins.c */ -int windows_set_local_purl(); -const char *windows_get_local_purl(); -PRBool windows_started(); - -/* In repl5_schedule.c */ -/* typedef struct schedule Schedule; */ -/* typedef void (*window_state_change_callback)(void *arg, PRBool opened); */ -Schedule *schedule_new(window_state_change_callback callback_fn, void *callback_arg, const char *session_id); -void schedule_destroy(Schedule *s); -int schedule_set(Schedule *sch, Slapi_Attr *attr); -char **schedule_get(Schedule *sch); -int schedule_in_window_now(Schedule *sch); -PRTime schedule_next(Schedule *sch); -int schedule_notify(Schedule *sch, Slapi_PBlock *pb); -void schedule_set_priority_attributes(Schedule *sch, char **prio_attrs, int override_schedule); -void schedule_set_startup_delay(Schedule *sch, size_t startup_delay); -void schedule_set_maximum_backlog(Schedule *sch, size_t max_backlog); -void schedule_notify_session(Schedule *sch, PRTime session_end_time, unsigned int flags); -#define REPLICATION_SESSION_SUCCESS 0 - -/* In repl5_bos.c */ -/* typedef struct repl_bos Repl_Bos; */ - -/* In repl5_agmt.c */ -/* typedef struct repl5agmt Repl_Agmt; */ -/* #define TRANSPORT_FLAG_SSL 1 */ -/* #define TRANSPORT_FLAG_TLS 2 */ -/* #define BINDMETHOD_SIMPLE_AUTH 1 */ -/* #define BINDMETHOD_SSL_CLIENTAUTH 2 */ -Repl_Agmt *windows_agmt_new_from_entry(Slapi_Entry *e); -/* Repl_Agmt *agmt_new_from_pblock(Slapi_PBlock *pb); */ -/* void agmt_delete(void **ra); */ -/* const Slapi_DN *agmt_get_dn_byref(const Repl_Agmt *ra); */ -/* int agmt_get_auto_initialize(const Repl_Agmt *ra); */ -/* long agmt_get_timeout(const Repl_Agmt *ra); */ -/* long agmt_get_busywaittime(const Repl_Agmt *ra); */ -/* long agmt_get_pausetime(const Repl_Agmt *ra); */ -int windows_agmt_start(Repl_Agmt *ra); -int windows_agmt_stop(Repl_Agmt *ra); -/* int agmt_replicate_now(Repl_Agmt *ra); */ -/* char *agmt_get_hostname(const Repl_Agmt *ra); */ -/* int agmt_get_port(const Repl_Agmt *ra); */ -/* PRUint32 agmt_get_transport_flags(const Repl_Agmt *ra); */ -/* char *agmt_get_binddn(const Repl_Agmt *ra); */ -/* struct berval *agmt_get_credentials(const Repl_Agmt *ra); */ -/* int agmt_get_bindmethod(const Repl_Agmt *ra); */ -Slapi_DN *windows_agmt_get_replarea(const Repl_Agmt *ra); -/* int agmt_is_fractional(const Repl_Agmt *ra); */ -/* int agmt_is_fractional_attr(const Repl_Agmt *ra, const char *attrname); */ -/* int agmt_is_50_mm_protocol(const Repl_Agmt *ra); */ -/* int agmt_matches_name(const Repl_Agmt *ra, const Slapi_DN *name); */ -/* int agmt_replarea_matches(const Repl_Agmt *ra, const Slapi_DN *name); */ -int windows_agmt_schedule_in_window_now(const Repl_Agmt *ra); -int windows_agmt_set_schedule_from_entry( Repl_Agmt *ra, const Slapi_Entry *e ); -/* int agmt_set_timeout_from_entry( Repl_Agmt *ra, const Slapi_Entry *e ); */ -/* int agmt_set_busywaittime_from_entry( Repl_Agmt *ra, const Slapi_Entry *e ); */ -/* int agmt_set_pausetime_from_entry( Repl_Agmt *ra, const Slapi_Entry *e ); */ -int windows_agmt_set_credentials_from_entry( Repl_Agmt *ra, const Slapi_Entry *e ); -/* int agmt_set_binddn_from_entry( Repl_Agmt *ra, const Slapi_Entry *e ); */ -/* int agmt_set_bind_method_from_entry( Repl_Agmt *ra, const Slapi_Entry *e ); */ -/* int agmt_set_transportinfo_from_entry( Repl_Agmt *ra, const Slapi_Entry *e ); */ -const char *windows_agmt_get_long_name(const Repl_Agmt *ra); -/* int agmt_initialize_replica(const Repl_Agmt *agmt); */ -/* void agmt_replica_init_done (const Repl_Agmt *agmt); */ -/* void agmt_notify_change(Repl_Agmt *ra, Slapi_PBlock *pb); */ -/* Object* agmt_get_consumer_ruv (Repl_Agmt *ra); */ -/* ReplicaId agmt_get_consumer_rid ( Repl_Agmt *ra, void *conn ); */ -/* int agmt_set_consumer_ruv (Repl_Agmt *ra, RUV *ruv); */ -void windows_agmt_update_consumer_ruv (Repl_Agmt *ra); -/* CSN* agmt_get_consumer_schema_csn (Repl_Agmt *ra); */ -/* void agmt_set_consumer_schema_csn (Repl_Agmt *ra, CSN *csn); */ -/* void agmt_set_last_update_in_progress (Repl_Agmt *ra, PRBool in_progress); */ -/* void agmt_set_last_update_start (Repl_Agmt *ra, time_t start_time); */ -/* void agmt_set_last_update_end (Repl_Agmt *ra, time_t end_time); */ -/* void agmt_set_last_update_status (Repl_Agmt *ra, int ldaprc, int replrc, const char *msg); */ -/* void agmt_set_update_in_progress (Repl_Agmt *ra, PRBool in_progress); */ -/* void agmt_set_last_init_start (Repl_Agmt *ra, time_t start_time); */ -/* void agmt_set_last_init_end (Repl_Agmt *ra, time_t end_time); */ -/* void agmt_set_last_init_status (Repl_Agmt *ra, int ldaprc, int replrc, const char *msg); */ -/* void agmt_inc_last_update_changecount (Repl_Agmt *ra, ReplicaId rid, int skipped); */ -/* void agmt_get_changecount_string (Repl_Agmt *ra, char *buf, int bufsize); */ - -/* typedef struct replica Replica; */ - -/* In repl5_agmtlist.c */ -int windows_agmtlist_config_init(); -void windows_agmtlist_shutdown(); -void windows_agmtlist_notify_all(Slapi_PBlock *pb); -Object* windows_agmtlist_get_first_agreement_for_replica(Replica *r); -Object* windows_agmtlist_get_next_agreement_for_replica(Replica *r, Object *prev); - - -/* In repl5_backoff.c */ -/* typedef struct backoff_timer Backoff_Timer; */ -#define BACKOFF_FIXED 1 -#define BACKOFF_EXPONENTIAL 2 -#define BACKOFF_RANDOM 3 -Backoff_Timer *backoff_new(int timer_type, int initial_interval, int max_interval); -time_t backoff_reset(Backoff_Timer *bt, slapi_eq_fn_t callback, void *callback_data); -time_t backoff_step(Backoff_Timer *bt); -int backoff_expired(Backoff_Timer *bt, int margin); -void backoff_delete(Backoff_Timer **btp); - -/* In repl5_connection.c */ -/* typedef struct repl_connection Repl_Connection; */ -/* typedef enum */ -/* { */ -/* CONN_OPERATION_SUCCESS, */ -/* CONN_OPERATION_FAILED, */ -/* CONN_NOT_CONNECTED, */ -/* CONN_SUPPORTS_DS5_REPL, */ -/* CONN_DOES_NOT_SUPPORT_DS5_REPL, */ -/* CONN_SCHEMA_UPDATED, */ -/* CONN_SCHEMA_NO_UPDATE_NEEDED, */ -/* CONN_LOCAL_ERROR, */ -/* CONN_BUSY, */ -/* CONN_SSL_NOT_ENABLED, */ -/* CONN_TIMEOUT */ -/* } ConnResult; */ - -Repl_Connection *windows_conn_new(Repl_Agmt *agmt); +/* windows_private.c */ +typedef struct windowsprivate Dirsync_Private; +Dirsync_Private* windows_private_new(); +void windows_private_set_windows_subtree (const Repl_Agmt *ra,const Slapi_DN* sdn ); +const Slapi_DN* windows_private_get_windows_subtree (const Repl_Agmt *ra); +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); +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); +int windows_private_load_dirsync_cookie(const Repl_Agmt *ra); +void windows_private_set_create_users(const Repl_Agmt *ra, PRBool value); +PRBool windows_private_create_users(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); + +/* 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); @@ -272,113 +53,3 @@ 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); - - -/* In repl5_protocol.c */ -typedef struct windows_repl_protocol Windows_Repl_Protocol; -Repl_Protocol *protocol_new(Repl_Agmt *agmt, int protocol_state); -void protocol_start(Repl_Protocol *rp); - -Repl_Agmt *protocol_get_agreement(Repl_Protocol *rp); -/* initiate total protocol */ -void protocol_initialize_replica(Repl_Protocol *rp); -/* stop protocol session in progress */ -void protocol_stop(Repl_Protocol *rp); -void protocol_free(Repl_Protocol **rpp); -void protocol_delete(Repl_Protocol **rpp); -PRBool protocol_set_active_protocol (Repl_Protocol *rp, PRBool total); -void protocol_clear_active_protocol (Repl_Protocol *rp); -Repl_Connection *protocol_get_connection(Repl_Protocol *rp); -void protocol_resume(Repl_Protocol *rp, int wakeup_action); -void protocol_notify_update(Repl_Protocol *rp); -void protocol_notify_agmt_changed(Repl_Protocol *rp, char * agmt_name); -void protocol_notify_window_opened (Repl_Protocol *rp); -void protocol_notify_window_closed (Repl_Protocol *rp); -Object *protocol_get_replica_object(Repl_Protocol *rp); -void protocol_replicate_now(Repl_Protocol *rp); - -/* In repl5_replica.c */ -/* typedef enum */ -/* { */ -/* REPLICA_TYPE_UNKNOWN, */ -/* REPLICA_TYPE_PRIMARY, */ -/* REPLICA_TYPE_READONLY, */ -/* REPLICA_TYPE_UPDATABLE, */ -/* REPLICA_TYPE_END */ -/* } ReplicaType; */ - -/* #define RUV_STORAGE_ENTRY_UNIQUEID "ffffffff-ffffffff-ffffffff-ffffffff" */ -/* #define START_ITERATION_ENTRY_UNIQUEID "00000000-00000000-00000000-00000000" */ -/* #define START_ITERATION_ENTRY_DN "cn=start iteration" */ - -/* typedef int (*FNEnumReplica) (Replica *r, void *arg); */ - -/* this function should be called to construct the replica object - from the data already in the DIT */ - Replica *windows_replica_new(const Slapi_DN *root); - -#define REPLICA_IN_USE 1 /* The replica is busy */ -#define REPLICA_INCREMENTAL_IN_PROGRESS 2 /* Set only between start and stop inc */ -#define REPLICA_TOTAL_IN_PROGRESS 4 /* Set only between start and stop total */ -#define REPLICA_AGREEMENTS_DISABLED 8 /* Replica is offline */ -PRBool replica_is_state_flag_set(Replica *r, PRInt32 flag); -void replica_set_state_flag (Replica *r, PRUint32 flag, PRBool clear); -void replica_enable_replication (Replica *r); -void replica_disable_replication (Replica *r, Object *r_obj); -int windows_replica_start_agreement(Replica *r, Repl_Agmt *ra); - -CSN* replica_generate_next_csn ( Slapi_PBlock *pb, const CSN *basecsn ); -int replica_get_attr ( Slapi_PBlock *pb, const char *type, void *value ); - -/* mapping tree extensions manipulation */ -void windows_mtnode_extension_init (); -void windows_mtnode_extension_destroy (); -void windows_mtnode_construct_replicas (); - -void windows_be_state_change (void *handle, char *be_name, int old_be_state, int new_be_state); - -/* In repl5_replica_config.c */ -int windows_replica_config_init(); -void windows_replica_config_destroy (); - -/* replutil.c */ -LDAPControl* create_managedsait_control (); -LDAPControl* create_backend_control(Slapi_DN *sdn); -void repl_set_mtn_state_and_referrals(const Slapi_DN *sdn, const char *mtn_state, - const RUV *ruv, char **ruv_referrals, - char **other_referrals); -void repl_set_repl_plugin_path(const char *path); - -/* repl5_updatedn_list.c */ -/* typedef void *ReplicaUpdateDNList; */ -/* typedef int (*FNEnumDN)(Slapi_DN *dn, void *arg); */ -ReplicaUpdateDNList replica_updatedn_list_new(const Slapi_Entry *entry); -void replica_updatedn_list_free(ReplicaUpdateDNList list); -void replica_updatedn_list_replace(ReplicaUpdateDNList list, const Slapi_ValueSet *vs); -void replica_updatedn_list_delete(ReplicaUpdateDNList list, const Slapi_ValueSet *vs); -void replica_updatedn_list_add(ReplicaUpdateDNList list, const Slapi_ValueSet *vs); -PRBool replica_updatedn_list_ismember(ReplicaUpdateDNList list, const Slapi_DN *dn); -char *replica_updatedn_list_to_string(ReplicaUpdateDNList list, const char *delimiter); -void replica_updatedn_list_enumerate(ReplicaUpdateDNList list, FNEnumDN fn, void *arg); - - -/* windows_private.c */ -PRBool windows_private_dirsync_has_more(const Repl_Agmt *ra); - -/* windows_protocol.c */ -int add_or_modify_user(Slapi_Entry *e); - - -void repl5_set_debug_timeout(const char *val); - -typedef struct windows_mtnode_extension -{ - Object *replica; -} windows_mtnode_extension; - - - - - -#endif /* _WINDOWSREPL5_H_ */ - |