diff options
author | Rich Megginson <rmeggins@redhat.com> | 2008-08-05 20:26:22 +0000 |
---|---|---|
committer | Rich Megginson <rmeggins@redhat.com> | 2008-08-05 20:26:22 +0000 |
commit | be459a234db6aca79b08f438a6ec5afb47581b72 (patch) | |
tree | 20d29b61fc1a1d82843a58c0a13258bd1a069e0c | |
parent | e0e27852ef4127538d16a7571411b96e9b0d5ca6 (diff) | |
download | ds-be459a234db6aca79b08f438a6ec5afb47581b72.tar.gz ds-be459a234db6aca79b08f438a6ec5afb47581b72.tar.xz ds-be459a234db6aca79b08f438a6ec5afb47581b72.zip |
Resolves: bug 457846
Bug Description: The Windows Sync API should have plug-in points
Reviewed by: nkinder (Thanks!)
Fix Description: Several plug-in points have been added to the windows sync code, available to regular plug-ins that register with the winsync api via the slapi api broker interface. winsync-plugin.h documents the use of these along with some example plug-in code. The windows private data structure has been extended to add two additional fields:
raw_entry - the raw entry read from AD - this is passed to several plug-in callbacks to allow them to have access to all of the attributes and values in the entry in case further processing is needed. This required a change to the function that reads the entry, to have it save the raw entry read each time from AD, in addition to the "cooked" entry it passes back to the caller.
api_cookie - this is the plug-in private data passed back to each plug-in callback and allows the plug-in to specify some additional context
Both of these are stored in the private data field in the agreement, so some of the existing functions had to be changed to pass in the connection object or the protocol object in order to gain access to the agreement object.
There were several small memory leaks in the existing code that have been fixed - these are the places where a free() function of some sort has been added. Also the usage of slapi_sdn_init_dn_byval leaked - slapi_sdn_new_dn_byval must be used here instead - cannot mix slapi_sdn_new with slapi_sdn_init*
I also cleaned up several compiler warnings.
The slapi changes are not strictly necessary, but they provide some conveniences to the winsync code and to plug-in writers. The good thing is that they were already private functions, so mostly just needed to have public api wrappers.
Platforms tested: RHEL5
Flag Day: no
Doc impact: no
-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 ); /* |