diff options
-rw-r--r-- | ldap/servers/plugins/replication/windows_protocol_util.c | 131 | ||||
-rw-r--r-- | ldap/servers/slapd/add.c | 2 | ||||
-rw-r--r-- | ldap/servers/slapd/back-ldbm/dblayer.c | 2 | ||||
-rw-r--r-- | ldap/servers/slapd/modutil.c | 22 | ||||
-rw-r--r-- | ldap/servers/slapd/slapi-plugin.h | 2 | ||||
-rw-r--r-- | ldap/servers/slapd/util.c | 1 |
6 files changed, 146 insertions, 14 deletions
diff --git a/ldap/servers/plugins/replication/windows_protocol_util.c b/ldap/servers/plugins/replication/windows_protocol_util.c index 1386833f..87994fc3 100644 --- a/ldap/servers/plugins/replication/windows_protocol_util.c +++ b/ldap/servers/plugins/replication/windows_protocol_util.c @@ -62,7 +62,7 @@ int ruv_private_new( RUV **ruv, RUV *clone ); static Slapi_Entry* windows_entry_already_exists(Slapi_Entry *e); static void extract_guid_from_entry_bv(Slapi_Entry *e, const struct berval **bv); #endif -static void windows_map_mods_for_replay(Private_Repl_Protocol *prp,LDAPMod **original_mods, LDAPMod ***returned_mods, int is_user, char** password); +static void windows_map_mods_for_replay(Private_Repl_Protocol *prp,LDAPMod **original_mods, LDAPMod ***returned_mods, int is_user, char** password, const Slapi_Entry *ad_entry); static int is_subject_of_agreement_local(const Slapi_Entry *local_entry,const Repl_Agmt *ra); static int windows_create_remote_entry(Private_Repl_Protocol *prp,Slapi_Entry *original_entry, Slapi_DN *remote_sdn, Slapi_Entry **remote_entry, char** password); static int windows_get_local_entry(const Slapi_DN* local_dn,Slapi_Entry **local_entry); @@ -1233,7 +1233,8 @@ windows_replay_update(Private_Repl_Protocol *prp, slapi_operation_parameters *op LDAPMod **mapped_mods = NULL; char *newrdn = NULL; - windows_map_mods_for_replay(prp,op->p.p_modify.modify_mods, &mapped_mods, is_user, &password); + windows_map_mods_for_replay(prp,op->p.p_modify.modify_mods, &mapped_mods, is_user, &password, + windows_private_get_raw_entry(prp->agmt)); if (is_user) { winsync_plugin_call_pre_ad_mod_user_mods_cb(prp->agmt, windows_private_get_raw_entry(prp->agmt), @@ -1731,6 +1732,104 @@ windows_delete_local_entry(Slapi_DN *sdn){ return return_value; } +/* + Before we send the modify to AD, we need to check to see if the mod still + applies - the entry in AD may have been modified, and those changes not sync'd + back to the DS, since the way winsync currently works is that it polls periodically + using DirSync for changes in AD - note that this does not guarantee that the mod + will apply cleanly, since there is still a small window of time between the time + we read the entry from AD and the time the mod op is sent, but doing this check + here should substantially reduce the chances of these types of out-of-sync problems + + If we do find a mod that does not apply cleanly, we just discard it and log an + error message to that effect. +*/ +static int +mod_already_made(Private_Repl_Protocol *prp, Slapi_Mod *smod, const Slapi_Entry *ad_entry) +{ + int retval = 0; + int op = 0; + const char *type = NULL; + + if (!slapi_mod_isvalid(smod)) { /* bogus */ + slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, + "%s: mod_already_made: " + "modify operation is null - skipping.\n", + agmt_get_long_name(prp->agmt)); + return 1; + } + + op = slapi_mod_get_operation(smod); + type = slapi_mod_get_type(smod); + if (SLAPI_IS_MOD_ADD(op)) { /* make sure value is not there */ + struct berval *bv = NULL; + for (bv = slapi_mod_get_first_value(smod); + bv; bv = slapi_mod_get_next_value(smod)) { + Slapi_Value *sv = slapi_value_new(); + slapi_value_init_berval(sv, bv); /* copies bv_val */ + if (slapi_entry_attr_has_syntax_value(ad_entry, type, sv)) { + slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, + "%s: mod_already_made: " + "remote entry attr [%s] already has value [%s] - will not send.\n", + agmt_get_long_name(prp->agmt), type, + slapi_value_get_string(sv)); + slapi_mod_remove_value(smod); /* removes the value at the current iterator pos */ + } + slapi_value_free(&sv); + } + /* if all values were removed, no need to send the mod */ + if (slapi_mod_get_num_values(smod) == 0) { + slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, + "%s: mod_already_made: " + "remote entry attr [%s] had all mod values removed - will not send.\n", + agmt_get_long_name(prp->agmt), type); + retval = 1; + } + } else if (SLAPI_IS_MOD_DELETE(op)) { /* make sure value or attr is there */ + Slapi_Attr *attr = NULL; + + /* if attribute does not exist, no need to send the delete */ + if (slapi_entry_attr_find(ad_entry, type, &attr) || !attr) { + slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, + "%s: mod_already_made: " + "remote entry attr [%s] already deleted - will not send.\n", + agmt_get_long_name(prp->agmt), type); + retval = 1; + } else if (slapi_mod_get_num_values(smod) > 0) { + /* if attr exists, remove mods that have already been applied */ + struct berval *bv = NULL; + for (bv = slapi_mod_get_first_value(smod); + bv; bv = slapi_mod_get_next_value(smod)) { + Slapi_Value *sv = slapi_value_new(); + slapi_value_init_berval(sv, bv); /* copies bv_val */ + if (!slapi_entry_attr_has_syntax_value(ad_entry, type, sv)) { + slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, + "%s: mod_already_made: " + "remote entry attr [%s] already deleted value [%s] - will not send.\n", + agmt_get_long_name(prp->agmt), type, + slapi_value_get_string(sv)); + slapi_mod_remove_value(smod); /* removes the value at the current iterator pos */ + } + slapi_value_free(&sv); + } + /* if all values were removed, no need to send the mod */ + if (slapi_mod_get_num_values(smod) == 0) { + slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, + "%s: mod_already_made: " + "remote entry attr [%s] had all mod values removed - will not send.\n", + agmt_get_long_name(prp->agmt), type); + retval = 1; + } + } /* else if no values specified, this means delete the attribute */ + } else { /* allow this mod */ + slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, + "%s: mod_already_made: " + "skipping mod op [%d]\n", + agmt_get_long_name(prp->agmt), op); + } + + return retval; +} static int windows_check_mods_for_rdn_change(Private_Repl_Protocol *prp, LDAPMod **original_mods, @@ -1905,12 +2004,13 @@ 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, const Slapi_Entry *ad_entry) { Slapi_Mods smods = {0}; Slapi_Mods mapped_smods = {0}; LDAPMod *mod = NULL; int is_nt4 = windows_private_get_isnt4(prp->agmt); + Slapi_Mod *mysmod = NULL; LDAPDebug( LDAP_DEBUG_TRACE, "=> windows_map_mods_for_replay\n", 0, 0, 0 ); @@ -1945,8 +2045,9 @@ windows_map_mods_for_replay(Private_Repl_Protocol *prp,LDAPMod **original_mods, } } - /* copy over the mod */ - slapi_mods_add_modbvps(&mapped_smods,mod->mod_op,attr_type,mod->mod_bvalues); + /* create the new smod to add to the mapped_smods */ + mysmod = slapi_mod_new(); + slapi_mod_init_byval(mysmod, mod); /* copy contents */ } else { char *mapped_type = NULL; @@ -1967,7 +2068,8 @@ windows_map_mods_for_replay(Private_Repl_Protocol *prp,LDAPMod **original_mods, map_dn_values(prp,vs,&mapped_values, 1 /* to windows */,0); if (mapped_values) { - slapi_mods_add_mod_values(&mapped_smods,mod->mod_op,mapped_type,valueset_get_valuearray(mapped_values)); + mysmod = slapi_mod_new(); + slapi_mod_init_valueset_byval(mysmod, mod->mod_op, mapped_type, mapped_values); slapi_valueset_free(mapped_values); mapped_values = NULL; } else @@ -1975,7 +2077,10 @@ windows_map_mods_for_replay(Private_Repl_Protocol *prp,LDAPMod **original_mods, /* this might be a del: mod, in which case there are no values */ if (mod->mod_op & LDAP_MOD_DELETE) { - slapi_mods_add_mod_values(&mapped_smods, LDAP_MOD_DELETE, mapped_type, NULL); + 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); } } slapi_mod_done(&smod); @@ -2004,7 +2109,10 @@ windows_map_mods_for_replay(Private_Repl_Protocol *prp,LDAPMod **original_mods, slapi_mod_done(&smod); } - slapi_mods_add_modbvps(&mapped_smods,mod->mod_op,mapped_type,mod->mod_bvalues); + /* create the new smod to add to the mapped_smods */ + mysmod = slapi_mod_new(); + slapi_mod_init_byval(mysmod, mod); /* copy contents */ + slapi_mod_set_type(mysmod, mapped_type); } slapi_ch_free_string(&mapped_type); } else @@ -2050,6 +2158,13 @@ windows_map_mods_for_replay(Private_Repl_Protocol *prp,LDAPMod **original_mods, } } /* Otherwise we do not copy this mod at all */ + if (mysmod && !mod_already_made(prp, mysmod, ad_entry)) { /* make sure this mod is still valid to send */ + slapi_mods_add_ldapmod(&mapped_smods, slapi_mod_get_ldapmod_passout(mysmod)); + } + if (mysmod) { + slapi_mod_free(&mysmod); + } + mod = slapi_mods_get_next_mod(&smods); } slapi_mods_done (&smods); diff --git a/ldap/servers/slapd/add.c b/ldap/servers/slapd/add.c index f3929481..b69da2e5 100644 --- a/ldap/servers/slapd/add.c +++ b/ldap/servers/slapd/add.c @@ -745,7 +745,7 @@ static int check_rdn_for_created_attrs(Slapi_Entry *e) char *type[] = {SLAPI_ATTR_UNIQUEID, "modifytimestamp", "createtimestamp", "creatorsname", "modifiersname", 0}; - if (rdn = slapi_rdn_new()) { + if ((rdn = slapi_rdn_new())) { slapi_rdn_init_dn(rdn, slapi_entry_get_dn_const(e)); for (i = 0; type[i] != NULL; i++) { diff --git a/ldap/servers/slapd/back-ldbm/dblayer.c b/ldap/servers/slapd/back-ldbm/dblayer.c index e8472d2b..4eeb93c1 100644 --- a/ldap/servers/slapd/back-ldbm/dblayer.c +++ b/ldap/servers/slapd/back-ldbm/dblayer.c @@ -3884,7 +3884,7 @@ unsigned long db_strtoul(const char *str, int *err) * are silently converted to the equivalent unsigned long int value. */ /* We don't want to make it happen. */ - for (p = str; p && *p && (*p == ' ' || *p == '\t'); p++) ; + for (p = (char *)str; p && *p && (*p == ' ' || *p == '\t'); p++) ; if ('-' == *p) { if (err) *err = ERANGE; return val; diff --git a/ldap/servers/slapd/modutil.c b/ldap/servers/slapd/modutil.c index e36eedb7..b063fa9d 100644 --- a/ldap/servers/slapd/modutil.c +++ b/ldap/servers/slapd/modutil.c @@ -595,6 +595,21 @@ slapi_mod_init_byval (Slapi_Mod *smod, const LDAPMod *mod) } void +slapi_mod_init_valueset_byval(Slapi_Mod *smod, int op, const char *type, const Slapi_ValueSet *svs) +{ + PR_ASSERT(smod!=NULL); + slapi_mod_init(smod, 0); + slapi_mod_set_operation (smod, op); + slapi_mod_set_type (smod, type); + if (svs!=NULL) { + Slapi_Value **svary = valueset_get_valuearray(svs); + valuearray_get_bervalarray(svary, &smod->mod->mod_bvalues); + smod->num_values = slapi_valueset_count(svs); + smod->num_elements = smod->num_values + 1; + } +} + +void slapi_mod_free (Slapi_Mod **smod) { slapi_mod_done(*smod); @@ -750,15 +765,16 @@ slapi_mod_isvalid (const Slapi_Mod *mod) if (mod == NULL || mod->mod == NULL) return 0; - op = mod->mod->mod_op && ~LDAP_MOD_BVALUES; + op = mod->mod->mod_op; - if (op != LDAP_MOD_ADD && op != LDAP_MOD_DELETE && op != LDAP_MOD_REPLACE) + if (!SLAPI_IS_MOD_ADD(op) && !SLAPI_IS_MOD_DELETE(op) && !SLAPI_IS_MOD_REPLACE(op)) return 0; if (mod->mod->mod_type == NULL) return 0; - if (op != LDAP_MOD_DELETE && mod->num_values == 0) + /* add op must have at least 1 value */ + if (SLAPI_IS_MOD_ADD(op) && (mod->num_values == 0)) return 0; return 1; diff --git a/ldap/servers/slapd/slapi-plugin.h b/ldap/servers/slapd/slapi-plugin.h index 5ffb8608..87d8cd6e 100644 --- a/ldap/servers/slapd/slapi-plugin.h +++ b/ldap/servers/slapd/slapi-plugin.h @@ -573,6 +573,8 @@ void slapi_mod_init(Slapi_Mod *smod, int initCount); void slapi_mod_init_byval(Slapi_Mod *smod, const LDAPMod *mod); void slapi_mod_init_byref(Slapi_Mod *smod, LDAPMod *mod); void slapi_mod_init_passin(Slapi_Mod *smod, LDAPMod *mod); +/* init a mod and set the mod values to be a copy of the given valueset */ +void slapi_mod_init_valueset_byval(Slapi_Mod *smod, int op, const char *type, const Slapi_ValueSet *svs); void slapi_mod_add_value(Slapi_Mod *smod, const struct berval *val); void slapi_mod_remove_value(Slapi_Mod *smod); struct berval *slapi_mod_get_first_value(Slapi_Mod *smod); diff --git a/ldap/servers/slapd/util.c b/ldap/servers/slapd/util.c index d53f1e74..8e4876e9 100644 --- a/ldap/servers/slapd/util.c +++ b/ldap/servers/slapd/util.c @@ -207,7 +207,6 @@ escape_filter_value(const char* str, int len, char buf[BUFSIZ]) void strcpy_unescape_value( char *d, const char *s ) { - char *head = d; int gotesc = 0; const char *end = s + strlen(s); for ( ; *s; s++ ) |