751 lines
24 KiB
C
751 lines
24 KiB
C
/*++
|
||
|
||
Copyright (c) 1990 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
attrtest.c
|
||
|
||
Abstract:
|
||
|
||
This file contains various test routines that call internal SAM server
|
||
routines for a unit test.
|
||
|
||
THE ROUTINES IN THIS FILE ARE FOR SAM SEVER TEST PURPOSES ONLY.
|
||
|
||
There are a number of server-side unit tests aimed at private routines
|
||
within the SAM server. These tests are defined in this file. This file
|
||
should only be compiled into the SAM server when it is built as a stand-
|
||
alone executable (built in the \um subdir). Therefore, it is only listed
|
||
in the sources file in the \um subdir.
|
||
|
||
Because the SAM code relies on a fairly large amount of state information
|
||
being in place from the initialization of the server, it is difficult to
|
||
write a unit test that "plugs in" to the server from the outside.
|
||
|
||
Tests:
|
||
|
||
BasicAttributeTest - This test creates a full set of SAM user-object
|
||
attributes and context, writes this to the DS, reads it back into a
|
||
SAM context buffer, and compares the before-and-after buffers for byte
|
||
equivalence.
|
||
|
||
AdvancedAttributeTest - This test calls the attribute Get/Set routines
|
||
in attr.c, with SAM objects from the DS backing store.
|
||
|
||
Author:
|
||
|
||
Chris Mayhall (ChrisMay) 19-Jun-1996
|
||
|
||
Environment:
|
||
|
||
User Mode - Win32
|
||
|
||
Revision History:
|
||
|
||
ChrisMay 19-Jun-1996
|
||
Created initial file.
|
||
ChrisMay 25-Jun-1996
|
||
Fleshed out more of the basic attribute test--now compares input/out-
|
||
put contexts and their attribute buffers (OnDisk member) for errors
|
||
during test, in the form of non-matching bytes. Added variable-attr-
|
||
ibute tests and verification.
|
||
ChrisMay 02-Jul-1996
|
||
Added Unicode-string test case and verification. Variable attributes.
|
||
ChrisMay 03-Jul-1996
|
||
Added access attribute test case and verification. Added test for
|
||
SampSetVariableAttributes with buffer resizing.
|
||
|
||
--*/
|
||
|
||
#include <samsrvp.h>
|
||
#include <dsutilp.h>
|
||
#include <dslayer.h>
|
||
#include <mappings.h>
|
||
#include <testutil.h>
|
||
|
||
// Forward Declarations
|
||
|
||
NTSTATUS
|
||
SampValidateAttributes(
|
||
IN PSAMP_OBJECT Context,
|
||
IN ULONG AttributeGroup
|
||
);
|
||
|
||
NTSTATUS
|
||
SampSetVariableAttribute(
|
||
IN PSAMP_OBJECT Context,
|
||
IN ULONG AttributeIndex,
|
||
IN ULONG Qualifier,
|
||
IN PUCHAR Buffer,
|
||
IN ULONG Length
|
||
);
|
||
|
||
// Private debugging display routine is enabled when ATTRTEST_DBG_PRINTF = 1.
|
||
|
||
#define ATTRTEST_DBG_PRINTF 0
|
||
|
||
#if (ATTRTEST_DBG_PRINTF == 1)
|
||
#define DebugPrint printf
|
||
#else
|
||
#define DebugPrint
|
||
#endif
|
||
|
||
//===========================BASIC ATTRIBUTE TEST=============================
|
||
|
||
NTSTATUS
|
||
BasicAttributeTest(
|
||
VOID *Parameter
|
||
)
|
||
{
|
||
NTSTATUS NtStatus = STATUS_INTERNAL_ERROR;
|
||
NTSTATUS NtStatus2 = STATUS_INTERNAL_ERROR;
|
||
PDSNAME ObjectDsName = NULL;
|
||
WCHAR Buffer1[128];
|
||
WCHAR *NamePrefix = NULL;
|
||
ULONG NamePrefixLength = 0;
|
||
ULONG Rid = 1001;
|
||
BYTE AttributeBuffer1[BUF_SIZE];
|
||
BYTE AttributeBuffer2[BUF_SIZE];
|
||
SAMP_OBJECT WriteObjectContext;
|
||
SAMP_OBJECT ReadObjectContext;
|
||
BOOLEAN UseKeyHandle = FALSE;
|
||
ULONG AttributeGroup = SAMP_FIXED_ATTRIBUTES;
|
||
BOOLEAN Identical = FALSE;
|
||
UCHAR DomainSid[] = {1,4,1,2,3,4,5,6,1,0,0,0,2,0,0,0,3,0,0,0,4,0,0,0};
|
||
|
||
// BUG: Hard-coded ObjectName used in test data.
|
||
|
||
WCHAR ObjectName[] = L"/o=NT/ou=DS/cn=Configuration/cn=User1";
|
||
|
||
// Set up the DS attribute blocks used to initialize the test. These
|
||
// attributes are not actually part of the test, but only serve to set
|
||
// up the initial environment for the attribute test.
|
||
|
||
ATTRVAL SecurityDescriptorVal[] =
|
||
{
|
||
{sizeof(SECURITY_DESCRIPTOR), NULL},
|
||
{sizeof(ULONG),(UCHAR *) &Rid}
|
||
};
|
||
|
||
ATTRTYP SecurityDescriptorType[] =
|
||
{
|
||
SAMP_USER_SECURITY_DESCRIPTOR,
|
||
SAMP_FIXED_USER_USERID
|
||
};
|
||
|
||
DEFINE_ATTRBLOCK2(SdBlock, SecurityDescriptorType, SecurityDescriptorVal);
|
||
|
||
// The DS requires a default security descriptor for object creation, so
|
||
// put one together (in self-relative format).
|
||
|
||
NtStatus = BuildDefaultSecurityDescriptor(
|
||
&(SecurityDescriptorVal[0].pVal),
|
||
&(SecurityDescriptorVal[0].valLen));
|
||
|
||
if (!NT_SUCCESS(NtStatus))
|
||
{
|
||
return(NtStatus);
|
||
}
|
||
|
||
// Set up the object's DS name.
|
||
|
||
ObjectDsName = (PDSNAME)Buffer1;
|
||
|
||
SampInitializeDsName(ObjectDsName,
|
||
NamePrefix,
|
||
NamePrefixLength,
|
||
ObjectName,
|
||
sizeof(ObjectName));
|
||
|
||
RtlZeroMemory(AttributeBuffer1, BUF_SIZE);
|
||
|
||
NtStatus = BuildObjectContext(SampUserObjectType,
|
||
ObjectDsName,
|
||
AttributeBuffer1,
|
||
&WriteObjectContext);
|
||
|
||
if (!NT_SUCCESS(NtStatus))
|
||
{
|
||
return(NtStatus);
|
||
}
|
||
|
||
RtlZeroMemory(AttributeBuffer2, BUF_SIZE);
|
||
|
||
NtStatus = BuildObjectContext(SampUserObjectType,
|
||
ObjectDsName,
|
||
AttributeBuffer2,
|
||
&ReadObjectContext);
|
||
|
||
if (NT_SUCCESS(NtStatus))
|
||
{
|
||
DebugPrint("ATTRTEST: Built Object(%d) Context Successfully\n",
|
||
SampUserObjectType);
|
||
|
||
// Object is a DSNAME data type; create a default user object
|
||
// for the test.
|
||
|
||
NtStatus = SampDsCreateObject(ObjectDsName,
|
||
SampUserObjectType,
|
||
&SdBlock,
|
||
(PSID)DomainSid
|
||
);
|
||
|
||
if (NT_SUCCESS(NtStatus))
|
||
{
|
||
// Attempt to set ALL of the SAM user attributes on the newly
|
||
// created object. Note that UseKeyHandle is only used for
|
||
// SAM-registry operations, so is NULL here.
|
||
|
||
|
||
NtStatus = SampStoreObjectAttributes(&WriteObjectContext,
|
||
UseKeyHandle);
|
||
|
||
|
||
if (NT_SUCCESS(NtStatus))
|
||
{
|
||
DebugPrint("SampStoreObjectAttributes status = 0x%lx\n",
|
||
NtStatus);
|
||
|
||
// Reset the dirty flags on the written attributes so
|
||
// that the later context comparison will pass (note
|
||
// that SampStoreObjectAttributes sets these flags to
|
||
// FALSE.
|
||
|
||
WriteObjectContext.FixedDirty = TRUE;
|
||
WriteObjectContext.VariableDirty = TRUE;
|
||
|
||
// Reset the "FixedValid" context flag to FALSE so that
|
||
// the validation routine will re-read the attributes
|
||
// from the DS backing store.
|
||
|
||
ReadObjectContext.FixedValid = FALSE;
|
||
|
||
// Validate the fixed-length attributes.
|
||
|
||
NtStatus = SampValidateAttributes(&ReadObjectContext,
|
||
AttributeGroup);
|
||
|
||
if (NT_SUCCESS(NtStatus))
|
||
{
|
||
// Compare the input/output contexts to make sure
|
||
// the data hasn't been changed.
|
||
|
||
Identical = CompareContexts(&WriteObjectContext,
|
||
&ReadObjectContext);
|
||
|
||
if (TRUE == Identical)
|
||
{
|
||
DebugPrint("Contexts are identical\n");
|
||
}
|
||
else
|
||
{
|
||
DebugPrint("Contexts are different\n");
|
||
}
|
||
}
|
||
else
|
||
{
|
||
DebugPrint("SampValidateAttributes error = 0x%lx\n",
|
||
NtStatus);
|
||
}
|
||
|
||
if (NT_SUCCESS(NtStatus) && (TRUE == Identical))
|
||
{
|
||
// Reset the "VariableValid" context flag to FALSE so
|
||
// that the validation routine will re-read the attr-
|
||
// ibutes from the DS backing store.
|
||
|
||
ReadObjectContext.VariableValid = FALSE;
|
||
AttributeGroup = SAMP_VARIABLE_ATTRIBUTES;
|
||
|
||
// Validate the variable-length attributes.
|
||
|
||
NtStatus = SampValidateAttributes(&ReadObjectContext,
|
||
AttributeGroup);
|
||
|
||
if (NT_SUCCESS(NtStatus))
|
||
{
|
||
// Compare the input/output contexts to make sure
|
||
// the data hasn't been changed.
|
||
|
||
Identical = CompareContexts(&WriteObjectContext,
|
||
&ReadObjectContext);
|
||
|
||
if (TRUE == Identical)
|
||
{
|
||
DebugPrint("Contexts are identical\n");
|
||
}
|
||
else
|
||
{
|
||
DebugPrint("Contexts are different\n");
|
||
}
|
||
}
|
||
else
|
||
{
|
||
DebugPrint(
|
||
"SampValidateAttributes error = 0x%lx\n",
|
||
NtStatus);
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
DebugPrint("SampStoreObjectAttributes error = 0x%lx\n",
|
||
NtStatus);
|
||
}
|
||
|
||
// Clean up so that the test can be re-run.
|
||
|
||
NtStatus = SampDsDeleteObject(ObjectDsName);
|
||
|
||
if (!NT_SUCCESS(NtStatus))
|
||
{
|
||
DebugPrint("SampDsDeleteObject error = 0x%lx\n", NtStatus);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
DebugPrint("SampDsCreateObject error = 0x%lx\n", NtStatus);
|
||
}
|
||
}
|
||
|
||
// Commit the DS transaction.
|
||
|
||
NtStatus2 = SampMaybeEndDsTransaction(FALSE);
|
||
|
||
ASSERT(!SampExistsDsTransaction());
|
||
|
||
if (!NT_SUCCESS(NtStatus2) )
|
||
{
|
||
DebugPrint("SampMaybeEndDsTransaction error = 0x%lx\n", NtStatus2);
|
||
}
|
||
|
||
if ((NT_SUCCESS(NtStatus)) && NT_SUCCESS(NtStatus2) && (TRUE == Identical))
|
||
{
|
||
printf("\nBasicAttributeTest PASSED\n");
|
||
}
|
||
else
|
||
{
|
||
printf("\nBasicAttributeTest FAILED\n");
|
||
}
|
||
|
||
return(NtStatus);
|
||
}
|
||
|
||
|
||
|
||
NTSTATUS
|
||
AdvancedAttributeTest(
|
||
VOID *Parameter
|
||
)
|
||
{
|
||
NTSTATUS NtStatus = STATUS_INTERNAL_ERROR;
|
||
NTSTATUS NtStatus2 = STATUS_INTERNAL_ERROR;
|
||
PDSNAME ObjectDsName = NULL;
|
||
WCHAR Buffer1[128];
|
||
WCHAR *NamePrefix = NULL;
|
||
ULONG NamePrefixLength = 0;
|
||
ULONG Rid = 1001;
|
||
BYTE AttributeBuffer1[BUF_SIZE];
|
||
PBYTE AttributeBuffer2 = NULL;
|
||
SAMP_OBJECT WriteObjectContext;
|
||
SAMP_OBJECT ReadObjectContext;
|
||
BOOLEAN UseKeyHandle = FALSE;
|
||
ULONG AttributeGroup = SAMP_FIXED_ATTRIBUTES;
|
||
BOOLEAN Identical = FALSE;
|
||
BOOLEAN MakeCopy = TRUE;
|
||
PVOID FixedData = NULL;
|
||
UNICODE_STRING UnicodeString;
|
||
ULONG Revision = 0;
|
||
PSECURITY_DESCRIPTOR SecurityDescriptor = NULL;
|
||
PLARGE_INTEGER LargeIntArray = NULL;
|
||
ULONG Count = 0;
|
||
LOGON_HOURS LogonHours;
|
||
ULONG Qualifier = 1;
|
||
WCHAR NewAccountName[] = L"NewAccountName";
|
||
ULONG Length = sizeof(NewAccountName);
|
||
|
||
// BUG: Hard-coded ObjectName used in test data.
|
||
|
||
WCHAR ObjectName[] = L"/o=NT/ou=DS/cn=Configuration/cn=User1";
|
||
|
||
// Set up the DS attribute blocks used to initialize the test. These
|
||
// attributes are not actually part of the test, but only serve to set
|
||
// up the initial environment for the attribute test.
|
||
|
||
ATTRVAL SecurityDescriptorVal[] =
|
||
{
|
||
{sizeof(SECURITY_DESCRIPTOR), NULL},
|
||
{sizeof(ULONG),(UCHAR *) &Rid}
|
||
};
|
||
|
||
ATTRTYP SecurityDescriptorType[] =
|
||
{
|
||
SAMP_USER_SECURITY_DESCRIPTOR,
|
||
SAMP_FIXED_USER_USERID
|
||
};
|
||
|
||
DEFINE_ATTRBLOCK2(SdBlock, SecurityDescriptorType, SecurityDescriptorVal);
|
||
|
||
UCHAR DomainSid[] = {1,4,1,2,3,4,5,6,1,0,0,0,2,0,0,0,3,0,0,0,4,0,0,0};
|
||
|
||
// The DS requires a default security descriptor for object creation, so
|
||
// put one together (in self-relative format).
|
||
|
||
NtStatus = BuildDefaultSecurityDescriptor(
|
||
&(SecurityDescriptorVal[0].pVal),
|
||
&(SecurityDescriptorVal[0].valLen));
|
||
|
||
if (!NT_SUCCESS(NtStatus))
|
||
{
|
||
return(NtStatus);
|
||
}
|
||
|
||
// Set up the object's DS name.
|
||
|
||
ObjectDsName = (PDSNAME)Buffer1;
|
||
|
||
SampInitializeDsName(ObjectDsName,
|
||
NamePrefix,
|
||
NamePrefixLength,
|
||
ObjectName,
|
||
sizeof(ObjectName));
|
||
|
||
RtlZeroMemory(AttributeBuffer1, BUF_SIZE);
|
||
|
||
NtStatus = BuildObjectContext(SampUserObjectType,
|
||
ObjectDsName,
|
||
AttributeBuffer1,
|
||
&WriteObjectContext);
|
||
|
||
if (!NT_SUCCESS(NtStatus))
|
||
{
|
||
return(NtStatus);
|
||
}
|
||
|
||
// The second attribute buffer must be allocated from the heap because
|
||
// SampSetVariableAttribute may grow the buffer, releasing the original
|
||
// buffer.
|
||
|
||
AttributeBuffer2 = RtlAllocateHeap(RtlProcessHeap(), 0, BUF_SIZE);
|
||
|
||
if (NULL != AttributeBuffer2)
|
||
{
|
||
RtlZeroMemory(AttributeBuffer2, BUF_SIZE);
|
||
|
||
NtStatus = BuildObjectContext(SampUserObjectType,
|
||
ObjectDsName,
|
||
AttributeBuffer2,
|
||
&ReadObjectContext);
|
||
}
|
||
else
|
||
{
|
||
NtStatus = STATUS_NO_MEMORY;
|
||
}
|
||
|
||
if (NT_SUCCESS(NtStatus))
|
||
{
|
||
DebugPrint("ATTRTEST: Built Object(%d) Context Successfully\n",
|
||
SampUserObjectType);
|
||
|
||
// Object is a DSNAME data type; create a default user object
|
||
// for the test.
|
||
|
||
NtStatus = SampDsCreateObject(ObjectDsName,
|
||
SampUserObjectType,
|
||
&SdBlock,
|
||
(PSID) DomainSid
|
||
);
|
||
|
||
if (NT_SUCCESS(NtStatus))
|
||
{
|
||
// Attempt to set ALL of the SAM user attributes on the newly
|
||
// created object. Note that UseKeyHandle is only used for
|
||
// SAM-registry operations, so is NULL here.
|
||
|
||
|
||
NtStatus = SampStoreObjectAttributes(&WriteObjectContext,
|
||
UseKeyHandle);
|
||
|
||
|
||
if (NT_SUCCESS(NtStatus))
|
||
{
|
||
DebugPrint("SampStoreObjectAttributes status = 0x%lx\n",
|
||
NtStatus);
|
||
|
||
// Reset the dirty flags on the written attributes so
|
||
// that the later context comparison will pass (note
|
||
// that SampStoreObjectAttributes sets these flags to
|
||
// FALSE.
|
||
|
||
WriteObjectContext.FixedDirty = TRUE;
|
||
WriteObjectContext.VariableDirty = TRUE;
|
||
|
||
// Reset the "FixedValid" context flag to FALSE so that
|
||
// the validation routine will re-read the attributes
|
||
// from the DS backing store.
|
||
|
||
ReadObjectContext.FixedValid = FALSE;
|
||
|
||
NtStatus = SampGetFixedAttributes(&ReadObjectContext,
|
||
MakeCopy,
|
||
&FixedData);
|
||
|
||
if (NT_SUCCESS(NtStatus))
|
||
{
|
||
DebugPrint("Comparing fixed attributes...\n");
|
||
|
||
// Compare the input/output attributes to make sure
|
||
// the data hasn't been changed.
|
||
|
||
Identical = CompareFixedAttributes(
|
||
&WriteObjectContext,
|
||
FixedData);
|
||
|
||
if (TRUE == Identical)
|
||
{
|
||
DebugPrint("Fixed attributes are identical\n");
|
||
}
|
||
else
|
||
{
|
||
DebugPrint("Fixed attributes are different\n");
|
||
}
|
||
|
||
// The copy of the fixed attributes was allocated via
|
||
// MIDL_user_allocate from SAM.
|
||
|
||
MIDL_user_free(FixedData);
|
||
}
|
||
else
|
||
{
|
||
DebugPrint("SampGetFixedAttributes error = 0x%lx\n",
|
||
NtStatus);
|
||
}
|
||
|
||
if (NT_SUCCESS(NtStatus) && (TRUE == Identical))
|
||
{
|
||
// BUG: Work in progress.
|
||
|
||
// NtStatus = SampSetFixedAttributes();
|
||
}
|
||
|
||
// The following tests are for variable-length attrs.
|
||
|
||
if (NT_SUCCESS(NtStatus) && (TRUE == Identical))
|
||
{
|
||
RtlZeroMemory(&UnicodeString,
|
||
sizeof(UNICODE_STRING));
|
||
|
||
NtStatus = SampGetUnicodeStringAttribute(
|
||
&ReadObjectContext,
|
||
SAMP_USER_ACCOUNT_NAME,
|
||
MakeCopy,
|
||
&UnicodeString);
|
||
|
||
if (NT_SUCCESS(NtStatus))
|
||
{
|
||
DebugPrint("Comparing unicode string attribute...\n");
|
||
|
||
Identical = CompareVariableAttributes(
|
||
&WriteObjectContext,
|
||
SAMP_USER_ACCOUNT_NAME,
|
||
UnicodeString.Buffer);
|
||
|
||
if (TRUE == Identical)
|
||
{
|
||
DebugPrint("Variable attributes are identical\n");
|
||
}
|
||
else
|
||
{
|
||
DebugPrint("Variable attributes are different\n");
|
||
}
|
||
|
||
MIDL_user_free(UnicodeString.Buffer);
|
||
}
|
||
else
|
||
{
|
||
DebugPrint("SampGetUnicodeStringAttribute error = 0x%lx\n",
|
||
NtStatus);
|
||
}
|
||
}
|
||
|
||
if (NT_SUCCESS(NtStatus) && (TRUE == Identical))
|
||
{
|
||
// BUG: Sid is an attribute of the domain object, not the user object.
|
||
|
||
// NtStatus = SampGetSidAttribute();
|
||
}
|
||
|
||
if (NT_SUCCESS(NtStatus) && (TRUE == Identical))
|
||
{
|
||
NtStatus = SampGetAccessAttribute(
|
||
&ReadObjectContext,
|
||
SAMP_USER_SECURITY_DESCRIPTOR,
|
||
MakeCopy,
|
||
&Revision,
|
||
&SecurityDescriptor);
|
||
|
||
if (NT_SUCCESS(NtStatus))
|
||
{
|
||
DebugPrint("Comparing access attribute...\n");
|
||
|
||
// BUG: Need to compare revision levels also.
|
||
|
||
Identical = CompareVariableAttributes(
|
||
&WriteObjectContext,
|
||
SAMP_USER_SECURITY_DESCRIPTOR,
|
||
SecurityDescriptor);
|
||
|
||
if (TRUE == Identical)
|
||
{
|
||
DebugPrint("Variable attributes are identical\n");
|
||
}
|
||
else
|
||
{
|
||
DebugPrint("Variable attributes are different\n");
|
||
}
|
||
|
||
MIDL_user_free(SecurityDescriptor);
|
||
}
|
||
else
|
||
{
|
||
DebugPrint("SampGetAccessAttribute error = 0x%lx\n",
|
||
NtStatus);
|
||
}
|
||
}
|
||
|
||
if (NT_SUCCESS(NtStatus) && (TRUE == Identical))
|
||
{
|
||
// BUG: This routine is not used in the DS version?
|
||
|
||
// NtStatus = SampGetUlongArrayAttribute();
|
||
}
|
||
|
||
if (NT_SUCCESS(NtStatus) && (TRUE == Identical))
|
||
{
|
||
// BUG: This routine is not used in the DS version?
|
||
|
||
// NtStatus = SampGetLargeIntArrayAttribute();
|
||
}
|
||
|
||
if (NT_SUCCESS(NtStatus) && (TRUE == Identical))
|
||
{
|
||
// BUG: This routine is not used in the DS version?
|
||
|
||
// NtStatus = SampGetSidArrayAttribute();
|
||
}
|
||
|
||
if (NT_SUCCESS(NtStatus) && (TRUE == Identical))
|
||
{
|
||
RtlZeroMemory(&LogonHours, sizeof(LOGON_HOURS));
|
||
|
||
NtStatus = SampGetLogonHoursAttribute(
|
||
&ReadObjectContext,
|
||
SAMP_USER_LOGON_HOURS,
|
||
MakeCopy,
|
||
&LogonHours);
|
||
|
||
if (NT_SUCCESS(NtStatus))
|
||
{
|
||
DebugPrint("Comparing logon hours attribute...\n");
|
||
|
||
// The SAM attribute buffer contains the data
|
||
// that is the LogonHours.LogonHours member and
|
||
// not the entire LogonHours Structure.
|
||
|
||
Identical = CompareVariableAttributes(
|
||
&WriteObjectContext,
|
||
SAMP_USER_LOGON_HOURS,
|
||
LogonHours.LogonHours);
|
||
|
||
if (TRUE == Identical)
|
||
{
|
||
DebugPrint("Variable attributes are identical\n");
|
||
}
|
||
else
|
||
{
|
||
DebugPrint("Variable attributes are different\n");
|
||
}
|
||
|
||
MIDL_user_free(LogonHours.LogonHours);
|
||
}
|
||
else
|
||
{
|
||
DebugPrint("SampGetAccessAttribute error = 0x%lx\n",
|
||
NtStatus);
|
||
}
|
||
}
|
||
|
||
if (NT_SUCCESS(NtStatus) && (TRUE == Identical))
|
||
{
|
||
// Attempt to update the user's full name attribute
|
||
// with a longer string, forcing this routine to grow
|
||
// the attribute buffer.
|
||
|
||
NtStatus = SampSetVariableAttribute(
|
||
&ReadObjectContext,
|
||
SAMP_USER_ACCOUNT_NAME,
|
||
Qualifier,
|
||
(PUCHAR)NewAccountName,
|
||
Length);
|
||
|
||
if (NT_SUCCESS(NtStatus))
|
||
{
|
||
// BUG: Need to verify that the update was correct.
|
||
|
||
// For now, verified in the debugger by dumping
|
||
// the attribute buffer...
|
||
|
||
DebugPrint("SampSetVariableAttribute succeeded\n");
|
||
}
|
||
else
|
||
{
|
||
DebugPrint("SampSetVariableAttribute error = 0x%lx\n",
|
||
NtStatus);
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
DebugPrint("SampStoreObjectAttributes error = 0x%lx\n",
|
||
NtStatus);
|
||
}
|
||
|
||
// Clean up so that the test can be re-run.
|
||
|
||
NtStatus = SampDsDeleteObject(ObjectDsName);
|
||
|
||
if (!NT_SUCCESS(NtStatus))
|
||
{
|
||
DebugPrint("SampDsDeleteObject error = 0x%lx\n", NtStatus);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
DebugPrint("SampDsCreateObject error = 0x%lx\n", NtStatus);
|
||
}
|
||
}
|
||
|
||
// Commit the DS transaction.
|
||
|
||
NtStatus2 = SampMaybeEndDsTransaction(FALSE);
|
||
|
||
ASSERT(!SampExistsDsTransaction());
|
||
|
||
if (!NT_SUCCESS(NtStatus2) )
|
||
{
|
||
DebugPrint("SampMaybeEndDsTransaction error = 0x%lx\n", NtStatus2);
|
||
}
|
||
|
||
if ((NT_SUCCESS(NtStatus)) && NT_SUCCESS(NtStatus2) && (TRUE == Identical))
|
||
{
|
||
printf("\nAdvancedAttributeTest PASSED\n");
|
||
}
|
||
else
|
||
{
|
||
printf("\nAdvancedAttributeTest FAILED\n");
|
||
}
|
||
|
||
return(NtStatus);
|
||
}
|