in TestSuites/ADFamily/src/Adapter/MS-ADTS-LDAP/AD_LDAPModelAdapter.cs [1667:2289]
public void DeleteOperation(
string delObjDn,
RightsOnParentObjects parentRights,
RightsOnObjects objectRights,
string control,
ADImplementations service,
ServerVersion dcLevel,
bool isRODC,
out ConstrOnDelOpErr errorStatus)
{
#region Variables
SecurityIdentifier sidOftheNewObject = null;
Guid guidOfNewObject = Guid.Empty;
bool isEntryExist = false;
string delObjRdnType = string.Empty;
string delObjRdnValue = string.Empty;
int delObjInstanceType = 0;
SecurityIdentifier delObjOldSid = null;
Guid delObjOldGuid = Guid.Empty;
int searchFlags = 0;
string objDelTombStoneDN = string.Empty;
ICollection<AdtsSearchResultEntryPacket> searchResponse;
string[] searchAttrVals = null;
SearchResult tombStoneSearchResultEntry = null;
bool isSpecialDn = false;
#endregion
#region Connect and Bind
if (isConnected == false)
{
if (isRODC)
{
SetConnectAndBind(service, RODCNetbiosName);
}
else
{
SetConnectAndBind(service, PDCNetbiosName);
}
}
#endregion
#region Search for Attribute Schema that has fPRESERVEONDELETE search flag contained
//Searching for those attributes whose search flags is set : fPRESERVEONDELETE"
// [MS-ADTS] section 2.2.9 Search Flags
// PR (fPRESERVEONDELETE, 0x00000008): Specifies that the attribute MUST be preserved on objects after deletion
// of the object (that is, when the object is transformed to a tombstone (2), deleted-object, or recycled-object).
// This flag is ignored on link attributes, objectCategory, and sAMAccountType.
result = adLdapClient.SearchObject(
schemaNC,
System.DirectoryServices.Protocols.SearchScope.Subtree,
"(searchFlags=8)",
new string[] { "distinguishedName", "searchFlags" },
null,
out searchResponse,
isWindows);
if (result.ToLower().Contains("success")
&& searchResponse != null)
{
Site.Log.Add(LogEntryKind.Debug, string.Format("The attribute schemas that have fPRESERVEONDELETE search flag on are:"));
foreach (AdtsSearchResultEntryPacket entrypacket in searchResponse)
{
searchAttrVals = adLdapClient.GetAttributeValuesInString(entrypacket, "distinguishedName");
Site.Log.Add(LogEntryKind.Debug, string.Format("distinguishedName: {0}", searchAttrVals[0]));
searchAttrVals = adLdapClient.GetAttributeValuesInString(entrypacket, "searchFlags");
Site.Log.Add(LogEntryKind.Debug, string.Format("searchFlags: {0}", searchAttrVals[0]));
}
}
#endregion
#region Finalize DN of the object to be deleted
delObjDn = delObjDn.Replace("DC=adts88", rootDomainNC);
delObjDn = delObjDn.Replace("WIN-6IEHBFZ8AMV", currentWorkingDC.NetbiosName);
delObjDn = delObjDn.Replace("ADTS88", currentWorkingDC.Domain.NetbiosName);
delObjDn = delObjDn.Replace("520ec681-1336-471b-93af-c27b780083d9", forestDNSZonesObjCN);
// distinguishedName: CN=TestGroup,CN=DirectoryUpdates,CN=Configuration,CN={368E6FB2-DBCB-41A1-B65B-18FAC4B5516E}
// => distinguishedName: CN=TestGroup,(default NC)
delObjDn = delObjDn.Replace("CN=Configuration,CN={368E6FB2-DBCB-41A1-B65B-18FAC4B5516E}",
configurationNC);
// assign RDN type and value "CN=XXX" or "DC=XXX"
delObjRdnType = delObjDn.Split(',')[0].Split('=')[0].Trim();
delObjRdnValue = delObjDn.Split(',')[0].Split('=')[1].Trim();
if (delObjDn.Equals(rootDomainNC)
|| delObjDn.Equals("CN=Users," + rootDomainNC)
|| delObjDn.Equals(string.Format("CN=NTDS Settings,CN={0},CN=Servers,CN=Default-First-Site-Name,CN=Sites,{1}", currentWorkingDC.NetbiosName, configurationNC))
|| delObjDn.Equals(string.Format("CN={0},CN=Servers,CN=Default-First-Site-Name,CN=Sites,{1}", currentWorkingDC.NetbiosName, configurationNC))
|| delObjDn.Equals(string.Format("CN=RID Set,CN={0},OU=Domain Controllers,{1}", currentWorkingDC.NetbiosName, rootDomainNC))
|| delObjDn.Equals(string.Format("CN={0},OU=Domain Controllers,{1}", currentWorkingDC.NetbiosName, rootDomainNC))
|| delObjRdnValue.Equals(currentWorkingDC.NetbiosName)
|| delObjRdnValue.Equals("Enterprise Configuration")
|| delObjRdnValue.Equals("Enterprise Schema"))
{
// special DN should all return UnSpecifiedError
isSpecialDn = true;
}
#endregion
#region Search if object to be deleted exists in regular state
result = adLdapClient.SearchObject(
delObjDn,
System.DirectoryServices.Protocols.SearchScope.Base,
"(objectClass=*)",
new string[] { "objectSid", "objectGUID", "instanceType", "groupType", "sAMAccountName" },
null,
out searchResponse,
isWindows);
if (result.ToLower().Contains("success")
&& searchResponse != null)
{
Site.Log.Add(LogEntryKind.Debug, string.Format("The object to be deleted {0} exists in regular state.", delObjDn));
isEntryExist = true;
foreach (AdtsSearchResultEntryPacket entrypacket in searchResponse)
{
searchAttrVals = adLdapClient.GetAttributeValuesInString(entrypacket, "objectSid");
if (searchAttrVals != null)
{
delObjOldSid = new SecurityIdentifier(Encoding.ASCII.GetBytes(searchAttrVals[0]), 0);
Site.Log.Add(LogEntryKind.Debug, string.Format("objectSid: {0}", delObjOldSid.Value.ToString()));
}
else
{
Site.Log.Add(LogEntryKind.Debug, "objectSid attribute not found on object.");
}
searchAttrVals = adLdapClient.GetAttributeValuesInString(entrypacket, "objectGUID");
if (searchAttrVals != null)
{
delObjOldGuid = new Guid(Encoding.ASCII.GetBytes(searchAttrVals[0]));
if (!guidHashTable.ContainsKey(delObjDn))
{
guidHashTable.Add(delObjDn, delObjOldGuid);
}
Site.Log.Add(LogEntryKind.Debug, string.Format("objectGUID: {0}", delObjOldGuid.ToString()));
}
else
{
Site.Log.Add(LogEntryKind.Debug, "objectGUID attribute not found on object.");
}
searchAttrVals = adLdapClient.GetAttributeValuesInString(entrypacket, "instanceType");
if (searchAttrVals != null)
{
delObjInstanceType = int.Parse(searchAttrVals[0], CultureInfo.InvariantCulture);
Site.Log.Add(LogEntryKind.Debug, string.Format("instanceType: {0}", searchAttrVals[0]));
}
else
{
Site.Log.Add(LogEntryKind.Debug, "instanceType attribute not found on object.");
}
searchAttrVals = adLdapClient.GetAttributeValuesInString(entrypacket, "groupType");
if (searchAttrVals != null)
{
Site.Log.Add(LogEntryKind.Debug, string.Format("groupType: {0}", searchAttrVals[0]));
}
else
{
Site.Log.Add(LogEntryKind.Debug, "groupType attribute not found on object.");
}
searchAttrVals = adLdapClient.GetAttributeValuesInString(entrypacket, "sAMAccountName");
if (searchAttrVals != null)
{
Site.Log.Add(LogEntryKind.Debug, string.Format("sAMAccountName: {0}", searchAttrVals[0]));
}
else
{
Site.Log.Add(LogEntryKind.Debug, "sAMAccountName attribute not found on object.");
}
}
}
else
{
Site.Log.Add(LogEntryKind.Debug, string.Format("The object to be deleted {0} is not in regular state.", delObjDn));
isEntryExist = false;
}
#endregion
#region If object to be deleted is ForestDnsZones and it does not exist => add it
//Check if the object: DC=ForestDnsZones exists or not, if not, add it to AD to make sure the object exist
if (!isEntryExist
&& (delObjRdnValue == forestDNSZonesObjCN))
{
AddForestDnsZones(forestDNSZonesObjCN);
isEntryExist = true;
}
#endregion
#region Search if the object to be deleted is in tombstone
if (!isEntryExist)
{
tombStoneSearchResultEntry = Utilities.GetDeletedObject(guidHashTable[delObjDn].ToString(), defaultNC, currentWorkingDC.FQDN, currentPort);
if (tombStoneSearchResultEntry != null)
{
objDelTombStoneDN = tombStoneSearchResultEntry.Properties["distinguishedName"][0].ToString();
}
}
#endregion
#region Delete the tombstone-object
if (!isEntryExist
&& !(string.IsNullOrEmpty(objDelTombStoneDN)))
{
result = adLdapClient.DeleteObject(
objDelTombStoneDN,
null,
isWindows);
Site.Log.Add(LogEntryKind.Debug, string.Format("Delete operation on tombstone object {0} result: {1}", objDelTombStoneDN, result));
if (service == ADImplementations.AD_DS)
{
#region Verify Deleted Object: Distinguished Name
VerifyDeletedObjectsDN(
objDelTombStoneDN,
delObjRdnValue,
new Guid((byte[])tombStoneSearchResultEntry.Properties["objectGUID"][0]).ToString());
#endregion
#region Verify Deleted Object: LastKnownParent and LastKnownRDN
string attrLastKnownParent = string.Empty;
string lastKnownRDN = string.Empty;
if (tombStoneSearchResultEntry.Properties["lastKnownParent"].Count != 0)
{
foreach (string propertyValue in tombStoneSearchResultEntry.Properties["lastKnownParent"])
{
if (propertyValue.Equals("CN=Users," + rootDomainNC, StringComparison.InvariantCultureIgnoreCase)
|| propertyValue.Equals("CN=Computers," + rootDomainNC, StringComparison.InvariantCultureIgnoreCase))
{
attrLastKnownParent = propertyValue;
break;
}
}
}
if (tombStoneSearchResultEntry.Properties["msDS-LastKnownRDN"].Count != 0)
{
foreach (string propertyValue in tombStoneSearchResultEntry.Properties["msDS-LastKnownRDN"])
{
if (propertyValue.Equals(delObjRdnValue, StringComparison.InvariantCultureIgnoreCase))
{
lastKnownRDN = propertyValue;
break;
}
}
}
if (!string.IsNullOrEmpty(attrLastKnownParent))
{
VerifyDeletedObjectsRDNAndParent(delObjDn, delObjRdnValue, attrLastKnownParent, lastKnownRDN);
}
else
{
Site.Log.Add(LogEntryKind.Debug,
string.Format("Attribute LastKnownParent is not found in tombStoneResult for {0}.", delObjDn));
if (tombStoneSearchResultEntry == null)
{
Site.Log.Add(LogEntryKind.Debug, string.Format("TombStoneResultEntry is null"));
}
else
{
Site.Log.Add(LogEntryKind.Debug, string.Format("TombStoneResultEntry is not null: "));
foreach (string name in tombStoneSearchResultEntry.Properties.PropertyNames)
{
Site.Log.Add(LogEntryKind.Debug, string.Format("Attribute name: {0}", name));
Site.Log.Add(LogEntryKind.Debug, string.Format("Attribute value:"));
foreach (object value in tombStoneSearchResultEntry.Properties[name])
{
Site.Log.Add(LogEntryKind.Debug, string.Format("{0};", value.ToString()));
}
}
}
}
#endregion
#region Verify Deleted Object: isDeleted and isRecycled
string isDeleted = string.Empty;
string isRecycled = string.Empty;
if (tombStoneSearchResultEntry.Properties["isDeleted"] != null
&& tombStoneSearchResultEntry.Properties["isDeleted"].Count > 0)
{
isDeleted = ((bool)tombStoneSearchResultEntry.Properties["isDeleted"][0]).ToString();
}
if (tombStoneSearchResultEntry.Properties["isRecycled"] != null
&& tombStoneSearchResultEntry.Properties["isRecycled"].Count > 0)
{
isRecycled = ((bool)tombStoneSearchResultEntry.Properties["isRecycled"][0]).ToString();
}
VerifyDeletedObject(isDeleted, isRecycled);
#endregion
#region Verify Deleted Object: Other non-empty attributes
List<string> attributeNotEmpty = new List<string>();
foreach (string propertyName in tombStoneSearchResultEntry.Properties.PropertyNames)
{
if (tombStoneSearchResultEntry.Properties[propertyName].Count != 0)
{
attributeNotEmpty.Add(propertyName.ToLower(CultureInfo.InvariantCulture));
}
}
VerifyTombstone(attributeNotEmpty, service);
if (Utilities.IsOptionalFeatureEnabled(
forestScopePartialDN + ',' + configurationNC,
recycleBinPartialDN + ',' + configurationNC))
{
VerifyDeletedObjects(attributeNotEmpty);
}
#endregion
}
}
#endregion
#region Deleted the deleted-object
if (!isEntryExist
&& (delObjDn.Equals(testUser0DNForDs, StringComparison.InvariantCultureIgnoreCase)
|| delObjDn.Equals(testUser1DNForDs, StringComparison.InvariantCultureIgnoreCase)
|| delObjDn.Equals(testUser4DNForDs, StringComparison.InvariantCultureIgnoreCase)
|| delObjDn.Equals(testUserGroup0DNForDs, StringComparison.InvariantCultureIgnoreCase)))
{
string guid = guidHashTable[delObjDn].ToString();
string deletedBaseDN = "CN=Deleted Objects," + rootDomainNC;
string objCN = delObjDn.Split(',')[0].Trim().ToString();
string deletedObjDN = objCN + "\\0ADEL:" + guid + "," + deletedBaseDN;
// LDAP_SERVER_SHOW_DELETED_OID "1.2.840.113556.1.4.417"
// LDAP_SERVER_SHOW_RECYCLED_OID "1.2.840.113556.1.4.2064"
DirectoryControl[] controls = new DirectoryControl[]{
new DirectoryControl(ExtendedControl.LDAP_SERVER_SHOW_DELETED_OID, null, true, true),
new DirectoryControl(ExtendedControl.LDAP_SERVER_SHOW_RECYCLED_OID, null, true, true)
};
result = adLdapClient.DeleteObject(
deletedObjDN,
controls,
isWindows);
if (result.ToLower().Contains("success"))
{
string isDelete = string.Empty;
string isRecycle = string.Empty;
List<string> attributeNotEmpty = new List<string>();
Microsoft.Protocols.TestTools.StackSdk.ActiveDirectory.Adts.Asn1CodecV3.SearchResultEntry resultEntry = SearchDeletedObject(
delObjDn,
ExtendedControl.LDAP_SERVER_SHOW_DELETED_OID + ";" + ExtendedControl.LDAP_SERVER_SHOW_RECYCLED_OID);
PartialAttributeList attributeNames = resultEntry.attributes;
foreach (PartialAttributeList_element attribute in attributeNames.Elements)
{
string attributeString = Encoding.ASCII.GetString(attribute.type.ByteArrayValue);
AttributeValue[] attributeValList = attribute.vals.Elements;
foreach (AttributeValue attributeVal in attributeValList)
{
string attributeValue = Encoding.ASCII.GetString(attributeVal.ByteArrayValue);
if (attributeString.Equals("isDeleted", StringComparison.OrdinalIgnoreCase))
{
isDelete = bool.Parse(attributeValue).ToString();
}
if (attributeString.Equals("isRecycled", StringComparison.OrdinalIgnoreCase))
{
isRecycle = bool.Parse(attributeValue).ToString();
}
attributeNotEmpty.Add(attributeString.ToLower(CultureInfo.InvariantCulture));
}
}
VerifyDeletedObject(isDelete, isRecycle);
if (Utilities.IsOptionalFeatureEnabled(forestScopePartialDN + ',' + configurationNC, recycleBinPartialDN + ',' + configurationNC))
{
if (attributeNotEmpty.Contains("isRecycled".ToLower(CultureInfo.InvariantCulture)))
{
VerifyRecycledObjects(attributeNotEmpty, service);
}
}
}
}
#endregion
#region Delete the regular object
else
{
result = adLdapClient.DeleteObject(delObjDn, null, isWindows);
}
if (!isWindows)
{
#region Switch ErrorStatus Non-Windows
switch (result)
{
case "Referral":
errorStatus = ConstrOnDelOpErr.Referral_UnKnownError;
break;
case "UnwillingToPerform":
errorStatus = ConstrOnDelOpErr.UnwillingToPerform_UnKnownError;
break;
case "NotAllowedOnNonLeaf":
errorStatus = ConstrOnDelOpErr.NotAllowedOnNonLeaf_UnKnownError;
break;
case "Success":
#region Searching for Deleted Object in Tombstones
tombStoneSearchResultEntry = Utilities.GetDeletedObject(guidHashTable[delObjDn].ToString(), defaultNC, currentWorkingDC.FQDN, currentPort);
if (tombStoneSearchResultEntry != null)
{
List<string> attributesAreNotNull = new List<string>();
foreach (string key in tombStoneSearchResultEntry.Properties.PropertyNames)
{
attributesAreNotNull.Add(key.ToLower(CultureInfo.InvariantCulture));
foreach (object value in tombStoneSearchResultEntry.Properties[key])
{
if (key.ToLower(CultureInfo.InvariantCulture) == "isdeleted")
{
Site.CaptureRequirementIfAreEqual<string>(value.ToString().ToLower(CultureInfo.InvariantCulture), "true", 889, "During the Delete operation, the isDeleted attribute is set to true on tombstones.");
Site.CaptureRequirementIfAreEqual<string>(value.ToString().ToLower(CultureInfo.InvariantCulture), "true", 924, "During the delete operation, the isDeleted attribute is set to true.");
}
if (key.ToLower(CultureInfo.InvariantCulture) == "distinguishedname")
{
//for distinguished Name attribute fPRESERVEONDELETE is set by default
Site.CaptureRequirementIfAreEqual<string>(value.ToString().Substring(0, value.ToString().IndexOf('=')), delObjRdnType, 920, "During the delete operation, the attribute that equals the rdnType of the object is retained.");
searchFlags = IntegerSymbols.ParseSystemFlagsValue("searchflags", "fPRESERVEONDELETE");
Type type = IntegerSymbols.GetSymbolEnumType("searchflags");
result = IntegerSymbols.UnparseUInt32Enum(type, (uint)searchFlags);
Site.CaptureRequirementIfAreEqual<string>(result, "fPRESERVEONDELETE", 921, "During the delete operation, any attribute that has fPRESERVEONDELETE flag set in its searchFlags is retained, except objectCategory and sAMAccountType, which are always removed, regardless of the value of their searchFlags.");
string[] DeletedObjectsContainer = value.ToString().Split(new char[] { ',' });
Site.CaptureRequirementIfAreEqual<string>(DeletedObjectsContainer[1].ToString(), "CN=Deleted Objects", 892, "During the Delete operation, the tombstone remains in the database for at least the tombstone lifetime time interval after its deletion but the Deleted Objects container(which is considered a tombstone if the Recycle Bin optional feature is not enabled) always remains available.");
}
if (key.ToLower(CultureInfo.InvariantCulture) == "objectsid")
{
if (value is byte[])
{
byte[] byteVal = value as byte[];
sidOftheNewObject = new SecurityIdentifier(byteVal, 0);
}
Site.CaptureRequirementIfAreEqual(delObjOldSid, sidOftheNewObject, 890, "During the Delete operation, the tombstone retains the objectGUID and objectSid (if any) attributes of the original object.");
}
if (key.ToLower(CultureInfo.InvariantCulture) == "objectguid")
{
if (value is byte[])
{
byte[] byteVal = value as byte[];
guidOfNewObject = new Guid(byteVal);
Site.CaptureRequirementIfAreEqual(delObjOldGuid, guidOfNewObject, 890, "During the Delete operation, the tombstone retains the objectGUID and objectSid (if any) attributes of the original object.");
}
}
if (key.ToLower(CultureInfo.InvariantCulture) == "instancetype")
{
searchFlags = IntegerSymbols.ParseSystemFlagsValue("searchflags", "fPRESERVEONDELETE");
Type type = IntegerSymbols.GetSymbolEnumType("searchflags");
result = IntegerSymbols.UnparseUInt32Enum(type, (uint)searchFlags);
Site.CaptureRequirementIfAreEqual<string>(result, "fPRESERVEONDELETE", 921, "During the delete operation, any attribute that has fPRESERVEONDELETE flag set in its searchFlags is retained, except objectCategory and sAMAccountType, which are always removed, regardless of the value of their searchFlags.");
Site.CaptureRequirementIfAreEqual<int>(delObjInstanceType, int.Parse(value.ToString(), CultureInfo.InvariantCulture), 916, "During the delete operation, all attribute values are removed from the object except instanceType, objectGUID, objectSid, distinguishedName.");
}
}
}
VerifyDeletedObjectRetainedAttribute(attributesAreNotNull);
}
else
{
Site.Log.Add(LogEntryKind.Debug, "No object exists");
}
#endregion
errorStatus = ConstrOnDelOpErr.success;
break;
default:
errorStatus = ConstrOnDelOpErr.UnSpecifiedError;
break;
}
#endregion
}
else
{
#region Switch ErrorStatus Windows
switch (result)
{
case "Referral_ERROR_DS_REFERRAL":
errorStatus = ConstrOnDelOpErr.Referral_ERROR_DS_REFERRAL;
break;
case "UnwillingToPerform_ERROR_DS_CANT_DELETE":
errorStatus = ConstrOnDelOpErr.UnwillingToPerform_ERROR_DS_CANT_DELETE;
break;
case "NotAllowedOnNonLeaf_ERROR_DS_CHILDREN_EXIST":
errorStatus = ConstrOnDelOpErr.NotAllowedOnNonLeaf_ERROR_DS_CHILDREN_EXIST;
break;
case "UnwillingToPerform_ERROR_DS_ILLEGAL_MOD_OPERATION":
errorStatus = ConstrOnDelOpErr.UnwillingToPerform_ERROR_DS_ILLEGAL_MOD_OPERATION;
break;
case "Success_STATUS_SUCCESS":
#region Searching for Deleted Object in Tombstones
if (isEntryExist)
{
tombStoneSearchResultEntry = Utilities.GetDeletedObject(guidHashTable[delObjDn].ToString(), defaultNC, currentWorkingDC.FQDN, currentPort);
if (tombStoneSearchResultEntry != null)
{
List<string> attributesAreNotNull = new List<string>();
foreach (string key in tombStoneSearchResultEntry.Properties.PropertyNames)
{
attributesAreNotNull.Add(key.ToLower(CultureInfo.InvariantCulture));
foreach (object value in tombStoneSearchResultEntry.Properties[key])
{
if (key.ToLower(CultureInfo.InvariantCulture) == "isdeleted")
{
Site.CaptureRequirementIfAreEqual<string>(value.ToString().ToLower(CultureInfo.InvariantCulture), "true", 889, "During the Delete operation, the isDeleted attribute is set to true on tombstones.");
Site.CaptureRequirementIfAreEqual<string>(value.ToString().ToLower(CultureInfo.InvariantCulture), "true", 924, "During the delete operation, the isDeleted attribute is set to true.");
}
if (key.ToLower(CultureInfo.InvariantCulture) == "distinguishedname")
{
Site.CaptureRequirementIfAreEqual<string>(value.ToString().Substring(0, value.ToString().IndexOf('=')).ToLower(CultureInfo.InvariantCulture), delObjRdnType.ToLower(CultureInfo.InvariantCulture), 920, "During the delete operation, the attribute that equals the rdnType of the object is retained.");
searchFlags = IntegerSymbols.ParseSystemFlagsValue("searchflags", "fPRESERVEONDELETE");
Type type = IntegerSymbols.GetSymbolEnumType("searchflags");
result = IntegerSymbols.UnparseUInt32Enum(type, (uint)searchFlags);
Site.CaptureRequirementIfAreEqual<string>(result.ToLower(CultureInfo.InvariantCulture), "fPRESERVEONDELETE".ToLower(CultureInfo.InvariantCulture), 921, "During the delete operation, any attribute that has fPRESERVEONDELETE flag set in its searchFlags is retained, except objectCategory and sAMAccountType, which are always removed, regardless of the value of their searchFlags.");
string[] DeletedObjectsContainer = value.ToString().Split(new char[] { ',' });
Site.CaptureRequirementIfAreEqual<string>(DeletedObjectsContainer[1].ToString().ToLower(CultureInfo.InvariantCulture), "CN=Deleted Objects".ToLower(CultureInfo.InvariantCulture), 892, "During the Delete operation, the tombstone remains in the database for at least the tombstone lifetime time interval after its deletion but the Deleted Objects container(which is considered a tombstone if the Recycle Bin optional feature is not enabled) always remains available.");
}
if (key.ToLower(CultureInfo.InvariantCulture) == "objectsid")
{
if (value is byte[])
{
byte[] byteVal = value as byte[];
sidOftheNewObject = new SecurityIdentifier(byteVal, 0);
}
}
if (key.ToLower(CultureInfo.InvariantCulture) == "objectguid")
{
if (value is byte[])
{
byte[] byteVal = value as byte[];
guidOfNewObject = new Guid(byteVal);
}
}
if (key.ToLower(CultureInfo.InvariantCulture) == "instancetype")
{
searchFlags = IntegerSymbols.ParseSystemFlagsValue("searchflags", "fPRESERVEONDELETE");
Type type = IntegerSymbols.GetSymbolEnumType("searchflags");
result = IntegerSymbols.UnparseUInt32Enum(type, (uint)searchFlags);
Site.CaptureRequirementIfAreEqual<string>(result.ToLower(CultureInfo.InvariantCulture), "fPRESERVEONDELETE".ToLower(CultureInfo.InvariantCulture), 921, "During the delete operation, any attribute that has fPRESERVEONDELETE flag set in its searchFlags is retained, except objectCategory and sAMAccountType, which are always removed, regardless of the value of their searchFlags.");
}
}
}
VerifyDeletedObjectRetainedAttribute(attributesAreNotNull);
}
}
else
{
Site.Log.Add(LogEntryKind.Debug, "No object exists");
}
#endregion
errorStatus = ConstrOnDelOpErr.success;
break;
default:
errorStatus = ConstrOnDelOpErr.UnSpecifiedError;
break;
}
#endregion
}
#endregion
#region Return values for specific attributes
if (result.Contains("NoSuchObject"))
{
errorStatus = ConstrOnDelOpErr.NoSuchObject;
}
if (result.Contains("NoSuchObject") && isRODC)
{
errorStatus = ConstrOnDelOpErr.NoSuchObject;
}
if ((errorStatus != ConstrOnDelOpErr.success)
&& isSpecialDn)
{
errorStatus = ConstrOnDelOpErr.UnSpecifiedError;
}
#endregion
}