ldap/servers/plugins/posix-winsync/posix-group-func.c | 2
ldap/servers/plugins/replication/windows_protocol_util.c | 557 +++++++++++----
ldap/servers/slapd/slapi-plugin.h | 10
ldap/servers/slapd/valueset.c | 23
4 files changed, 447 insertions(+), 145 deletions(-)
New commits:
commit 737169e0afd0547b6de0a61081508314d076cc6a
Author: Noriko Hosoi <nhosoi(a)redhat.com>
Date: Thu Feb 20 14:32:41 2014 -0800
Ticket #415 - winsync doesn't sync DN valued attributes if DS DN value doesn't
exist
Bug description:
2 case were fixed.
1) A group on AD has a member which is not a target of windows
sync and exists only on AD. The member value in the group is
synchronized to DS. If an operation is executed on AD so that
the member is replaced with other members which are the target
of the windows sync, the new member values are not synchronized.
2) If a group on AD and DS have members which are local and are
not synchronized and the members are removed in the group on
the other side, the delete operation is synchronized and
deletes all the members including the local members.
Fix description:
1) In windows_generate_update_mods, even if a sync'ed member value
in a DS entry is not the target of windows sync and it is does
not exist on DS, a following modify operation including the member
value is proceeded by confirming the existence on AD.
2) AD->DS: in windows_map_mods_for_replay
DS->AD: in windwos_generate_update_mods
added the code to check if an attribute is completely deleted on
one side, then the each value on the other side is in the sync
scope or not. Put the value to the mod for the delete only if
the value is in the sync scope.
Reviewed by Rich (Thank you!!)
https://fedorahosted.org/389/ticket/415
(cherry picked from commit 03814dd74df7f1f0d2842c5096c6425609da6f2c)
(cherry picked from commit 8772ea1ac524f1f011d51d0a42c0055f5641e2e6)
diff --git a/ldap/servers/plugins/posix-winsync/posix-group-func.c
b/ldap/servers/plugins/posix-winsync/posix-group-func.c
index 60528f5..6a7aa84 100644
--- a/ldap/servers/plugins/posix-winsync/posix-group-func.c
+++ b/ldap/servers/plugins/posix-winsync/posix-group-func.c
@@ -100,7 +100,7 @@ getEntry(const char *udn, char **attrs)
}
else {
slapi_log_error(SLAPI_LOG_FATAL, POSIX_WINSYNC_PLUGIN_NAME,
- "getEntry: error searching for uid: %d", rc);
+ "getEntry: error searching for uid: %d\n", rc);
}
return NULL;
diff --git a/ldap/servers/plugins/replication/windows_protocol_util.c
b/ldap/servers/plugins/replication/windows_protocol_util.c
index bac6573..811d2fd 100644
--- a/ldap/servers/plugins/replication/windows_protocol_util.c
+++ b/ldap/servers/plugins/replication/windows_protocol_util.c
@@ -409,12 +409,19 @@ map_dn_values(Private_Repl_Protocol *prp,Slapi_ValueSet
*original_values, Slapi_
int retval = 0;
int i = 0;
+ if (NULL == mapped_values) {
+ slapi_log_error(SLAPI_LOG_REPL, windows_repl_plugin_name,
+ "%s: map_dn_values: arg mapped_values is NULL.\n",
+ agmt_get_long_name(prp->agmt));
+ return;
+ }
+
/* Set the keep raw entry flag to avoid overwriting the existing raw entry. */
windows_private_set_keep_raw_entry(prp->agmt, 1);
/* For each value: */
- i= slapi_valueset_first_value(original_values,&original_value);
- while ( i != -1 ) {
+ i= slapi_valueset_first_value(original_values,&original_value);
+ while ( i != -1 ) {
int is_ours = 0;
char *new_dn_string = NULL;
@@ -480,7 +487,7 @@ map_dn_values(Private_Repl_Protocol *prp,Slapi_ValueSet
*original_values, Slapi_
local_entry = NULL;
}
} else
- {
+ { /* from windows */
Slapi_Entry *remote_entry = NULL;
Slapi_DN *local_dn = NULL;
/* Try to get the remote entry */
@@ -1584,89 +1591,111 @@ windows_replay_update(Private_Repl_Protocol *prp,
slapi_operation_parameters *op
slapi_entry_free(ad_entry); /* getting sets windows_private_get_raw_entry */
}
+ /*
+ * If the magic objectclass and attributes have been added to the entry
+ * to make the entry sync-able, add the entry first, then apply the other
+ * mods
+ */
+ if (sync_attrs_added(op->p.p_modify.modify_mods, local_entry)) {
+ Slapi_Entry *ad_entry = 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,
- local_entry,
- 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,
- local_entry,
- op->p.p_modify.modify_mods,
- remote_dn,
- &mapped_mods);
+ return_value =
process_replay_add(prp,local_entry,local_entry,local_dn,remote_dn,is_user,missing_entry,&password);
+ slapi_log_error(SLAPI_LOG_REPL, windows_repl_plugin_name,
+ "%s: windows_replay_update: "
+ "The modify operation added the sync objectclass and attribute,
so "
+ "the entry was added to windows - result [%d]\n",
+ agmt_get_long_name(prp->agmt), return_value);
+ if (return_value) {
+ break; /* error adding entry - cannot continue */
}
+ /* the modify op needs the new remote entry, so retrieve it */
+ windows_get_remote_entry(prp, remote_dn, &ad_entry);
+ slapi_entry_free(ad_entry); /* getting sets windows_private_get_raw_entry */
+ }
- /* Check if a naming attribute is being modified. */
- if (windows_check_mods_for_rdn_change(prp, op->p.p_modify.modify_mods,
local_entry, remote_dn, &newrdn)) {
- /* Issue MODRDN */
- slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "%s: renaming remote entry
\"%s\" with new RDN of \"%s\"\n",
- agmt_get_long_name(prp->agmt), slapi_sdn_get_dn(remote_dn), newrdn);
- return_value = windows_conn_send_rename(prp->conn, slapi_sdn_get_dn(remote_dn),
- newrdn, NULL, 1 /* delete old RDN */,
- NULL, NULL /* returned controls */);
- slapi_ch_free_string(&newrdn);
- }
+ 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,
+ local_entry,
+ 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,
+ local_entry,
+ 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 )
- {
- return_value = CONN_OPERATION_SUCCESS;
- } else
+ /* Check if a naming attribute is being modified. */
+ if (windows_check_mods_for_rdn_change(prp, op->p.p_modify.modify_mods, local_entry,
remote_dn, &newrdn)) {
+ /* Issue MODRDN */
+ slapi_log_error(SLAPI_LOG_REPL, windows_repl_plugin_name, "%s: renaming remote
entry \"%s\" with new RDN of \"%s\"\n",
+ agmt_get_long_name(prp->agmt), slapi_sdn_get_dn(remote_dn),
newrdn);
+ return_value = windows_conn_send_rename(prp->conn, slapi_sdn_get_dn(remote_dn),
+ newrdn, NULL, 1 /* delete old RDN */,
+ NULL, NULL /* returned controls */);
+ slapi_ch_free_string(&newrdn);
+ }
+
+ /* It's possible that the mapping process results in an empty mod list, in which
case we don't bother with the replay */
+ if ((mapped_mods == NULL) || (*mapped_mods == NULL))
+ {
+ return_value = CONN_OPERATION_SUCCESS;
+ } else
+ {
+ int ldap_op = 0;
+ int ldap_result_code = 0;
+ if (slapi_is_loglevel_set(SLAPI_LOG_REPL))
{
- int ldap_op = 0;
- int ldap_result_code = 0;
- if (slapi_is_loglevel_set(SLAPI_LOG_REPL))
+ int i = 0;
+ slapi_log_error(SLAPI_LOG_REPL, windows_repl_plugin_name,
+ "dump mods for replay update:\n");
+ for(i=0;mapped_mods[i];i++)
{
- int i = 0;
- slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,"dump mods for replay
update:");
- for(i=0;mapped_mods[i];i++)
- {
- slapi_mod_dump(mapped_mods[i],i);
- }
- }
- return_value = windows_conn_send_modify(prp->conn, slapi_sdn_get_dn(remote_dn),
mapped_mods, NULL, NULL /* returned controls */);
- windows_conn_get_error(prp->conn, &ldap_op, &ldap_result_code);
- if ((return_value != CONN_OPERATION_SUCCESS) && !ldap_result_code) {
- /* op failed but no ldap error code ??? */
- ldap_result_code = LDAP_OPERATIONS_ERROR;
- }
- if (is_user) {
- winsync_plugin_call_post_ad_mod_user_mods_cb(prp->agmt,
- windows_private_get_raw_entry(prp->agmt),
- local_dn, local_entry,
- op->p.p_modify.modify_mods,
- remote_dn, mapped_mods, &ldap_result_code);
- } else if (is_group) {
- winsync_plugin_call_post_ad_mod_group_mods_cb(prp->agmt,
- windows_private_get_raw_entry(prp->agmt),
- local_dn, local_entry,
- op->p.p_modify.modify_mods,
- remote_dn, mapped_mods, &ldap_result_code);
- }
- /* see if plugin reset success/error condition */
- if ((return_value != CONN_OPERATION_SUCCESS) && !ldap_result_code) {
- return_value = CONN_OPERATION_SUCCESS;
- windows_conn_set_error(prp->conn, ldap_result_code);
- } else if ((return_value == CONN_OPERATION_SUCCESS) && ldap_result_code) {
- return_value = CONN_OPERATION_FAILED;
- windows_conn_set_error(prp->conn, ldap_result_code);
+ slapi_mod_dump(mapped_mods[i],i);
}
}
- if (mapped_mods)
- {
- ldap_mods_free(mapped_mods,1);
- mapped_mods = NULL;
+ return_value = windows_conn_send_modify(prp->conn, slapi_sdn_get_dn(remote_dn),
mapped_mods, NULL, NULL /* returned controls */);
+ windows_conn_get_error(prp->conn, &ldap_op, &ldap_result_code);
+ if ((return_value != CONN_OPERATION_SUCCESS) && !ldap_result_code) {
+ /* op failed but no ldap error code ??? */
+ ldap_result_code = LDAP_OPERATIONS_ERROR;
+ }
+ if (is_user) {
+ winsync_plugin_call_post_ad_mod_user_mods_cb(prp->agmt,
+
windows_private_get_raw_entry(prp->agmt),
+ local_dn, local_entry,
+ op->p.p_modify.modify_mods,
+ remote_dn, mapped_mods,
&ldap_result_code);
+ } else if (is_group) {
+ winsync_plugin_call_post_ad_mod_group_mods_cb(prp->agmt,
+
windows_private_get_raw_entry(prp->agmt),
+ local_dn, local_entry,
+ op->p.p_modify.modify_mods,
+ remote_dn, mapped_mods,
&ldap_result_code);
}
+ /* see if plugin reset success/error condition */
+ if ((return_value != CONN_OPERATION_SUCCESS) && !ldap_result_code) {
+ return_value = CONN_OPERATION_SUCCESS;
+ windows_conn_set_error(prp->conn, ldap_result_code);
+ } else if ((return_value == CONN_OPERATION_SUCCESS) && ldap_result_code) {
+ return_value = CONN_OPERATION_FAILED;
+ windows_conn_set_error(prp->conn, ldap_result_code);
+ }
+ }
+ if (mapped_mods)
+ {
+ ldap_mods_free(mapped_mods,1);
+ mapped_mods = NULL;
}
break;
+ }
case SLAPI_OPERATION_DELETE:
if (delete_remote_entry_allowed(local_entry))
{
@@ -2569,17 +2598,34 @@ done:
static void
-windows_map_mods_for_replay(Private_Repl_Protocol *prp,LDAPMod **original_mods, LDAPMod
***returned_mods, int is_user, char** password)
+windows_map_mods_for_replay(Private_Repl_Protocol *prp,
+ LDAPMod **original_mods,
+ LDAPMod ***returned_mods,
+ int is_user,
+ char** password)
{
Slapi_Mods smods = {0};
Slapi_Mods mapped_smods = {0};
LDAPMod *mod = NULL;
- int is_nt4 = windows_private_get_isnt4(prp->agmt);
+ int is_nt4 = 0;
Slapi_Mod *mysmod = NULL;
const Slapi_Entry *ad_entry = NULL;
Slapi_Entry *ad_entry_copy = NULL;
+ const Slapi_DN *windows_subtree = NULL;
LDAPDebug( LDAP_DEBUG_TRACE, "=> windows_map_mods_for_replay\n", 0, 0, 0
);
+ if (NULL == prp) {
+ LDAPDebug(LDAP_DEBUG_TRACE,
+ "<= windows_map_mods_for_replay; NULL protocol; NOOP\n", 0, 0,
0);
+ return;
+ }
+ windows_subtree = windows_private_get_windows_subtree(prp->agmt);
+ if (NULL == windows_subtree) {
+ LDAPDebug(LDAP_DEBUG_TRACE,
+ "<= windows_map_mods_for_replay; NULL agreement subtree;
NOOP\n", 0, 0, 0);
+ return;
+ }
+ is_nt4 = windows_private_get_isnt4(prp->agmt);
/* Iterate through the original mods, looking each attribute type up in the maps for
either user or group */
@@ -2667,13 +2713,66 @@ windows_map_mods_for_replay(Private_Repl_Protocol *prp,LDAPMod
**original_mods,
mapped_values = NULL;
} else
{
- /* this might be a del: mod, in which case there are no values */
- if (mod->mod_op & LDAP_MOD_DELETE)
+ if (slapi_valueset_isempty(vs) && (mod->mod_op & LDAP_MOD_DELETE))
{
- mysmod = slapi_mod_new();
- slapi_mod_init(mysmod, 0);
- slapi_mod_set_operation(mysmod, LDAP_MOD_DELETE|LDAP_MOD_BVALUES);
- slapi_mod_set_type(mysmod, mapped_type);
+ /* modify - del all, in which case there are no values */
+ Slapi_Attr *attr = NULL;
+
+ /*
+ * ad_entry:
+ * get mapped_type values
+ * get in-scope values from the values
+ */
+ slapi_entry_attr_find(ad_entry, mapped_type, &attr);
+ if (attr) {
+ Slapi_ValueSet *thisvs = NULL;
+ Slapi_Value *valp = NULL;
+ Slapi_DN *sdn = slapi_sdn_new();
+ int i;
+ int is_in_subtree = 0;
+ Slapi_Value **myva = NULL;
+
+ slapi_attr_get_valueset(attr, &thisvs); /* thisvs is dup'ed */
+ for (i = slapi_valueset_first_value(thisvs, &valp);
+ (i != -1) && (valp != NULL);
+ i = slapi_valueset_next_value(thisvs, i, &valp)) {
+ /* valp is a pointer to va in thisvs */
+ const char *strval = slapi_value_get_string(valp); /* no dup */
+ if (strval) {
+ slapi_sdn_set_dn_byref(sdn, strval);
+ is_in_subtree = slapi_sdn_scope_test(sdn, windows_subtree,
+ LDAP_SCOPE_SUBTREE);
+ if (is_in_subtree) {
+ /*
+ * If delete all on DS,
+ * we could delete the values on AD in the scope.
+ */
+ /* myva is (re)allocated and valp is copied */
+ valuearray_add_value(&myva, valp);
+ }
+ }
+ }
+ if (myva) {
+ Slapi_ValueSet *myvs = NULL;
+
+ myvs = slapi_valueset_new();
+ valueset_set_valuearray_passin(myvs, myva);
+ mysmod = slapi_mod_new();
+ slapi_mod_init_valueset_byval(mysmod,
+ LDAP_MOD_DELETE|LDAP_MOD_BVALUES,
+ mapped_type,
+ myvs);
+ slapi_valueset_free(myvs);
+ }
+ slapi_sdn_free(&sdn);
+ slapi_valueset_free(thisvs);
+ } else {
+ /*
+ * No corresponsing attribute in AD.
+ * There's no need to do anything on AD.
+ * slapi_mod_set_type(mysmod, mapped_type);
+ */
+ }
}
}
slapi_mod_done(&smod);
@@ -4236,19 +4335,20 @@ windows_generate_update_mods(Private_Repl_Protocol
*prp,Slapi_Entry *remote_entr
int is_group = 0;
int rc = 0;
int is_nt4 = windows_private_get_isnt4(prp->agmt);
+ const Slapi_DN *local_subtree = NULL;
/* Iterate over the attributes on the remote entry, updating the local entry where
appropriate */
LDAPDebug( LDAP_DEBUG_TRACE, "=> windows_generate_update_mods\n", 0, 0, 0
);
*do_modify = 0;
- if (!remote_entry || !local_entry) {
- slapi_log_error(SLAPI_LOG_REPL, windows_repl_plugin_name,
- "%s: windows_generate_update_mods: remote_entry is [%s]
local_entry is [%s] "
- "cannot generate update mods\n",
agmt_get_long_name(prp->agmt),
- remote_entry ? slapi_entry_get_dn_const(remote_entry) :
"NULL",
- local_entry ? slapi_entry_get_dn_const(local_entry) :
"NULL");
- goto bail;
- }
+ if (!remote_entry || !local_entry) {
+ slapi_log_error(SLAPI_LOG_REPL, windows_repl_plugin_name,
+ "%s: windows_generate_update_mods: remote_entry is [%s]
local_entry is [%s] "
+ "cannot generate update mods\n",
agmt_get_long_name(prp->agmt),
+ remote_entry ? slapi_entry_get_dn_const(remote_entry) :
"NULL",
+ local_entry ? slapi_entry_get_dn_const(local_entry) :
"NULL");
+ goto bail;
+ }
if (to_windows)
{
@@ -4258,8 +4358,8 @@ windows_generate_update_mods(Private_Repl_Protocol *prp,Slapi_Entry
*remote_entr
windows_is_remote_entry_user_or_group(remote_entry,&is_user,&is_group);
}
- for (rc = slapi_entry_first_attr(remote_entry, &attr); rc == 0;
- rc = slapi_entry_next_attr(remote_entry, attr, &attr))
+ for (rc = slapi_entry_first_attr(remote_entry, &attr); rc == 0;
+ rc = slapi_entry_next_attr(remote_entry, attr, &attr))
{
int is_present_local = 0;
char *type = NULL;
@@ -4403,15 +4503,17 @@ windows_generate_update_mods(Private_Repl_Protocol
*prp,Slapi_Entry *remote_entr
} else {
/* A dn-valued attribute : need to take special steps */
Slapi_ValueSet *mapped_remote_values = NULL;
+ Slapi_ValueSet *local_values = NULL;
+
+ /* We ignore any DNs that are outside the scope of the agreement (on both sides) */
+ slapi_attr_get_valueset(local_attr,&local_values);
+
/* First map all the DNs to that they're in a consistent domain */
map_dn_values(prp,vs,&mapped_remote_values, to_windows,0);
if (mapped_remote_values)
{
- Slapi_ValueSet *local_values = NULL;
Slapi_ValueSet *restricted_local_values = NULL;
/* Now do a compare on the values, generating mods to bring them into consistency
(if any) */
- /* We ignore any DNs that are outside the scope of the agreement (on both sides) */
- slapi_attr_get_valueset(local_attr,&local_values);
if (local_values)
{
map_dn_values(prp,local_values,&restricted_local_values,!to_windows,1);
@@ -4423,6 +4525,9 @@ windows_generate_update_mods(Private_Repl_Protocol *prp,Slapi_Entry
*remote_entr
}
else
{
+ windows_generate_dn_value_mods(local_type, local_attr, smods,
+ mapped_remote_values,
+ local_values,do_modify);
slapi_log_error(SLAPI_LOG_REPL, windows_repl_plugin_name,
"windows_generate_update_mods: no restricted local values found for
"
"local attribute %s in local entry %s for remote attribute "
@@ -4432,9 +4537,9 @@ windows_generate_update_mods(Private_Repl_Protocol *prp,Slapi_Entry
*remote_entr
type ? type : "NULL",
slapi_entry_get_dn(remote_entry));
}
- slapi_valueset_free(local_values);
- local_values = NULL;
} else {
+ windows_generate_dn_value_mods(local_type, local_attr, smods,
+ mapped_remote_values, NULL, do_modify);
slapi_log_error(SLAPI_LOG_REPL, windows_repl_plugin_name,
"windows_generate_update_mods: no local values found for "
"local attribute %s in local entry %s for remote attribute "
@@ -4447,18 +4552,25 @@ windows_generate_update_mods(Private_Repl_Protocol
*prp,Slapi_Entry *remote_entr
slapi_valueset_free(mapped_remote_values);
mapped_remote_values = NULL;
} else {
- slapi_log_error(SLAPI_LOG_REPL, windows_repl_plugin_name,
- "windows_generate_update_mods: could not map the values in "
- "local attribute %s in local entry %s for remote attribute "
- "%s in remote entry %s\n",
- local_type,
- slapi_entry_get_dn(local_entry),
- type ? type : "NULL",
- slapi_entry_get_dn(remote_entry));
+ if (local_values) {
+ windows_generate_dn_value_mods(local_type, local_attr, smods,
+ NULL, local_values, do_modify);
+ } else {
+ slapi_log_error(SLAPI_LOG_REPL, windows_repl_plugin_name,
+ "windows_generate_update_mods: could not map the values in
"
+ "local attribute %s in local entry %s for remote attribute
"
+ "%s in remote entry %s\n",
+ local_type,
+ slapi_entry_get_dn(local_entry),
+ type ? type : "NULL",
+ slapi_entry_get_dn(remote_entry));
+ }
}
+ slapi_valueset_free(local_values);
+ local_values = NULL;
}
} else
- {
+ { /* !is_present_local || is_guid */
if (!is_present_local)
{
slapi_log_error(SLAPI_LOG_REPL, windows_repl_plugin_name,
@@ -4555,37 +4667,91 @@ windows_generate_update_mods(Private_Repl_Protocol
*prp,Slapi_Entry *remote_entr
slapi_ch_free_string(&local_type);
}
- /* Check if any attributes were deleted from the remote entry */
- entry_first_deleted_attribute(remote_entry, &del_attr);
- while (del_attr != NULL) {
- Slapi_Attr *local_attr = NULL;
- char *type = NULL;
- char *local_type = NULL;
- int mapdn = 0;
+ /* Check if any attributes were deleted from the remote entry */
+ entry_first_deleted_attribute(remote_entry, &del_attr);
+ local_subtree = windows_private_get_directory_subtree(prp->agmt);
+ while (del_attr != NULL) {
+ Slapi_Attr *local_attr = NULL;
+ char *type = NULL;
+ char *local_type = NULL;
+ int mapdn = 0;
- /* Map remote type to local type */
+ /* Map remote type to local type */
slapi_attr_get_type(del_attr, &type);
- if ( is_straight_mapped_attr(type,is_user,is_nt4) ) {
- local_type = slapi_ch_strdup(type);
- } else {
- windows_map_attr_name(type , to_windows, is_user, 0 /* not create
*/, &local_type, &mapdn);
- }
-
- /* Check if this attr exists in the local entry */
- if (local_type) {
- slapi_entry_attr_find(local_entry, local_type, &local_attr);
- if (local_attr) {
- slapi_log_error(SLAPI_LOG_REPL,
windows_repl_plugin_name,
- "windows_generate_update_mods: deleting %s
attribute from local entry\n", local_type);
- /* Delete this attr from the local entry */
- slapi_mods_add_mod_values(smods, LDAP_MOD_DELETE,
local_type, NULL);
+ if ( is_straight_mapped_attr(type,is_user,is_nt4) ) {
+ local_type = slapi_ch_strdup(type);
+ } else {
+ windows_map_attr_name(type , to_windows, is_user, 0 /* not create */, &local_type,
&mapdn);
+ }
+
+ /* Check if this attr exists in the local entry */
+ if (local_type) {
+ slapi_entry_attr_find(local_entry, local_type, &local_attr);
+ if (local_attr) {
+ Slapi_Mod *mysmod = NULL;
+ slapi_log_error(SLAPI_LOG_REPL, windows_repl_plugin_name,
+ "windows_generate_update_mods: deleting %s attribute from local entry\n",
local_type);
+ /* Delete this attr from the local entry */
+ /* if type is dn and the dn is out of winsync scope, keep them.
+ * othewise delete all attr. */
+ if (mapdn) {
+ Slapi_ValueSet *vs = NULL;
+ Slapi_Value *valp = NULL;
+ Slapi_DN *sdn = slapi_sdn_new();
+ int i = 0;
+ int is_in_subtree = 0;
+ Slapi_Value **myva = NULL;
+
+ slapi_attr_get_valueset(local_attr, &vs); /* thisvs is dup'ed */
+ for (i = slapi_valueset_first_value(vs, &valp);
+ (i != -1) && (valp != NULL);
+ i = slapi_valueset_next_value(vs, i, &valp)) {
+ /* valp is a pointer to va in vs */
+ const char *strval = slapi_value_get_string(valp); /* no dup */
+ if (strval) {
+ slapi_sdn_set_dn_byref(sdn, strval);
+ is_in_subtree = slapi_sdn_scope_test(sdn, local_subtree,
+ LDAP_SCOPE_SUBTREE);
+ if (is_in_subtree) {
+ /*
+ * If delete all on AD,
+ * we could delete the values on DS in the scope.
+ */
+ /* myva is (re)allocated and valp is copied */
+ valuearray_add_value(&myva, valp);
+ }
+ }
+ }
+ if (myva) {
+ Slapi_ValueSet *myvs = NULL;
+
+ myvs = slapi_valueset_new();
+ valueset_set_valuearray_passin(myvs, myva);
+ mysmod = slapi_mod_new();
+ slapi_mod_init_valueset_byval(mysmod,
+ LDAP_MOD_DELETE|LDAP_MOD_BVALUES,
+ local_type,
+ myvs);
+ slapi_valueset_free(myvs);
+ }
+ slapi_sdn_free(&sdn);
+ slapi_valueset_free(vs);
+ if (mysmod) {
+ slapi_mods_add_ldapmod(smods, slapi_mod_get_ldapmod_passout(mysmod));
+ }
+ if (mysmod) {
+ slapi_mod_free(&mysmod);
+ }
+ } else {
+ slapi_mods_add_mod_values(smods, LDAP_MOD_DELETE, local_type, NULL);
+ }
*do_modify = 1;
- }
- }
+ }
+ }
- entry_next_deleted_attribute(remote_entry, &del_attr);
+ entry_next_deleted_attribute(remote_entry, &del_attr);
slapi_ch_free_string(&local_type);
- }
+ }
if (to_windows) {
if (is_user) {
@@ -4690,7 +4856,7 @@ windows_update_remote_entry(Private_Repl_Protocol *prp,Slapi_Entry
*remote_entry
static int
windows_update_local_entry(Private_Repl_Protocol *prp,Slapi_Entry
*remote_entry,Slapi_Entry *local_entry)
{
- Slapi_Mods smods;
+ Slapi_Mods smods = {0};
int retval = 0;
Slapi_PBlock *pb = NULL;
int do_modify = 0;
@@ -4736,9 +4902,9 @@ windows_update_local_entry(Private_Repl_Protocol *prp,Slapi_Entry
*remote_entry,
/* compare the parents */
retval = windows_get_superior_change(prp,
- slapi_entry_get_sdn(local_entry),
- mapped_sdn,
- &newsuperior, 0 /* to_windows */);
+ slapi_entry_get_sdn(local_entry),
+ mapped_sdn,
+ &newsuperior, 0 /* to_windows */);
if (newsuperior || newrdn) {
char *escaped_filter_val;
@@ -5439,7 +5605,7 @@ retry:
void
windows_dirsync_inc_run(Private_Repl_Protocol *prp)
- {
+{
int rc = 0;
int done = 0;
diff --git a/ldap/servers/slapd/slapi-plugin.h b/ldap/servers/slapd/slapi-plugin.h
index dc7f87f..5c29b0c 100644
--- a/ldap/servers/slapd/slapi-plugin.h
+++ b/ldap/servers/slapd/slapi-plugin.h
@@ -7005,6 +7005,16 @@ int slapi_set_plugin_default_config(const char *type, Slapi_Value
*value);
*/
int slapi_get_plugin_default_config(char *type, Slapi_ValueSet **valueset);
+/**
+ * Checks if a \c Slapi_ValueSet structure has values
+ *
+ * \param vs Pointer to the \c Slapi_ValueSet structure of which
+ * you wish to get the count.
+ * \return 1 if there are no values contained in the \c Slapi_ValueSet structure.
+ * \return 0 if there are values contained in the \c Slapi_ValueSet structure.
+ */
+int slapi_valueset_isempty(const Slapi_ValueSet *vs);
+
int slapi_check_account_lock( Slapi_PBlock *pb, Slapi_Entry *bind_target_entry, int
pwresponse_req, int check_password_policy, int send_result);
/* backend get/set info */
diff --git a/ldap/servers/slapd/valueset.c b/ldap/servers/slapd/valueset.c
index de6914f..732b411 100644
--- a/ldap/servers/slapd/valueset.c
+++ b/ldap/servers/slapd/valueset.c
@@ -890,12 +890,24 @@ slapi_valueset_set_valueset(Slapi_ValueSet *vs1, const
Slapi_ValueSet *vs2)
int
slapi_valueset_first_value( Slapi_ValueSet *vs, Slapi_Value **v )
{
+ if (NULL == vs) {
+ if (v) {
+ *v = NULL;
+ }
+ return 0;
+ }
return valuearray_first_value(vs->va,v);
}
int
slapi_valueset_next_value( Slapi_ValueSet *vs, int index, Slapi_Value **v)
{
+ if (NULL == vs) {
+ if (v) {
+ *v = NULL;
+ }
+ return index;
+ }
return valuearray_next_value(vs->va,index,v);
}
@@ -914,8 +926,17 @@ slapi_valueset_count( const Slapi_ValueSet *vs)
}
int
+slapi_valueset_isempty(const Slapi_ValueSet *vs)
+{
+ return valueset_isempty(vs);
+}
+
+int
valueset_isempty( const Slapi_ValueSet *vs)
{
+ if (NULL == vs) {
+ return 1; /* true */
+ }
return valuearray_isempty(vs->va);
}
@@ -924,7 +945,7 @@ Slapi_Value *
slapi_valueset_find(const Slapi_Attr *a, const Slapi_ValueSet *vs, const Slapi_Value *v)
{
Slapi_Value *r= NULL;
- if(!valuearray_isempty(vs->va))
+ if(vs && !valuearray_isempty(vs->va))
{
int i= valuearray_find(a,vs->va,v);
if(i!=-1)
commit 5324aeca04c8fd0dd3787565815e92bfad1eb3d4
Author: Noriko Hosoi <nhosoi(a)redhat.com>
Date: Thu Feb 20 14:29:16 2014 -0800
Ticket #47642 - Windows Sync group issues
Bug Description: When an entry is moved on AD, and the entry is
a member of a group, the value of the member in the group is
automatically updated. But Windows Sync Control request only
returns the renamed entry; it does not return the group having
the member in it even though the value is updated. This is
because an AD group stores DNT (Distinguish Name Tag -- ID in
integer) instead of the dn itself. Since the rename operation
does not change DNT, the group entry on AD has no change, either.
On the DS side, the group entry stores the full DN which needs
to be adjusted to the renamed DN to complete the synchronization
with AD.
Fix Description: Once rename operation is received from AD,
windows_update_local_entry searches groups having a member value
matches the pre-renamed dn on DS, and replaces the old dn with the
renamed one.
Thanks to tbordaz(a)redhat.com for pointing out the possibility of
NULL dereference. The problem is fixed, as well.
Thanks to rmeggins(a)redhat.com for suggesting to escape the search
filter value. It was added.
https://fedorahosted.org/389/ticket/47642
(cherry picked from commit 98ddd817e26f236adebd80270ec71d7ec372c20e)
(cherry picked from commit 86515d1b18a96b9d7e6143f870b343030a7af5a7)
(cherry picked from commit ab4893cb851533d89e1b02c91972255a48776ce4)
diff --git a/ldap/servers/plugins/replication/windows_protocol_util.c
b/ldap/servers/plugins/replication/windows_protocol_util.c
index 93246ec..bac6573 100644
--- a/ldap/servers/plugins/replication/windows_protocol_util.c
+++ b/ldap/servers/plugins/replication/windows_protocol_util.c
@@ -3871,6 +3871,7 @@ map_entry_dn_inbound_ext(Slapi_Entry *e, Slapi_DN **dn, const
Repl_Agmt *ra, int
} else
{
/* Error, no username */
+ retval = ENTRY_NOTFOUND;
}
}
if (new_dn)
@@ -4689,7 +4690,7 @@ windows_update_remote_entry(Private_Repl_Protocol *prp,Slapi_Entry
*remote_entry
static int
windows_update_local_entry(Private_Repl_Protocol *prp,Slapi_Entry
*remote_entry,Slapi_Entry *local_entry)
{
- Slapi_Mods smods = {0};
+ Slapi_Mods smods;
int retval = 0;
Slapi_PBlock *pb = NULL;
int do_modify = 0;
@@ -4701,14 +4702,24 @@ windows_update_local_entry(Private_Repl_Protocol *prp,Slapi_Entry
*remote_entry,
Slapi_DN *mapped_sdn = NULL;
Slapi_RDN rdn = {0};
Slapi_Entry *orig_local_entry = NULL;
+ const Slapi_DN *orig_local_sdn = NULL;
+
+ /* Variables for updating local groups */
+ Slapi_Entry **entries = NULL;
+ char *filter_string = NULL;
+ const Slapi_DN *local_subtree = NULL;
+ const Slapi_DN *local_subtree_sdn = NULL;
+ char *attrs[3];
+ /* Variables for updating local groups */
+ slapi_mods_init(&smods, 0);
windows_is_local_entry_user_or_group(local_entry, &is_user, &is_group);
/* Get the mapped DN. We don't want to locate the existing entry by
* guid or username. We want to get the mapped DN just as we would
* if we were creating a new entry. */
retval = map_entry_dn_inbound_ext(remote_entry, &mapped_sdn, prp->agmt, 0 /*
use_guid */, 0 /* use_username */);
- if (retval != 0) {
+ if (retval || (NULL == mapped_sdn)) {
slapi_log_error(SLAPI_LOG_REPL, windows_repl_plugin_name,
"unable to map remote entry to local DN\n");
return retval;
@@ -4730,8 +4741,10 @@ windows_update_local_entry(Private_Repl_Protocol *prp,Slapi_Entry
*remote_entry,
&newsuperior, 0 /* to_windows */);
if (newsuperior || newrdn) {
+ char *escaped_filter_val;
+ const char *ptr;
/* remote parent is different from the local parent */
- Slapi_PBlock *pb = slapi_pblock_new ();
+ pb = slapi_pblock_new ();
if (NULL == newrdn) {
newdn = slapi_entry_get_dn_const(local_entry);
@@ -4778,10 +4791,102 @@ windows_update_local_entry(Private_Repl_Protocol *prp,Slapi_Entry
*remote_entry,
orig_local_entry = NULL;
goto bail;
}
- }
-
- slapi_mods_init (&smods, 0);
+ /* WinSync control req does not return the member updates
+ * in the groups caused by moving member entries.
+ * We need to update the local groups manually... */
+ local_subtree = agmt_get_replarea(prp->agmt);
+ local_subtree_sdn = local_subtree;
+ orig_local_sdn = slapi_entry_get_sdn_const(orig_local_entry);
+ escaped_filter_val = slapi_ch_malloc(slapi_sdn_get_ndn_len(orig_local_sdn) * 3 + 1);
+ ptr = escape_filter_value((char *)slapi_sdn_get_ndn(orig_local_sdn),
+ slapi_sdn_get_ndn_len(orig_local_sdn), escaped_filter_val);
+ /* Search entries which have pre-renamed members */
+ filter_string =
PR_smprintf("(&(objectclass=ntGroup)(|(member=%s)(uniquemember=%s)))",
+ ptr, ptr);
+ slapi_ch_free_string(&escaped_filter_val);
+ attrs[0] = "member";
+ attrs[1] = "uniquemember";
+ attrs[2] = NULL;
+ pb = slapi_pblock_new ();
+ slapi_search_internal_set_pb(pb, slapi_sdn_get_dn(local_subtree_sdn),
+ LDAP_SCOPE_SUBTREE, filter_string, attrs, 0, NULL, NULL,
+ repl_get_plugin_identity(PLUGIN_MULTIMASTER_REPLICATION),
0);
+ slapi_search_internal_pb(pb);
+ slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &retval);
+ if (LDAP_SUCCESS == retval) {
+ Slapi_Entry **ep;
+ const char *prev_member = slapi_sdn_get_ndn(orig_local_sdn);
+ const char *new_member = slapi_sdn_get_ndn(mapped_sdn);
+ size_t prev_member_len = slapi_sdn_get_ndn_len(orig_local_sdn);
+ size_t new_member_len = strlen(new_member);
+ slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &entries);
+ for (ep = entries; ep && *ep; ep++) {
+ /* there are group entries whose member matches the renamed entry. */
+ Slapi_PBlock *mod_pb = NULL;
+ Slapi_Attr *mattr = NULL;
+ Slapi_Attr *umattr = NULL;
+ char *type = NULL;
+ slapi_entry_attr_find(*ep, "member", &mattr);
+ slapi_entry_attr_find(*ep, "uniquemember", &umattr);
+ if (mattr) {
+ if (umattr) {
+ /* This entry has both member and uniquemember ... */
+ Slapi_Value *v = NULL;
+ int i = 0;
+ for (i = slapi_attr_first_value(mattr, &v);
+ v && (i != -1);
+ i = slapi_attr_next_value(mattr, i, &v)) {
+ const char *s = slapi_value_get_string(v);
+ if (NULL == s) {
+ continue;
+ }
+ if (0 == strcasecmp(s, prev_member)) {
+ type = "member";
+ break;
+ }
+ }
+ if (!type) {
+ type = "uniquemember";
+ }
+ } else {
+ type = "member";
+ }
+ } else {
+ if (umattr) {
+ type = "uniquemember";
+ }
+ }
+ if (type) {
+ mod_pb = slapi_pblock_new();
+ slapi_mods_add(&smods, LDAP_MOD_DELETE, type, prev_member_len, prev_member);
+ slapi_mods_add(&smods, LDAP_MOD_ADD, type, new_member_len, new_member);
+ slapi_modify_internal_set_pb_ext(mod_pb, slapi_entry_get_sdn(*ep),
+ slapi_mods_get_ldapmods_byref(&smods), NULL,
NULL,
+
repl_get_plugin_identity(PLUGIN_MULTIMASTER_REPLICATION),
+ 0);
+ slapi_modify_internal_pb(mod_pb);
+ slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &retval);
+ if (retval) {
+ slapi_log_error(SLAPI_LOG_FATAL, windows_repl_plugin_name,
+ "windows_update_local_entry: "
+ "failed to modify entry %s replacing %s with %s "
+ "- error %d:%s\n",
+ slapi_entry_get_dn(*ep), prev_member, new_member,
+ retval, ldap_err2string(retval));
+ }
+ slapi_pblock_destroy(mod_pb);
+ slapi_mods_done(&smods);
+ } /* if (type) */
+ } /* for (ep = entries; ep && *ep; ep++) */
+ } /* if (LDAP_SUCCESS == retval) - searching with "(|(member=..)(uniquemember=..))
*/
+ slapi_free_search_results_internal(pb);
+ slapi_pblock_destroy(pb);
+ if (filter_string) {
+ PR_smprintf_free(filter_string);
+ }
+ slapi_sdn_free((Slapi_DN **)&local_subtree);
+ } /* if (newsuperior || newrdn) */
retval =
windows_generate_update_mods(prp,remote_entry,local_entry,0,&smods,&do_modify);
/* Now perform the modify if we need to */