--- modules/univention/s4connector/s4/__init__.py (Revision 70207) +++ modules/univention/s4connector/s4/__init__.py (Arbeitskopie) @@ -2422,6 +2422,35 @@ ud.debug(ud.LDAP, ud.ALL, "sync_from_ucs: addlist: %s" % addlist) try: self.lo_s4.lo.add_ext_s(compatible_modstring(object['dn']), compatible_addlist(addlist), serverctrls=ctrls) #FIXME encoding + except ldap.ALREADY_EXISTS as ex: + sAMAccountName_attr_value = object['attributes'].get('sAMAccountName')[0] + objectSid_attr_value = object['attributes'].get('objectSid')[0] + objectSid = decode_sid(objectSid_attr_value) + if not (sAMAccountName_attr_value and objectSid): + raise ## unknown situation + filter_s4 = '(&(sAMAccountName=%s)(objectSid=%s)(isDeleted=TRUE))' % (sAMAccountName_attr_value, objectSid) + ud.debug(ud.LDAP, ud.WARN, "sync_from_ucs: Error during add, searching for conflicting deleted object in S4. Filter: %s" % filter_s4) + result = self.lo_s4.lo.search_ext_s(self.lo_s4.base, ldap.SCOPE_SUBTREE, filter_s4, ['objectClass', 'objectCategory', 'isDeleted', 'isRecycled', 'lastKnownParent'], serverctrls=[self.ctrl_show_deleted, LDAPControl(LDB_CONTROL_DOMAIN_SCOPE_OID, criticality=0)]) + if not result or len(result)>1: ## the latter would indicate corruption + ud.debug(ud.LDAP, ud.WARN,"sync_from_ucs: No conflicting object found.") + raise ## unknown situation + (deleted_object_dn, deleted_object) = result[0] + ud.debug(ud.LDAP, ud.WARN, "sync_from_ucs: Reanimating deleted object in S4: %s" % deleted_object_dn) + ## Currently tombstone_reanimate.c and tests/python/tombstone_reanimation.py + ## which implement https://msdn.microsoft.com/en-us/library/cc223467.aspx (MS-ADTS 3.1.1.5.3.7) + ## are disabled in Samba. Workaround: + idx = deleted_object_dn.find('\x0ADEL:') + reanimate_modlist = [(ldap.MOD_DELETE, 'isDeleted', 'TRUE')] + reanimate_modlist.append((ldap.MOD_DELETE, 'lastKnownParent', deleted_object['lastKnownParent'][0])) + reanimate_modlist.append((ldap.MOD_DELETE, 'isRecycled', 'TRUE')) + if not deleted_object.get('objectCategory'): + top_most_structural_objectclass = deleted_object['objectClass'][-1] + result = self.lo_s4.lo.search_ext_s("CN=Schema,CN=Configuration,%s" % self.lo_s4.base, ldap.SCOPE_SUBTREE, 'lDAPDisplayName=%s' % top_most_structural_objectclass, ['defaultObjectCategory']) + reanimate_modlist.append((ldap.MOD_ADD, 'objectCategory', result[0][1]['defaultObjectCategory'][0])) + self.lo_s4.lo.modify_ext_s(compatible_modstring(deleted_object_dn), compatible_modlist(reanimate_modlist), serverctrls=[self.ctrl_show_deleted,]) + self.lo_s4.lo.rename_s(compatible_modstring(deleted_object_dn), deleted_object_dn[:idx], newsuperior=deleted_object['lastKnownParent'], delold=1) + ## and retry + return self.sync_from_ucs(property_type, object, pre_mapped_ucs_dn, old_dn, old_ucs_object, new_ucs_object) except: ud.debug(ud.LDAP, ud.ERROR, "sync_from_ucs: traceback during add object: %s" % object['dn']) ud.debug(ud.LDAP, ud.ERROR, "sync_from_ucs: traceback due to addlist: %s" % addlist)