From 66124e450402caa4e53179d1f8aa3995dbc2a797 Mon Sep 17 00:00:00 2001 From: Ludwig Krispenz Date: Fri, 25 Nov 2016 09:37:13 +0100 Subject: [PATCH] ticket 49043 - initial fix this fix does: - add "objectclass: ldapsubentry" to the conflict entry, this hides conflict entries from normal searches - if an entry turned into a conflict has valid children, move them to the valid entry. This will show all valid entries without "nsuniquid" in the dn NOTE: the fix for 49050 is required --- ldap/servers/plugins/replication/repl5_plugins.c | 16 +- ldap/servers/plugins/replication/urp.c | 280 ++++++++++++++++++++++- ldap/servers/plugins/replication/urp.h | 2 + 3 files changed, 292 insertions(+), 6 deletions(-) diff --git a/ldap/servers/plugins/replication/repl5_plugins.c b/ldap/servers/plugins/replication/repl5_plugins.c index 70e003b..09d6232 100644 --- a/ldap/servers/plugins/replication/repl5_plugins.c +++ b/ldap/servers/plugins/replication/repl5_plugins.c @@ -811,7 +811,20 @@ multimaster_bepreop_modrdn (Slapi_PBlock *pb) return rc; } -int +int +multimaster_bepostop_add (Slapi_PBlock *pb) +{ + Slapi_Operation *op; + + slapi_pblock_get(pb, SLAPI_OPERATION, &op); + if ( ! operation_is_flag_set (op, OP_FLAG_REPL_FIXUP) ) + { + urp_post_add_operation (pb); + } + return SLAPI_PLUGIN_SUCCESS; +} + +int multimaster_bepostop_modrdn (Slapi_PBlock *pb) { Slapi_Operation *op; @@ -921,6 +934,7 @@ multimaster_be_betxnpostop_add (Slapi_PBlock *pb) int rc = 0; /* original betxnpost */ rc = write_changelog_and_ruv(pb); + rc |= multimaster_bepostop_add(pb); return rc; } diff --git a/ldap/servers/plugins/replication/urp.c b/ldap/servers/plugins/replication/urp.c index 64810e9..c42d84d 100644 --- a/ldap/servers/plugins/replication/urp.c +++ b/ldap/servers/plugins/replication/urp.c @@ -24,12 +24,17 @@ extern int slapi_log_urp; static int urp_add_resolve_parententry (Slapi_PBlock *pb, char *sessionid, Slapi_Entry *entry, Slapi_Entry *parententry, CSN *opcsn); -static int urp_annotate_dn (char *sessionid, const Slapi_Entry *entry, CSN *opcsn, const char *optype); +static int urp_annotate_dn (char *sessionid, const Slapi_Entry *entry, CSN *opcsn, const char *optype, char **conflict_dn); static int urp_naming_conflict_removal (Slapi_PBlock *pb, char *sessionid, CSN *opcsn, const char *optype); static int mod_namingconflict_attr (const char *uniqueid, const Slapi_DN *entrysdn, const Slapi_DN *conflictsdn, CSN *opcsn, const char *optype); +static int mod_objectclass_attr (const char *uniqueid, const Slapi_DN *entrysdn, const Slapi_DN *conflictsdn, CSN *opcsn, const char *optype); static int del_replconflict_attr (const Slapi_Entry *entry, CSN *opcsn, int opflags); static char *get_dn_plus_uniqueid(char *sessionid,const Slapi_DN *oldsdn,const char *uniqueid); static int is_suffix_entry (Slapi_PBlock *pb, Slapi_Entry *entry, Slapi_DN **parenddn); +static int is_conflict_entry(Slapi_Entry *entry); +static char * urp_get_valid_parent_nsuniqueid ( Slapi_DN *parentdn ); +static char * urp_get_conflict_dn_for_nsuniqueid ( char *nsuniqueid, Slapi_DN *parentdn ); +static int urp_rename_conflict_children(char *old_parent, const Slapi_DN *new_parent); /* * Return 0 for OK, -1 for Error. @@ -198,6 +203,20 @@ urp_add_operation( Slapi_PBlock *pb ) */ slapi_value_set_string (*vals, buf); } + + /* add the ldapsubentry objectclass if not present */ + slapi_entry_attr_find(addentry, "objectclass", &attr); + if (attr != NULL) { + struct berval bv; + bv.bv_val = "ldapsubentry"; + bv.bv_len = strlen(bv.bv_val); + if (slapi_attr_value_find(attr, &bv) != 0) { + Slapi_Value *new_v = slapi_value_new(); + slapi_value_init_berval(new_v, &bv); + slapi_attr_add_value(attr, new_v); + slapi_entry_set_flag(addentry, SLAPI_ENTRY_LDAPSUBENTRY); + } + } /* slapi_pblock_get(pb, SLAPI_ADD_TARGET, &dn); */ slapi_pblock_get(pb, SLAPI_ADD_TARGET_SDN, &sdn); slapi_sdn_free(&sdn); @@ -219,8 +238,9 @@ urp_add_operation( Slapi_PBlock *pb ) } else if(r>0) { + char *conflict_dn = NULL; /* Existing entry is a loser */ - if (!urp_annotate_dn(sessionid, existing_dn_entry, opcsn, "ADD")) + if (!urp_annotate_dn(sessionid, existing_dn_entry, opcsn, "ADD", &conflict_dn)) { op_result= LDAP_OPERATIONS_ERROR; slapi_pblock_set(pb, SLAPI_RESULT_CODE, &op_result); @@ -234,6 +254,7 @@ urp_add_operation( Slapi_PBlock *pb ) /* The backend add code should now search for the existing entry again. */ rc= slapi_setbit_int(rc,SLAPI_RTN_BIT_FETCH_EXISTING_DN_ENTRY); rc= slapi_setbit_int(rc,SLAPI_RTN_BIT_FETCH_PARENT_ENTRY); + slapi_pblock_set(pb, SLAPI_URP_NAMING_COLLISION_DN, conflict_dn); } PROFILE_POINT; /* Add Conflict; Entry Exists; Rename Existing Entry */ } @@ -457,7 +478,7 @@ urp_modrdn_operation( Slapi_PBlock *pb ) { /* The existing entry is a loser */ - int resolve = urp_annotate_dn (sessionid, existing_entry, opcsn, "MODRDN"); + int resolve = urp_annotate_dn (sessionid, existing_entry, opcsn, "MODRDN", NULL); if(!resolve) { op_result= LDAP_OPERATIONS_ERROR; @@ -578,7 +599,7 @@ bailout: /* * Return 0 for OK, -1 for Error */ -int +int urp_delete_operation( Slapi_PBlock *pb ) { const Slapi_Entry *deleteentry; @@ -646,6 +667,39 @@ urp_delete_operation( Slapi_PBlock *pb ) return rc; } +/* + * Return 0 for OK, -1 for Error + */ +int +urp_post_add_operation( Slapi_PBlock *pb ) +{ + char sessionid[REPL_SESSION_ID_SIZE]; + Slapi_Operation *op; + CSN *opcsn; + Slapi_Entry *addentry; + char *conflict_dn = NULL; + const char *valid_dn = NULL; + + slapi_pblock_get( pb, SLAPI_URP_NAMING_COLLISION_DN, &conflict_dn ); + if (conflict_dn == NULL) { + /* there was no conflicting entry, done */ + return 0; + } + + slapi_pblock_get( pb, SLAPI_OPERATION, &op); + get_repl_session_id (pb, sessionid, &opcsn); + slapi_log_err(SLAPI_LOG_ERR, sessionid, + "urp_post_add_operation - Entry %s is conflict entry, check for children\n", + conflict_dn); + slapi_pblock_get( pb, SLAPI_ADD_ENTRY, &addentry ); + valid_dn = slapi_entry_get_dn_const(addentry); + slapi_log_err(SLAPI_LOG_ERR, sessionid, + "urp_post_add_operation - Entry %s is valid entry, check for children\n", + valid_dn); + urp_rename_conflict_children(conflict_dn, slapi_entry_get_sdn_const(addentry)); + return 0; +} + int urp_post_modrdn_operation (Slapi_PBlock *pb) { CSN *opcsn; @@ -828,6 +882,44 @@ urp_fixup_rename_entry (const Slapi_Entry *entry, const char *newrdn, const char } int +urp_fixup_move_entry (const Slapi_Entry *entry, const Slapi_DN *newsuperior, int opflags) +{ + Slapi_PBlock *newpb; + /* Slapi_Operation *op; + CSN *opcsn;*/ + int op_result; + + newpb = slapi_pblock_new(); + + /* + * Must mark this operation as replicated, + * so that the frontend doesn't add extra attributes. + */ + slapi_rename_internal_set_pb_ext ( + newpb, + slapi_entry_get_sdn_const (entry), + slapi_entry_get_rdn_const(entry), /*NewRDN*/ + newsuperior, /*NewSuperior*/ + 0, /* !Delete Old RDNS */ + NULL, /*Controls*/ + slapi_entry_get_uniqueid (entry), /*uniqueid*/ + repl_get_plugin_identity(PLUGIN_MULTIMASTER_REPLICATION), + OP_FLAG_REPLICATED | OP_FLAG_REPL_FIXUP | opflags); + + /* set operation csn to the entry's dncsn */ + /* TBD check which csn to use + opcsn = (CSN *)entry_get_dncsn (entry); + slapi_pblock_get (newpb, SLAPI_OPERATION, &op); + operation_set_csn (op, opcsn); + TBD */ + slapi_modrdn_internal_pb(newpb); + slapi_pblock_get(newpb, SLAPI_PLUGIN_INTOP_RESULT, &op_result); + slapi_pblock_destroy(newpb); + + return op_result; +} + +int urp_fixup_delete_entry (const char *uniqueid, const char *dn, CSN *opcsn, int opflags) { Slapi_PBlock *newpb; @@ -955,6 +1047,21 @@ urp_add_resolve_parententry (Slapi_PBlock *pb, char *sessionid, Slapi_Entry *ent goto bailout; } + if(is_conflict_entry(parententry)) + { + /* The parent is a conflict entry + * move the new child below the valid entry + */ + char *valid_nsuniqueid = urp_get_valid_parent_nsuniqueid(parentdn); + if (valid_nsuniqueid) { + struct slapi_operation_parameters *op_params; + slapi_pblock_get( pb, SLAPI_OPERATION_PARAMETERS, &op_params ); + /* free it ? */ + op_params->p.p_add.parentuniqueid = valid_nsuniqueid; + } + goto bailout; + } + /* The parent is healthy */ /* Now we need to check that the parent has the correct DN */ if (slapi_sdn_isparent(slapi_entry_get_sdn(parententry), slapi_entry_get_sdn(entry))) @@ -1003,7 +1110,7 @@ bailout: * a new entry (the operation entry) see urp_add_operation. */ static int -urp_annotate_dn (char *sessionid, const Slapi_Entry *entry, CSN *opcsn, const char *optype) +urp_annotate_dn (char *sessionid, const Slapi_Entry *entry, CSN *opcsn, const char *optype, char **conflict_dn) { int rc = 0; /* Fail */ int op_result; @@ -1016,8 +1123,10 @@ urp_annotate_dn (char *sessionid, const Slapi_Entry *entry, CSN *opcsn, const ch basesdn = slapi_entry_get_sdn_const (entry); basedn = slapi_entry_get_dn_const (entry); newrdn = get_rdn_plus_uniqueid ( sessionid, basedn, uniqueid ); + if (conflict_dn) *conflict_dn = NULL; if(newrdn) { mod_namingconflict_attr (uniqueid, basesdn, basesdn, opcsn, optype); + mod_objectclass_attr (uniqueid, basesdn, basesdn, opcsn, optype); slapi_log_err (slapi_log_urp, sessionid, "urp_annotate_dn - %s --> %s\n", basedn, newrdn); op_result = urp_fixup_rename_entry ( entry, newrdn, NULL, 0 ); @@ -1027,6 +1136,9 @@ urp_annotate_dn (char *sessionid, const Slapi_Entry *entry, CSN *opcsn, const ch slapi_log_err (slapi_log_urp, sessionid, "urp_annotate_dn - Naming conflict %s. Renamed existing entry to %s\n", optype, newrdn); + if (conflict_dn) { + *conflict_dn = slapi_ch_smprintf("%s,%s",newrdn,slapi_dn_find_parent(basedn)); + } rc = 1; break; case LDAP_NO_SUCH_OBJECT: @@ -1064,6 +1176,132 @@ urp_annotate_dn (char *sessionid, const Slapi_Entry *entry, CSN *opcsn, const ch } return rc; } +static char * +urp_get_conflict_dn_for_nsuniqueid ( char *nsuniqueid, Slapi_DN *parentdn ) +{ + Slapi_PBlock *newpb = NULL; + Slapi_Entry **entries = NULL; + int op_result = LDAP_SUCCESS; + char *conflict_dn = NULL; + char *filter = NULL; + + filter = slapi_filter_sprintf("((&(objectclass=ldapsubentry)(nsuniqueid=%s))", nsuniqueid); + newpb = slapi_pblock_new(); + slapi_search_internal_set_pb(newpb, + slapi_sdn_get_dn(parentdn), + LDAP_SCOPE_ONELEVEL, + filter, + NULL, /* Attrs */ + 0, /* AttrOnly */ + NULL, /* Controls */ + NULL, /* UniqueID */ + repl_get_plugin_identity(PLUGIN_MULTIMASTER_REPLICATION), + 0); + slapi_search_internal_pb(newpb); + slapi_pblock_get(newpb, SLAPI_PLUGIN_INTOP_RESULT, &op_result); + slapi_pblock_get(newpb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &entries); + + if ( (op_result != LDAP_SUCCESS) || (entries == NULL) ) + { + /* Log a message */ + goto done; + } + + conflict_dn = slapi_entry_attr_get_charptr(entries[0], "nsuniqueid"); +done: + slapi_free_search_results_internal(newpb); + slapi_pblock_destroy(newpb); + newpb = NULL; + if (filter) { + PR_smprintf_free(filter); + } + + return conflict_dn; + +} +static char * +urp_get_valid_parent_nsuniqueid ( Slapi_DN *parentdn ) +{ + Slapi_PBlock *newpb = NULL; + Slapi_Entry **entries = NULL; + int op_result = LDAP_SUCCESS; + char *nsuid = NULL; + + newpb = slapi_pblock_new(); + slapi_search_internal_set_pb(newpb, + slapi_sdn_get_dn(parentdn), + LDAP_SCOPE_BASE, + "objectclass=*", + NULL, /* Attrs */ + 0, /* AttrOnly */ + NULL, /* Controls */ + NULL, /* UniqueID */ + repl_get_plugin_identity(PLUGIN_MULTIMASTER_REPLICATION), + 0); + slapi_search_internal_pb(newpb); + slapi_pblock_get(newpb, SLAPI_PLUGIN_INTOP_RESULT, &op_result); + slapi_pblock_get(newpb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &entries); + + if ( (op_result != LDAP_SUCCESS) || (entries == NULL) ) + { + /* Log a message */ + goto done; + } + + nsuid = slapi_entry_attr_get_charptr(entries[0], "nsuniqueid"); +done: + slapi_free_search_results_internal(newpb); + slapi_pblock_destroy(newpb); + newpb = NULL; + + return nsuid; +} + +static int +urp_rename_conflict_children(char *old_parent, const Slapi_DN *new_parent) +{ + Slapi_PBlock *newpb = NULL; + Slapi_Entry **entries = NULL; + int op_result = LDAP_SUCCESS; + int i; + + newpb = slapi_pblock_new(); + slapi_search_internal_set_pb(newpb, + old_parent, + LDAP_SCOPE_ONELEVEL, + "objectclass=*", + NULL, /* Attrs */ + 0, /* AttrOnly */ + NULL, /* Controls */ + NULL, /* UniqueID */ + repl_get_plugin_identity(PLUGIN_MULTIMASTER_REPLICATION), + 0); + slapi_search_internal_pb(newpb); + slapi_pblock_get(newpb, SLAPI_PLUGIN_INTOP_RESULT, &op_result); + slapi_pblock_get(newpb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &entries); + + if ( (op_result != LDAP_SUCCESS) || (entries == NULL) ) + { + /* Log a message */ + goto done; + } + for (i = 0; NULL != entries[i]; i++) { + slapi_log_err(SLAPI_LOG_ERR, "session test", + "urp_rename_conflict children - Renaming: %s\n", + slapi_entry_get_dn_const(entries[i])); + op_result = urp_fixup_move_entry(entries[i],new_parent,0); + slapi_log_err(SLAPI_LOG_ERR, "session test", + "urp_rename_conflict children - Renam: %s, Result: %d\n", + slapi_entry_get_dn_const(entries[i]), op_result); + } + +done: + slapi_free_search_results_internal(newpb); + slapi_pblock_destroy(newpb); + newpb = NULL; + + return op_result; +} /* * An URP Naming Collision helper function. Retrieves a list of entries @@ -1314,6 +1552,19 @@ bail: } static int +is_conflict_entry(Slapi_Entry *entry) +{ + int is_conflict = 0; + char *replconflict = slapi_entry_attr_get_charptr(entry,ATTR_NSDS5_REPLCONFLICT ); + if (replconflict) { + is_conflict = 1; + slapi_ch_free_string(&replconflict); + } + + return is_conflict; +} + +static int is_suffix_entry ( Slapi_PBlock *pb, Slapi_Entry *entry, Slapi_DN **parentdn ) { return is_suffix_dn ( pb, slapi_entry_get_sdn(entry), parentdn ); @@ -1379,6 +1630,25 @@ mod_namingconflict_attr (const char *uniqueid, const Slapi_DN *entrysdn, } static int +mod_objectclass_attr (const char *uniqueid, const Slapi_DN *entrysdn, + const Slapi_DN *conflictsdn, CSN *opcsn, + const char *optype) +{ + Slapi_Mods smods; + int op_result; + + slapi_mods_init (&smods, 2); + slapi_mods_add (&smods, LDAP_MOD_ADD, "objectclass", strlen("ldapsubentry"),"ldapsubentry"); + op_result = urp_fixup_modify_entry (uniqueid, entrysdn, opcsn, &smods, 0); + slapi_mods_done (&smods); + if (op_result == LDAP_TYPE_OR_VALUE_EXISTS) { + /* the objectclass was already present */ + op_result = LDAP_SUCCESS; + } + return op_result; +} + +static int del_replconflict_attr (const Slapi_Entry *entry, CSN *opcsn, int opflags) { Slapi_Attr *attr; diff --git a/ldap/servers/plugins/replication/urp.h b/ldap/servers/plugins/replication/urp.h index 0d1cc05..7be88af 100644 --- a/ldap/servers/plugins/replication/urp.h +++ b/ldap/servers/plugins/replication/urp.h @@ -23,6 +23,7 @@ int urp_modify_operation( Slapi_PBlock *pb ); int urp_add_operation( Slapi_PBlock *pb ); int urp_delete_operation( Slapi_PBlock *pb ); +int urp_post_add_operation( Slapi_PBlock *pb ); int urp_post_delete_operation( Slapi_PBlock *pb ); int urp_modrdn_operation( Slapi_PBlock *pb ); int urp_post_modrdn_operation( Slapi_PBlock *pb ); @@ -33,6 +34,7 @@ int urp_fixup_add_entry (Slapi_Entry *e, const char *target_uniqueid, const char int urp_fixup_delete_entry (const char *uniqueid, const char *dn, CSN *opcsn, int opflags); int urp_fixup_rename_entry (const Slapi_Entry *entry, const char *newrdn, const char *parentuniqueid, int opflags); int urp_fixup_modify_entry (const char *uniqueid, const Slapi_DN *sdn, CSN *opcsn, Slapi_Mods *smods, int opflags); +int urp_fixup_move_entry (const Slapi_Entry *entry, const Slapi_DN *newsuperior, int opflags); int is_suffix_dn (Slapi_PBlock *pb, const Slapi_DN *dn, Slapi_DN **parenddn); int is_suffix_dn_ext (Slapi_PBlock *pb, const Slapi_DN *dn, Slapi_DN **parenddn, int is_tombstone); -- 2.4.3