diff options
-rw-r--r-- | ldap/servers/plugins/replication/windows_connection.c | 132 | ||||
-rw-r--r-- | ldap/servers/plugins/replication/windows_private.c | 415 | ||||
-rw-r--r-- | ldap/servers/plugins/replication/windows_protocol_util.c | 136 | ||||
-rw-r--r-- | ldap/servers/plugins/replication/windows_tot_protocol.c | 21 | ||||
-rw-r--r-- | ldap/servers/plugins/replication/windowsrepl.h | 98 | ||||
-rw-r--r-- | ldap/servers/plugins/replication/winsync-plugin.h | 534 | ||||
-rw-r--r-- | ldap/servers/slapd/charray.c | 5 | ||||
-rw-r--r-- | ldap/servers/slapd/control.c | 36 | ||||
-rw-r--r-- | ldap/servers/slapd/slapi-plugin.h | 25 |
9 files changed, 1327 insertions, 75 deletions
diff --git a/ldap/servers/plugins/replication/windows_connection.c b/ldap/servers/plugins/replication/windows_connection.c index 2c54c64b..32787c4c 100644 --- a/ldap/servers/plugins/replication/windows_connection.c +++ b/ldap/servers/plugins/replication/windows_connection.c @@ -512,15 +512,17 @@ windows_perform_operation(Repl_Connection *conn, int optype, const char *dn, /* Copied from the chaining backend*/ static Slapi_Entry * -windows_LDAPMessage2Entry(LDAP * ld, LDAPMessage * msg, int attrsonly) { +windows_LDAPMessage2Entry(Repl_Connection *conn, LDAPMessage * msg, int attrsonly) { - Slapi_Entry *e = slapi_entry_alloc(); + Slapi_Entry *rawentry = NULL; + Slapi_Entry *e = NULL; char *a = NULL; BerElement * ber = NULL; + LDAP *ld = conn->ld; + + windows_private_set_raw_entry(conn->agmt, NULL); /* clear it first */ - if ( e == NULL ) return NULL; if (msg == NULL) { - slapi_entry_free(e); return NULL; } @@ -529,10 +531,21 @@ windows_LDAPMessage2Entry(LDAP * ld, LDAPMessage * msg, int attrsonly) { * attribute type and values ARE allocated */ + e = slapi_entry_alloc(); + if ( e == NULL ) return NULL; slapi_entry_set_dn( e, ldap_get_dn( ld, msg ) ); + rawentry = slapi_entry_alloc(); + if ( rawentry == NULL ) { + slapi_entry_free(e); + return NULL; + } + slapi_entry_set_dn( rawentry, slapi_ch_strdup(slapi_entry_get_dn(e)) ); for ( a = ldap_first_attribute( ld, msg, &ber ); a!=NULL; a=ldap_next_attribute( ld, msg, ber ) ) { + struct berval ** aVal = ldap_get_values_len( ld, msg, a); + slapi_entry_add_values(rawentry, a, aVal); + if (0 == strcasecmp(a,"dnsRecord") || 0 == strcasecmp(a,"dnsproperty") || 0 == strcasecmp(a,"dscorepropagationdata")) { @@ -548,10 +561,8 @@ windows_LDAPMessage2Entry(LDAP * ld, LDAPMessage * msg, int attrsonly) { 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); char *type_to_use = NULL; /* Work around the fact that we alias street and streetaddress, while Microsoft do not */ if (0 == strcasecmp(a,"streetaddress")) @@ -575,15 +586,18 @@ windows_LDAPMessage2Entry(LDAP * ld, LDAPMessage * msg, int attrsonly) { slapi_entry_add_values( e, type_to_use, aVal); } - ldap_memfree(a); - ldap_value_free_len(aVal); } } + ldap_memfree(a); + ldap_value_free_len(aVal); } if ( NULL != ber ) { ldap_ber_free( ber, 0 ); } + + windows_private_set_raw_entry(conn->agmt, rawentry); /* windows private now owns rawentry */ + return e; } @@ -599,11 +613,6 @@ ConnResult windows_search_entry_ext(Repl_Connection *conn, char* searchbase, char *filter, Slapi_Entry **entry, LDAPControl **serverctrls) { ConnResult return_value = 0; - int ldap_rc = 0; - LDAPMessage *res = NULL; - int nummessages = 0; - int numentries = 0; - int numreferences = 0; LDAPDebug( LDAP_DEBUG_TRACE, "=> windows_search_entry\n", 0, 0, 0 ); @@ -611,15 +620,41 @@ windows_search_entry_ext(Repl_Connection *conn, char* searchbase, char *filter, if (windows_conn_connected(conn)) { - ldap_rc = ldap_search_ext_s(conn->ld, searchbase, LDAP_SCOPE_SUBTREE, - filter, NULL, 0 /* attrsonly */, - serverctrls , NULL /* client controls */, + int ldap_rc = 0; + LDAPMessage *res = NULL; + char *searchbase_copy = slapi_ch_strdup(searchbase); + int scope = LDAP_SCOPE_SUBTREE; + char *filter_copy = slapi_ch_strdup(filter); + char **attrs = NULL; + LDAPControl **serverctrls_copy = NULL; + + slapi_add_controls(&serverctrls_copy, serverctrls, 1 /* make a copy we can free */); + + LDAPDebug( LDAP_DEBUG_REPL, "Calling windows entry search request plugin\n", 0, 0, 0 ); + + winsync_plugin_call_pre_ad_search_cb(conn->agmt, NULL, &searchbase_copy, &scope, &filter_copy, + &attrs, &serverctrls_copy); + + ldap_rc = ldap_search_ext_s(conn->ld, searchbase_copy, scope, + filter_copy, attrs, 0 /* attrsonly */, + serverctrls_copy , NULL /* client controls */, &conn->timeout, 0 /* sizelimit */, &res); + + slapi_ch_free_string(&searchbase_copy); + slapi_ch_free_string(&filter_copy); + slapi_ch_array_free(attrs); + attrs = NULL; + ldap_controls_free(serverctrls_copy); + serverctrls_copy = NULL; + if (LDAP_SUCCESS == ldap_rc) { LDAPMessage *message = ldap_first_entry(conn->ld, res); if (slapi_is_loglevel_set(SLAPI_LOG_REPL)) { + int nummessages = 0; + int numentries = 0; + int numreferences = 0; nummessages = ldap_count_messages(conn->ld, res); numentries = ldap_count_entries(conn->ld, res); numreferences = ldap_count_references(conn->ld, res); @@ -629,7 +664,7 @@ windows_search_entry_ext(Repl_Connection *conn, char* searchbase, char *filter, if (NULL != entry) { - *entry = windows_LDAPMessage2Entry(conn->ld,message,0); + *entry = windows_LDAPMessage2Entry(conn,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 @@ -664,42 +699,46 @@ windows_search_entry_ext(Repl_Connection *conn, char* searchbase, char *filter, ConnResult send_dirsync_search(Repl_Connection *conn) { - int rc; ConnResult return_value; - LDAPControl *server_controls[2]; - int msgid; - - const char *op_string = NULL; - - const char* old_dn = NULL; - char* dn = NULL; LDAPDebug( LDAP_DEBUG_TRACE, "=> send_dirsync_search\n", 0, 0, 0 ); - /* need to strip the dn down to dc= */ - old_dn = slapi_sdn_get_ndn( windows_private_get_windows_subtree(conn->agmt) ); - dn = strstr(old_dn, "dc="); - if (windows_conn_connected(conn)) { + const char *op_string = NULL; + int rc; + int scope = LDAP_SCOPE_SUBTREE; + char *filter = slapi_ch_strdup("(objectclass=*)"); + char **attrs = NULL; + LDAPControl **server_controls = NULL; + int msgid; + /* need to strip the dn down to dc= */ + const char *old_dn = slapi_sdn_get_ndn( windows_private_get_windows_subtree(conn->agmt) ); + char *dn = slapi_ch_strdup(strstr(old_dn, "dc=")); + if (conn->supports_dirsync == 0) { - server_controls[0] = NULL; /* unsupported */ + /* unsupported */ } else { - server_controls[0] = windows_private_dirsync_control(conn->agmt); + slapi_add_control_ext(&server_controls, + windows_private_dirsync_control(conn->agmt), + 0 /* no copy - passin */); } - server_controls[1] = NULL; conn->last_operation = CONN_SEARCH; conn->status = STATUS_SEARCHING; op_string = "search"; + LDAPDebug( LDAP_DEBUG_REPL, "Calling dirsync search request plugin\n", 0, 0, 0 ); + + winsync_plugin_call_dirsync_search_params_cb(conn->agmt, old_dn, &dn, &scope, &filter, + &attrs, &server_controls); + 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); + rc = ldap_search_ext( conn->ld, dn, scope, filter, attrs, PR_FALSE, server_controls, + NULL /* ClientControls */, 0,0, &msgid); if (LDAP_SUCCESS == rc) { @@ -723,11 +762,13 @@ send_dirsync_search(Repl_Connection *conn) return_value = CONN_OPERATION_FAILED; } } - if (server_controls[0]) - { - ldap_control_free(server_controls[0]); - } - + /* cleanup */ + slapi_ch_free_string(&dn); + slapi_ch_free_string(&filter); + slapi_ch_array_free(attrs); + attrs = NULL; + ldap_controls_free(server_controls); + server_controls = NULL; } else { @@ -852,7 +893,7 @@ Slapi_Entry * windows_conn_get_search_result(Repl_Connection *conn) { 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 = windows_LDAPMessage2Entry(conn->ld,lm,0); + e = windows_LDAPMessage2Entry(conn,lm,0); ldap_memfree(dn); } } @@ -1424,6 +1465,13 @@ windows_conn_replica_supports_dirsync(Repl_Connection *conn) LDAPDebug( LDAP_DEBUG_TRACE, "=> windows_conn_replica_supports_dirsync\n", 0, 0, 0 ); +#ifdef WINSYNC_TEST + /* used to fake out dirsync to think it's talking to a real ad when in fact + it's just talking to another directory server */ + conn->supports_dirsync = 1; + return CONN_SUPPORTS_DIRSYNC; +#endif + if (windows_conn_connected(conn)) { if (conn->supports_dirsync == -1) { @@ -1882,7 +1930,7 @@ repl5_stop_debug_timeout(Slapi_Eq_Context eqctx, int *setlevel) LDAPDebug( LDAP_DEBUG_TRACE, "=> repl5_stop_debug_timeout\n", 0, 0, 0 ); if (eqctx && !*setlevel) { - int found = slapi_eq_cancel(eqctx); + (void)slapi_eq_cancel(eqctx); } if (s_debug_timeout && s_debug_level && *setlevel) { diff --git a/ldap/servers/plugins/replication/windows_private.c b/ldap/servers/plugins/replication/windows_private.c index 5baa7ce2..d6176b53 100644 --- a/ldap/servers/plugins/replication/windows_private.c +++ b/ldap/servers/plugins/replication/windows_private.c @@ -70,8 +70,12 @@ struct windowsprivate { * so we only have to allocate each filter once instead of doing it every time we receive a change. */ Slapi_Filter *directory_filter; /* Used for checking if local entries need to be sync'd to AD */ Slapi_Filter *deleted_filter; /* Used for checking if an entry is an AD tombstone */ + Slapi_Entry *raw_entry; /* "raw" un-schema processed last entry read from AD */ + void *api_cookie; /* private data used by api callbacks */ }; +static void windows_private_set_windows_domain(const Repl_Agmt *ra, char *domain); + static int true_value_from_string(char *val) { @@ -99,7 +103,6 @@ windows_parse_config_entry(Repl_Agmt *ra, const char *type, Slapi_Entry *e) windows_private_set_windows_subtree(ra, slapi_sdn_new_dn_passin(tmpstr) ); } retval = 1; - slapi_ch_free((void**)&tmpstr); } if (type == NULL || slapi_attr_types_equivalent(type,type_nsds7DirectoryReplicaArea)) { @@ -109,7 +112,6 @@ windows_parse_config_entry(Repl_Agmt *ra, const char *type, Slapi_Entry *e) windows_private_set_directory_subtree(ra, slapi_sdn_new_dn_passin(tmpstr) ); } retval = 1; - slapi_ch_free((void**)&tmpstr); } if (type == NULL || slapi_attr_types_equivalent(type,type_nsds7CreateNewUsers)) { @@ -173,6 +175,8 @@ windows_init_agreement_from_entry(Repl_Agmt *ra, Slapi_Entry *e) agmt_set_priv(ra,windows_private_new()); windows_parse_config_entry(ra,NULL,e); + + windows_plugin_init(ra); } const char* windows_private_get_purl(const Repl_Agmt *ra) @@ -214,6 +218,9 @@ void windows_agreement_delete(Repl_Agmt *ra) slapi_filter_free(dp->directory_filter, 1); slapi_filter_free(dp->deleted_filter, 1); + slapi_entry_free(dp->raw_entry); + dp->raw_entry = NULL; + dp->api_cookie = NULL; slapi_ch_free((void **)dp); LDAPDebug( LDAP_DEBUG_TRACE, "<= windows_private_delete\n", 0, 0, 0 ); @@ -401,7 +408,7 @@ const Slapi_DN* windows_private_get_directory_subtree (const Repl_Agmt *ra) } /* Takes a copy of the sdn passed in */ -void windows_private_set_windows_subtree (const Repl_Agmt *ra,const Slapi_DN* sdn ) +void windows_private_set_windows_subtree (const Repl_Agmt *ra,Slapi_DN* sdn ) { Dirsync_Private *dp; @@ -413,14 +420,15 @@ void windows_private_set_windows_subtree (const Repl_Agmt *ra,const Slapi_DN* sd dp = (Dirsync_Private *) agmt_get_priv(ra); PR_ASSERT (dp); - - dp->windows_subtree = slapi_sdn_dup(sdn); + + slapi_sdn_free(&dp->windows_subtree); + dp->windows_subtree = sdn; LDAPDebug( LDAP_DEBUG_TRACE, "<= windows_private_set_windows_replarea\n", 0, 0, 0 ); } /* Takes a copy of the sdn passed in */ -void windows_private_set_directory_subtree (const Repl_Agmt *ra,const Slapi_DN* sdn ) +void windows_private_set_directory_subtree (const Repl_Agmt *ra,Slapi_DN* sdn ) { Dirsync_Private *dp; @@ -433,7 +441,8 @@ void windows_private_set_directory_subtree (const Repl_Agmt *ra,const Slapi_DN* dp = (Dirsync_Private *) agmt_get_priv(ra); PR_ASSERT (dp); - dp->directory_subtree = slapi_sdn_dup(sdn); + slapi_sdn_free(&dp->directory_subtree); + dp->directory_subtree = sdn; LDAPDebug( LDAP_DEBUG_TRACE, "<= windows_private_set_directory_replarea\n", 0, 0, 0 ); } @@ -516,6 +525,7 @@ LDAPControl* windows_private_dirsync_control(const Repl_Agmt *ra) LDAPControl *control = NULL; BerElement *ber; Dirsync_Private *dp; + char iscritical = PR_TRUE; LDAPDebug( LDAP_DEBUG_TRACE, "=> windows_private_dirsync_control\n", 0, 0, 0 ); @@ -527,7 +537,10 @@ LDAPControl* windows_private_dirsync_control(const Repl_Agmt *ra) ber_printf( ber, "{iio}", dp->dirsync_flags, dp->dirsync_maxattributecount, dp->dirsync_cookie, dp->dirsync_cookie_len ); - slapi_build_control( REPL_DIRSYNC_CONTROL_OID, ber, PR_TRUE, &control); +#ifdef WINSYNC_TEST + iscritical = PR_FALSE; +#endif + slapi_build_control( REPL_DIRSYNC_CONTROL_OID, ber, iscritical, &control); ber_free(ber,1); @@ -787,3 +800,389 @@ int windows_private_load_dirsync_cookie(const Repl_Agmt *ra) return rc; } +/* get returns a pointer to the structure - do not free */ +Slapi_Entry *windows_private_get_raw_entry(const Repl_Agmt *ra) +{ + Dirsync_Private *dp; + + LDAPDebug( LDAP_DEBUG_TRACE, "=> windows_private_get_raw_entry\n", 0, 0, 0 ); + + dp = (Dirsync_Private *) agmt_get_priv(ra); + PR_ASSERT (dp); + + LDAPDebug( LDAP_DEBUG_TRACE, "<= windows_private_get_raw_entry\n", 0, 0, 0 ); + + return dp->raw_entry; +} + +/* this is passin - windows_private owns the pointer, not a copy */ +void windows_private_set_raw_entry(const Repl_Agmt *ra, Slapi_Entry *e) +{ + Dirsync_Private *dp; + + LDAPDebug( LDAP_DEBUG_TRACE, "=> windows_private_set_raw_entry\n", 0, 0, 0 ); + + dp = (Dirsync_Private *) agmt_get_priv(ra); + PR_ASSERT (dp); + + slapi_entry_free(dp->raw_entry); + dp->raw_entry = e; + + LDAPDebug( LDAP_DEBUG_TRACE, "<= windows_private_set_raw_entry\n", 0, 0, 0 ); +} + +void *windows_private_get_api_cookie(const Repl_Agmt *ra) +{ + Dirsync_Private *dp; + + LDAPDebug( LDAP_DEBUG_TRACE, "=> windows_private_get_api_cookie\n", 0, 0, 0 ); + + dp = (Dirsync_Private *) agmt_get_priv(ra); + PR_ASSERT (dp); + + LDAPDebug( LDAP_DEBUG_TRACE, "<= windows_private_get_api_cookie\n", 0, 0, 0 ); + + return dp->api_cookie; +} + +void windows_private_set_api_cookie(Repl_Agmt *ra, void *api_cookie) +{ + Dirsync_Private *dp; + + LDAPDebug( LDAP_DEBUG_TRACE, "=> windows_private_set_api_cookie\n", 0, 0, 0 ); + + dp = (Dirsync_Private *) agmt_get_priv(ra); + PR_ASSERT (dp); + dp->api_cookie = api_cookie; + + LDAPDebug( LDAP_DEBUG_TRACE, "<= windows_private_set_api_cookie\n", 0, 0, 0 ); +} + +/* an array of function pointers */ +static void **_WinSyncAPI = NULL; + +void +windows_plugin_init(Repl_Agmt *ra) +{ + void *cookie = NULL; + winsync_plugin_init_cb initfunc = NULL; + + LDAPDebug( LDAP_DEBUG_PLUGIN, "--> windows_plugin_init_start -- begin\n",0,0,0); + + /* if the function pointer array is null, get the functions - we will + call init once per replication agreement, but will only grab the + api once */ + if((NULL == _WinSyncAPI) && + (slapi_apib_get_interface(WINSYNC_v1_0_GUID, &_WinSyncAPI) || + (NULL == _WinSyncAPI))) + { + LDAPDebug( LDAP_DEBUG_PLUGIN, + "<-- windows_plugin_init_start -- no windows plugin API registered for GUID [%s] -- end\n", + WINSYNC_v1_0_GUID,0,0); + return; + } + + initfunc = (winsync_plugin_init_cb)_WinSyncAPI[WINSYNC_PLUGIN_INIT_CB]; + if (initfunc) { + cookie = (*initfunc)(windows_private_get_directory_subtree(ra), + windows_private_get_windows_subtree(ra)); + } + windows_private_set_api_cookie(ra, cookie); + + LDAPDebug( LDAP_DEBUG_PLUGIN, "<-- windows_plugin_init_start -- end\n",0,0,0); + return; +} + +void +winsync_plugin_call_dirsync_search_params_cb(const Repl_Agmt *ra, const char *agmt_dn, + char **base, int *scope, char **filter, + char ***attrs, LDAPControl ***serverctrls) +{ + winsync_search_params_cb thefunc = + (_WinSyncAPI && _WinSyncAPI[WINSYNC_PLUGIN_DIRSYNC_SEARCH_CB]) ? + (winsync_search_params_cb)_WinSyncAPI[WINSYNC_PLUGIN_DIRSYNC_SEARCH_CB] : + NULL; + + if (!thefunc) { + return; + } + + (*thefunc)(windows_private_get_api_cookie(ra), agmt_dn, base, scope, filter, + attrs, serverctrls); + + return; +} + +void +winsync_plugin_call_pre_ad_search_cb(const Repl_Agmt *ra, const char *agmt_dn, + char **base, int *scope, char **filter, + char ***attrs, LDAPControl ***serverctrls) +{ + winsync_search_params_cb thefunc = + (_WinSyncAPI && _WinSyncAPI[WINSYNC_PLUGIN_PRE_AD_SEARCH_CB]) ? + (winsync_search_params_cb)_WinSyncAPI[WINSYNC_PLUGIN_PRE_AD_SEARCH_CB] : + NULL; + + if (!thefunc) { + return; + } + + (*thefunc)(windows_private_get_api_cookie(ra), agmt_dn, base, scope, filter, + attrs, serverctrls); + + return; +} + +void +winsync_plugin_call_pre_ds_search_entry_cb(const Repl_Agmt *ra, const char *agmt_dn, + char **base, int *scope, char **filter, + char ***attrs, LDAPControl ***serverctrls) +{ + winsync_search_params_cb thefunc = + (_WinSyncAPI && _WinSyncAPI[WINSYNC_PLUGIN_PRE_DS_SEARCH_ENTRY_CB]) ? + (winsync_search_params_cb)_WinSyncAPI[WINSYNC_PLUGIN_PRE_DS_SEARCH_ENTRY_CB] : + NULL; + + if (!thefunc) { + return; + } + + (*thefunc)(windows_private_get_api_cookie(ra), agmt_dn, base, scope, filter, + attrs, serverctrls); + + return; +} + +void +winsync_plugin_call_pre_ds_search_all_cb(const Repl_Agmt *ra, const char *agmt_dn, + char **base, int *scope, char **filter, + char ***attrs, LDAPControl ***serverctrls) +{ + winsync_search_params_cb thefunc = + (_WinSyncAPI && _WinSyncAPI[WINSYNC_PLUGIN_PRE_DS_SEARCH_ALL_CB]) ? + (winsync_search_params_cb)_WinSyncAPI[WINSYNC_PLUGIN_PRE_DS_SEARCH_ALL_CB] : + NULL; + + if (!thefunc) { + return; + } + + (*thefunc)(windows_private_get_api_cookie(ra), agmt_dn, base, scope, filter, + attrs, serverctrls); + + return; +} + +void +winsync_plugin_call_pre_ad_mod_user_cb(const Repl_Agmt *ra, const Slapi_Entry *rawentry, + Slapi_Entry *ad_entry, Slapi_Entry *ds_entry, + Slapi_Mods *smods, int *do_modify) +{ + winsync_pre_mod_cb thefunc = + (_WinSyncAPI && _WinSyncAPI[WINSYNC_PLUGIN_PRE_AD_MOD_USER_CB]) ? + (winsync_pre_mod_cb)_WinSyncAPI[WINSYNC_PLUGIN_PRE_AD_MOD_USER_CB] : + NULL; + + if (!thefunc) { + return; + } + + (*thefunc)(windows_private_get_api_cookie(ra), rawentry, ad_entry, + ds_entry, smods, do_modify); + + return; +} + +void +winsync_plugin_call_pre_ad_mod_group_cb(const Repl_Agmt *ra, const Slapi_Entry *rawentry, + Slapi_Entry *ad_entry, Slapi_Entry *ds_entry, + Slapi_Mods *smods, int *do_modify) +{ + winsync_pre_mod_cb thefunc = + (_WinSyncAPI && _WinSyncAPI[WINSYNC_PLUGIN_PRE_AD_MOD_GROUP_CB]) ? + (winsync_pre_mod_cb)_WinSyncAPI[WINSYNC_PLUGIN_PRE_AD_MOD_GROUP_CB] : + NULL; + + if (!thefunc) { + return; + } + + (*thefunc)(windows_private_get_api_cookie(ra), rawentry, ad_entry, + ds_entry, smods, do_modify); + + return; +} + +void +winsync_plugin_call_pre_ds_mod_user_cb(const Repl_Agmt *ra, const Slapi_Entry *rawentry, + Slapi_Entry *ad_entry, Slapi_Entry *ds_entry, + Slapi_Mods *smods, int *do_modify) +{ + winsync_pre_mod_cb thefunc = + (_WinSyncAPI && _WinSyncAPI[WINSYNC_PLUGIN_PRE_DS_MOD_USER_CB]) ? + (winsync_pre_mod_cb)_WinSyncAPI[WINSYNC_PLUGIN_PRE_DS_MOD_USER_CB] : + NULL; + + if (!thefunc) { + return; + } + + (*thefunc)(windows_private_get_api_cookie(ra), rawentry, ad_entry, + ds_entry, smods, do_modify); + + return; +} + +void +winsync_plugin_call_pre_ds_mod_group_cb(const Repl_Agmt *ra, const Slapi_Entry *rawentry, + Slapi_Entry *ad_entry, Slapi_Entry *ds_entry, + Slapi_Mods *smods, int *do_modify) +{ + winsync_pre_mod_cb thefunc = + (_WinSyncAPI && _WinSyncAPI[WINSYNC_PLUGIN_PRE_DS_MOD_GROUP_CB]) ? + (winsync_pre_mod_cb)_WinSyncAPI[WINSYNC_PLUGIN_PRE_DS_MOD_GROUP_CB] : + NULL; + + if (!thefunc) { + return; + } + + (*thefunc)(windows_private_get_api_cookie(ra), rawentry, ad_entry, + ds_entry, smods, do_modify); + + return; +} + +void +winsync_plugin_call_pre_ds_add_user_cb(const Repl_Agmt *ra, const Slapi_Entry *rawentry, + Slapi_Entry *ad_entry, Slapi_Entry *ds_entry) +{ + winsync_pre_add_cb thefunc = + (_WinSyncAPI && _WinSyncAPI[WINSYNC_PLUGIN_PRE_DS_ADD_USER_CB]) ? + (winsync_pre_add_cb)_WinSyncAPI[WINSYNC_PLUGIN_PRE_DS_ADD_USER_CB] : + NULL; + + if (!thefunc) { + return; + } + + (*thefunc)(windows_private_get_api_cookie(ra), rawentry, ad_entry, + ds_entry); + + return; +} + +void +winsync_plugin_call_pre_ds_add_group_cb(const Repl_Agmt *ra, const Slapi_Entry *rawentry, + Slapi_Entry *ad_entry, Slapi_Entry *ds_entry) +{ + winsync_pre_add_cb thefunc = + (_WinSyncAPI && _WinSyncAPI[WINSYNC_PLUGIN_PRE_DS_ADD_GROUP_CB]) ? + (winsync_pre_add_cb)_WinSyncAPI[WINSYNC_PLUGIN_PRE_DS_ADD_GROUP_CB] : + NULL; + + if (!thefunc) { + return; + } + + (*thefunc)(windows_private_get_api_cookie(ra), rawentry, ad_entry, + ds_entry); + + return; +} + +void +winsync_plugin_call_get_new_ds_user_dn_cb(const Repl_Agmt *ra, const Slapi_Entry *rawentry, + Slapi_Entry *ad_entry, char **new_dn_string, + const Slapi_DN *ds_suffix, const Slapi_DN *ad_suffix) +{ + winsync_get_new_dn_cb thefunc = + (_WinSyncAPI && _WinSyncAPI[WINSYNC_PLUGIN_GET_NEW_DS_USER_DN_CB]) ? + (winsync_get_new_dn_cb)_WinSyncAPI[WINSYNC_PLUGIN_GET_NEW_DS_USER_DN_CB] : + NULL; + + if (!thefunc) { + return; + } + + (*thefunc)(windows_private_get_api_cookie(ra), rawentry, ad_entry, + new_dn_string, ds_suffix, ad_suffix); + + return; +} + +void +winsync_plugin_call_get_new_ds_group_dn_cb(const Repl_Agmt *ra, const Slapi_Entry *rawentry, + Slapi_Entry *ad_entry, char **new_dn_string, + const Slapi_DN *ds_suffix, const Slapi_DN *ad_suffix) +{ + winsync_get_new_dn_cb thefunc = + (_WinSyncAPI && _WinSyncAPI[WINSYNC_PLUGIN_GET_NEW_DS_GROUP_DN_CB]) ? + (winsync_get_new_dn_cb)_WinSyncAPI[WINSYNC_PLUGIN_GET_NEW_DS_GROUP_DN_CB] : + NULL; + + if (!thefunc) { + return; + } + + (*thefunc)(windows_private_get_api_cookie(ra), rawentry, ad_entry, + new_dn_string, ds_suffix, ad_suffix); + + return; +} + +void +winsync_plugin_call_pre_ad_mod_user_mods_cb(const Repl_Agmt *ra, const Slapi_Entry *rawentry, + const Slapi_DN *local_dn, LDAPMod * const *origmods, + Slapi_DN *remote_dn, LDAPMod ***modstosend) +{ + winsync_pre_ad_mod_mods_cb thefunc = + (_WinSyncAPI && _WinSyncAPI[WINSYNC_PLUGIN_PRE_AD_MOD_USER_MODS_CB]) ? + (winsync_pre_ad_mod_mods_cb)_WinSyncAPI[WINSYNC_PLUGIN_PRE_AD_MOD_USER_MODS_CB] : + NULL; + + if (!thefunc) { + return; + } + + (*thefunc)(windows_private_get_api_cookie(ra), rawentry, local_dn, + origmods, remote_dn, modstosend); + + return; +} + +void +winsync_plugin_call_pre_ad_mod_group_mods_cb(const Repl_Agmt *ra, const Slapi_Entry *rawentry, + const Slapi_DN *local_dn, LDAPMod * const *origmods, + Slapi_DN *remote_dn, LDAPMod ***modstosend) +{ + winsync_pre_ad_mod_mods_cb thefunc = + (_WinSyncAPI && _WinSyncAPI[WINSYNC_PLUGIN_PRE_AD_MOD_GROUP_MODS_CB]) ? + (winsync_pre_ad_mod_mods_cb)_WinSyncAPI[WINSYNC_PLUGIN_PRE_AD_MOD_GROUP_MODS_CB] : + NULL; + + if (!thefunc) { + return; + } + + (*thefunc)(windows_private_get_api_cookie(ra), rawentry, local_dn, + origmods, remote_dn, modstosend); + + return; +} + +int +winsync_plugin_call_can_add_entry_to_ad_cb(const Repl_Agmt *ra, const Slapi_Entry *local_entry, + const Slapi_DN *remote_dn) +{ + winsync_can_add_to_ad_cb thefunc = + (_WinSyncAPI && _WinSyncAPI[WINSYNC_PLUGIN_CAN_ADD_ENTRY_TO_AD_CB]) ? + (winsync_can_add_to_ad_cb)_WinSyncAPI[WINSYNC_PLUGIN_CAN_ADD_ENTRY_TO_AD_CB] : + NULL; + + if (!thefunc) { + return 1; /* default is entry can be added to AD */ + } + + return (*thefunc)(windows_private_get_api_cookie(ra), local_entry, remote_dn); +} diff --git a/ldap/servers/plugins/replication/windows_protocol_util.c b/ldap/servers/plugins/replication/windows_protocol_util.c index 8088d622..b893aac2 100644 --- a/ldap/servers/plugins/replication/windows_protocol_util.c +++ b/ldap/servers/plugins/replication/windows_protocol_util.c @@ -668,6 +668,7 @@ windows_acquire_replica(Private_Repl_Protocol *prp, RUV **ruv, int check_ruv) return_value = ACQUIRE_FATAL_ERROR; } slapi_sdn_free(&replarea_sdn); + csn_free(¤t_csn); } } @@ -1004,7 +1005,6 @@ process_replay_add(Private_Repl_Protocol *prp, slapi_operation_parameters *op, S } if (cn_string) { - char *rdnstr = NULL; char *container_str = NULL; const char *suffix = slapi_sdn_get_dn(windows_private_get_windows_subtree(prp->agmt)); @@ -1184,7 +1184,19 @@ windows_replay_update(Private_Repl_Protocol *prp, slapi_operation_parameters *op agmt_get_long_name(prp->agmt), op2string(op->operation_type), op->target_address.dn, slapi_sdn_get_dn(remote_dn)); 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 */ + /* + we should check the modify case first and check the list of mods - + if the magic objectclass (ntuser) and attributes (ntUserCreateNewAccount + or ntGroupCreateNewAccount) then we should fall through to the ADD case + since the user wants to add the user to AD - could maybe just change + process_replay_add slightly, to add the mods list from the modify + operation - process_replay_add already turns the entry into a mods list + to pass to the ldap add operation, so it should not be too much more + trouble to apply the additional mods from the modify operation - we'll + have to pass in local entry, or perhaps just change the operation from + modify to an add, and set the op->p.p_add.target_entry to the local_entry + which gets retrieved above + */ case SLAPI_OPERATION_ADD: return_value = process_replay_add(prp,op,local_entry,local_dn,remote_dn,is_user,missing_entry,&password); break; @@ -1193,6 +1205,22 @@ windows_replay_update(Private_Repl_Protocol *prp, slapi_operation_parameters *op LDAPMod **mapped_mods = NULL; windows_map_mods_for_replay(prp,op->p.p_modify.modify_mods, &mapped_mods, is_user, &password); + if (is_user) { + winsync_plugin_call_pre_ad_mod_user_mods_cb(prp->agmt, + windows_private_get_raw_entry(prp->agmt), + local_dn, + op->p.p_modify.modify_mods, + remote_dn, + &mapped_mods); + } else if (is_group) { + winsync_plugin_call_pre_ad_mod_group_mods_cb(prp->agmt, + windows_private_get_raw_entry(prp->agmt), + local_dn, + op->p.p_modify.modify_mods, + remote_dn, + &mapped_mods); + } + /* 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 ) { @@ -1304,7 +1332,7 @@ is_straight_mapped_attr(const char *type, int is_user /* or group */, int is_nt4 char *this_attr = NULL; char **list = is_user ? (is_nt4 ? nt4_user_matching_attributes : windows_user_matching_attributes) : (is_nt4 ? nt4_group_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]) + while ((this_attr = list[offset])) { if (0 == slapi_attr_type_cmp(this_attr, type, SLAPI_TYPE_CMP_SUBTYPE)) { @@ -1327,7 +1355,7 @@ windows_map_attr_name(const char *original_type , int to_windows, int is_user, i *mapped_type = NULL; /* Iterate over the map entries looking for the type we have */ - while(this_map = &(our_map[offset])) + 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; @@ -1500,7 +1528,6 @@ windows_create_remote_entry(Private_Repl_Protocol *prp,Slapi_Entry *original_ent if (0 == slapi_attr_type_cmp(new_type, "streetAddress", SLAPI_TYPE_CMP_SUBTYPE)) { if (slapi_valueset_count(vs) > 1) { int i = 0; - const char *street_value = NULL; Slapi_Value *value = NULL; Slapi_Value *new_value = NULL; @@ -2026,6 +2053,10 @@ find_entry_by_attr_value(const char *attribute, const char *value, Slapi_Entry * int rval = 0; const char *subtree_dn = NULL; int not_unique = 0; + char *subtree_dn_copy = NULL; + int scope = LDAP_SCOPE_SUBTREE; + char **attrs = NULL; + LDAPControl **server_controls = NULL; if (pb == NULL) goto done; @@ -2036,12 +2067,21 @@ find_entry_by_attr_value(const char *attribute, const char *value, Slapi_Entry * goto done; subtree_dn = slapi_sdn_get_dn(windows_private_get_directory_subtree(ra)); + subtree_dn_copy = slapi_ch_strdup(subtree_dn); - slapi_search_internal_set_pb(pb, subtree_dn, - LDAP_SCOPE_SUBTREE, query, NULL, 0, NULL, NULL, + winsync_plugin_call_pre_ds_search_entry_cb(ra, NULL, &subtree_dn_copy, &scope, &query, + &attrs, &server_controls); + + slapi_search_internal_set_pb(pb, subtree_dn_copy, + scope, query, attrs, 0, server_controls, NULL, (void *)plugin_get_default_component_id(), 0); slapi_search_internal_pb(pb); + slapi_ch_free_string(&subtree_dn_copy); slapi_ch_free_string(&query); + slapi_ch_array_free(attrs); + attrs = NULL; + ldap_controls_free(server_controls); + server_controls = NULL; slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &rval); if (rval != LDAP_SUCCESS) @@ -2096,7 +2136,7 @@ dedash_guid(char *str) char *p = str; char c = '\0'; - while (c = *p) + while ((c = *p)) { if ('-' == c) { @@ -2254,7 +2294,7 @@ map_windows_tombstone_dn(Slapi_Entry *e, Slapi_DN **dn, Private_Repl_Protocol *p /* The tombstone suffix discards any containers, so we need * to trim the DN to only dc components. */ - if (suffix = slapi_sdn_get_dn(windows_private_get_windows_subtree(prp->agmt))) { + if ((suffix = slapi_sdn_get_dn(windows_private_get_windows_subtree(prp->agmt)))) { /* If this isn't found, it is treated as an error below. */ suffix = (const char *) PL_strcasestr(suffix,"dc="); } @@ -2358,7 +2398,6 @@ static Slapi_DN *make_dn_from_guid(char *guid, int is_nt4, const char* suffix) char *dn_string = NULL; if (guid) { - new_dn = slapi_sdn_new(); if (is_nt4) { dn_string = PR_smprintf("GUID=%s,%s",guid,suffix); @@ -2366,7 +2405,7 @@ static Slapi_DN *make_dn_from_guid(char *guid, int is_nt4, const char* suffix) { dn_string = PR_smprintf("<GUID=%s>",guid); } - slapi_sdn_init_dn_byval(new_dn,dn_string); + new_dn = slapi_sdn_new_dn_byval(dn_string); PR_smprintf_free(dn_string); } /* dn string is now inside the Slapi_DN, and will be freed by its owner */ @@ -2452,6 +2491,7 @@ map_entry_dn_outbound(Slapi_Entry *e, Slapi_DN **dn, Private_Repl_Protocol *prp, * without removing the ntUniqueID attribute. We should verify that the entry really * exists in AD. */ rc = windows_get_remote_entry(prp, new_dn, &remote_entry); + slapi_sdn_free(&new_dn); if (0 == rc && remote_entry) { slapi_entry_free(remote_entry); } else { @@ -2471,7 +2511,6 @@ map_entry_dn_outbound(Slapi_Entry *e, Slapi_DN **dn, Private_Repl_Protocol *prp, } if (cn_string) { - char *rdnstr = NULL; char *container_str = NULL; container_str = extract_container(slapi_entry_get_sdn_const(e), @@ -2719,9 +2758,23 @@ map_entry_dn_inbound(Slapi_Entry *e, Slapi_DN **dn, const Repl_Agmt *ra) if (is_user) { new_dn_string = PR_smprintf("uid=%s,%s%s",username,container_str,suffix); + winsync_plugin_call_get_new_ds_user_dn_cb(ra, + windows_private_get_raw_entry(ra), + e, + &new_dn_string, + windows_private_get_directory_subtree(ra), + windows_private_get_windows_subtree(ra)); } else { new_dn_string = PR_smprintf("cn=%s,%s%s",username,container_str,suffix); + if (is_group) { + winsync_plugin_call_get_new_ds_group_dn_cb(ra, + windows_private_get_raw_entry(ra), + e, + &new_dn_string, + windows_private_get_directory_subtree(ra), + windows_private_get_windows_subtree(ra)); + } } new_dn = slapi_sdn_new_dn_byval(new_dn_string); PR_smprintf_free(new_dn_string); @@ -2939,6 +2992,18 @@ windows_create_local_entry(Private_Repl_Protocol *prp,Slapi_Entry *remote_entry, { slapi_entry_add_string(local_entry,"sn",username); } + + if (is_user) { + winsync_plugin_call_pre_ds_add_user_cb(prp->agmt, + windows_private_get_raw_entry(prp->agmt), + remote_entry, + local_entry); + } else if (is_group) { + winsync_plugin_call_pre_ds_add_group_cb(prp->agmt, + windows_private_get_raw_entry(prp->agmt), + remote_entry, + local_entry); + } /* Store it */ windows_dump_entry("Adding new local entry",local_entry); pb = slapi_pblock_new(); @@ -2951,6 +3016,7 @@ windows_create_local_entry(Private_Repl_Protocol *prp,Slapi_Entry *remote_entry, "add operation of entry %s returned: %d\n", slapi_sdn_get_dn(local_sdn), retval); } error: + slapi_ch_free_string(&guid_str); if (pb) { slapi_pblock_destroy(pb); @@ -3115,7 +3181,6 @@ windows_generate_update_mods(Private_Repl_Protocol *prp,Slapi_Entry *remote_entr * sure we don't try to send more than one value. */ if (slapi_valueset_count(vs) > 1) { int i = 0; - const char *street_value = NULL; Slapi_Value *value = NULL; Slapi_Value *new_value = NULL; @@ -3229,7 +3294,6 @@ windows_generate_update_mods(Private_Repl_Protocol *prp,Slapi_Entry *remote_entr * sure we don't try to send more than one value. */ if (slapi_valueset_count(vs) > 1) { int i = 0; - const char *street_value = NULL; Slapi_Value *value = NULL; Slapi_Value *new_value = NULL; @@ -3318,6 +3382,40 @@ windows_generate_update_mods(Private_Repl_Protocol *prp,Slapi_Entry *remote_entr slapi_ch_free_string(&local_type); } + if (to_windows) { + if (is_user) { + winsync_plugin_call_pre_ad_mod_user_cb(prp->agmt, + windows_private_get_raw_entry(prp->agmt), + local_entry, /* the cooked ad entry */ + remote_entry, /* the ds entry */ + smods, + do_modify); + } else if (is_group) { + winsync_plugin_call_pre_ad_mod_group_cb(prp->agmt, + windows_private_get_raw_entry(prp->agmt), + local_entry, /* the cooked ad entry */ + remote_entry, /* the ds entry */ + smods, + do_modify); + } + } else { + if (is_user) { + winsync_plugin_call_pre_ds_mod_user_cb(prp->agmt, + windows_private_get_raw_entry(prp->agmt), + remote_entry, /* the cooked ad entry */ + local_entry, /* the ds entry */ + smods, + do_modify); + } else if (is_group) { + winsync_plugin_call_pre_ds_mod_group_cb(prp->agmt, + windows_private_get_raw_entry(prp->agmt), + remote_entry, /* the cooked ad entry */ + local_entry, /* the ds entry */ + smods, + do_modify); + } + } + if (slapi_is_loglevel_set(SLAPI_LOG_REPL) && *do_modify) { slapi_mods_dump(smods,"windows sync"); @@ -3412,10 +3510,16 @@ windows_process_total_add(Private_Repl_Protocol *prp,Slapi_Entry *e, Slapi_DN* r Slapi_Entry *mapped_entry = NULL; char *password = NULL; const Slapi_DN* local_dn = NULL; + int can_add = winsync_plugin_call_can_add_entry_to_ad_cb(prp->agmt, e, remote_dn); /* First map the entry */ local_dn = slapi_entry_get_sdn_const(e); - if (missing_entry) - retval = windows_create_remote_entry(prp, e, remote_dn, &mapped_entry, &password); + if (missing_entry) { + if (can_add) { + retval = windows_create_remote_entry(prp, e, remote_dn, &mapped_entry, &password); + } else { + return retval; /* cannot add and no entry to modify */ + } + } /* Convert entry to mods */ if (0 == retval && mapped_entry) { diff --git a/ldap/servers/plugins/replication/windows_tot_protocol.c b/ldap/servers/plugins/replication/windows_tot_protocol.c index 6e01f633..09ecbc8e 100644 --- a/ldap/servers/plugins/replication/windows_tot_protocol.c +++ b/ldap/servers/plugins/replication/windows_tot_protocol.c @@ -99,11 +99,15 @@ windows_tot_run(Private_Repl_Protocol *prp) int rc; callback_data cb_data; Slapi_PBlock *pb; - const char* dn; + char* dn; RUV *ruv = NULL; RUV *starting_ruv = NULL; Replica *replica = NULL; Object *local_ruv_obj = NULL; + int scope = LDAP_SCOPE_SUBTREE; + char *filter = slapi_ch_strdup("(|(objectclass=ntuser)(objectclass=ntgroup))"); + char **attrs = NULL; + LDAPControl **server_controls = NULL; LDAPDebug( LDAP_DEBUG_TRACE, "=> windows_tot_run\n", 0, 0, 0 ); @@ -168,13 +172,15 @@ windows_tot_run(Private_Repl_Protocol *prp) /* send everything */ - dn = slapi_sdn_get_dn( windows_private_get_directory_subtree(prp->agmt)); + dn = slapi_ch_strdup(slapi_sdn_get_dn( windows_private_get_directory_subtree(prp->agmt))); + + winsync_plugin_call_pre_ds_search_all_cb(prp->agmt, NULL, &dn, &scope, &filter, + &attrs, &server_controls); pb = slapi_pblock_new (); /* Perform a subtree search for any ntuser or ntgroup entries underneath the * suffix defined in the sync agreement. */ - slapi_search_internal_set_pb (pb, dn, - LDAP_SCOPE_SUBTREE, "(|(objectclass=ntuser)(objectclass=ntgroup))", NULL, 0, NULL, NULL, + slapi_search_internal_set_pb (pb, dn, scope, filter, attrs, 0, server_controls, NULL, repl_get_plugin_identity (PLUGIN_MULTIMASTER_REPLICATION), 0); cb_data.prp = prp; cb_data.rc = 0; @@ -186,6 +192,13 @@ windows_tot_run(Private_Repl_Protocol *prp) get_result /* result callback */, send_entry /* entry callback */, NULL /* referral callback*/); + slapi_ch_free_string(&dn); + slapi_ch_free_string(&filter); + slapi_ch_array_free(attrs); + attrs = NULL; + ldap_controls_free(server_controls); + server_controls = NULL; + slapi_pblock_destroy (pb); agmt_set_last_init_end(prp->agmt, current_time()); rc = cb_data.rc; diff --git a/ldap/servers/plugins/replication/windowsrepl.h b/ldap/servers/plugins/replication/windowsrepl.h index 3691664a..47138656 100644 --- a/ldap/servers/plugins/replication/windowsrepl.h +++ b/ldap/servers/plugins/replication/windowsrepl.h @@ -44,9 +44,9 @@ /* 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 ); +void windows_private_set_windows_subtree (const Repl_Agmt *ra,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 ); +void windows_private_set_directory_subtree (const Repl_Agmt *ra,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); @@ -63,7 +63,6 @@ PRBool windows_private_create_users(const Repl_Agmt *ra); void windows_private_set_create_groups(const Repl_Agmt *ra, PRBool value); PRBool windows_private_create_groups(const Repl_Agmt *ra); const char *windows_private_get_windows_domain(const Repl_Agmt *ra); -static void windows_private_set_windows_domain(const Repl_Agmt *ra, char *domain); int windows_private_get_isnt4(const Repl_Agmt *ra); void windows_private_set_isnt4(const Repl_Agmt *ra, int isit); int windows_private_get_iswin2k3(const Repl_Agmt *ra); @@ -71,6 +70,16 @@ void windows_private_set_iswin2k3(const Repl_Agmt *ra, int isit); Slapi_Filter* windows_private_get_directory_filter(const Repl_Agmt *ra); Slapi_Filter* windows_private_get_deleted_filter(const Repl_Agmt *ra); const char* windows_private_get_purl(const Repl_Agmt *ra); +/* + * The raw entry is the last raw entry read from AD - raw as opposed + * "cooked" - that is, having had schema processing done + */ +/* get returns a pointer to the structure - do not free */ +Slapi_Entry *windows_private_get_raw_entry(const Repl_Agmt *ra); +/* this is passin - windows_private owns the pointer, not a copy */ +void windows_private_set_raw_entry(const Repl_Agmt *ra, Slapi_Entry *e); +void *windows_private_get_api_cookie(const Repl_Agmt *ra); +void windows_private_set_api_cookie(Repl_Agmt *ra, void *cookie); /* in windows_connection.c */ ConnResult windows_conn_connect(Repl_Connection *conn); @@ -112,3 +121,86 @@ int windows_check_user_password(Repl_Connection *conn, Slapi_DN *sdn, char *pass /* Used for GUID format conversion */ #define NTUNIQUEID_LENGTH 32 #define AD_GUID_LENGTH 36 + +/* called for each replication agreement - so the winsync + plugin can be agreement specific and store agreement + specific data +*/ +void windows_plugin_init(Repl_Agmt *ra); + +void winsync_plugin_call_dirsync_search_params_cb(const Repl_Agmt *ra, const char *agmt_dn, char **base, int *scope, char **filter, char ***attrs, LDAPControl ***serverctrls); +/* called before searching for a single entry from AD - agmt_dn will be NULL */ +void winsync_plugin_call_pre_ad_search_cb(const Repl_Agmt *ra, const char *agmt_dn, char **base, int *scope, char **filter, char ***attrs, LDAPControl ***serverctrls); +/* called before an internal search to get a single DS entry - agmt_dn will be NULL */ +void winsync_plugin_call_pre_ds_search_entry_cb(const Repl_Agmt *ra, const char *agmt_dn, char **base, int *scope, char **filter, char ***attrs, LDAPControl ***serverctrls); +/* called before the total update to get all entries from the DS to sync to AD */ +void winsync_plugin_call_pre_ds_search_all_cb(const Repl_Agmt *ra, const char *agmt_dn, char **base, int *scope, char **filter, char ***attrs, LDAPControl ***serverctrls); + +void winsync_plugin_call_pre_ad_mod_user_cb(const Repl_Agmt *ra, const Slapi_Entry *rawentry, Slapi_Entry *ad_entry, Slapi_Entry *ds_entry, Slapi_Mods *smods, int *do_modify); +void winsync_plugin_call_pre_ad_mod_group_cb(const Repl_Agmt *ra, const Slapi_Entry *rawentry, Slapi_Entry *ad_entry, Slapi_Entry *ds_entry, Slapi_Mods *smods, int *do_modify); +void winsync_plugin_call_pre_ds_mod_user_cb(const Repl_Agmt *ra, const Slapi_Entry *rawentry, Slapi_Entry *ad_entry, Slapi_Entry *ds_entry, Slapi_Mods *smods, int *do_modify); +void winsync_plugin_call_pre_ds_mod_group_cb(const Repl_Agmt *ra, const Slapi_Entry *rawentry, Slapi_Entry *ad_entry, Slapi_Entry *ds_entry, Slapi_Mods *smods, int *do_modify); + +void winsync_plugin_call_pre_ds_add_user_cb(const Repl_Agmt *ra, const Slapi_Entry *rawentry, Slapi_Entry *ad_entry, Slapi_Entry *ds_entry); +void winsync_plugin_call_pre_ds_add_group_cb(const Repl_Agmt *ra, const Slapi_Entry *rawentry, Slapi_Entry *ad_entry, Slapi_Entry *ds_entry); + +void winsync_plugin_call_get_new_ds_user_dn_cb(const Repl_Agmt *ra, const Slapi_Entry *rawentry, Slapi_Entry *ad_entry, + char **new_dn_string, const Slapi_DN *ds_suffix, const Slapi_DN *ad_suffix); +void winsync_plugin_call_get_new_ds_group_dn_cb(const Repl_Agmt *ra, const Slapi_Entry *rawentry, Slapi_Entry *ad_entry, + char **new_dn_string, const Slapi_DN *ds_suffix, const Slapi_DN *ad_suffix); + +void winsync_plugin_call_pre_ad_mod_user_mods_cb(const Repl_Agmt *ra, const Slapi_Entry *rawentry, const Slapi_DN *local_dn, LDAPMod * const *origmods, Slapi_DN *remote_dn, LDAPMod ***modstosend); +void winsync_plugin_call_pre_ad_mod_group_mods_cb(const Repl_Agmt *ra, const Slapi_Entry *rawentry, const Slapi_DN *local_dn, LDAPMod * const *origmods, Slapi_DN *remote_dn, LDAPMod ***modstosend); + +int winsync_plugin_call_can_add_entry_to_ad_cb(const Repl_Agmt *ra, const Slapi_Entry *local_entry, const Slapi_DN *remote_dn); +/* + Call stack for all places where windows_LDAPMessage2Entry is called: + + windows_LDAPMessage2Entry + ++windows_seach_entry_ext + ++++windows_search_entry + ++++++windows_get_remote_entry + map_dn_values + windows_create_remote_entry + process_replay_add + windows_process_total_add + windows_map_mods_for_replay + windows_replay_update + send_updates + windows_inc_run + windows_create_local_entry + windows_process_dirsync_entry + windows_generate_update_mods + windows_update_remote_entry + process_replay_add + windows_process_total_add + windows_update_local_entry + windows_process_dirsync_entry + process_replay_add + windows_replay_update + map_entry_dn_outbound + map_dn_values + windows_replay_update + windows_process_total_entry + send_entry + windows_tot_run + windows_process_total_add + windows_process_total_entry + send_entry + windows_tot_run + windows_process_dirsync_entry + windows_dirsync_inc_run + find_entry_by_attr_value_remote + map_entry_dn_outbound + ++++windows_get_remote_tombstone + map_windows_tombstone_dn + process_replay_add + ++windows_conn_get_search_result + windows_dirsync_inc_run + + + windows_inc_protocol + ++send_updates + ++++windows_replay_update +*/ +/* #define WINSYNC_TEST 1 */ /* fake ad is really just a regular ds */ diff --git a/ldap/servers/plugins/replication/winsync-plugin.h b/ldap/servers/plugins/replication/winsync-plugin.h new file mode 100644 index 00000000..882e4144 --- /dev/null +++ b/ldap/servers/plugins/replication/winsync-plugin.h @@ -0,0 +1,534 @@ +/** BEGIN COPYRIGHT BLOCK + * This Program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation; version 2 of the License. + * + * This Program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with + * this Program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place, Suite 330, Boston, MA 02111-1307 USA. + * + * In addition, as a special exception, Red Hat, Inc. gives You the additional + * right to link the code of this Program with code not covered under the GNU + * General Public License ("Non-GPL Code") and to distribute linked combinations + * including the two, subject to the limitations in this paragraph. Non-GPL Code + * permitted under this exception must only link to the code of this Program + * through those well defined interfaces identified in the file named EXCEPTION + * found in the source code files (the "Approved Interfaces"). The files of + * Non-GPL Code may instantiate templates or use macros or inline functions from + * the Approved Interfaces without causing the resulting work to be covered by + * the GNU General Public License. Only Red Hat, Inc. may make changes or + * additions to the list of Approved Interfaces. You must obey the GNU General + * Public License in all respects for all of the Program code and other code used + * in conjunction with the Program except the Non-GPL Code covered by this + * exception. If you modify this file, you may extend this exception to your + * version of the file, but you are not obligated to do so. If you do not wish to + * provide this exception without modification, you must delete this exception + * statement from your version and license this file solely under the GPL without + * exception. + * + * + * Copyright (C) 2008 Red Hat, Inc. + * All rights reserved. + * END COPYRIGHT BLOCK **/ +#ifndef WINSYNC_PLUGIN_PUBLIC_API +#define WINSYNC_PLUGIN_PUBLIC_API + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +/* windows_private.c */ + +#include "slapi-plugin.h" + +/* + * WinSync plug-in API + */ +#define WINSYNC_v1_0_GUID "CDA8F029-A3C6-4EBB-80B8-A2E183DB0481" + +/* + * The plugin will define this callback in order to initialize itself. + * The ds subtree and the ad subtree from the sync agreement are passed in. + * These are read only. + * The return value is private data to the plugin that will be passed back + * at each callback + */ +typedef void * (*winsync_plugin_init_cb)(const Slapi_DN *ds_subtree, const Slapi_DN *ad_subtree); +#define WINSYNC_PLUGIN_INIT_CB 1 +/* agmt_dn - const - the original AD base dn from the winsync agreement + scope - set directly e.g. *scope = 42; + base, filter - malloced - to set, free first e.g. + slapi_ch_free_string(filter); + *base = slapi_ch_strdup("(objectclass=foobar)"); + winsync code will use slapi_ch_free_string to free this value, so no static strings + attrs - NULL or null terminated array of strings - can use slapi_ch_array_add to add e.g. + slapi_ch_array_add(attrs, slapi_ch_strdup("myattr")); + attrs will be freed with slapi_ch_array_free, so caller must own the memory + serverctrls - NULL or null terminated array of LDAPControl* - can use slapi_add_control_ext to add + slapi_add_control_ext(serverctrls, mynewctrl, 1 / add a copy /); + serverctrls will be freed with ldap_controls_free, so caller must own memory +*/ +typedef void (*winsync_search_params_cb)(void *cookie, const char *agmt_dn, char **base, int *scope, char **filter, char ***attrs, LDAPControl ***serverctrls); +#define WINSYNC_PLUGIN_DIRSYNC_SEARCH_CB 2 /* serverctrls will already contain the DirSync control */ +#define WINSYNC_PLUGIN_PRE_AD_SEARCH_CB 3 +#define WINSYNC_PLUGIN_PRE_DS_SEARCH_ENTRY_CB 4 +#define WINSYNC_PLUGIN_PRE_DS_SEARCH_ALL_CB 5 +/* + * These callbacks are the main entry points that allow the plugin + * to intercept modifications to local and remote entries. + * rawentry - the raw AD entry, read directly from AD - this is read only + * ad_entry - the "cooked" AD entry - the DN in this entry should be set + * when the operation is to modify the AD entry + * ds_entry - the entry from the ds - the DN in this entry should be set + * when the operation is to modify the DS entry + * smods - the post-processing modifications - these should be modified + * by the plugin as needed + * do_modify - if the code has some modifications that need to be applied, this + * will be set to true - if the plugin has added some items to smods + * this should be set to true - if the plugin has removed all of + * the smods, and no operation should be performed, this should + * be set to false + */ +typedef void (*winsync_pre_mod_cb)(void *cookie, const Slapi_Entry *rawentry, Slapi_Entry *ad_entry, Slapi_Entry *ds_entry, Slapi_Mods *smods, int *do_modify); +#define WINSYNC_PLUGIN_PRE_AD_MOD_USER_CB 6 +#define WINSYNC_PLUGIN_PRE_AD_MOD_GROUP_CB 7 +#define WINSYNC_PLUGIN_PRE_DS_MOD_USER_CB 8 +#define WINSYNC_PLUGIN_PRE_DS_MOD_GROUP_CB 9 +/* + * These callbacks are called when a new entry is being added to the + * local directory server from AD. + * rawentry - the raw AD entry, read directly from AD - this is read only + * ad_entry - the "cooked" AD entry + * ds_entry - the entry to be added to the DS - all modifications should + * be made to this entry, including changing the DN if needed, + * since the DN of this entry will be used as the ADD target DN + * This entry will already have had the default schema mapping applied + */ +typedef void (*winsync_pre_add_cb)(void *cookie, const Slapi_Entry *rawentry, Slapi_Entry *ad_entry, Slapi_Entry *ds_entry); +#define WINSYNC_PLUGIN_PRE_DS_ADD_USER_CB 10 +#define WINSYNC_PLUGIN_PRE_DS_ADD_GROUP_CB 11 +/* + * If a new entry has been added to AD, and we're sync'ing it over + * to the DS, we may need to create a new DN for the entry. The + * code tries to come up with a reasonable DN, but the plugin may + * have different ideas. These callbacks allow the plugin to specify + * what the new DN for the new entry should be. This is called from + * map_entry_dn_inbound which is called from various places where the DN for + * the new entry is needed. The winsync_plugin_call_pre_ds_add_* callbacks + * can also be used to set the DN just before the entry is stored in the DS. + * This is also used when we are mapping a dn valued attribute e.g. owner + * or secretary + * rawentry - the raw AD entry, read directly from AD - this is read only + * ad_entry - the "cooked" AD entry + * new_dn_string - the given value will be the default value created by the sync code + * to change it, slapi_ch_free_string first, then malloc the value to use + * ds_suffix - the suffix from the DS side of the sync agreement + * ad_suffix - the suffix from the AD side of the sync agreement + */ +typedef void (*winsync_get_new_dn_cb)(void *cookie, const Slapi_Entry *rawentry, Slapi_Entry *ad_entry, char **new_dn_string, + const Slapi_DN *ds_suffix, const Slapi_DN *ad_suffix); +#define WINSYNC_PLUGIN_GET_NEW_DS_USER_DN_CB 12 +#define WINSYNC_PLUGIN_GET_NEW_DS_GROUP_DN_CB 13 +/* + * These callbacks are called when a mod operation is going to be replayed + * to AD. This case is different than the pre add or pre mod callbacks + * above because in this context, we may only have the list of modifications + * and the DN to which the mods were applied. + * rawentry - the raw AD entry, read directly from AD - may be NULL + * local_dn - the original local DN used in the modification + * origmods - the original mod list + * remote_dn - this is the DN which will be used with the remote modify operation + * to AD - the winsync code may have already attempted to calculate its value + * modstosend - this is the list of modifications which will be sent - the winsync + * code will already have done its default mapping to these values + * + */ +typedef void (*winsync_pre_ad_mod_mods_cb)(void *cookie, const Slapi_Entry *rawentry, const Slapi_DN *local_dn, LDAPMod * const *origmods, Slapi_DN *remote_dn, LDAPMod ***modstosend); +#define WINSYNC_PLUGIN_PRE_AD_MOD_USER_MODS_CB 14 +#define WINSYNC_PLUGIN_PRE_AD_MOD_GROUP_MODS_CB 15 + +/* + * Callbacks used to determine if an entry should be added to the + * AD side if it does not already exist. + * local_entry - the candidate entry to test + * remote_DN - the candidate remote entry to add + */ +typedef int (*winsync_can_add_to_ad_cb)(void *cookie, const Slapi_Entry *local_entry, const Slapi_DN *remote_dn); +#define WINSYNC_PLUGIN_CAN_ADD_ENTRY_TO_AD_CB 16 + +/* + The following are sample code stubs to show how to implement + a plugin which uses this api +*/ + +#ifdef WINSYNC_SAMPLE_CODE + +#include "slapi-plugin.h" +#include "winsync-plugin.h" + +static char *test_winsync_plugin_name = "test_winsync_api"; + +static void * +test_winsync_api_init(const Slapi_DN *ds_subtree, const Slapi_DN *ad_subtree) +{ + slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name, + "--> test_winsync_init [%s] [%s] -- begin\n", + slapi_sdn_get_dn(ds_subtree), + slapi_sdn_get_dn(ad_subtree)); + + slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name, + "<-- test_winsync_init -- end\n"); + + return NULL; +} + +static void +test_winsync_dirsync_search_params_cb(void *cbdata, const char *agmt_dn, + char **base, int *scope, char **filter, + char ***attrs, LDAPControl ***serverctrls) +{ + slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name, + "--> test_winsync_dirsync_search_params_cb -- begin\n"); + + slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name, + "<-- test_winsync_dirsync_search_params_cb -- end\n"); + + return; +} + +/* called before searching for a single entry from AD - agmt_dn will be NULL */ +static void +test_winsync_pre_ad_search_cb(void *cbdata, const char *agmt_dn, + char **base, int *scope, char **filter, + char ***attrs, LDAPControl ***serverctrls) +{ + slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name, + "--> test_winsync_pre_ad_search_cb -- begin\n"); + + slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name, + "<-- test_winsync_pre_ad_search_cb -- end\n"); + + return; +} + +/* called before an internal search to get a single DS entry - agmt_dn will be NULL */ +static void +test_winsync_pre_ds_search_entry_cb(void *cbdata, const char *agmt_dn, + char **base, int *scope, char **filter, + char ***attrs, LDAPControl ***serverctrls) +{ + slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name, + "--> test_winsync_pre_ds_search_cb -- begin\n"); + + slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name, + "<-- test_winsync_pre_ds_search_cb -- end\n"); + + return; +} + +/* called before the total update to get all entries from the DS to sync to AD */ +static void +test_winsync_pre_ds_search_all_cb(void *cbdata, const char *agmt_dn, + char **base, int *scope, char **filter, + char ***attrs, LDAPControl ***serverctrls) +{ + slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name, + "--> test_winsync_pre_ds_search_all_cb -- orig filter [%s] -- begin\n", + ((filter && *filter) ? *filter : "NULL")); + + /* We only want to grab users from the ds side - no groups */ + slapi_ch_free_string(filter); + /* maybe use ntUniqueId=* - only get users that have already been + synced with AD already - ntUniqueId and ntUserDomainId are + indexed for equality only - need to add presence? */ + *filter = slapi_ch_strdup("(&(objectclass=ntuser)(ntUserDomainId=*))"); + + slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name, + "<-- test_winsync_pre_ds_search_all_cb -- end\n"); + + return; +} + +static void +test_winsync_pre_ad_mod_user_cb(void *cbdata, const Slapi_Entry *rawentry, + Slapi_Entry *ad_entry, Slapi_Entry *ds_entry, + Slapi_Mods *smods, int *do_modify) +{ + slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name, + "--> test_winsync_pre_ad_mod_user_cb -- begin\n"); + + slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name, + "<-- test_winsync_pre_ad_mod_user_cb -- end\n"); + + return; +} + +static void +test_winsync_pre_ad_mod_group_cb(void *cbdata, const Slapi_Entry *rawentry, + Slapi_Entry *ad_entry, Slapi_Entry *ds_entry, + Slapi_Mods *smods, int *do_modify) +{ + slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name, + "--> test_winsync_pre_ad_mod_group_cb -- begin\n"); + + slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name, + "<-- test_winsync_pre_ad_mod_group_cb -- end\n"); + + return; +} + +static void +test_winsync_pre_ds_mod_user_cb(void *cbdata, const Slapi_Entry *rawentry, + Slapi_Entry *ad_entry, Slapi_Entry *ds_entry, + Slapi_Mods *smods, int *do_modify) +{ + slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name, + "--> test_winsync_pre_ds_mod_user_cb -- begin\n"); + + slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name, + "<-- test_winsync_pre_ds_mod_user_cb -- end\n"); + + return; +} + +static void +test_winsync_pre_ds_mod_group_cb(void *cbdata, const Slapi_Entry *rawentry, + Slapi_Entry *ad_entry, Slapi_Entry *ds_entry, + Slapi_Mods *smods, int *do_modify) +{ + slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name, + "--> test_winsync_pre_ds_mod_group_cb -- begin\n"); + + slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name, + "<-- test_winsync_pre_ds_mod_group_cb -- end\n"); + + return; +} + +static void +test_winsync_pre_ds_add_user_cb(void *cbdata, const Slapi_Entry *rawentry, + Slapi_Entry *ad_entry, Slapi_Entry *ds_entry) +{ + slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name, + "--> test_winsync_pre_ds_add_user_cb -- begin\n"); + + slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name, + "<-- test_winsync_pre_ds_add_user_cb -- end\n"); + + return; +} + +static void +test_winsync_pre_ds_add_group_cb(void *cbdata, const Slapi_Entry *rawentry, + Slapi_Entry *ad_entry, Slapi_Entry *ds_entry) +{ + slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name, + "--> test_winsync_pre_ds_add_group_cb -- begin\n"); + + slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name, + "<-- test_winsync_pre_ds_add_group_cb -- end\n"); + + return; +} + +static void +test_winsync_get_new_ds_user_dn_cb(void *cbdata, const Slapi_Entry *rawentry, + Slapi_Entry *ad_entry, char **new_dn_string, + const Slapi_DN *ds_suffix, const Slapi_DN *ad_suffix) +{ + char **rdns = NULL; + + slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name, + "--> test_winsync_get_new_ds_user_dn_cb -- old dn [%s] -- begin\n", + *new_dn_string); + + rdns = ldap_explode_dn(*new_dn_string, 0); + if (!rdns || !rdns[0]) { + ldap_value_free(rdns); + return; + } + + slapi_ch_free_string(new_dn_string); + *new_dn_string = PR_smprintf("%s,%s", rdns[0], slapi_sdn_get_dn(ds_suffix)); + ldap_value_free(rdns); + + slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name, + "<-- test_winsync_get_new_ds_user_dn_cb -- new dn [%s] -- end\n", + *new_dn_string); + + return; +} + +static void +test_winsync_get_new_ds_group_dn_cb(void *cbdata, const Slapi_Entry *rawentry, + Slapi_Entry *ad_entry, char **new_dn_string, + const Slapi_DN *ds_suffix, const Slapi_DN *ad_suffix) +{ + slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name, + "--> test_winsync_get_new_ds_group_dn_cb -- begin\n"); + + slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name, + "<-- test_winsync_get_new_ds_group_dn_cb -- end\n"); + + return; +} + +static void +test_winsync_pre_ad_mod_user_mods_cb(void *cbdata, const Slapi_Entry *rawentry, + const Slapi_DN *local_dn, LDAPMod * const *origmods, + Slapi_DN *remote_dn, LDAPMod ***modstosend) +{ + slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name, + "--> test_winsync_pre_ad_mod_user_mods_cb -- begin\n"); + + slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name, + "<-- test_winsync_pre_ad_mod_user_mods_cb -- end\n"); + + return; +} + +static void +test_winsync_pre_ad_mod_group_mods_cb(void *cbdata, const Slapi_Entry *rawentry, + const Slapi_DN *local_dn, LDAPMod * const *origmods, + Slapi_DN *remote_dn, LDAPMod ***modstosend) +{ + slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name, + "--> test_winsync_pre_ad_mod_group_mods_cb -- begin\n"); + + slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name, + "<-- test_winsync_pre_ad_mod_group_mods_cb -- end\n"); + + return; +} + +static int +test_winsync_can_add_entry_to_ad_cb(void *cbdata, const Slapi_Entry *local_entry, + const Slapi_DN *remote_dn) +{ + slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name, + "--> test_winsync_can_add_entry_to_ad_cb -- begin\n"); + + slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name, + "<-- test_winsync_can_add_entry_to_ad_cb -- end\n"); + + return 0; /* false - do not allow entries to be added to ad */ +} + +/** + * Plugin identifiers + */ +static Slapi_PluginDesc test_winsync_pdesc = { + "test-winsync-plugin", + PLUGIN_MAGIC_VENDOR_STR, + PRODUCTTEXT, + "test winsync plugin" +}; + +static Slapi_ComponentId *test_winsync_plugin_id = NULL; + +static void *test_winsync_api[] = { + NULL, /* reserved for api broker use, must be zero */ + test_winsync_api_init, + test_winsync_dirsync_search_params_cb, + test_winsync_pre_ad_search_cb, + test_winsync_pre_ds_search_entry_cb, + test_winsync_pre_ds_search_all_cb, + test_winsync_pre_ad_mod_user_cb, + test_winsync_pre_ad_mod_group_cb, + test_winsync_pre_ds_mod_user_cb, + test_winsync_pre_ds_mod_group_cb, + test_winsync_pre_ds_add_user_cb, + test_winsync_pre_ds_add_group_cb, + test_winsync_get_new_ds_user_dn_cb, + test_winsync_get_new_ds_group_dn_cb, + test_winsync_pre_ad_mod_user_mods_cb, + test_winsync_pre_ad_mod_group_mods_cb, + test_winsync_can_add_entry_to_ad_cb +}; + +static int +test_winsync_plugin_start(Slapi_PBlock *pb) +{ + slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name, + "--> test_winsync_plugin_start -- begin\n"); + + if( slapi_apib_register(WINSYNC_v1_0_GUID, test_winsync_api) ) { + slapi_log_error( SLAPI_LOG_FATAL, test_winsync_plugin_name, + "<-- test_winsync_plugin_start -- failed to register winsync api -- end\n"); + return -1; + } + + slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name, + "<-- test_winsync_plugin_start -- end\n"); + return 0; +} + +static int +test_winsync_plugin_close(Slapi_PBlock *pb) +{ + slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name, + "--> test_winsync_plugin_close -- begin\n"); + + slapi_apib_unregister(WINSYNC_v1_0_GUID); + + slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name, + "<-- test_winsync_plugin_close -- end\n"); + return 0; +} + +/* this is the slapi plugin init function, + not the one used by the winsync api +*/ +int test_winsync_plugin_init(Slapi_PBlock *pb) +{ + slapi_log_error(SLAPI_LOG_PLUGIN, test_winsync_plugin_name, + "--> test_winsync_plugin_init -- begin\n"); + + if ( slapi_pblock_set( pb, SLAPI_PLUGIN_VERSION, + SLAPI_PLUGIN_VERSION_01 ) != 0 || + slapi_pblock_set(pb, SLAPI_PLUGIN_START_FN, + (void *) test_winsync_plugin_start ) != 0 || + slapi_pblock_set(pb, SLAPI_PLUGIN_CLOSE_FN, + (void *) test_winsync_plugin_close ) != 0 || + slapi_pblock_set( pb, SLAPI_PLUGIN_DESCRIPTION, + (void *)&test_winsync_pdesc ) != 0 ) + { + slapi_log_error( SLAPI_LOG_FATAL, test_winsync_plugin_name, + "<-- test_winsync_plugin_init -- failed to register plugin -- end\n"); + return -1; + } + + /* Retrieve and save the plugin identity to later pass to + internal operations */ + if (slapi_pblock_get(pb, SLAPI_PLUGIN_IDENTITY, &test_winsync_plugin_id) != 0) { + slapi_log_error(SLAPI_LOG_FATAL, test_winsync_plugin_name, + "<-- test_winsync_plugin_init -- failed to retrieve plugin identity -- end\n"); + return -1; + } + + slapi_log_error( SLAPI_LOG_PLUGIN, test_winsync_plugin_name, + "<-- test_winsync_plugin_init -- end\n"); + return 0; +} + +/* +dn: cn=Test Winsync API,cn=plugins,cn=config +objectclass: top +objectclass: nsSlapdPlugin +objectclass: extensibleObject +cn: Test Winsync API +nsslapd-pluginpath: libtestwinsync-plugin +nsslapd-plugininitfunc: test_winsync_plugin_init +nsslapd-plugintype: preoperation +nsslapd-pluginenabled: on +nsslapd-plugin-depends-on-type: database +nsslapd-plugin-depends-on-named: Multimaster Replication Plugin +*/ + +#endif /* WINSYNC_SAMPLE_CODE */ + +#endif /* WINSYNC_PLUGIN_PUBLIC_API */ diff --git a/ldap/servers/slapd/charray.c b/ldap/servers/slapd/charray.c index 2f97f4d1..e57d9099 100644 --- a/ldap/servers/slapd/charray.c +++ b/ldap/servers/slapd/charray.c @@ -246,6 +246,11 @@ slapi_ch_array_free( char **array ) charray_free (array); } +void +slapi_ch_array_add( char ***a, char *s ) +{ + charray_add(a, s); +} /* case insensitive search */ int diff --git a/ldap/servers/slapd/control.c b/ldap/servers/slapd/control.c index 5bf4c7e3..3d0a4f9e 100644 --- a/ldap/servers/slapd/control.c +++ b/ldap/servers/slapd/control.c @@ -474,9 +474,14 @@ write_controls( BerElement *ber, LDAPControl **ctrls ) /* * duplicate "newctrl" and add it to the array of controls "*ctrlsp" * note that *ctrlsp may be reset and that it is okay to pass NULL for it. + * IF copy is true, a copy of the passed in control will be added - copy + * made with slapi_dup_control - if copy is false, the control + * will be used directly and may be free'd by ldap_controls_free - so + * make sure it is ok for the control array to own the pointer you + * pass in */ void -add_control( LDAPControl ***ctrlsp, LDAPControl *newctrl ) +add_control_ext( LDAPControl ***ctrlsp, LDAPControl *newctrl, int copy ) { int count; @@ -491,10 +496,29 @@ add_control( LDAPControl ***ctrlsp, LDAPControl *newctrl ) *ctrlsp = (LDAPControl **)slapi_ch_realloc( (char *)*ctrlsp, ( count + 2 ) * sizeof(LDAPControl *)); - (*ctrlsp)[ count ] = slapi_dup_control( newctrl ); + if (copy) { + (*ctrlsp)[ count ] = slapi_dup_control( newctrl ); + } else { + (*ctrlsp)[ count ] = newctrl; + } (*ctrlsp)[ ++count ] = NULL; } +/* + * duplicate "newctrl" and add it to the array of controls "*ctrlsp" + * note that *ctrlsp may be reset and that it is okay to pass NULL for it. + */ +void +add_control( LDAPControl ***ctrlsp, LDAPControl *newctrl ) +{ + add_control_ext(ctrlsp, newctrl, 1 /* copy */); +} + +void +slapi_add_control_ext( LDAPControl ***ctrlsp, LDAPControl *newctrl, int copy ) +{ + add_control_ext(ctrlsp, newctrl, copy); +} /* * return a malloc'd copy of "ctrl" @@ -527,6 +551,14 @@ slapi_dup_control( LDAPControl *ctrl ) return( rctrl ); } +void +slapi_add_controls( LDAPControl ***ctrlsp, LDAPControl **newctrls, int copy ) +{ + int ii; + for (ii = 0; newctrls && newctrls[ii]; ++ii) { + slapi_add_control_ext(ctrlsp, newctrls[ii], copy); + } +} int slapi_build_control( char *oid, BerElement *ber, diff --git a/ldap/servers/slapd/slapi-plugin.h b/ldap/servers/slapd/slapi-plugin.h index 56959b3d..23fa2af9 100644 --- a/ldap/servers/slapd/slapi-plugin.h +++ b/ldap/servers/slapd/slapi-plugin.h @@ -835,6 +835,24 @@ int slapi_build_control( char *oid, BerElement *ber, int slapi_build_control_from_berval( char *oid, struct berval *bvp, char iscritical, LDAPControl **ctrlp ); +/* Given an array of controls e.g. LDAPControl **ctrls, add the given + control to the end of the array, growing the array with realloc + e.g. slapi_add_control_ext(&ctrls, newctrl, 1); + if ctrls is NULL, the array will be created with malloc + if copy is true, the given control will be copied + if copy is false, the given control will be used and owned by the array + if copy is false, make sure the control can be freed by ldap_controls_free +*/ +void slapi_add_control_ext( LDAPControl ***ctrlsp, LDAPControl *newctrl, int copy ); + +/* Given an array of controls e.g. LDAPControl **ctrls, add all of the given + controls in the newctrls array to the end of ctrls, growing the array with realloc + if ctrls is NULL, the array will be created with malloc + if copy is true, each given control will be copied + if copy is false, each given control will be used and owned by the array + if copy is false, make sure each control can be freed by ldap_controls_free +*/ +void slapi_add_controls( LDAPControl ***ctrlsp, LDAPControl **newctrls, int copy ); /* * routines for dealing with extended operations @@ -865,6 +883,13 @@ int slapi_pwpolicy_make_response_control (Slapi_PBlock *pb, int seconds, int log * routine for freeing the ch_arrays returned by the slapi_get*_copy functions above */ void slapi_ch_array_free( char **array ); +/* + * Add the given string to the given null terminated array. + * s is not copied, so if you want to add a copy of s to the + * array, use slapi_ch_strdup(s) + * if *a is NULL, a new array will be created + */ +void slapi_ch_array_add( char ***array, char *string ); /* |