mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
722 lines
16 KiB
722 lines
16 KiB
/*++
|
|
|
|
Copyright (c) 1990 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
srvtest.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.
|
|
|
|
Author:
|
|
|
|
Chris Mayhall (ChrisMay) 07-Jun-1996
|
|
|
|
Environment:
|
|
|
|
User Mode - Win32
|
|
|
|
Revision History:
|
|
|
|
ChrisMay 09-May-1996
|
|
Created initial file, SampStoreObjectAttributes test.
|
|
ChrisMay 12-May-1996
|
|
Moved BasicStorageTest to stgtest.c to reduce the number of merge
|
|
conflicts (from everyone partying on a single file).
|
|
|
|
--*/
|
|
|
|
#include <samsrvp.h>
|
|
#include <dsutilp.h>
|
|
#include <dslayer.h>
|
|
#include <mappings.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <testutil.h>
|
|
|
|
|
|
// Private debugging display routine is enabled when DSUTIL_DBG_PRINTF = 1.
|
|
|
|
#define SRVTEST_DBG_PRINTF 1
|
|
|
|
#if (SRVTEST_DBG_PRINTF == 1)
|
|
#define DebugPrint printf
|
|
#else
|
|
#define DebugPrint
|
|
#endif
|
|
|
|
|
|
|
|
|
|
BOOL
|
|
CompareAttrBlocks(
|
|
ATTRBLOCK * attr1,
|
|
ATTRBLOCK * attr2
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Compares two attrblocks, typically used to test the results
|
|
of a modify -read loop
|
|
|
|
Arguments
|
|
|
|
attr1 - first AttrBlock
|
|
attr2 - Second attrBlock
|
|
|
|
Return Values
|
|
|
|
TRUE - Attrblocks are same
|
|
FALSE - Attrblocks are different
|
|
|
|
--*/
|
|
{
|
|
ULONG Index;
|
|
ULONG Index2;
|
|
|
|
if (attr1->attrCount != attr2->attrCount)
|
|
goto False;
|
|
|
|
for (Index=0;Index<attr1->attrCount;Index++)
|
|
{
|
|
// compare Types
|
|
if (attr1->pAttr[Index].attrTyp != attr2->pAttr[Index].attrTyp)
|
|
goto False;
|
|
// Comapre val Counts
|
|
if (attr1->pAttr[Index].AttrVal.valCount !=
|
|
attr2->pAttr[Index].AttrVal.valCount
|
|
)
|
|
goto False;
|
|
// compare Values
|
|
for (Index2=0;Index2< attr1->pAttr[Index].AttrVal.valCount;Index2++)
|
|
{
|
|
// Compare Length of each value
|
|
if ( attr1->pAttr[Index].AttrVal.pAVal[Index2].valLen !=
|
|
attr2->pAttr[Index].AttrVal.pAVal[Index2].valLen
|
|
)
|
|
goto False;
|
|
// Compare Memory of each value
|
|
if (memcmp( (void *) attr1->pAttr[Index].AttrVal.pAVal[Index2].pVal,
|
|
(void *) attr2->pAttr[Index].AttrVal.pAVal[Index2].pVal,
|
|
attr1->pAttr[Index].AttrVal.pAVal[Index2].valLen
|
|
) !=0)
|
|
goto False;
|
|
}
|
|
}
|
|
return TRUE;
|
|
|
|
False:
|
|
return FALSE;
|
|
}
|
|
|
|
VOID
|
|
SetDefaultEnterpriseName(
|
|
TESTINFO *TstInfo
|
|
)
|
|
/*++
|
|
|
|
Routine Description
|
|
|
|
Sets the Default Enterprise Name to /o=NT/ou=DS
|
|
|
|
|
|
--*/
|
|
{
|
|
|
|
WCHAR DefaultDomainName[] = L"/o=NT/ou=DS";
|
|
|
|
RtlCopyMemory(
|
|
TstInfo->EnterpriseName,
|
|
DefaultDomainName,
|
|
sizeof(DefaultDomainName)
|
|
);
|
|
|
|
TstInfo->EnterpriseNameLen = sizeof(DefaultDomainName);
|
|
}
|
|
|
|
|
|
VOID
|
|
ReadNamePrefix(
|
|
TESTINFO *TstInfo
|
|
)
|
|
/*++
|
|
|
|
Routine Description
|
|
|
|
Reads the o=, and ou= fields for test purposes
|
|
|
|
Arguments
|
|
|
|
NamePrefixBuffer - Holds the pointer to the string
|
|
NamePrefixLen - Holds the total length in bytes of the string.
|
|
Length includes the terminating NULL character.
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONG CharCount = 0;
|
|
|
|
// First Obtain the Name Prefix
|
|
|
|
printf("Please Enter the Name Prefix:\n\n");
|
|
printf("The Name Prefix is in the following Format\n");
|
|
printf("/o=<enterprise name>/ou=<site name>\n");
|
|
wscanf(L"%s",TstInfo->EnterpriseName);
|
|
CharCount = wcslen(TstInfo->EnterpriseName);
|
|
TstInfo->EnterpriseNameLen = sizeof(WCHAR) * ( CharCount + 1);
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
BuildDefaultSecurityDescriptor(
|
|
OUT PSECURITY_DESCRIPTOR *pSD,
|
|
OUT ULONG * Size
|
|
)
|
|
|
|
/*++
|
|
|
|
|
|
Routine Description:
|
|
|
|
This routine builds a self-relative security descriptor ready
|
|
to be applied to one of the SAM objects.
|
|
|
|
Arguments:
|
|
pSD the security descriptor in self relative form
|
|
Size The size of it in bytes
|
|
|
|
Return Value:
|
|
|
|
TBS.
|
|
|
|
--*/
|
|
{
|
|
|
|
|
|
|
|
SECURITY_DESCRIPTOR Absolute;
|
|
PSECURITY_DESCRIPTOR Relative;
|
|
PACL TmpAcl;
|
|
PACCESS_ALLOWED_ACE TmpAce;
|
|
PSID TmpSid;
|
|
ULONG Length, i;
|
|
PULONG RidLocation;
|
|
BOOLEAN IgnoreBoolean;
|
|
ACCESS_MASK MappedMask;
|
|
PSID AceSid[10]; // Don't expect more than 10 ACEs in any of these.
|
|
ACCESS_MASK AceMask[10];
|
|
NTSTATUS Status;
|
|
GENERIC_MAPPING GenericMap =
|
|
{
|
|
USER_READ,
|
|
USER_WRITE,
|
|
USER_EXECUTE,
|
|
USER_ALL_ACCESS
|
|
};
|
|
|
|
|
|
//
|
|
// The approach is to set up an absolute security descriptor that
|
|
// looks like what we want and then copy it to make a self-relative
|
|
// security descriptor.
|
|
//
|
|
|
|
|
|
Status = RtlCreateSecurityDescriptor(
|
|
&Absolute,
|
|
SECURITY_DESCRIPTOR_REVISION1
|
|
);
|
|
ASSERT( NT_SUCCESS(Status) );
|
|
|
|
|
|
|
|
//
|
|
// Owner
|
|
//
|
|
|
|
Status = RtlSetOwnerSecurityDescriptor (&Absolute, SampAdministratorsAliasSid, FALSE );
|
|
ASSERT(NT_SUCCESS(Status));
|
|
|
|
|
|
|
|
//
|
|
// Group
|
|
//
|
|
|
|
Status = RtlSetGroupSecurityDescriptor (&Absolute, SampAdministratorsAliasSid, FALSE );
|
|
ASSERT(NT_SUCCESS(Status));
|
|
|
|
|
|
AceSid[0] = SampWorldSid;
|
|
AceMask[0] = (USER_ALL_ACCESS);
|
|
|
|
AceSid[1] = SampAdministratorsAliasSid;
|
|
AceMask[1] = (USER_ALL_ACCESS);
|
|
|
|
|
|
|
|
|
|
//
|
|
// Discretionary ACL
|
|
//
|
|
// Calculate its length,
|
|
// Allocate it,
|
|
// Initialize it,
|
|
// Add each ACE
|
|
// Add it to the security descriptor
|
|
//
|
|
|
|
Length = (ULONG)sizeof(ACL);
|
|
for (i=0; i<2; i++) {
|
|
|
|
Length += RtlLengthSid( AceSid[i] ) +
|
|
(ULONG)sizeof(ACCESS_ALLOWED_ACE) -
|
|
(ULONG)sizeof(ULONG); //Subtract out SidStart field length
|
|
}
|
|
|
|
TmpAcl = RtlAllocateHeap( RtlProcessHeap(), 0, Length );
|
|
ASSERT(TmpAcl != NULL);
|
|
|
|
|
|
Status = RtlCreateAcl( TmpAcl, Length, ACL_REVISION2);
|
|
ASSERT( NT_SUCCESS(Status) );
|
|
|
|
for (i=0; i<2; i++) {
|
|
MappedMask = AceMask[i];
|
|
RtlMapGenericMask( &MappedMask, &GenericMap );
|
|
Status = RtlAddAccessAllowedAce (
|
|
TmpAcl,
|
|
ACL_REVISION2,
|
|
MappedMask,
|
|
AceSid[i]
|
|
);
|
|
ASSERT( NT_SUCCESS(Status) );
|
|
}
|
|
|
|
Status = RtlSetDaclSecurityDescriptor (&Absolute, TRUE, TmpAcl, FALSE );
|
|
ASSERT(NT_SUCCESS(Status));
|
|
|
|
|
|
|
|
|
|
//
|
|
// Sacl
|
|
//
|
|
|
|
|
|
Length = (ULONG)sizeof(ACL) +
|
|
RtlLengthSid( SampWorldSid ) +
|
|
(ULONG)sizeof(SYSTEM_AUDIT_ACE) -
|
|
(ULONG)sizeof(ULONG); //Subtract out SidStart field length
|
|
TmpAcl = RtlAllocateHeap( RtlProcessHeap(), 0, Length );
|
|
ASSERT(TmpAcl != NULL);
|
|
|
|
Status = RtlCreateAcl( TmpAcl, Length, ACL_REVISION2);
|
|
ASSERT( NT_SUCCESS(Status) );
|
|
|
|
Status = RtlAddAuditAccessAce (
|
|
TmpAcl,
|
|
ACL_REVISION2,
|
|
(GenericMap.GenericWrite | DELETE | WRITE_DAC | ACCESS_SYSTEM_SECURITY) & ~READ_CONTROL,
|
|
SampWorldSid,
|
|
TRUE, //AuditSuccess,
|
|
TRUE //AuditFailure
|
|
);
|
|
ASSERT( NT_SUCCESS(Status) );
|
|
|
|
Status = RtlSetSaclSecurityDescriptor (&Absolute, TRUE, TmpAcl, FALSE );
|
|
ASSERT(NT_SUCCESS(Status));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
// Convert the Security Descriptor to Self-Relative
|
|
//
|
|
// Get the length needed
|
|
// Allocate that much memory
|
|
// Copy it
|
|
// Free the generated absolute ACLs
|
|
//
|
|
|
|
Length = 0;
|
|
Status = RtlAbsoluteToSelfRelativeSD( &Absolute, NULL, &Length );
|
|
ASSERT(Status == STATUS_BUFFER_TOO_SMALL);
|
|
|
|
Relative = RtlAllocateHeap( RtlProcessHeap(), 0, Length );
|
|
ASSERT(Relative != NULL);
|
|
Status = RtlAbsoluteToSelfRelativeSD(&Absolute, Relative, &Length );
|
|
ASSERT(NT_SUCCESS(Status));
|
|
|
|
|
|
RtlFreeHeap( RtlProcessHeap(), 0, Absolute.Dacl );
|
|
RtlFreeHeap( RtlProcessHeap(), 0, Absolute.Sacl );
|
|
|
|
*pSD = Relative;
|
|
*Size = Length;
|
|
|
|
return(Status);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NTSTATUS __stdcall
|
|
SampTestDsLayer(
|
|
VOID * Param
|
|
)
|
|
/*++
|
|
Executes a simple set of tests to unit test
|
|
the DS interface Layer
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status;
|
|
TESTINFO *TstInfo = (TESTINFO *) Param;
|
|
|
|
//
|
|
// Declare Buffers to hold all our DsNames
|
|
//
|
|
|
|
WCHAR Buffer[256];
|
|
WCHAR Buffer2[256];
|
|
|
|
//
|
|
// Declare the names of the Domain and User Objects that
|
|
// we will be creating
|
|
//
|
|
|
|
WCHAR ObjectName[] = L"/cn=NewContainer/cn=user2";
|
|
WCHAR ContainerName[] = L"/cn=NewContainer";
|
|
|
|
//
|
|
// Variables to hold our DsNames
|
|
//
|
|
|
|
DSNAME *pDsName;
|
|
DSNAME *pContainer;
|
|
DSNAME *ReturnedObject = NULL;
|
|
|
|
BOOLEAN ObjectCreated = FALSE;
|
|
BOOLEAN ContainerCreated = FALSE;
|
|
|
|
SECURITY_DESCRIPTOR SdAbsolute;
|
|
UNICODE_STRING NameToLookup;
|
|
|
|
ATTRBLOCK AttrsRead;
|
|
|
|
//
|
|
// declare the attribute values to set
|
|
//
|
|
|
|
WCHAR UserAccountName[] = L"User2";
|
|
CHAR UnicodePwd[] = {0,1,2,3,4,5,6,7,8,9};
|
|
ULONG RevisionLevel = 4;
|
|
LARGE_INTEGER LastLogoff = {123456789, 123456789};
|
|
|
|
ATTRVAL AttributeValuesToSet []=
|
|
{
|
|
{sizeof(UserAccountName), (UCHAR *) UserAccountName}, // UNICODE Str
|
|
{sizeof(UnicodePwd), (UCHAR *) UnicodePwd }, // Binary
|
|
{sizeof(ULONG), (UCHAR *) & RevisionLevel }, // Integer
|
|
{sizeof(LARGE_INTEGER), (UCHAR *) &LastLogoff} // Large Integer
|
|
};
|
|
|
|
//
|
|
// declare attribute types
|
|
//
|
|
|
|
ATTRTYP AttributeTypesToSet[]=
|
|
{
|
|
SAMP_USER_ACCOUNT_NAME,
|
|
SAMP_USER_UNICODE_PWD,
|
|
SAMP_FIXED_USER_REVISION_LEVEL,
|
|
SAMP_FIXED_USER_LAST_LOGOFF
|
|
};
|
|
|
|
ULONG Rid =1;
|
|
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};
|
|
|
|
ATTRTYP UserCreateType[]=
|
|
{
|
|
SAMP_USER_SECURITY_DESCRIPTOR,
|
|
SAMP_FIXED_USER_USERID
|
|
};
|
|
|
|
ATTRVAL UserCreateVal [] =
|
|
{
|
|
{sizeof(SECURITY_DESCRIPTOR),NULL},
|
|
{sizeof(ULONG), (UCHAR *) & Rid}
|
|
};
|
|
|
|
ATTRTYP DomainCreateType []=
|
|
{
|
|
SAMP_DOMAIN_SECURITY_DESCRIPTOR ,
|
|
SAMP_DOMAIN_SID
|
|
};
|
|
|
|
ATTRVAL DomainCreateVal []=
|
|
{
|
|
{ sizeof(SECURITY_DESCRIPTOR),NULL},
|
|
{ sizeof(DomainSid), (UCHAR *) DomainSid }
|
|
};
|
|
|
|
|
|
//
|
|
// declare Attrblock's
|
|
//
|
|
|
|
DEFINE_ATTRBLOCK4(AttrBlock, AttributeTypesToSet, AttributeValuesToSet);
|
|
DEFINE_ATTRBLOCK2(DomainCreate,DomainCreateType,DomainCreateVal);
|
|
DEFINE_ATTRBLOCK2(UserCreate,UserCreateType,UserCreateVal);
|
|
|
|
//
|
|
// Log Test Name
|
|
//
|
|
|
|
printf("TESTING DS LAYER\n");
|
|
|
|
//
|
|
// Initialize an Object to Create
|
|
//
|
|
|
|
pDsName = (DSNAME *) Buffer;
|
|
SampInitializeDsName(
|
|
pDsName,
|
|
TstInfo->EnterpriseName,
|
|
TstInfo->EnterpriseNameLen,
|
|
ObjectName,
|
|
sizeof(ObjectName)
|
|
);
|
|
|
|
//
|
|
// Initialize Name of Container Object
|
|
//
|
|
|
|
pContainer = (DSNAME *) Buffer2;
|
|
|
|
SampInitializeDsName(
|
|
pContainer,
|
|
TstInfo->EnterpriseName,
|
|
TstInfo->EnterpriseNameLen,
|
|
ContainerName,
|
|
sizeof(ContainerName)
|
|
);
|
|
|
|
//
|
|
// Build a default secuirty Descriptor for Domain Object
|
|
//
|
|
|
|
Status = BuildDefaultSecurityDescriptor(
|
|
&(DomainCreateVal[0].pVal),
|
|
&(DomainCreateVal[0].valLen)
|
|
);
|
|
|
|
|
|
//
|
|
// Build Default Security Descriptor for User Object
|
|
//
|
|
|
|
Status = BuildDefaultSecurityDescriptor(
|
|
&(UserCreateVal[0].pVal),
|
|
&(UserCreateVal[0].valLen)
|
|
);
|
|
|
|
|
|
|
|
//
|
|
// Create the container Object
|
|
//
|
|
|
|
Status = SampDsCreateObject(
|
|
pContainer,
|
|
SampDomainObjectType,
|
|
&DomainCreate,
|
|
(PSID) DomainSid
|
|
);
|
|
if (Status != STATUS_SUCCESS)
|
|
{
|
|
printf("Container Creation Failed\n");
|
|
goto Error;
|
|
}
|
|
|
|
ContainerCreated = TRUE;
|
|
|
|
//
|
|
// Create the user Object
|
|
//
|
|
|
|
Status = SampDsCreateObject(
|
|
pDsName,
|
|
SampUserObjectType,
|
|
&UserCreate,
|
|
(PSID) DomainSid
|
|
);
|
|
|
|
if (Status != STATUS_SUCCESS)
|
|
{
|
|
printf("Object Creation Failed\n");
|
|
goto Error;
|
|
}
|
|
|
|
ObjectCreated = TRUE;
|
|
|
|
//
|
|
// Set some attributes on the object
|
|
//
|
|
|
|
Status = SampDsSetAttributes(
|
|
pDsName,
|
|
0,
|
|
SampUserObjectType,
|
|
&AttrBlock
|
|
);
|
|
if (Status != STATUS_SUCCESS)
|
|
{
|
|
printf("Set Attributes Failed\n");
|
|
goto Error;
|
|
}
|
|
|
|
//
|
|
// Read back the same attributes
|
|
//
|
|
|
|
Status = SampDsRead(
|
|
pDsName,
|
|
0,
|
|
SampUserObjectType,
|
|
&AttrBlock,
|
|
&AttrsRead
|
|
);
|
|
if (Status != STATUS_SUCCESS)
|
|
{
|
|
printf("Read Attributes Failed\n");
|
|
goto Error;
|
|
}
|
|
|
|
//
|
|
// verify that they match
|
|
//
|
|
|
|
if ( !CompareAttrBlocks(&AttrBlock,&AttrsRead))
|
|
{
|
|
printf("ATTRBLOCK COMPARISON FAILED\n");
|
|
goto Error;
|
|
}
|
|
|
|
//
|
|
// Find the Object using the RID
|
|
//
|
|
|
|
Status = SampDsLookupObjectByRid(pContainer, Rid, &ReturnedObject);
|
|
if (Status != STATUS_SUCCESS)
|
|
{
|
|
printf("Lookup Object By Rid Failed\n");
|
|
goto Error;
|
|
}
|
|
|
|
//
|
|
// Free the returned Object
|
|
//
|
|
|
|
MIDL_user_free(ReturnedObject);
|
|
|
|
NameToLookup.Buffer = UserAccountName;
|
|
NameToLookup.Length = wcslen(UserAccountName);
|
|
NameToLookup.MaximumLength = wcslen(UserAccountName);
|
|
|
|
// Find the Object using Name
|
|
Status = SampDsLookupObjectByName(
|
|
pContainer,
|
|
SampUserObjectType,
|
|
&NameToLookup,
|
|
&ReturnedObject
|
|
);
|
|
|
|
if (Status != STATUS_SUCCESS)
|
|
{
|
|
printf("Lookup Object By Name Failed\n");
|
|
goto Error;
|
|
}
|
|
|
|
MIDL_user_free(ReturnedObject);
|
|
|
|
// delete the object
|
|
Status = SampDsDeleteObject(pDsName);
|
|
if (Status != STATUS_SUCCESS)
|
|
{
|
|
printf("Delete Object Failed\n");
|
|
goto Error;
|
|
}
|
|
|
|
|
|
ObjectCreated = FALSE;
|
|
|
|
|
|
Status = SampDsDeleteObject(pContainer);
|
|
if (Status != STATUS_SUCCESS)
|
|
{
|
|
printf("Delete Container Failed\n");
|
|
goto Error;
|
|
}
|
|
|
|
Status = SampMaybeEndDsTransaction(FALSE);
|
|
|
|
if (Status != STATUS_SUCCESS)
|
|
{
|
|
printf("SampMaybeEndDsTransaction error = 0x%lx\n", Status);
|
|
goto Error;
|
|
}
|
|
|
|
ContainerCreated = FALSE;
|
|
|
|
printf("DSLAYER TEST PASSED\n");
|
|
|
|
|
|
Cleanup:
|
|
|
|
return Status;
|
|
|
|
Error:
|
|
|
|
if (ObjectCreated)
|
|
SampDsDeleteObject(pDsName);
|
|
|
|
if (ContainerCreated)
|
|
SampDsDeleteObject(pContainer);
|
|
|
|
SampMaybeEndDsTransaction(TRUE);
|
|
|
|
printf(" ******** TEST FAILED **********\n");
|
|
goto Cleanup;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|