self.remove_all_unknown_attributes = False
self.remove_all_empty_attributes = False
self.fix_all_normalisation = False
+ self.fix_all_duplicates = False
self.fix_all_DN_GUIDs = False
self.fix_all_binary_dn = False
self.remove_all_deleted_DN_links = False
validate=False):
self.report("Normalised attribute %s" % attrname)
+ def err_duplicate_values(self, dn, attrname, dup_values, values):
+ '''fix attribute normalisation errors'''
+ self.report("ERROR: Duplicate values for attribute '%s' in '%s'" % (attrname, dn))
+ self.report("Values contain a duplicate: [%s]/[%s]!" % (','.join(dup_values), ','.join(values)))
+ if not self.confirm_all("Fix duplicates for '%s' from '%s'?" % (attrname, dn), 'fix_all_duplicates'):
+ self.report("Not fixing attribute '%s'" % attrname)
+ return
+
+ m = ldb.Message()
+ m.dn = dn
+ m[attrname] = ldb.MessageElement(values, ldb.FLAG_MOD_REPLACE, attrname)
+
+ if self.do_modify(m, ["relax:0", "show_recycled:1"],
+ "Failed to remove duplicate value on attribute %s" % attrname,
+ validate=False):
+ self.report("Removed duplicate value on attribute %s" % attrname)
+
def is_deleted_objects_dn(self, dsdb_dn):
'''see if a dsdb_Dn is the special Deleted Objects DN'''
return dsdb_dn.prefix == "B:32:%s:" % dsdb.DS_GUID_DELETED_OBJECTS_CONTAINER
# it's some form of DN, do specialised checking on those
error_count += self.check_dn(obj, attrname, syntax_oid)
+ values = set()
# check for incorrectly normalised attributes
for val in obj[attrname]:
+ values.add(str(val))
+
normalised = self.samdb.dsdb_normalise_attributes(self.samdb_schema, attrname, [val])
if len(normalised) != 1 or normalised[0] != val:
self.err_normalise_mismatch(dn, attrname, obj[attrname])
error_count += 1
break
+ if len(obj[attrname]) != len(values):
+ self.err_duplicate_values(dn, attrname, obj[attrname], list(values))
+ error_count += 1
+ break
+
if str(attrname).lower() == "instancetype":
calculated_instancetype = self.calculate_instancetype(dn)
if len(obj["instanceType"]) != 1 or obj["instanceType"][0] != str(calculated_instancetype):
return 0
}
+check_forced_duplicate_values() {
+ if [ x$RELEASE = x"release-4-1-0rc3" ]; then
+ ldif=$release_dir/forced-duplicate-value-for-dbcheck.ldif
+ TZ=UTC $ldbmodify -H tdb://$PREFIX_ABS/${RELEASE}/private/sam.ldb.d/DC%3DRELEASE-4-1-0RC3,DC%3DSAMBA,DC%3DCORP.ldb $ldif
+ if [ "$?" != "0" ]; then
+ return 1
+ fi
+ else
+ return 0
+ fi
+}
+
+# This should 'fail', because it returns the number of modified records
+dbcheck_after_dup() {
+ if [ x$RELEASE = x"release-4-1-0rc3" ]; then
+ $PYTHON $BINDIR/samba-tool dbcheck --cross-ncs --fix --yes -H tdb://$PREFIX_ABS/${RELEASE}/private/sam.ldb $@
+ else
+ return 1
+ fi
+}
+
+check_expected_after_dup_values() {
+ if [ x$RELEASE = x"release-4-1-0rc3" ]; then
+ tmpldif=$PREFIX_ABS/$RELEASE/expected-otherphone-after-dbcheck.ldif.tmp
+ TZ=UTC $ldbsearch -H tdb://$PREFIX_ABS/${RELEASE}/private/sam.ldb cn=administrator -s base -b cn=administrator,cn=users,DC=release-4-1-0rc3,DC=samba,DC=corp otherHomePhone --sorted --show-binary | sort > $tmpldif
+ diff $tmpldif $release_dir/expected-otherphone-after-dbcheck.ldif
+ if [ "$?" != "0" ]; then
+ return 1
+ fi
+ fi
+ return 0
+}
+
# But having fixed it all up, this should pass
dbcheck_clean() {
$PYTHON $BINDIR/samba-tool dbcheck --cross-ncs -H tdb://$PREFIX_ABS/${RELEASE}/private/sam.ldb $@
testit "check_expected_before_values" check_expected_before_values
testit_expect_failure "dbcheck" dbcheck
testit "check_expected_after_values" check_expected_after_values
+ testit "check_forced_duplicate_values" check_forced_duplicate_values
+ testit_expect_failure "dbcheck_after_dup" dbcheck_after_dup
+ testit "check_expected_after_dup_values" check_expected_after_dup_values
testit "dbcheck_clean" dbcheck_clean
testit_expect_failure "dbcheck_acl_reset" dbcheck_acl_reset
testit "dbcheck_acl_reset_clean" dbcheck_acl_reset_clean