[Fedora-directory-commits] ldapserver/ldap/servers/plugins/replication winsync-plugin.h, NONE, 1.1 windows_connection.c, 1.18, 1.19 windows_private.c, 1.17, 1.18 windows_protocol_util.c, 1.38, 1.39 windows_tot_protocol.c, 1.12, 1.13 windowsrepl.h, 1.14, 1.15

Richard Allen Megginson (rmeggins) fedora-directory-commits at redhat.com
Tue Aug 5 20:26:24 UTC 2008


Author: rmeggins

Update of /cvs/dirsec/ldapserver/ldap/servers/plugins/replication
In directory cvs-int.fedora.redhat.com:/tmp/cvs-serv4163/ldapserver/ldap/servers/plugins/replication

Modified Files:
	windows_connection.c windows_private.c windows_protocol_util.c 
	windows_tot_protocol.c windowsrepl.h 
Added Files:
	winsync-plugin.h 
Log Message:
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



--- NEW FILE winsync-plugin.h ---
/** 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 */


Index: windows_connection.c
===================================================================
RCS file: /cvs/dirsec/ldapserver/ldap/servers/plugins/replication/windows_connection.c,v
retrieving revision 1.18
retrieving revision 1.19
diff -u -r1.18 -r1.19
--- windows_connection.c	18 Oct 2007 00:08:31 -0000	1.18
+++ windows_connection.c	5 Aug 2008 20:26:21 -0000	1.19
@@ -512,15 +512,17 @@
 
 /* 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 @@
 	 * 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 @@
 			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 @@
 					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 @@
 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 @@
 
 	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 @@
 
 			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 @@
 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 @@
 				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_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 @@
 
 	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 @@
 	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) {


Index: windows_private.c
===================================================================
RCS file: /cvs/dirsec/ldapserver/ldap/servers/plugins/replication/windows_private.c,v
retrieving revision 1.17
retrieving revision 1.18
diff -u -r1.17 -r1.18
--- windows_private.c	18 Oct 2007 00:08:31 -0000	1.17
+++ windows_private.c	5 Aug 2008 20:26:22 -0000	1.18
@@ -70,8 +70,12 @@
    * 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_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_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 @@
 	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 @@
 	
 	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 @@
 }
 
 /* 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 @@
 
 	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 @@
 	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 *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 @@
 
 	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 @@
 	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);
+}


Index: windows_protocol_util.c
===================================================================
RCS file: /cvs/dirsec/ldapserver/ldap/servers/plugins/replication/windows_protocol_util.c,v
retrieving revision 1.38
retrieving revision 1.39
diff -u -r1.38 -r1.39
--- windows_protocol_util.c	19 Oct 2007 02:09:24 -0000	1.38
+++ windows_protocol_util.c	5 Aug 2008 20:26:22 -0000	1.39
@@ -668,6 +668,7 @@
 				return_value = ACQUIRE_FATAL_ERROR;
 			}
 			slapi_sdn_free(&replarea_sdn);
+			csn_free(&current_csn);
 		}
 	}
 
@@ -1004,7 +1005,6 @@
 			}
 
 			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 @@
 			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 @@
 				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 @@
 	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 @@
 	*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 @@
 					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 @@
 	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 @@
 		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 @@
 	char *p = str;
 	char c = '\0';
 
-	while (c = *p)
+	while ((c = *p))
 	{
 		if ('-' == c)
 		{
@@ -2254,7 +2294,7 @@
 
 	/* 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 @@
 	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 @@
 		{
 			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 @@
 		 * 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 @@
 				}
 
 				if (cn_string) {
-					char *rdnstr = NULL;
 					char *container_str = NULL;
 
 					container_str = extract_container(slapi_entry_get_sdn_const(e),
@@ -2719,9 +2758,23 @@
 			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 @@
 	{
 		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 @@
 			"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 @@
 						 * 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 @@
 							 * 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 @@
 		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 @@
 	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) 
 	{


Index: windows_tot_protocol.c
===================================================================
RCS file: /cvs/dirsec/ldapserver/ldap/servers/plugins/replication/windows_tot_protocol.c,v
retrieving revision 1.12
retrieving revision 1.13
diff -u -r1.12 -r1.13
--- windows_tot_protocol.c	18 Oct 2007 00:08:31 -0000	1.12
+++ windows_tot_protocol.c	5 Aug 2008 20:26:22 -0000	1.13
@@ -99,11 +99,15 @@
     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 @@
 	
 
 	/* 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 @@
                                        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;


Index: windowsrepl.h
===================================================================
RCS file: /cvs/dirsec/ldapserver/ldap/servers/plugins/replication/windowsrepl.h,v
retrieving revision 1.14
retrieving revision 1.15
diff -u -r1.14 -r1.15
--- windowsrepl.h	27 Sep 2007 18:33:30 -0000	1.14
+++ windowsrepl.h	5 Aug 2008 20:26:22 -0000	1.15
@@ -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 @@
 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 @@
 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 @@
 /* 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 */




More information about the Fedora-directory-commits mailing list