NT4/private/lsa/server/ctlsarpc.c
2020-09-30 17:12:29 +02:00

15306 lines
382 KiB
C

/*++
Copyright (c) 1991 Microsoft Corporation
Module Name:
ctlsarpc.c
Abstract:
Local Security Authority Subsystem - CT for RPC interface
This test exercises the LSA API that use RPC.
Author:
Scott Birrell (ScottBi) April 26, 1991
Environment:
Revision History:
--*/
#include <lsasrvp.h>
#include "ntrpcp.h"
#include "samsrv.h"
typedef enum _USERS {
Fred,
Wilma,
Pebbles,
Barney,
Betty,
Bambam,
Dino
} USERS;
typedef struct _CT_UNKNOWN_SID_ENTRY {
PSID Sid;
UNICODE_STRING Name;
UNICODE_STRING DomainName;
BOOLEAN DomainKnown;
} CT_UNKNOWN_SID_ENTRY, *PCT_UNKNOWN_SID_ENTRY;
#define CT_UNKNOWN_SID_COUNT ((ULONG) 0x00000040)
typedef struct _CT_UNKNOWN_NAME_ENTRY {
UNICODE_STRING Name;
UNICODE_STRING DomainName;
PSID DomainSid;
BOOLEAN DomainKnown;
} CT_UNKNOWN_NAME_ENTRY, *PCT_UNKNOWN_NAME_ENTRY;
#define CT_UNKNOWN_NAME_COUNT ((ULONG) 0x00000040)
//
// Information for a SAM Domain account
//
typedef struct _CT_DOMAIN_ACCOUNT_INFO {
UNICODE_STRING Name;
ULONG Rid;
} CT_DOMAIN_ACCOUNT_INFO, *PCT_DOMAIN_ACCOUNT_INFO;
//
// Enumeration Information returned on a single call to an enumeration
// API.
//
typedef struct _CT_LSA_SINGLE_CALL_ENUM_INFO {
ULONG CountReturned;
PVOID EnumInfoReturned;
} CT_LSA_SINGLE_CALL_ENUM_INFO, *PCT_LSA_SINGLE_CALL_ENUM_INFO;
//
// Sam Account Types
//
typedef enum _CT_SAM_ACCOUNT_TYPE {
CT_SAM_USER = 1,
CT_SAM_GROUP,
CT_SAM_ALIAS
} CT_SAM_ACCOUNT_TYPE, *PCT_SAM_ACCOUNT_TYPE;
#define TstAllocatePool(IgnoredPoolType,NumberOfBytes) \
RtlAllocateHeap(RtlProcessHeap(), 0, NumberOfBytes)
#define TstDeallocatePool(Pointer) \
RtlFreeHeap(RtlProcessHeap(), 0, Pointer)
//
// Define the Bedrock domain and its inhabitants
//
// Bedrock Domain S-1-39824-21-3-17
// Fred S-1-39824-21-3-17-2
// Wilma S-1-39824-21-3-17-3
// Pebbles S-1-39824-21-3-17-4
// Dino S-1-39824-21-3-17-5
// Barney S-1-39824-21-3-17-6
// Betty S-1-39824-21-3-17-7
// Bambam S-1-39824-21-3-17-8
// Flintstone S-1-39824-21-3-17-9
// Rubble S-1-39824-21-3-17-10
// Adult S-1-39824-21-3-17-11
// Child S-1-39824-21-3-17-12
// Neanderthol S-1-39824-21-3-17-13
//
#define BEDROCK_AUTHORITY {0,0,0,0,155,144}
#define BEDROCKA_AUTHORITY {0,0,0,0,155,145}
#define BEDROCKB_AUTHORITY {0,0,0,0,155,146}
#define BEDROCKC_AUTHORITY {0,0,0,0,155,147}
#define BEDROCKD_AUTHORITY {0,0,0,0,155,148}
#define BEDROCKE_AUTHORITY {0,0,0,0,155,149}
#define BEDROCK_SUBAUTHORITY_0 0x00000015L
#define BEDROCK_SUBAUTHORITY_1 0x00000003L
#define BEDROCK_SUBAUTHORITY_2 0x00000011L
#define BEDROCKA_SUBAUTHORITY_0 0x00000015L
#define BEDROCKA_SUBAUTHORITY_1 0x00000003L
#define BEDROCKA_SUBAUTHORITY_2 0x00000111L
#define BEDROCKB_SUBAUTHORITY_0 0x00000015L
#define BEDROCKB_SUBAUTHORITY_1 0x00000003L
#define BEDROCKB_SUBAUTHORITY_2 0x00000211L
#define BEDROCKC_SUBAUTHORITY_0 0x00000015L
#define BEDROCKC_SUBAUTHORITY_1 0x00000003L
#define BEDROCKC_SUBAUTHORITY_2 0x00000311L
#define BEDROCKD_SUBAUTHORITY_0 0x00000015L
#define BEDROCKD_SUBAUTHORITY_1 0x00000003L
#define BEDROCKD_SUBAUTHORITY_2 0x00000411L
#define BEDROCKE_SUBAUTHORITY_0 0x00000015L
#define BEDROCKE_SUBAUTHORITY_1 0x00000003L
#define BEDROCKE_SUBAUTHORITY_2 0x00000511L
#define FRED_RID 0x00000002L
#define WILMA_RID 0x00000003L
#define PEBBLES_RID 0x00000004L
#define DINO_RID 0x00000005L
#define BARNEY_RID 0x00000006L
#define BETTY_RID 0x00000007L
#define BAMBAM_RID 0x00000008L
#define FLINTSTONE_RID 0x00000009L
#define RUBBLE_RID 0x0000000AL
#define ADULT_RID 0x0000000BL
#define CHILD_RID 0x0000000CL
#define NEANDERTHOL_RID 0x0000000DL
PSID BedrockDomainSid;
PSID BedrockADomainSid;
PSID BedrockBDomainSid;
PSID BedrockCDomainSid;
PSID BedrockDDomainSid;
PSID BedrockEDomainSid;
PSID FredSid;
PSID WilmaSid;
PSID PebblesSid;
PSID DinoSid;
PSID BarneySid;
PSID BettySid;
PSID BambamSid;
PSID FlintstoneSid;
PSID RubbleSid;
PSID AdultSid;
PSID ChildSid;
PSID NeandertholSid;
UNICODE_STRING BedrockDomainName;
UNICODE_STRING BedrockADomainName;
UNICODE_STRING BedrockBDomainName;
UNICODE_STRING BedrockCDomainName;
UNICODE_STRING BedrockDDomainName;
UNICODE_STRING BedrockEDomainName;
UNICODE_STRING FredName;
UNICODE_STRING WilmaName;
UNICODE_STRING PebblesName;
UNICODE_STRING DinoName;
UNICODE_STRING BarneyName;
UNICODE_STRING BettyName;
UNICODE_STRING BambamName;
UNICODE_STRING FlintstoneName;
UNICODE_STRING RubbleName;
UNICODE_STRING AdultName;
UNICODE_STRING ChildName;
UNICODE_STRING NeandertholName;
//
// Define various constants specific to this test.
//
#define CT_PAGED_POOL ((ULONG) 0x00008000L)
#define CT_NON_PAGED_POOL ((ULONG) 0x00003000L)
#define CT_MIN_WORKING_SET ((ULONG) 0x00000500L)
#define CT_MAX_WORKING_SET ((ULONG) 0x00004000L)
#define CT_TRUSTED_POSIX_OFFSET ((ULONG) 0x00004444L)
#define CT_TRUSTED_CONTROLLER_COUNT ((ULONG) 0x00000004L)
#define CT_ACCOUNT_DOMAIN_RID ((ULONG) 0x00008128L)
#define CT_PRIMARY_DOMAIN_RID (CT_ACCOUNT_DOMAIN_RID + 1)
OBJECT_ATTRIBUTES ObjectAttributes;
SECURITY_QUALITY_OF_SERVICE SecurityQualityOfService;
QUOTA_LIMITS QuotaLimitsLsa;
LSA_HANDLE PolicyHandle = NULL;
QUOTA_LIMITS QuotaLimitsGetFred;
QUOTA_LIMITS QuotaLimitsSetFred;
POLICY_AUDIT_LOG_INFO FredPolicyAuditLogInfo;
POLICY_AUDIT_EVENTS_INFO FredPolicyAuditEventsInfo;
POLICY_PRIMARY_DOMAIN_INFO FredPolicyPrimaryDomainInfo;
POLICY_PD_ACCOUNT_INFO FredPolicyPdAccountInfo;
POLICY_ACCOUNT_DOMAIN_INFO FredPolicyAccountDomainInfo;
POLICY_LSA_SERVER_ROLE_INFO FredPolicyLsaServerRoleInfo;
POLICY_REPLICA_SOURCE_INFO FredPolicyReplicaSourceInfo;
POLICY_DEFAULT_QUOTA_INFO FredPolicyDefaultQuotaInfo;
POLICY_MODIFICATION_INFO FredPolicyModificationInfo;
typedef struct _CT_SECRET_INFO {
UNICODE_STRING SecretName;
UNICODE_STRING CurrentValue;
UNICODE_STRING OldValue;
PUNICODE_STRING ReturnedCurrentValue;
PUNICODE_STRING ReturnedOldValue;
} CT_SECRET_INFO, *PCT_SECRET_INFO;
CT_SECRET_INFO SecretInfoFred;
CT_SECRET_INFO SecretInfoWilma;
CT_SECRET_INFO SecretInfoPebbles;
CT_SECRET_INFO SecretInfoDino;
CT_SECRET_INFO SecretInfoBarney;
ACCESS_MASK DesiredAccessFred;
ACCESS_MASK DesiredAccessWilma;
ACCESS_MASK DesiredAccessPebbles;
ACCESS_MASK DesiredAccessDino;
ACCESS_MASK DesiredAccessBarney;
ACCESS_MASK DesiredAccessBedrockA;
ACCESS_MASK DesiredAccessBedrockB;
ACCESS_MASK DesiredAccessBedrockC;
ACCESS_MASK DesiredAccessBedrockD;
ACCESS_MASK DesiredAccessBedrockE;
LSA_HANDLE AccountHandleFred;
LSA_HANDLE AccountHandleWilma;
LSA_HANDLE AccountHandlePebbles;
LSA_HANDLE AccountHandleDino;
LSA_HANDLE AccountHandleBarney;
LSA_HANDLE AccountHandleFred2;
LSA_HANDLE AccountHandleWilma2;
LSA_HANDLE AccountHandlePebbles2;
LSA_HANDLE AccountHandleDino2;
LSA_HANDLE AccountHandleFred3;
LSA_HANDLE AccountHandleFredOpen;
LSA_HANDLE AccountHandleWilmaOpen;
LSA_HANDLE AccountHandlePebblesOpen;
LSA_HANDLE AccountHandleDinoOpen;
PPRIVILEGE_SET PrivilegesAddFred;
PPRIVILEGE_SET PrivilegesEnumFred;
PPRIVILEGE_SET PrivilegesRemoveFred;
PULONG BadAddress = (PULONG) 0xefefefef;
LSA_TRUST_INFORMATION TrustedDomainInfoBedrockA;
LSA_TRUST_INFORMATION TrustedDomainInfoBedrockB;
LSA_TRUST_INFORMATION TrustedDomainInfoBedrockC;
LSA_TRUST_INFORMATION TrustedDomainInfoBedrockD;
LSA_TRUST_INFORMATION TrustedDomainInfoBedrockE;
LSA_HANDLE TrustedDomainHandleBedrockA;
LSA_HANDLE TrustedDomainHandleBedrockB;
LSA_HANDLE TrustedDomainHandleBedrockC;
LSA_HANDLE TrustedDomainHandleBedrockD;
LSA_HANDLE TrustedDomainHandleBedrockE;
LSA_HANDLE TrustedDomainHandleBedrockA2;
LSA_HANDLE TrustedDomainHandleBedrockB2;
LSA_HANDLE TrustedDomainHandleBedrockC2;
LSA_HANDLE TrustedDomainHandleBedrockD2;
LSA_HANDLE TrustedDomainHandleBedrockA3;
LSA_HANDLE TrustedDomainHandleBedrockAOpen;
LSA_HANDLE TrustedDomainHandleBedrockBOpen;
LSA_HANDLE TrustedDomainHandleBedrockCOpen;
LSA_HANDLE TrustedDomainHandleBedrockDOpen;
LSA_HANDLE SecretHandleFred;
LSA_HANDLE SecretHandleWilma;
LSA_HANDLE SecretHandlePebbles;
LSA_HANDLE SecretHandleDino;
LSA_HANDLE SecretHandleBarney;
LSA_HANDLE SecretHandleFred2;
LSA_HANDLE SecretHandleWilma2;
LSA_HANDLE SecretHandlePebbles2;
LSA_HANDLE SecretHandleDino2;
LSA_HANDLE SecretHandleFred3;
LSA_HANDLE SecretHandleFredOpen;
LSA_HANDLE SecretHandleWilmaOpen;
LSA_HANDLE SecretHandlePebblesOpen;
LSA_HANDLE SecretHandleDinoOpen;
int Level;
BOOLEAN SidFound;
ULONG EnumNumber;
ULONG Base, Index, SearchIndex;
ULONG CountReturned;
PVOID EnumerationInformation;
ULONG EnumerationContext;
ULONG PreferedMaximumLength;
PUNICODE_STRING SystemName = NULL;
typedef struct _CT_LSA_ACCOUNT_SID_INFO {
PSID Sid;
BOOLEAN SidFound;
} CT_LSA_ACCOUNT_SID_INFO;
CT_LSA_ACCOUNT_SID_INFO AccountSidInfo[4];
typedef struct _CT_LSA_TRUSTED_DOMAIN_SID_INFO {
PSID Sid;
BOOLEAN SidFound;
} CT_LSA_TRUSTED_DOMAIN_SID_INFO;
CT_LSA_TRUSTED_DOMAIN_SID_INFO TrustedDomainSidInfo[4];
typedef struct _CT_LSA_SECRET_NAME_INFO {
UNICODE_STRING Name;
BOOLEAN NameFound;
} CT_LSA_SECRET_NAME_INFO;
CT_LSA_SECRET_NAME_INFO SecretNameInfo[4];
//
// Main is just a wrapper for the main test routines
//
//
// Globally Visible Table of Sids.
//
PSID AccountDomainSid = NULL;
PSID PrimaryDomainSid = NULL;
PSID *TrustedDomainSids = NULL;
BOOLEAN
CtLsaVariableInitialization();
BOOLEAN
CtLsaPolicyObject(
IN BOOLEAN TrustedClient
);
BOOLEAN
CtLsaPolicyOpenClose(
);
BOOLEAN
CtLsaPolicySetQueryInfo(
);
BOOLEAN
CtLsaPolicySerialNumber(
IN BOOLEAN TrustedClient
);
BOOLEAN
CtLsaPolicySetQuerySub(
IN POLICY_INFORMATION_CLASS InformationClass,
IN PVOID PolicyInformation
);
BOOLEAN
CtLsaPolicyInfoClassCompare(
IN POLICY_INFORMATION_CLASS InformationClass,
IN PVOID PolicyInformation1,
IN PVOID PolicyInformation2
);
BOOLEAN
CtLsaPolicyQueryInfoAllowed(
IN POLICY_INFORMATION_CLASS InformationClass
);
BOOLEAN
CtLsaPolicySetInfoAllowed(
IN POLICY_INFORMATION_CLASS InformationClass
);
ULONG
CtLsaPolicyInfoClassSize(
IN POLICY_INFORMATION_CLASS InformationClass
);
BOOLEAN
CtLsaPolicyAuditLogInfo();
BOOLEAN
CtLsaPolicyAuditEventsInfo();
BOOLEAN
CtLsaPolicyPrimaryDomainInfo();
BOOLEAN
CtLsaPolicyPdAccountInfo();
BOOLEAN
CtLsaPolicyAccountDomainInfo();
BOOLEAN
CtLsaPolicyLsaServerRoleInfo();
BOOLEAN
CtLsaPolicyReplicaSourceInfo();
BOOLEAN
CtLsaPolicyDefaultQuotaInfo();
BOOLEAN
CtLsaPolicyModificationInfo();
BOOLEAN
CtLsaAccountObject(
IN BOOLEAN TrustedClient
);
BOOLEAN
CtLsaAccountCreate(
);
BOOLEAN
CtLsaAccountOpenClose(
);
BOOLEAN
CtLsaAccountPrivileges(
);
BOOLEAN
CtLsaAccountQuotaLimits(
);
BOOLEAN
CtLsaAccountSystemAccess(
);
BOOLEAN
CtLsaAccountEnumeration(
);
BOOLEAN
CtLsaAccountDelete(
);
BOOLEAN
CtLsaTrustedDomainObject(
IN BOOLEAN TrustedClient
);
BOOLEAN
CtLsaTrustedDomainCreate(
);
BOOLEAN
CtLsaTrustedDomainOpenClose(
);
BOOLEAN
CtLsaTrustedDomainSetQueryInfo(
);
BOOLEAN
CtLsaTrustedDomainAccountInfo(
);
BOOLEAN
CtLsaTrustedDomainControllersInfo(
);
BOOLEAN
CtLsaTrustedDomainPosixOffsetInfo(
);
BOOLEAN
CtLsaTrustedDomainSetQuerySub(
IN TRUSTED_INFORMATION_CLASS InformationClass,
IN PVOID TrustedDomainInformation
);
BOOLEAN
CtLsaTrustedDomainInfoClassCompare(
IN TRUSTED_INFORMATION_CLASS InformationClass,
IN PVOID TrustedDomainInformation1,
IN PVOID TrustedDomainInformation2
);
BOOLEAN
CtLsaTrustedDomainQueryInfoAllowed(
IN TRUSTED_INFORMATION_CLASS InformationClass
);
BOOLEAN
CtLsaTrustedDomainSetInfoAllowed(
IN TRUSTED_INFORMATION_CLASS InformationClass
);
BOOLEAN
CtLsaTrustedDomainEnumeration(
);
BOOLEAN
CtLsaTrustedDomainDelete(
);
VOID
CtLsaTrustedDomainSetInfo(
IN PSID DomainSid,
IN PUNICODE_STRING DomainName,
OUT PLSA_TRUST_INFORMATION TrustedDomainInfo
);
BOOLEAN
CtLsaSecretObject(
IN BOOLEAN TrustedClient
);
BOOLEAN
CtLsaSecretCreate(
);
BOOLEAN
CtLsaSecretOpenClose(
);
BOOLEAN
CtLsaSecretSetQueryValue(
);
BOOLEAN
CtLsaSecretEnumeration(
);
BOOLEAN
CtLsaSecretSetTimes(
);
BOOLEAN
CtLsaSecretDelete(
);
BOOLEAN
CtLsaSecretCleanup(
);
NTSTATUS
CtSecretSetInfo(
IN PUCHAR SecretNameText,
IN PUCHAR CurrentValueText,
IN PUCHAR OldValueText,
OUT PCT_SECRET_INFO SecretInformation
);
BOOLEAN
CtLsaGeneralAPI(
IN OPTIONAL PUNICODE_STRING WorkstationName
);
BOOLEAN
CtLsaLookupSids(
IN OPTIONAL PUNICODE_STRING WorkstationName
);
BOOLEAN
CtLsaLookupSidsInSamDomain(
IN OPTIONAL PUNICODE_STRING WorkstationName,
IN PUNICODE_STRING DomainControllerName,
IN PUNICODE_STRING SamDomainName,
IN CT_SAM_ACCOUNT_TYPE SamAccountType
);
BOOLEAN
CtLsaLookupNames(
IN PUNICODE_STRING WorkstationName
);
BOOLEAN
CtLsaLookupNamesInSamDomain(
IN OPTIONAL PUNICODE_STRING WorkstationName,
IN PUNICODE_STRING DomainControllerName,
IN PUNICODE_STRING SamDomainName,
IN CT_SAM_ACCOUNT_TYPE SamAccountType
);
BOOLEAN
CtLsaLookupConfigure(
IN OPTIONAL PUNICODE_STRING WorkstationName,
IN OPTIONAL PUNICODE_STRING PrimaryDomainName,
IN PSID PrimaryDomainSid,
IN PUNICODE_STRING PrimaryDomainCtrlrNames,
IN ULONG PrimaryDomainCtrlrCount,
IN OPTIONAL PUNICODE_STRING TrustedDomainNames,
IN PSID *TrustedDomainSids,
IN ULONG TrustedDomainCount,
IN PUNICODE_STRING TrustedDomainCtrlrNames,
IN ULONG TrustedDomainCtrlrTotal,
IN PULONG TrustedDomainCtrlrCounts
);
BOOLEAN
CtLsaLookupConfigureWksta(
IN PUNICODE_STRING WorkstationName,
IN PUNICODE_STRING PrimaryDomainName,
IN PUNICODE_STRING PrimaryDomainSid,
IN PUNICODE_STRING PrimaryDomainCtrlrNames,
IN ULONG PrimaryDomainCtrlrCount
);
BOOLEAN
CtLsaLookupConfigurePDC(
IN PUNICODE_STRING PrimaryDomainName,
IN PSID PrimaryDomainSid,
IN PUNICODE_STRING PrimaryDomainCtrlrNames,
IN ULONG PrimaryDomainCtrlrCount,
IN PUNICODE_STRING TrustedDomainNames,
IN PSID *TrustedDomainSids,
IN ULONG TrustedDomainCount,
IN PUNICODE_STRING TrustedDomainCtrlrNames,
IN ULONG TrustedDomainCtrlrTotal,
IN PULONG TrustedDomainCtrlrCounts
);
BOOLEAN
CtLsaGeneraLookupConfigureTDC(
IN PUNICODE_STRING TrustedDomainNames,
IN PSID *TrustedDomainSids,
IN ULONG TrustedDomainCount,
IN PUNICODE_STRING TrustedDomainCtrlrNames,
IN ULONG TrustedDomainCtrlrTotal,
IN PULONG TrustedDomainCtrlrCounts
);
NTSTATUS
CtLsaLookupConfigureTrustedDomain(
IN LSA_HANDLE PolicyHandle,
IN PLSA_TRUST_INFORMATION TrustedDomainInformation,
IN PTRUSTED_CONTROLLERS_INFO TrustedControllersInfo
);
BOOLEAN
CtLsaLookupPrintConfiguration(
IN PUNICODE_STRING WorkstationName,
IN PUNICODE_STRING PrimaryDomainName,
IN PUNICODE_STRING PrimaryDomainCtrlrNames,
IN ULONG PrimaryDomainCtrlrCount,
IN PUNICODE_STRING TrustedDomainNames,
IN ULONG TrustedDomainCount,
IN PUNICODE_STRING TrustedDomainCtrlrNames,
IN PULONG TrustedDomainCtrlrCounts
);
BOOLEAN
CtLsaGeneralConstructSids(
OUT PSID *AccountDomainSid,
OUT PSID *PrimaryDomainSid,
OUT PSID **TrustedDomainSids,
IN ULONG TrustedDomainCount
);
BOOLEAN
CtLsaGeneralSetQuerySecurityObject(
IN OPTIONAL PUNICODE_STRING WorkstationName
);
BOOLEAN
CtLsaGeneralEnumeratePrivileges(
IN OPTIONAL PUNICODE_STRING WorkstationName
);
BOOLEAN
CtLsaGeneralClearAuditLog(
IN OPTIONAL PUNICODE_STRING WorkstationName
);
NTSTATUS
CtLsaSetQuerySecurityObjectSub(
IN LSA_HANDLE ObjectHandle,
IN PSID NewOwnerSid
);
BOOLEAN
CtLsaGeneralInitUnknownSid(
IN PSID Sid,
OUT PCT_UNKNOWN_SID_ENTRY UnknownSidInfo,
IN BOOLEAN DomainKnown
);
VOID
CtLsaGeneralInitUnknownName(
IN PUNICODE_STRING Name,
IN OPTIONAL PUNICODE_STRING DomainName,
IN OPTIONAL PSID DomainSid,
OUT PCT_UNKNOWN_NAME_ENTRY UnknownNameInfo,
IN BOOLEAN DomainKnown
);
NTSTATUS
CtLsaGeneralSidToLogicalNameObject(
IN PSID Sid,
OUT PUNICODE_STRING LogicalName
);
BOOLEAN
CtLsaGeneralVerifyTrustInfo(
IN PLSA_TRUST_INFORMATION TrustInformation,
IN PLSAP_WELL_KNOWN_SID_ENTRY WellKnownSidEntry
);
BOOLEAN
CtLsaGeneralBuildSid(
PSID *Sid,
PSID DomainSid,
ULONG RelativeId
);
VOID
CtLsaInitObjectAttributes(
IN POBJECT_ATTRIBUTES ObjectAttributes,
IN PSECURITY_QUALITY_OF_SERVICE SecurityQualityOfService
);
BOOLEAN
CtEqualQuotaLimits(
IN PQUOTA_LIMITS QuotaLimits1,
IN PQUOTA_LIMITS QuotaLimits2
);
NTSTATUS
CtRtlConvertSidToUnicodeString(
IN PSID Sid,
OUT PUNICODE_STRING UnicodeString
);
VOID
CtLsaUsage(
);
VOID
lsassmain(
);
/////////////////////////////////////////////////////////////////////////////
// //
// LSA Component Test for RPC API - main program //
// //
/////////////////////////////////////////////////////////////////////////////
#define CT_MAX_CONTROLLERS ((ULONG) 0x00000080)
#define CT_MAX_PRIMARY_DOMAIN_CTRLRS ((ULONG) 0x00000020)
#define CT_MAX_TRUSTED_DOMAINS ((ULONG) 0x00000020)
#define CT_MAX_TRUSTED_DOMAIN_CTRLRS ((ULONG) 0x00000020)
VOID _CRTAPI1
main (argc, argv)
int argc;
char **argv;
{
int Index;
int IterationCount, Count;
ULONG LongCount;
BOOLEAN Forever;
NTSTATUS Status = STATUS_SUCCESS;
BOOLEAN BooleanStatus = TRUE;
ANSI_STRING WorkstationNameAnsi;
ANSI_STRING TrustedDomainNameAnsi;
ANSI_STRING TrustedDomainCtrlrNameAnsi;
UNICODE_STRING WorkstationName;
UNICODE_STRING PrimaryDomainCtrlrNames[CT_MAX_PRIMARY_DOMAIN_CTRLRS];
UNICODE_STRING TrustedDomainNames[CT_MAX_TRUSTED_DOMAINS];
UNICODE_STRING TrustedDomainCtrlrNames[CT_MAX_TRUSTED_DOMAIN_CTRLRS];
BOOLEAN WorkstationSpecified = FALSE;
BOOLEAN PrimaryDomainSpecified = FALSE;
BOOLEAN TrustedDomainsSpecified = FALSE;
BOOLEAN SamDatabasesAlreadyLoaded = FALSE;
ULONG PrimaryDomainCtrlrCount;
ULONG TrustedDomainCount;
ULONG TrustedDomainCtrlrTotal;
ULONG TrustedDomainCtrlrCounts[CT_MAX_TRUSTED_DOMAINS];
BOOLEAN TrustedDomainControllerKeywordExpected = FALSE;
BOOLEAN ConfigureSystem = FALSE;
BOOLEAN RunAllTests = FALSE;
BOOLEAN RunGeneralApiTests = FALSE;
BOOLEAN RunLookupApiTests = FALSE;
BOOLEAN RunPolicyObjectApiTests = FALSE;
BOOLEAN RunAccountObjectApiTests = FALSE;
BOOLEAN RunTrustedDomainObjectApiTests = FALSE;
BOOLEAN RunSecretObjectApiTests = FALSE;
BOOLEAN TrustedClient = FALSE;
BOOLEAN RunLsaInit = FALSE;
RtlZeroMemory( &WorkstationName,sizeof(UNICODE_STRING) );
RtlZeroMemory(
PrimaryDomainCtrlrNames,
sizeof(UNICODE_STRING) * CT_MAX_PRIMARY_DOMAIN_CTRLRS
);
RtlZeroMemory(
TrustedDomainNames,
sizeof(UNICODE_STRING) * CT_MAX_TRUSTED_DOMAINS
);
RtlZeroMemory(
TrustedDomainCtrlrNames,
sizeof(UNICODE_STRING) * CT_MAX_TRUSTED_DOMAIN_CTRLRS
);
RtlZeroMemory(
TrustedDomainCtrlrCounts,
sizeof(ULONG) * CT_MAX_TRUSTED_DOMAINS
);
if (argc < 1) {
CtLsaUsage();
return;
}
//
// Parse the parameters (if any). Assume that a parameter beginning
// \\ is the server name and a parameter beginning -l is the level
//
Level = 1;
IterationCount = 0;
PrimaryDomainCtrlrCount = 0;
TrustedDomainCount = 0;
TrustedDomainCtrlrTotal = 0;
if (argc >= 2) {
for(Index = 1; Index < argc; Index++) {
if (strncmp(argv[Index], "-level", 6) == 0) {
Level = atoi(argv[Index]+2);
if ((Level < 1) || (Level > 2)) {
DbgPrint("Level not 1 or 2\n");
DbgPrint("Test abandoned\n");
BooleanStatus = FALSE;
break;
}
} else if (strncmp(argv[Index], "-cfg", 4) == 0) {
ConfigureSystem = TRUE;
} else if (strncmp(argv[Index], "-c", 2) == 0) {
IterationCount = atoi(argv[Index]+2);
if (IterationCount < 0) {
DbgPrint("Iteration Count < 0\n");
DbgPrint("Test abandoned\n");
BooleanStatus = FALSE;
break;
}
} else if (strncmp(argv[Index], "-wks", 4) == 0) {
//
// The Workstation Name keyword has been specified. Save
// its name for LSA Configuration.
//
if (Index + 1 >= argc) {
DbgPrint("Workstation name missing\n");
BooleanStatus = FALSE;
break;
}
Index++;
if (strncmp(argv[Index], "-", 1) == 0) {
continue;
}
if (strncmp(argv[Index], "\\\\", 2) != 0) {
DbgPrint(".. Invalid workstation name\n");
BooleanStatus = FALSE;
break;
}
//
// A workstation name is specified. Construct a Unicode
// String containing the specified name.
//
WorkstationSpecified = TRUE;
RtlInitString( &WorkstationNameAnsi, argv[Index] );
Status = RtlAnsiStringToUnicodeString(
&WorkstationName,
&WorkstationNameAnsi,
TRUE
);
if (!NT_SUCCESS(Status)) {
DbgPrint(
"LSA RPC CT - Failed building Workstation Name\n"
"... RtlAnsiStringToUnicodeString returned 0x%lx\n",
Status
);
DbgPrint("LSA RPC CT - Whole test abandoned\n");
break;
}
} else if (strncmp(argv[Index], "-pdc", 4) == 0) {
//
// The Primary Domain Controller Keyword has been specified.
//
if (Index + 1 >= argc) {
DbgPrint("No Primary Domain Controllers given\n");
BooleanStatus = FALSE;
break;
}
Index++;
if (strncmp(argv[Index], "-", 1) == 0) {
DbgPrint("No Primary Domain Controllers given\n");
BooleanStatus = FALSE;
break;
}
//
// One or more Primary Domain Controller names have been specified.
// Since the Primary Domain is also trusted, save the names
// in the Trusted Domain Names array.
//
PrimaryDomainCtrlrCount = 0;
while ((Index < argc) && strncmp(argv[Index], "-", 1) != 0) {
if (strncmp(argv[Index], "\\\\", 2) != 0) {
DbgPrint(".. Invalid Primary Domain Ctrlr Name\n");
BooleanStatus = FALSE;
break;
}
RtlInitString( &TrustedDomainCtrlrNameAnsi, argv[Index] );
Status = RtlAnsiStringToUnicodeString(
&TrustedDomainCtrlrNames[ TrustedDomainCtrlrTotal ],
&TrustedDomainCtrlrNameAnsi,
TRUE
);
if (!NT_SUCCESS(Status)) {
DbgPrint("LSA RPC CT - failed 0x%lx building Primary", Status);
DbgPrint(" Domain Controller Name\n");
DbgPrint("LSA RPC CT - Whole test abandoned\n");
BooleanStatus = FALSE;
break;
}
PrimaryDomainCtrlrCount++;
TrustedDomainCtrlrTotal++;
Index++;
}
Index--;
TrustedDomainCtrlrCounts[0] = PrimaryDomainCtrlrCount;
} else if (strncmp(argv[Index], "-pd", 3) == 0) {
//
// The Primary Domain Name Keyword has been specified.
//
if (Index + 1 >= argc) {
DbgPrint("Primary Domain name missing\n");
BooleanStatus = FALSE;
break;
}
Index++;
if (strncmp(argv[Index], "-", 1) == 0) {
continue;
}
//
// A Primary Domain name has been specified. Save the name.
// Also, save the name in slot 0 of the TrustedDomainNames
// array.
//
PrimaryDomainSpecified = TRUE;
RtlInitString( &TrustedDomainNameAnsi, argv[Index] );
Status = RtlAnsiStringToUnicodeString(
TrustedDomainNames,
&TrustedDomainNameAnsi,
TRUE
);
if (!NT_SUCCESS(Status)) {
DbgPrint("LSA RPC CT - failed 0x%lx building Primary", Status);
DbgPrint(" Domain Name\n");
DbgPrint("LSA RPC CT - Whole test abandoned\n");
break;
}
TrustedDomainCount++;
} else if (strncmp(argv[Index], "-tdc", 4) == 0) {
//
// A Trusted Domain Controller Keyword has been specified.
// Verify that one is expected.
//
if (!TrustedDomainControllerKeywordExpected) {
BooleanStatus = FALSE;
DbgPrint(
"-tdc keyword specified when not expected"
);
}
TrustedDomainControllerKeywordExpected = FALSE;
if (Index + 1 >= argc) {
DbgPrint("No Trusted Domain Controllers given\n");
BooleanStatus = FALSE;
break;
}
Index++;
if (strncmp(argv[Index], "-", 1) == 0) {
DbgPrint("No Trusted Domain Controllers given\n");
BooleanStatus = FALSE;
break;
}
//
// One or more Trusted Domain Controller names have been specified.
// Save the names.
//
while ((Index < argc) && strncmp(argv[Index], "-", 1) != 0) {
if (strncmp(argv[Index], "\\\\", 2) != 0) {
DbgPrint(".. Invalid Trusted Domain Ctrlr Name\n");
BooleanStatus = FALSE;
break;
}
RtlInitString( &TrustedDomainCtrlrNameAnsi, argv[Index] );
Status = RtlAnsiStringToUnicodeString(
&TrustedDomainCtrlrNames[ TrustedDomainCtrlrTotal ],
&TrustedDomainCtrlrNameAnsi,
TRUE
);
if (!NT_SUCCESS(Status)) {
DbgPrint(
"LSA RPC CT - failed 0x%lx building Trusted"
" Domain Controller Name\n"
"LSA RPC CT - Whole test abandoned\n",
Status
);
BooleanStatus = FALSE;
break;
}
TrustedDomainCtrlrTotal++;
TrustedDomainCtrlrCounts[TrustedDomainCount - 1]++;
Index++;
}
Index--;
} else if (strncmp(argv[Index], "-td", 3) == 0) {
//
// A Trusted Domain Name Keyword has been specified.
// One of these has to be specified for each Trusted Domain
// since each -td <TrustedDomainName> must be followed
// by -tdc [\\<TrustedDomainCtrlrName>]+
//
//
// Verify that the Primary Domain has already been specified.
// This is a Trusted Domain and it must be specified
// first. The PrimaryDomainSpecified flag should be set
// and the TrustedDomainCount should be 1.
//
if ((!PrimaryDomainSpecified) || TrustedDomainCount != 1) {
DbgPrint(
"Primary Domain must be specified before\n"
"Trusted Domains"
);
BooleanStatus = FALSE;
break;
}
if (Index + 1 >= argc) {
DbgPrint("Trusted Domain name missing\n");
BooleanStatus = FALSE;
break;
}
Index++;
if (strncmp(argv[Index], "-", 1) == 0) {
continue;
}
//
// A Trusted Domain Name is expected. Save it in the
// next available Slot in the TrustedDomainNames array.
// Note that Slot 0 is always reserved for the Primary
// Domain Name (the Primary Domain is always trusted by
// itself).
//
RtlInitString( &TrustedDomainNameAnsi, argv[Index] );
Status = RtlAnsiStringToUnicodeString(
&TrustedDomainNames[ TrustedDomainCount ],
&TrustedDomainNameAnsi,
TRUE
);
if (!NT_SUCCESS(Status)) {
DbgPrint(
"LSA RPC CT - failed 0x%lx building Trusted"
" Domain Controller Name\n"
"LSA RPC CT - Whole test abandoned\n",
Status
);
BooleanStatus = FALSE;
break;
}
TrustedDomainCount++;
TrustedDomainsSpecified = TRUE;
TrustedDomainControllerKeywordExpected = TRUE;
} else if (strncmp(argv[Index], "-sdb", 4) == 0) {
SamDatabasesAlreadyLoaded = TRUE;
} else if (strncmp(argv[Index], "-all", 4) == 0) {
RunAllTests = TRUE;
} else if (strncmp(argv[Index], "-general", 8) == 0) {
RunGeneralApiTests = TRUE;
} else if (strncmp(argv[Index], "-policy", 7) == 0) {
RunPolicyObjectApiTests = TRUE;
} else if (strncmp(argv[Index], "-account", 8) == 0) {
RunAccountObjectApiTests = TRUE;
} else if (strncmp(argv[Index], "-domain", 7) == 0) {
RunTrustedDomainObjectApiTests = TRUE;
} else if (strncmp(argv[Index], "-secret", 7) == 0) {
RunSecretObjectApiTests = TRUE;
} else if (strncmp(argv[Index], "-lookup", 7) == 0) {
RunLookupApiTests = TRUE;
} else if (strncmp(argv[Index], "-lsainit", 8) == 0) {
RunLsaInit = TRUE;
TrustedClient = TRUE;
} else {
CtLsaUsage();
BooleanStatus = FALSE;
break;
}
}
}
//
// If the parameter validation was unsuccessful, quit.
//
if (!NT_SUCCESS(Status)) {
BooleanStatus = FALSE;
}
if (!BooleanStatus) {
goto MainError;
}
//
// ctlsarpc command parameters have been validated. Before running
// tests, do normal LSA initialization if requested. This is run
// if and only if we are substituting for the LSA process (lsass.exe).
//
if (RunLsaInit) {
lsassmain();
}
//
// Initialize the Well Known Sids table.
//
if (!LsaIInitializeWellKnownSids( &WellKnownSids )) {
return;
}
//
// Construct a Table of Sids for allocation as the Account Domain,
// Primary Domain and other Trusted Domain Sids..
//
if (!CtLsaGeneralConstructSids(
&AccountDomainSid,
&PrimaryDomainSid,
&TrustedDomainSids,
TrustedDomainCount
)) {
goto MainError;
}
//
// Perform Configuration for the Lookup tests. Note that the
// Primary Domain Name and Controllers appear first in the
// TrustedDomainNames and TrustedDomainCtrlrNames arrays.
// The Trusted Domain Count includes 1 for the Primary Domain.
// The Trusted Domain Ctrlr Count includes the Primary Domain
// Ctrlr Count.
//
if (ConfigureSystem) {
if (!CtLsaLookupConfigure(
&WorkstationName,
&TrustedDomainNames[0],
PrimaryDomainSid,
&TrustedDomainCtrlrNames[0],
PrimaryDomainCtrlrCount,
TrustedDomainNames,
TrustedDomainSids,
TrustedDomainCount,
TrustedDomainCtrlrNames,
TrustedDomainCtrlrTotal,
TrustedDomainCtrlrCounts
)) {
goto MainError;
}
//
// If sdb flag not specified, remind caller to run bldsam2 on machines
// being configured.
//
if (!SamDatabasesAlreadyLoaded) {
DbgPrint(
"LSA RPC CT: Configuration for Lookup Sid/name tests complete\n"
"The -sdb flag was not specified - You must now run bldsam2\n"
"to load the SAM Databases for each machine involved\n"
);
goto MainFinish;
}
}
DbgPrint("LSA RPC CT - Test Begins\n");
//
// Setup test domains etc.
//
if (!CtLsaVariableInitialization()) {
DbgPrint("LSA RPC CT - Test Variable Initialization failed\n");
DbgPrint("Test abandoned\n");
return;
}
Forever = FALSE;
if (IterationCount == 0) {
IterationCount = 1;
Forever = TRUE;
}
for (Count = 0, LongCount =1; Count < IterationCount; Count++, LongCount++) {
if (LongCount == 0xffffffff) {
LongCount = 0;
}
DbgPrint("Iteration %d begins\n", LongCount);
if (RunAllTests || RunGeneralApiTests) {
if (!CtLsaGeneralAPI( &WorkstationName )) {
DbgPrint( "LSA RPC CT - General API test failed\n" );
}
}
if (RunLookupApiTests) {
if (!CtLsaLookupSids( &WorkstationName )) {
DbgPrint( "LSA RPC CT - Lookup Sids Tests failed\n" );
}
if (!CtLsaLookupNames( &WorkstationName )) {
DbgPrint( "LSA RPC CT - Lookup Names Tests failed\n" );
}
}
if (RunAllTests || RunPolicyObjectApiTests) {
if (!CtLsaPolicyObject(TrustedClient)) {
DbgPrint("LSA RPC CT - Policy Object API test failed\n");
}
}
if (RunAllTests || RunAccountObjectApiTests) {
if (!CtLsaAccountObject(TrustedClient)) {
DbgPrint("LSA RPC CT - Account Object API test failed\n");
}
}
if (RunAllTests || RunTrustedDomainObjectApiTests) {
if (!CtLsaTrustedDomainObject(TrustedClient)) {
DbgPrint(
"LSA RPC CT - Trusted Domain Object API test failed\n"
);
}
}
if (RunAllTests || RunSecretObjectApiTests) {
if (!CtLsaSecretObject(TrustedClient)) {
DbgPrint( "LSA RPC CT - Secret Object API test failed\n" );
}
}
if (Forever) {
Count = 0;
}
}
DbgPrint("LSA RPC CT - Test Ends\n");
MainFinish:
return;
MainError:
goto MainFinish;
}
VOID
CtLsaUsage(
)
/*++
Routine Description:
This function prints out the usage of the ctlsarpc command.
Arguments:
None.
Return Values:
None
--*/
{
DbgPrint(
"Usage: ctlsarpc [-level<Level]\n"
" [-c<IterationCount>]\n"
" [-policy][-account][-domain][-secret][-all]\n"
" [-cfg]\n"
" [-wks \\<WorkstationName> ]\n"
" [-pd <PrimaryDomainName> ]\n"
);
DbgPrint(
" [-pdc [\\<PDCName>]+]\n"
" [-td <TrustedDomainName>]\n"
" [-tdc [\\<TDCName>]+]\n"
" [-sdb]\n\n"
);
DbgPrint(
"where <Level> = 1 for normal test\n"
" <Level> = 2 for full test with exception cases\n"
" <IterationCount = iteration count (0 = forever)\n"
" -policy = Run Policy Object Tests\n"
" -account = Run Account Object Tests\n"
);
DbgPrint(
" -domain = Run TrustedDomain Object Tests\n"
" -secret = Run Secret Object Tests\n"
" -general = Run General non-object Specific Tests\n"
" -lookup = Run Lookup Sids/Names tests\n"
" -all = Run all of the above Tests (except Lookup Sids/Names\n"
);
DbgPrint(
" -cfg = Configure for Lookup Sid/Name tests\n"
" <WorkstationName> = name of workstation to\n"
" be configured for Sid/Name Lookup tests\n"
" <PrimaryDomainName> = name of Workstation's\n"
" Primary Domain\n"
);
DbgPrint(
" <PDCName> specifies a Primary Domain Controller\n"
" <TrustedDomainName> = name of a Domain that is\n"
" trusted for authentication by the PD\n"
" <TDCName> sspecifies a Trusted Domain Controller\n"
);
DbgPrint(
" -lsainit - Specifies that LSA initialization is to\n"
" be run. This is necessary for all tests involving\n"
" LsaIxx Api called by trusted callers linked to\n"
" the Security Process. If omitted, these tests\n"
" are skipped.\n"
);
}
BOOLEAN
CtLsaPolicyObject(
IN BOOLEAN TrustedClient
)
/*++
Routine Description:
This function tests the Lsa Policy Object API.
Arguments:
TrustedClient - Specifies whether Trusted Client variations
are to be run additionally. NOTE: These can only be run
with ctlsarpc -lsainit... substituted for lsass.exe
Return Value:
BOOLEAN - TRUE if successful, FALSE if any failures.
--*/
{
BOOLEAN BooleanStatus = TRUE;
LSA_HANDLE PolicyHandle = NULL;
DbgPrint("********************************************************\n");
DbgPrint("LSA RPC CT - Test Policy Object API\n");
DbgPrint("********************************************************\n");
if (!CtLsaPolicySerialNumber( TrustedClient )) {
DbgPrint("LSA RPC CT - Policy Serial Number test failed\n");
BooleanStatus = FALSE;
}
if (!CtLsaPolicyOpenClose()) {
DbgPrint("LSA RPC CT - Policy Open and Close test failed\n");
goto PolicyObjectError;
}
if (!CtLsaPolicySetQueryInfo()) {
DbgPrint("LSA RPC CT - Policy Set Query Info test failed\n");
BooleanStatus = FALSE;
}
PolicyObjectFinish:
return ( BooleanStatus );
PolicyObjectError:
BooleanStatus = FALSE;
goto PolicyObjectFinish;
}
BOOLEAN
CtLsaPolicyOpenClose(
)
/*++
Routine Description:
This function tests the opening and closing of the Policy Object
Arguments:
None.
Return Value:
BOOLEAN - TRUE if successful, FALSE if any failures.
--*/
{
NTSTATUS Status;
OBJECT_ATTRIBUTES ObjectAttributes;
SECURITY_QUALITY_OF_SERVICE SecurityQualityOfService;
LSA_HANDLE PolicyHandle[5];
ULONG Index;
DbgPrint("[1] - Test Policy Open and Close API\n");
CtLsaInitObjectAttributes(
&ObjectAttributes,
&SecurityQualityOfService
);
//
// Open 5 handles to the Policy Object
//
for (Index = 0; Index < 5; Index++) {
Status = LsaOpenPolicy(
SystemName,
&ObjectAttributes,
POLICY_VIEW_LOCAL_INFORMATION,
&PolicyHandle[Index]
);
if (!NT_SUCCESS(Status)) {
DbgPrint(
"LSA RPC CT - Policy object open handle %d failed 0x%lx\n",
Index,
Status
);
return FALSE;
}
}
//
// Close the 5 handles to the Policy Object just opened.
//
for (Index = 0; Index < 5; Index++) {
Status = LsaClose( PolicyHandle[Index] );
if (!NT_SUCCESS(Status)) {
DbgPrint(
"LSA RPC CT - Policy object close handle %d failed 0x%lx\n",
Index,
Status
);
return FALSE;
}
}
return TRUE;
}
BOOLEAN
CtLsaPolicySetQueryInfo(
)
/*++
Routine Description:
This function tests the LsaSetInformationPolicy and LsaQueryInformationPolicy
API.
Arguments:
None
Return Value:
BOOLEAN - TRUE if test is successful, else FALSE
--*/
{
BOOLEAN BooleanStatus = TRUE;
DbgPrint("[2] - Test Set and Query Info API on Policy Object\n");
BooleanStatus &= CtLsaPolicyAuditLogInfo();
BooleanStatus &= CtLsaPolicyAuditEventsInfo();
BooleanStatus &= CtLsaPolicyPrimaryDomainInfo();
BooleanStatus &= CtLsaPolicyPdAccountInfo();
BooleanStatus &= CtLsaPolicyAccountDomainInfo();
BooleanStatus &= CtLsaPolicyLsaServerRoleInfo();
BooleanStatus &= CtLsaPolicyReplicaSourceInfo();
BooleanStatus &= CtLsaPolicyDefaultQuotaInfo();
BooleanStatus &= CtLsaPolicyModificationInfo();
return(BooleanStatus);
}
BOOLEAN
CtLsaPolicySerialNumber(
IN BOOLEAN TrustedClient
)
/*++
Routine Description:
This function tests the LsaISetSerialNumberPolicy() and
LsaIGetSerialNumberPolicy() API. These are available to
Trusted Clients only.
Arguments:
TrustedClient - TRUE if client is trusted, else FALSE.
Return Values:
BOOLEAN - TRUE if test is successful, else FALSE.
--*/
{
NTSTATUS Status;
BOOLEAN BooleanStatus = TRUE;
LSAPR_HANDLE TrustedPolicyHandle = NULL;
LARGE_INTEGER SetModifiedCount, ReturnedModifiedCount;
LARGE_INTEGER SetCreationTime, ReturnedCreationTime;
DbgPrint("[3] - Test Set and Query Serial Number API on Policy Object\n");
if (!TrustedClient) {
DbgPrint("... test omitted because client is not trusted\n");
goto PolicySerialNumberFinish;
}
//
// First open a Trusted Handle to the LSA.
//
Status = LsaIOpenPolicyTrusted( &TrustedPolicyHandle );
if (!NT_SUCCESS(Status)) {
DbgPrint(
"LSA RPC CT - Get/Set Policy Serial Number Test failed\n"
"LsaIOpenPolicyTrusted returned 0x%lx\n",
Status
);
goto PolicySerialNumberError;
}
//
// Setup Database Creation Time and Serial Number.
//
Status = NtQuerySystemTime(&SetCreationTime);
if (!NT_SUCCESS(Status)) {
DbgPrint(
"LSA RPC CT - Get/Set Policy Serial Number Test failed\n"
"NtQuerySystemTime returned 0x%lx\n",
Status
);
goto PolicySerialNumberError;
}
ReturnedCreationTime = RtlConvertUlongToLargeInteger ( 0 );
SetModifiedCount = RtlConvertUlongToLargeInteger ( 0x00046656L );
ReturnedModifiedCount = RtlConvertUlongToLargeInteger ( 0 );
//
// Set the Policy Serial Number to a hardwired value.
//
Status = LsaISetSerialNumberPolicy(
TrustedPolicyHandle,
&SetModifiedCount,
&SetCreationTime,
FALSE
);
if (!NT_SUCCESS(Status)) {
DbgPrint(
"LSA RPC CT - Get/Set Policy Serial Number Test failed\n"
"LsaISetSerialNumberPolicy returned 0x%lx\n",
Status
);
goto PolicySerialNumberError;
}
//
// Now Query the Policy Serial Number just set.
//
Status = LsaIGetSerialNumberPolicy(
TrustedPolicyHandle,
&ReturnedModifiedCount,
&ReturnedCreationTime
);
if (!NT_SUCCESS(Status)) {
DbgPrint(
"LSA RPC CT - Get/Set Policy Serial Number Test failed\n"
"LsaIGetSerialNumberPolicy returned 0x%lx\n",
Status
);
goto PolicySerialNumberError;
}
//
// Now compare the ModifiedCount value returned with that set.
//
if (!( SetModifiedCount.QuadPart == ReturnedModifiedCount.QuadPart )) {
DbgPrint(
"LSA RPC CT - Get/Set Policy Serial Number Test failed\n"
"mismatch on ModifiedCount\n"
);
BooleanStatus = FALSE;
}
//
// Now compare the CreationTime value returned with that set.
//
if (!( SetCreationTime.QuadPart == ReturnedCreationTime.QuadPart )) {
DbgPrint(
"LSA RPC CT - Get/Set Policy Serial Number Test failed\n"
"mismatch on CreationTime\n"
);
BooleanStatus = FALSE;
}
if (!BooleanStatus) {
goto PolicySerialNumberError;
}
PolicySerialNumberFinish:
//
// If necessary, close the TrustedPolicyHandle.
//
if (TrustedPolicyHandle != NULL) {
Status = LsarClose( &TrustedPolicyHandle );
TrustedPolicyHandle = NULL;
if (!NT_SUCCESS(Status)) {
DbgPrint(
"LSA RPC CT - Get/Set Policy Serial Number failed\n"
"LsaClose on TrustedPolicyHandle returned 0x%lx\n",
Status
);
goto PolicySerialNumberError;
}
}
return(BooleanStatus);
PolicySerialNumberError:
BooleanStatus = FALSE;
goto PolicySerialNumberFinish;
}
BOOLEAN
CtLsaPolicyAuditLogInfo()
{
NTSTATUS Status;
BOOLEAN BooleanStatus = TRUE;
POLICY_AUDIT_LOG_INFO PolicyAuditLogInfo;
LARGE_INTEGER SystemTime;
LARGE_INTEGER TimeToShutdown;
LARGE_INTEGER AuditRetentionPeriod;
//
// Setup sample Audit Log Info
//
Status = NtQuerySystemTime(&SystemTime);
if (!NT_SUCCESS(Status)) {
DbgPrint("NtQuerySystemTime failed 0x%lx\n", Status);
BooleanStatus = FALSE;
return(BooleanStatus);
}
TimeToShutdown.HighPart = 0xABCD;
TimeToShutdown.LowPart = 0x12345678L;
AuditRetentionPeriod.HighPart = TimeToShutdown.HighPart;
AuditRetentionPeriod.LowPart = TimeToShutdown.LowPart;
PolicyAuditLogInfo.AuditLogPercentFull = (ULONG) 50;
PolicyAuditLogInfo.MaximumLogSize = (ULONG) 0x00001000L;
PolicyAuditLogInfo.AuditRetentionPeriod = AuditRetentionPeriod;
PolicyAuditLogInfo.TimeToShutdown = TimeToShutdown;
PolicyAuditLogInfo.AuditLogFullShutdownInProgress = TRUE;
BooleanStatus = CtLsaPolicySetQuerySub(
PolicyAuditLogInformation,
&PolicyAuditLogInfo
);
return(BooleanStatus);
}
BOOLEAN
CtLsaPolicyAuditEventsInfo()
{
BOOLEAN BooleanStatus = TRUE;
POLICY_AUDIT_EVENTS_INFO PolicyAuditEventsInfo;
POLICY_AUDIT_EVENT_TYPE EventType;
POLICY_AUDIT_EVENT_OPTIONS EventAuditingOptions[AuditEventMaxType+1];
//
// Setup sample Audit Events Info
//
PolicyAuditEventsInfo.AuditingMode = TRUE;
PolicyAuditEventsInfo.MaximumAuditEventCount = AuditEventMaxType;
for (EventType = AuditEventPrivilegedService;
EventType < AuditEventMaxType;
EventType++) {
EventAuditingOptions[EventType] =
(POLICY_AUDIT_EVENT_SUCCESS | POLICY_AUDIT_EVENT_FAILURE);
}
PolicyAuditEventsInfo.EventAuditingOptions = EventAuditingOptions;
BooleanStatus = CtLsaPolicySetQuerySub(
PolicyAuditEventsInformation,
&PolicyAuditEventsInfo
);
return(BooleanStatus);
}
BOOLEAN
CtLsaPolicyPrimaryDomainInfo()
{
BOOLEAN BooleanStatus = TRUE;
POLICY_PRIMARY_DOMAIN_INFO PolicyPrimaryDomainInfo;
//
// Setup sample Primary Domain Info
//
RtlInitUnicodeString( &PolicyPrimaryDomainInfo.Name, L"BedrockA");
PolicyPrimaryDomainInfo.Sid = BedrockADomainSid;
BooleanStatus = CtLsaPolicySetQuerySub(
PolicyPrimaryDomainInformation,
&PolicyPrimaryDomainInfo
);
return(BooleanStatus);
}
BOOLEAN
CtLsaPolicyPdAccountInfo()
{
BOOLEAN BooleanStatus = TRUE;
POLICY_PD_ACCOUNT_INFO PolicyPdAccountInfo;
//
// Setup sample PD Account Info
//
RtlInitUnicodeString( &PolicyPdAccountInfo.Name, L"BedrockC");
BooleanStatus = CtLsaPolicySetQuerySub(
PolicyPdAccountInformation,
&PolicyPdAccountInfo
);
return(BooleanStatus);
}
BOOLEAN
CtLsaPolicyAccountDomainInfo()
{
BOOLEAN BooleanStatus = TRUE;
POLICY_ACCOUNT_DOMAIN_INFO PolicyAccountDomainInfo;
//
// Setup sample Account Domain Info
//
RtlInitUnicodeString( &PolicyAccountDomainInfo.DomainName, L"BedrockB");
PolicyAccountDomainInfo.DomainSid = BedrockBDomainSid;
BooleanStatus = CtLsaPolicySetQuerySub(
PolicyAccountDomainInformation,
&PolicyAccountDomainInfo
);
return(BooleanStatus);
}
BOOLEAN
CtLsaPolicyLsaServerRoleInfo()
{
BOOLEAN BooleanStatus = TRUE;
POLICY_LSA_SERVER_ROLE_INFO PolicyLsaServerRoleInfo;
//
// Setup sample Policy Lsa Server Role Info
//
PolicyLsaServerRoleInfo.LsaServerRole = PolicyServerRolePrimary;
BooleanStatus = CtLsaPolicySetQuerySub(
PolicyLsaServerRoleInformation,
&PolicyLsaServerRoleInfo
);
return(BooleanStatus);
}
BOOLEAN
CtLsaPolicyReplicaSourceInfo()
{
BOOLEAN BooleanStatus = TRUE;
POLICY_REPLICA_SOURCE_INFO PolicyReplicaSourceInfo;
//
// Setup sample Policy Replica Source Info
//
RtlInitUnicodeString( &PolicyReplicaSourceInfo.ReplicaSource,L"BedrockD");
RtlInitUnicodeString( &PolicyReplicaSourceInfo.ReplicaAccountName,L"Barney");
BooleanStatus = CtLsaPolicySetQuerySub(
PolicyReplicaSourceInformation,
&PolicyReplicaSourceInfo
);
return(BooleanStatus);
}
BOOLEAN
CtLsaPolicyDefaultQuotaInfo()
{
BOOLEAN BooleanStatus = TRUE;
POLICY_DEFAULT_QUOTA_INFO PolicyDefaultQuotaInfo;
//
// Setup sample default quota limit values
//
PolicyDefaultQuotaInfo.QuotaLimits.PagedPoolLimit = CT_PAGED_POOL;
PolicyDefaultQuotaInfo.QuotaLimits.NonPagedPoolLimit = CT_NON_PAGED_POOL;
PolicyDefaultQuotaInfo.QuotaLimits.MinimumWorkingSetSize = CT_MIN_WORKING_SET;
PolicyDefaultQuotaInfo.QuotaLimits.MaximumWorkingSetSize = CT_MAX_WORKING_SET;
BooleanStatus = CtLsaPolicySetQuerySub(
PolicyDefaultQuotaInformation,
&PolicyDefaultQuotaInfo
);
return(BooleanStatus);
}
BOOLEAN
CtLsaPolicyModificationInfo()
{
BOOLEAN BooleanStatus = TRUE;
POLICY_MODIFICATION_INFO PolicyModificationInfo;
//
// Setup sample Modification Info values
//
PolicyModificationInfo.ModifiedId.LowPart = (ULONG) 0x00000000L;
PolicyModificationInfo.ModifiedId.HighPart = 3L;
PolicyModificationInfo.DatabaseCreationTime.LowPart = (ULONG) 0x00000000L;
PolicyModificationInfo.DatabaseCreationTime.HighPart = 4L;
BooleanStatus = CtLsaPolicySetQuerySub(
PolicyModificationInformation,
&PolicyModificationInfo
);
return(BooleanStatus);
}
BOOLEAN
CtLsaPolicySetQuerySub(
IN POLICY_INFORMATION_CLASS InformationClass,
IN PVOID PolicyInformation
)
{
NTSTATUS Status;
BOOLEAN BooleanStatus = TRUE;
OBJECT_ATTRIBUTES ObjectAttributes;
SECURITY_QUALITY_OF_SERVICE SecurityQualityOfService;
LSA_HANDLE PolicyHandleSet = NULL;
LSA_HANDLE PolicyHandleQuery = NULL;
LSA_HANDLE SavePolicyHandle = NULL;
PVOID ReturnedPolicyInformation;
PVOID SavedPolicyInformation;
ACCESS_MASK DesiredAccess;
BOOLEAN PolicyInfoSaved = FALSE;
ACCESS_MASK RequiredAccessSetPolicy[PolicyModificationInformation+1] =
{
0,
POLICY_AUDIT_LOG_ADMIN,
POLICY_SET_AUDIT_REQUIREMENTS,
POLICY_TRUST_ADMIN,
0,
POLICY_TRUST_ADMIN,
POLICY_SERVER_ADMIN,
POLICY_SERVER_ADMIN,
POLICY_SET_DEFAULT_QUOTA_LIMITS,
0
};
ACCESS_MASK RequiredAccessQueryPolicy[PolicyModificationInformation+1] =
{
0,
POLICY_VIEW_AUDIT_INFORMATION,
POLICY_VIEW_AUDIT_INFORMATION,
POLICY_VIEW_LOCAL_INFORMATION,
POLICY_GET_PRIVATE_INFORMATION,
POLICY_VIEW_LOCAL_INFORMATION,
POLICY_VIEW_LOCAL_INFORMATION,
POLICY_VIEW_LOCAL_INFORMATION,
POLICY_VIEW_LOCAL_INFORMATION,
0
};
CtLsaInitObjectAttributes(
&ObjectAttributes,
&SecurityQualityOfService
);
DbgPrint("...Testing information class %d\n", InformationClass);
//
// If this Information Policy Class can be set via non-trusted
// callers, we need to save it.
//
if (CtLsaPolicySetInfoAllowed(InformationClass) &&
CtLsaPolicyQueryInfoAllowed(InformationClass)) {
//
// Open handle for saving the existing Policy Information (if any) for
// this class.
//
Status = LsaOpenPolicy(
SystemName,
&ObjectAttributes,
GENERIC_ALL,
&SavePolicyHandle
);
if (!NT_SUCCESS(Status)) {
DbgPrint(
"LSA RPC CT - Policy object open handle failed 0x%lx\n",
Status
);
goto SetQueryInfoPolicyError;
}
//
// Now query the Policy Information set to be saved.
//
try {
Status = LsaQueryInformationPolicy(
SavePolicyHandle,
InformationClass,
&SavedPolicyInformation
);
} except (EXCEPTION_EXECUTE_HANDLER) {
DbgPrint("Lsa CT RPC - Access Violation: CtLsaPolicySetQuerySub\n");
DbgPrint(" within LsaQueryInformationPolicy call 1\n");
BooleanStatus = FALSE;
}
if (!BooleanStatus) {
goto SetQueryInfoPolicyError;
}
if (!NT_SUCCESS(Status)) {
goto SetQueryInfoPolicyError;
}
PolicyInfoSaved = TRUE;
}
//
// Open a handle to the Policy Object with the access required for
// setting the given Policy Information Class. If the Class
// is not settable via LsaSetInformationPolicy(), ie requires
// a trusted client, the call is expected to fail even if we open
// the Policy Object with GENERIC_ALL.
//
if (CtLsaPolicySetInfoAllowed(InformationClass)) {
DesiredAccess = RequiredAccessSetPolicy[InformationClass];
} else {
DesiredAccess = GENERIC_ALL;
}
Status = LsaOpenPolicy(
SystemName,
&ObjectAttributes,
DesiredAccess,
&PolicyHandleSet
);
if (!NT_SUCCESS(Status)) {
DbgPrint(
"LSA RPC CT - Policy object open handle failed 0x%lx\n",
Status
);
BooleanStatus = FALSE;
}
//
// Set the Policy Information for the specified class
//
try {
Status = LsaSetInformationPolicy(
PolicyHandleSet,
InformationClass,
PolicyInformation
);
} except (EXCEPTION_EXECUTE_HANDLER) {
DbgPrint("Lsa CT RPC - Access Violation: CtLsaPolicySetQuerySub\n");
DbgPrint(" within LsaSetInformationPolicy call 1\n");
BooleanStatus = FALSE;
}
if (!BooleanStatus) {
goto SetQueryInfoPolicyError;
}
//
// If setting of the InformationClass via LsaSetInformationPolicy()
// is allowed, we expect STATUS_SUCCESS, otherwise we expect
// STATUS_INVALID_PARAMETER.
//
if (CtLsaPolicySetInfoAllowed(InformationClass)) {
if (!NT_SUCCESS(Status)) {
DbgPrint(
"LsaSetInformationPolicy - Class %d failed 0x%lx\n",
InformationClass,
Status
);
BooleanStatus = FALSE;
}
} else {
//
// Information Class may not be set via LsaSetInformationPolicy
// We expect STATUS_INVALID_PARAMETER.
//
if (Status != STATUS_INVALID_PARAMETER) {
DbgPrint("LsaSetInformationPolicy - Attempt to set ");
DbgPrint("prohibited Information Class should have\n");
DbgPrint(
"failed 0x%lx\n (STATUS_INVALID_PARAMETER)",
STATUS_INVALID_PARAMETER
);
DbgPrint("instead returned 0x%lx\n", Status);
BooleanStatus = FALSE;
}
}
Status = LsaClose(PolicyHandleSet);
PolicyHandleSet = NULL;
//
// Now open a handle to the Policy Object with the access required for
// querying the given Policy Information Class. If the Class
// is not queryable via LsaQueryInformationPolicy(), ie requires
// a trusted client, the call is expected to fail even if we open
// the Policy Object with GENERIC_ALL.
//
if (CtLsaPolicyQueryInfoAllowed(InformationClass)) {
DesiredAccess = RequiredAccessQueryPolicy[InformationClass];
} else {
DesiredAccess = GENERIC_ALL;
}
Status = LsaOpenPolicy(
SystemName,
&ObjectAttributes,
DesiredAccess,
&PolicyHandleQuery
);
if (!NT_SUCCESS(Status)) {
DbgPrint(
"LSA RPC CT - Policy object open handle failed 0x%lx\n",
Status
);
goto SetQueryInfoPolicyError;
}
//
// Now query the Policy Information set
//
try {
Status = LsaQueryInformationPolicy(
PolicyHandleQuery,
InformationClass,
&ReturnedPolicyInformation
);
} except (EXCEPTION_EXECUTE_HANDLER) {
DbgPrint("Lsa CT RPC - Access Violation: CtLsaPolicySetQuerySub\n");
DbgPrint(" within LsaQueryInformationPolicy call 1\n");
BooleanStatus = FALSE;
}
if (!BooleanStatus) {
goto SetQueryInfoPolicyError;
}
//
// If querying of the InformationClass via LsaQueryInformationPolicy()
// is allowed, we expect STATUS_SUCCESS, otherwise we expect
// STATUS_INVALID_PARAMETER.
//
if (CtLsaPolicyQueryInfoAllowed(InformationClass)) {
if (!NT_SUCCESS(Status)) {
DbgPrint(
"LsaQueryInformationPolicy - Class %d failed 0x%lx\n",
InformationClass,
Status
);
BooleanStatus = FALSE;
}
} else {
//
// Information Class may not be queried via LsaQueryInformationPolicy
// We expect STATUS_INVALID_PARAMETER.
//
if (Status != STATUS_INVALID_PARAMETER) {
DbgPrint("LsaQueryInformationPolicy - Attempt to query ");
DbgPrint("prohibited Information Class should have\n");
DbgPrint(
"failed 0x%lx\n (STATUS_INVALID_PARAMETER)",
STATUS_INVALID_PARAMETER
);
DbgPrint("instead returned 0x%lx\n", Status);
BooleanStatus = FALSE;
}
}
//
// If set and query are both allowed for the Information Class, they
// should both have worked. In this case, compare the returned Policy
// information with that set
//
if (CtLsaPolicySetInfoAllowed(InformationClass) &&
CtLsaPolicyQueryInfoAllowed(InformationClass)) {
BooleanStatus &= CtLsaPolicyInfoClassCompare(
InformationClass,
PolicyInformation,
ReturnedPolicyInformation
);
}
Status = LsaClose(PolicyHandleQuery);
PolicyHandleQuery = NULL;
if (ReturnedPolicyInformation != NULL) {
Status = LsaFreeMemory(ReturnedPolicyInformation);
ReturnedPolicyInformation = NULL;
if (!NT_SUCCESS(Status)) {
DbgPrint("LSA RPC CT - Query Info Policy - LsaFreeMemory(ReturnedPolicyInformation)");
DbgPrint(" failed 0x%lx\n", Status);
BooleanStatus = FALSE;
}
}
//
// Now open a handle to the Policy Object with all accesses except the
// access required for setting the given Policy Information Class.
// If the Policy Information Class cannot be set via public API,
// open the handle instead with POLICY_ALL_ACCESS.
//
if (CtLsaPolicySetInfoAllowed(InformationClass)) {
DesiredAccess =
(POLICY_ALL_ACCESS & ~RequiredAccessSetPolicy[InformationClass]);
} else {
DesiredAccess = GENERIC_ALL;
}
Status = LsaOpenPolicy(
SystemName,
&ObjectAttributes,
DesiredAccess,
&PolicyHandleSet
);
if (!NT_SUCCESS(Status)) {
DbgPrint(
"LSA RPC CT - Policy object open handle failed 0x%lx\n",
Status
);
goto SetQueryInfoPolicyError;
}
//
// Attempt to set the Policy Information for the specified class
// using the handle opened above. This handle has either the
// complement of the accesses required (if the class is settable
// via LsaSetInformationPolicy()) or POLICY_ALL_ACCESS. In the
// former case, we should get STATUS_ACCESS_DENIED back from
// LsaSetInformationPolicy(), in the latter case, STATUS_INVALID_PARAMETER.
//
try {
Status = LsaSetInformationPolicy(
PolicyHandleSet,
InformationClass,
PolicyInformation
);
} except (EXCEPTION_EXECUTE_HANDLER) {
DbgPrint("Lsa CT RPC - Access Violation: CtLsaPolicySetQuerySub\n");
DbgPrint(" within LsaSetInformationPolicy call 2\n");
BooleanStatus = FALSE;
}
//
// If setting of the InformationClass via LsaSetInformationPolicy()
// is allowed, we expect STATUS_ACCESS_DENIED since we specified the
// complement of the access required (relative to POLICY_ALL_ACCESS).
// Otherwise we expect STATUS_INVALID_PARAMETER.
//
if (CtLsaPolicySetInfoAllowed(InformationClass)) {
if (Status != STATUS_ACCESS_DENIED) {
DbgPrint("LsaSetInformationPolicy Class");
DbgPrint(
" %d access mask 0x%lx should have failed 0x%lx (STATUS_ACCESS_DENIED)\n",
InformationClass,
DesiredAccess,
STATUS_ACCESS_DENIED
);
DbgPrint(
"since the required access for setting info is 0x%lx\n",
RequiredAccessSetPolicy[InformationClass]
);
DbgPrint(" but instead returned 0x%lx\n", Status);
BooleanStatus = FALSE;
}
} else {
//
// Information Class may not be set via LsaSetInformationPolicy
// We expect STATUS_INVALID_PARAMETER.
//
if (Status != STATUS_INVALID_PARAMETER) {
DbgPrint(
"LsaSetInformationPolicy - Attempt to set\n"
"prohibited Information Class should have\n"
"failed 0x%lx (STATUS_INVALID_PARAMETER)\n"
"instead returned 0x%lx\n",
STATUS_INVALID_PARAMETER,
Status
);
BooleanStatus = FALSE;
}
}
Status = LsaClose(PolicyHandleSet);
PolicyHandleSet = NULL;
//
// Now open a handle to the Policy Object with all accesses except the
// access required for querying the given Policy Information Class.
// If the Policy Information Class cannot be queried via public API,
// open the handle instead with POLICY_ALL_ACCESS.
//
if (CtLsaPolicyQueryInfoAllowed(InformationClass)) {
DesiredAccess =
(POLICY_ALL_ACCESS & ~RequiredAccessQueryPolicy[InformationClass]);
} else {
DesiredAccess = GENERIC_ALL;
}
Status = LsaOpenPolicy(
SystemName,
&ObjectAttributes,
DesiredAccess,
&PolicyHandleQuery
);
if (!NT_SUCCESS(Status)) {
DbgPrint(
"LSA RPC CT - Policy object open handle failed 0x%lx\n",
Status
);
goto SetQueryInfoPolicyError;
}
try {
//
// Now query the Policy Information set. This should fail
// STATUS_ACCESS_DENIED
//
Status = LsaQueryInformationPolicy(
PolicyHandleQuery,
InformationClass,
&ReturnedPolicyInformation
);
} except (EXCEPTION_EXECUTE_HANDLER) {
DbgPrint("Lsa CT RPC - Access Violation: CtLsaPolicySetQuerySub\n");
DbgPrint(" within LsaQueryInformationPolicy call 2\n");
BooleanStatus = FALSE;
}
//
// If querying of the InformationClass via LsaQueryInformationPolicy()
// is allowed, we expect STATUS_ACCESS_DENIED since we specified the
// complement of the access required (relative to POLICY_ALL_ACCESS).
// Otherwise we expect STATUS_INVALID_PARAMETER.
//
if (CtLsaPolicyQueryInfoAllowed(InformationClass)) {
if (Status != STATUS_ACCESS_DENIED) {
DbgPrint("LsaQueryInformationPolicy Class");
DbgPrint(
" %d access mask 0x%lx should have failed 0x%lx (STATUS_ACCESS_DENIED)\n",
InformationClass,
DesiredAccess,
STATUS_ACCESS_DENIED
);
DbgPrint(
"since the required access for querying info is 0x%lx\n",
RequiredAccessQueryPolicy[InformationClass]
);
DbgPrint(" but instead returned 0x%lx\n", Status);
BooleanStatus = FALSE;
}
} else {
//
// Information Class may not be queried via LsaQueryInformationPolicy
// We expect STATUS_INVALID_PARAMETER.
//
if (Status != STATUS_INVALID_PARAMETER) {
DbgPrint("LsaQueryInformationPolicy - Attempt to query ");
DbgPrint("prohibited Information Class should have\n");
DbgPrint(
"failed 0x%lx\n (STATUS_INVALID_PARAMETER)",
STATUS_INVALID_PARAMETER
);
DbgPrint("instead returned 0x%lx\n", Status);
BooleanStatus = FALSE;
}
}
if (ReturnedPolicyInformation != NULL) {
Status = LsaFreeMemory(ReturnedPolicyInformation);
ReturnedPolicyInformation = NULL;
if (!NT_SUCCESS(Status)) {
DbgPrint("LSA RPC CT - Query Info Policy - LsaFreeMemory(ReturnedPolicyInformation)");
DbgPrint(" failed 0x%lx\n", Status);
BooleanStatus = FALSE;
}
}
SetQueryInfoPolicyFinish:
//
// If we saved the old Policy Info, we need to restore it.
//
if (PolicyInfoSaved) {
PolicyInfoSaved = FALSE;
try {
Status = LsaSetInformationPolicy(
SavePolicyHandle,
InformationClass,
SavedPolicyInformation
);
} except (EXCEPTION_EXECUTE_HANDLER) {
DbgPrint("Lsa CT RPC - Access Violation: CtLsaPolicySetQuerySub\n");
DbgPrint(" within LsaQueryInformationPolicy call 1\n");
BooleanStatus = FALSE;
}
if (!BooleanStatus) {
goto SetQueryInfoPolicyError;
}
if (!NT_SUCCESS(Status)) {
DbgPrint(
"LSA RPC CT - Set/Query Info Policy Test failed\n"
"... failed to restore info policy for class %d\n"
"LsaSetInformationPolicy returned 0x%lx\n",
InformationClass,
Status
);
goto SetQueryInfoPolicyError;
}
}
if (PolicyHandleQuery != NULL) {
Status = LsaClose(PolicyHandleQuery);
PolicyHandleQuery = NULL;
if (!NT_SUCCESS( Status )) {
goto SetQueryInfoPolicyError;
}
}
return(BooleanStatus);
SetQueryInfoPolicyError:
BooleanStatus = FALSE;
goto SetQueryInfoPolicyFinish;
}
BOOLEAN
CtLsaPolicyInfoClassCompare(
IN POLICY_INFORMATION_CLASS InformationClass,
IN PVOID PolicyInformation1,
IN PVOID PolicyInformation2
)
/*++
Routine Description:
This function compares two sets of Policy Information for a known
Information Class.
Arguments:
InformationClass - Specifies a Policy Information Class
PolicyInformation1 - First comparand. Policy Information for the
given information class.
PolicyInformation2 - Second comparand. Policy Information for the
given information class.
Return Values:
BOOLEAN - TRUE if policy information sets are equal , else FALSE
--*/
{
BOOLEAN BooleanStatus = TRUE;
PPOLICY_AUDIT_LOG_INFO PolicyAuditLogInfo1;
PPOLICY_AUDIT_EVENTS_INFO PolicyAuditEventsInfo1;
PPOLICY_ACCOUNT_DOMAIN_INFO PolicyAccountDomainInfo1;
PPOLICY_PRIMARY_DOMAIN_INFO PolicyPrimaryDomainInfo1;
PPOLICY_PD_ACCOUNT_INFO PolicyPdAccountInfo1;
PPOLICY_LSA_SERVER_ROLE_INFO PolicyLsaServerRoleInfo1;
PPOLICY_REPLICA_SOURCE_INFO PolicyReplicaSourceInfo1;
PPOLICY_DEFAULT_QUOTA_INFO PolicyDefaultQuotaInfo1;
PPOLICY_MODIFICATION_INFO PolicyModificationInfo1;
PPOLICY_AUDIT_LOG_INFO PolicyAuditLogInfo2;
PPOLICY_AUDIT_EVENTS_INFO PolicyAuditEventsInfo2;
PPOLICY_ACCOUNT_DOMAIN_INFO PolicyAccountDomainInfo2;
PPOLICY_PRIMARY_DOMAIN_INFO PolicyPrimaryDomainInfo2;
PPOLICY_PD_ACCOUNT_INFO PolicyPdAccountInfo2;
PPOLICY_LSA_SERVER_ROLE_INFO PolicyLsaServerRoleInfo2;
PPOLICY_REPLICA_SOURCE_INFO PolicyReplicaSourceInfo2;
PPOLICY_DEFAULT_QUOTA_INFO PolicyDefaultQuotaInfo2;
PPOLICY_MODIFICATION_INFO PolicyModificationInfo2;
PQUOTA_LIMITS QuotaLimits1, QuotaLimits2;
//
// Switch on Information Class
//
switch (InformationClass) {
case PolicyAuditLogInformation:
PolicyAuditLogInfo1 = (PPOLICY_AUDIT_LOG_INFO) PolicyInformation1;
PolicyAuditLogInfo2 = (PPOLICY_AUDIT_LOG_INFO) PolicyInformation2;
if (PolicyAuditLogInfo1->AuditLogPercentFull !=
PolicyAuditLogInfo2->AuditLogPercentFull) {
DbgPrint("AuditLogPercentFull returned is incorrect\n");
BooleanStatus = FALSE;
}
if (PolicyAuditLogInfo1->MaximumLogSize !=
PolicyAuditLogInfo2->MaximumLogSize) {
DbgPrint("MaximumLogSize returned is incorrect\n");
BooleanStatus = FALSE;
}
if (!(PolicyAuditLogInfo1->AuditRetentionPeriod.QuadPart ==
PolicyAuditLogInfo2->AuditRetentionPeriod.QuadPart)) {
DbgPrint("AuditRetentionPeriod returned is incorrect\n");
BooleanStatus = FALSE;
}
if (PolicyAuditLogInfo1->AuditLogFullShutdownInProgress !=
PolicyAuditLogInfo2->AuditLogFullShutdownInProgress) {
DbgPrint("AuditLogFullShutdownInProgress returned is incorrect\n");
BooleanStatus = FALSE;
}
if (!(PolicyAuditLogInfo1->TimeToShutdown.QuadPart ==
PolicyAuditLogInfo2->TimeToShutdown.QuadPart)) {
DbgPrint("TimeToShutDown returned is incorrect\n");
BooleanStatus = FALSE;
}
break;
case PolicyAuditEventsInformation:
PolicyAuditEventsInfo1 = (PPOLICY_AUDIT_EVENTS_INFO) PolicyInformation1;
PolicyAuditEventsInfo2 = (PPOLICY_AUDIT_EVENTS_INFO) PolicyInformation2;
if (PolicyAuditEventsInfo1->AuditingMode !=
PolicyAuditEventsInfo2->AuditingMode) {
DbgPrint("Auditing Mode returned is incorrect\n");
BooleanStatus = FALSE;
}
if (PolicyAuditEventsInfo1->MaximumAuditEventCount !=
PolicyAuditEventsInfo2->MaximumAuditEventCount) {
DbgPrint("MaximumAuditEventCount returned is incorrect\n");
BooleanStatus = FALSE;
}
if (memcmp(
PolicyAuditEventsInfo1->EventAuditingOptions,
PolicyAuditEventsInfo2->EventAuditingOptions,
PolicyAuditEventsInfo1->MaximumAuditEventCount *
(ULONG) sizeof (POLICY_AUDIT_EVENT_OPTIONS)
) != 0) {
DbgPrint("EventAuditingOptions returned are incorrect\n");
BooleanStatus = FALSE;
}
break;
case PolicyPrimaryDomainInformation:
PolicyPrimaryDomainInfo1 = (PPOLICY_PRIMARY_DOMAIN_INFO) PolicyInformation1;
PolicyPrimaryDomainInfo2 = (PPOLICY_PRIMARY_DOMAIN_INFO) PolicyInformation2;
if (!RtlEqualUnicodeString(
&PolicyPrimaryDomainInfo1->Name,
&PolicyPrimaryDomainInfo2->Name,
FALSE
)) {
DbgPrint("Policy Info Class %d - mismatch on Name\n", InformationClass);
BooleanStatus = FALSE;
}
if (!RtlEqualSid(
PolicyPrimaryDomainInfo1->Sid,
PolicyPrimaryDomainInfo2->Sid
)) {
DbgPrint("Policy Info Class %d - mismatch on Sid\n", InformationClass);
BooleanStatus = FALSE;
}
break;
case PolicyAccountDomainInformation:
PolicyAccountDomainInfo1 = (PPOLICY_ACCOUNT_DOMAIN_INFO) PolicyInformation1;
PolicyAccountDomainInfo2 = (PPOLICY_ACCOUNT_DOMAIN_INFO) PolicyInformation2;
if (!RtlEqualUnicodeString(
&PolicyAccountDomainInfo1->DomainName,
&PolicyAccountDomainInfo2->DomainName,
FALSE
)) {
DbgPrint("Policy Info Class %d - mismatch on DomainName\n", InformationClass);
BooleanStatus = FALSE;
}
if (!RtlEqualSid(
PolicyAccountDomainInfo1->DomainSid,
PolicyAccountDomainInfo2->DomainSid
)) {
DbgPrint("Policy Info Class %d - mismatch on DomainSid\n", InformationClass);
BooleanStatus = FALSE;
}
break;
case PolicyPdAccountInformation:
PolicyPdAccountInfo1 = (PPOLICY_PD_ACCOUNT_INFO) PolicyInformation1;
PolicyPdAccountInfo2 = (PPOLICY_PD_ACCOUNT_INFO) PolicyInformation2;
if (!RtlEqualUnicodeString(
&PolicyPdAccountInfo1->Name,
&PolicyPdAccountInfo2->Name,
FALSE
)) {
DbgPrint(
"Policy Info Class %d - mismatch on Name\n",
InformationClass
);
BooleanStatus = FALSE;
}
break;
case PolicyLsaServerRoleInformation:
PolicyLsaServerRoleInfo1 = (PPOLICY_LSA_SERVER_ROLE_INFO) PolicyInformation1;
PolicyLsaServerRoleInfo2 = (PPOLICY_LSA_SERVER_ROLE_INFO) PolicyInformation2;
if (PolicyLsaServerRoleInfo1->LsaServerRole !=
PolicyLsaServerRoleInfo2->LsaServerRole) {
DbgPrint(
"Policy Info Class %d - mismatch on LsaServerRole\n",
InformationClass
);
BooleanStatus = FALSE;
}
break;
case PolicyReplicaSourceInformation:
PolicyReplicaSourceInfo1 = (PPOLICY_REPLICA_SOURCE_INFO) PolicyInformation1;
PolicyReplicaSourceInfo2 = (PPOLICY_REPLICA_SOURCE_INFO) PolicyInformation2;
if (!RtlEqualUnicodeString(
&PolicyReplicaSourceInfo1->ReplicaSource,
&PolicyReplicaSourceInfo2->ReplicaSource,
FALSE
)) {
DbgPrint(
"Policy Info Class %d - mismatch on Replica Source\n",
InformationClass
);
BooleanStatus = FALSE;
}
if (!RtlEqualUnicodeString(
&PolicyReplicaSourceInfo1->ReplicaAccountName,
&PolicyReplicaSourceInfo2->ReplicaAccountName,
FALSE
)) {
DbgPrint(
"Policy Info Class %d - mismatch on ReplicaAccountName\n",
InformationClass
);
BooleanStatus = FALSE;
}
break;
case PolicyDefaultQuotaInformation:
PolicyDefaultQuotaInfo1 = (PPOLICY_DEFAULT_QUOTA_INFO) PolicyInformation1;
PolicyDefaultQuotaInfo2 = (PPOLICY_DEFAULT_QUOTA_INFO) PolicyInformation2;
QuotaLimits1 = &PolicyDefaultQuotaInfo1->QuotaLimits;
QuotaLimits2 = &PolicyDefaultQuotaInfo2->QuotaLimits;
if (QuotaLimits1->PagedPoolLimit !=
QuotaLimits2->PagedPoolLimit) {
DbgPrint(
"Policy Info Class %d - mismatch on QuotaLimits PagedPoolLimit\n",
InformationClass
);
BooleanStatus = FALSE;
}
if (QuotaLimits1->NonPagedPoolLimit !=
QuotaLimits2->NonPagedPoolLimit) {
DbgPrint(
"Policy Info Class %d - mismatch on QuotaLimits NonPagedPoolLimit\n",
InformationClass
);
BooleanStatus = FALSE;
}
if (QuotaLimits1->MinimumWorkingSetSize !=
QuotaLimits2->MinimumWorkingSetSize) {
DbgPrint(
"Policy Info Class %d - mismatch on QuotaLimits MinimumWorkingSetSize\n",
InformationClass
);
BooleanStatus = FALSE;
}
if (QuotaLimits1->MaximumWorkingSetSize !=
QuotaLimits2->MaximumWorkingSetSize) {
DbgPrint(
"Policy Info Class %d - mismatch on QuotaLimits MaximumWorkingSetSize\n",
InformationClass
);
BooleanStatus = FALSE;
}
if (QuotaLimits1->PagefileLimit !=
QuotaLimits2->PagefileLimit) {
DbgPrint(
"Policy Info Class %d - mismatch on QuotaLimits PagefileLimit\n",
InformationClass
);
BooleanStatus = FALSE;
}
if (!(QuotaLimits1->TimeLimit.QuadPart ==
QuotaLimits2->TimeLimit.QuadPart
)) {
DbgPrint(
"Policy Info Class %d - mismatch on QuotaLimits TimeLimit\n",
InformationClass
);
BooleanStatus = FALSE;
}
break;
case PolicyModificationInformation:
PolicyModificationInfo1 = (PPOLICY_MODIFICATION_INFO) PolicyInformation1;
PolicyModificationInfo2 = (PPOLICY_MODIFICATION_INFO) PolicyInformation2;
if (!(PolicyModificationInfo1->ModifiedId.QuadPart ==
PolicyModificationInfo2->ModifiedId.QuadPart )) {
DbgPrint("ModifiedId returned is incorrect\n");
BooleanStatus = FALSE;
}
if (!(PolicyModificationInfo1->DatabaseCreationTime.QuadPart ==
PolicyModificationInfo2->DatabaseCreationTime.QuadPart )) {
DbgPrint("DatabaseCreationTime returned is incorrect\n");
BooleanStatus = FALSE;
}
break;
default:
BooleanStatus = FALSE;
DbgPrint(
"Bug in test program - Invalid Information Class %d\n",
InformationClass
);
break;
}
return(BooleanStatus);
}
BOOLEAN
CtLsaPolicyQueryInfoAllowed(
IN POLICY_INFORMATION_CLASS InformationClass
)
/*++
Routine Description:
This function determines whether querying of a Policy Information Class
is allowed via LsaQueryInformationPolicy. Note that all Policy
Information Classes may be queried via (to be implemented) trusted
clients to private API.
Arguments:
InformationClass - The Policy Information Class to be checked (assumed
valid).
Return Value:
BOOLEAN - TRUE if the information class can be queried via
LsaQueryInformationPolicy() else FALSE.
--*/
{
//
// Range check the InformationClass parameter.
//
if ((InformationClass < PolicyAuditLogInformation) ||
(InformationClass > PolicyModificationInformation)) {
DbgPrint("WARNING! CtLsaPolicyQueryInfoAllowed:\n");
DbgPrint(
" InformationClass %d is invalid - check caller\n",
InformationClass
);
return(FALSE);
}
//
// Check if this Information Class can be queried via
// LsaQueryInformationPolicy()
//
if (InformationClass == PolicyModificationInformation) {
return(FALSE);
}
return(TRUE);
}
BOOLEAN
CtLsaPolicySetInfoAllowed(
IN POLICY_INFORMATION_CLASS InformationClass
)
/*++
Routine Description:
This function determines whether setting of a Policy Information Class
is allowed via LsaSetInformationPolicy. Note that all Policy
Information Classes may be set via (to be implemented) trusted
clients to private API.
Arguments:
InformationClass - The Policy Information Class to be checked (assumed
valid).
Return Value:
BOOLEAN - TRUE idf the information class can be set via
LsaSetInformationPolicy() else FALSE.
--*/
{
//
// Range check the InformationClass parameter.
//
if ((InformationClass < PolicyAuditLogInformation) ||
(InformationClass > PolicyModificationInformation)) {
DbgPrint("WARNING! CtLsaPolicySetInfoAllowed:\n");
DbgPrint(
" InformationClass %d is invalid - check caller\n",
InformationClass
);
return(FALSE);
}
//
// Check if this Information Class can be set via
// LsaSetInformationPolicy().
//
if (InformationClass == PolicyPdAccountInformation) {
return(FALSE);
}
if (InformationClass == PolicyModificationInformation) {
return(FALSE);
}
return(TRUE);
}
BOOLEAN
CtLsaAccountObject(
IN BOOLEAN TrustedClient
)
/*++
Routine Description:
This function tests the Lsa Account Object API.
Arguments:
TrustedClient - Specifies whether Trusted Client variations
are to be run additionally. NOTE: These can only be run
with ctlsarpc -lsainit... substituted for lsass.exe
Return Value:
BOOLEAN - TRUE if successful, FALSE if any failures.
--*/
{
NTSTATUS Status;
BOOLEAN BooleanStatus = TRUE;
DbgPrint("********************************************************\n");
DbgPrint("LSA RPC CT - Test Lsa Account Object API\n");
DbgPrint("********************************************************\n");
//
// Open a handle to the LSA
//
CtLsaInitObjectAttributes(
&ObjectAttributes,
&SecurityQualityOfService
);
Status = LsaOpenPolicy(
SystemName,
&ObjectAttributes,
GENERIC_ALL,
&PolicyHandle
);
if (!NT_SUCCESS(Status)) {
DbgPrint("LSA RPC CT - Lsa Open failed 0x%lx\n", Status);
return FALSE;
}
//
// Test account creation. Abandon account testing if error.
//
if (!CtLsaAccountCreate()) {
return FALSE;
}
//
// Test account open and close. Abandon account testing if error.
//
if (!CtLsaAccountOpenClose()) {
return FALSE;
}
//
// Test account privileges.
//
if (!CtLsaAccountPrivileges()) {
BooleanStatus = FALSE;
}
//
// Test account quota limits.
//
if (!CtLsaAccountQuotaLimits()) {
BooleanStatus = FALSE;
}
//
// Test account enumeration.
//
if (!CtLsaAccountEnumeration()) {
BooleanStatus = FALSE;
}
//
// Test account System Access.
//
if (!CtLsaAccountSystemAccess()) {
BooleanStatus = FALSE;
}
//
// Test account deletion.
//
if (!CtLsaAccountDelete()) {
BooleanStatus = FALSE;
}
return BooleanStatus;
DBG_UNREFERENCED_PARAMETER( TrustedClient );
}
BOOLEAN
CtLsaAccountCreate(
)
/*++
Routine Description:
This function tests the LSA API that Create accounts.
Arguments:
None.
Return Value:
BOOLEAN - TRUE if successful, FALSE if any failures.
--*/
{
NTSTATUS Status;
DbgPrint("[1] - Test Account Creation API\n");
//
// Create the new accounts in the LSA Database.
//
DesiredAccessFred = GENERIC_ALL;
Status = LsaCreateAccount(
PolicyHandle,
FredSid,
DesiredAccessFred,
&AccountHandleFred
);
if (!NT_SUCCESS(Status)) {
DbgPrint("LSA RPC CT - Create Fred Acct failed 0x%lx\n", Status);
return FALSE;
}
DesiredAccessWilma = GENERIC_READ;
Status = LsaCreateAccount(
PolicyHandle,
WilmaSid,
DesiredAccessWilma,
&AccountHandleWilma
);
if (!NT_SUCCESS(Status)) {
DbgPrint("LSA RPC CT - Create Wilma Acct failed 0x%lx\n", Status);
return FALSE;
}
DesiredAccessPebbles = GENERIC_WRITE;
Status = LsaCreateAccount(
PolicyHandle,
PebblesSid,
DesiredAccessPebbles,
&AccountHandlePebbles
);
if (!NT_SUCCESS(Status)) {
DbgPrint("LSA RPC CT - Create Pebbles Acct failed 0x%lx\n", Status);
return FALSE;
}
DesiredAccessDino = GENERIC_EXECUTE;
Status = LsaCreateAccount(
PolicyHandle,
DinoSid,
DesiredAccessDino,
&AccountHandleDino
);
if (!NT_SUCCESS(Status)) {
DbgPrint("LSA RPC CT - Create Dino Acct failed 0x%lx\n", Status);
return FALSE;
}
//
// Close the accounts just created
//
Status = LsaClose(AccountHandleFred);
if (!NT_SUCCESS(Status)) {
DbgPrint("LSA RPC CT - Close new Fred account failed 0x%lx\n",
Status);
return FALSE;
}
Status = LsaClose(AccountHandleWilma);
if (!NT_SUCCESS(Status)) {
DbgPrint("LSA RPC CT - Close new Wilma account failed 0x%lx\n",
Status);
return FALSE;
}
Status = LsaClose(AccountHandlePebbles);
if (!NT_SUCCESS(Status)) {
DbgPrint(
"LSA RPC CT - Close new Pebbles account failed 0x%lx\n",
Status
);
return FALSE;
}
Status = LsaClose(AccountHandleDino);
if (!NT_SUCCESS(Status)) {
DbgPrint("LSA RPC CT - Close new Dino account failed 0x%lx\n",
Status);
return FALSE;
}
return TRUE;
}
BOOLEAN
CtLsaAccountOpenClose(
)
/*++
Routine Description:
This function tests the LSA API that open and close accounts.
Arguments:
None.
Return Value:
BOOLEAN - TRUE if successful, FALSE if any failures.
--*/
{
NTSTATUS Status;
BOOLEAN BooleanStatus;
PLSA_HANDLE BadHandleAddress;
DbgPrint("[2] - Test Account Open and Close API\n");
//
// Open the accounts created by CtLsaAccountCreate
//
Status = LsaOpenAccount(
PolicyHandle,
FredSid,
DesiredAccessFred,
&AccountHandleFred
);
if (!NT_SUCCESS(Status)) {
DbgPrint("LSA RPC CT - 1st Open Fred Acct failed 0x%lx\n", Status);
return FALSE;
}
Status = LsaOpenAccount(
PolicyHandle,
WilmaSid,
DesiredAccessWilma,
&AccountHandleWilma
);
if (!NT_SUCCESS(Status)) {
DbgPrint("LSA RPC CT - 1st Open Wilma Acct failed 0x%lx\n", Status);
return FALSE;
}
Status = LsaOpenAccount(
PolicyHandle,
PebblesSid,
DesiredAccessPebbles,
&AccountHandlePebbles
);
if (!NT_SUCCESS(Status)) {
DbgPrint("LSA RPC CT - 1st Open Pebbles Acct failed 0x%lx\n", Status);
return FALSE;
}
//
// Open Dino account.
// This is a spare call and should be changed in some way.
//
Status = LsaOpenAccount(
PolicyHandle,
DinoSid,
DesiredAccessDino,
&AccountHandleDino
);
if (!NT_SUCCESS(Status)) {
DbgPrint("LSA RPC CT - 1st Open Dino Acct failed 0x%lx\n", Status);
return FALSE;
}
//
// Now open each account a second time so we have 2 handles to each
// account.
//
Status = LsaOpenAccount(
PolicyHandle,
FredSid,
DesiredAccessFred,
&AccountHandleFred2
);
if (!NT_SUCCESS(Status)) {
DbgPrint("LSA RPC CT - 2nd Open Fred Acct failed 0x%lx\n", Status);
return FALSE;
}
Status = LsaOpenAccount(
PolicyHandle,
WilmaSid,
DesiredAccessWilma,
&AccountHandleWilma2
);
if (!NT_SUCCESS(Status)) {
DbgPrint("LSA RPC CT - 2nd Open Wilma Acct failed 0x%lx\n", Status);
return FALSE;
}
Status = LsaOpenAccount(
PolicyHandle,
PebblesSid,
DesiredAccessPebbles,
&AccountHandlePebbles2
);
if (!NT_SUCCESS(Status)) {
DbgPrint("LSA RPC CT - 2nd Open Pebbles Acct failed 0x%lx\n", Status);
return FALSE;
}
Status = LsaOpenAccount(
PolicyHandle,
DinoSid,
DesiredAccessDino,
&AccountHandleDino2
);
if (!NT_SUCCESS(Status)) {
DbgPrint("LSA RPC CT - Open Dino Acct failed 0x%lx\n", Status);
return FALSE;
}
//
// Close the 2nd handles to the accounts
//
Status = LsaClose( AccountHandleFred2 );
if (!NT_SUCCESS(Status)) {
DbgPrint("LSA RPC CT - Close Fred Acct hdl2 failed 0x%lx\n", Status);
return FALSE;
}
Status = LsaClose( AccountHandleWilma2 );
if (!NT_SUCCESS(Status)) {
DbgPrint("LSA RPC CT - Close Wilma Acct hdl2 failed 0x%lx\n",Status);
return FALSE;
}
Status = LsaClose( AccountHandlePebbles2 );
if (!NT_SUCCESS(Status)) {
DbgPrint("LSA RPC CT - Close Pebbles Acct hdl2 failed 0x%lx\n", Status);
return FALSE;
}
Status = LsaClose( AccountHandleDino2 );
if (!NT_SUCCESS(Status)) {
DbgPrint("LSA RPC CT - Close Dino Acct hdl2 failed 0x%lx\n", Status);
return FALSE;
}
BooleanStatus = TRUE;
//
// Try to create Fred again. We should get STATUS_OBJECT_NAME_COLLISION
//
Status = LsaCreateAccount(
PolicyHandle,
FredSid,
GENERIC_ALL,
&AccountHandleFred3
);
if (Status != STATUS_OBJECT_NAME_COLLISION) {
DbgPrint("LSA RPC CT - Create Fred Acct when Fred exists\n");
DbgPrint("and LSA_OBJECT_CREATE disposition specified\n");
DbgPrint("Expected 0x%lx (STATUS_OBJECT_NAME_COLLISION)\n",
STATUS_OBJECT_NAME_COLLISION);
DbgPrint("Got 0x%lx\n", Status);
BooleanStatus = FALSE;
}
return BooleanStatus;
if (Level == 2) {
//
// LsaOpenAccount with bad addresses
//
Status = LsaOpenAccount(
PolicyHandle,
FredSid,
DesiredAccessFred,
BadHandleAddress
);
//
// Lsa Close with bad address
//
Status = LsaClose( (LSA_HANDLE) BadAddress );
}
}
BOOLEAN
CtLsaAccountPrivileges(
)
/*++
Routine Description:
This function tests thei API that manipulate LSA Account Privileges
Arguments:
None.
Return Value:
None
--*/
{
NTSTATUS Status;
PPRIVILEGE_SET *BadPrivilegeSetAddress = NULL;
DbgPrint("[3] - Test Account Privileges API\n");
//
// Add three privileges to the Fred account - BACKUP, RESTORE and
// LOCK_MEMORY
//
PrivilegesAddFred = RtlAllocateHeap(
RtlProcessHeap(), 0,
sizeof (PRIVILEGE_SET) +
2 * sizeof (LUID_AND_ATTRIBUTES)
);
if (PrivilegesAddFred == NULL) {
DbgPrint("LSA RPC CT - Alloc Mem for PrivilegesAddFred failed\n");
return FALSE;
}
PrivilegesAddFred->PrivilegeCount = 3;
PrivilegesAddFred->Control = 0;
PrivilegesAddFred->Privilege[0].Luid.LowPart = SE_BACKUP_PRIVILEGE;
PrivilegesAddFred->Privilege[0].Luid.HighPart = 0;
PrivilegesAddFred->Privilege[0].Attributes =
SE_PRIVILEGE_ENABLED_BY_DEFAULT;
PrivilegesAddFred->Privilege[1].Luid.LowPart = SE_RESTORE_PRIVILEGE;
PrivilegesAddFred->Privilege[1].Luid.HighPart = 0;
PrivilegesAddFred->Privilege[1].Attributes =
SE_PRIVILEGE_ENABLED_BY_DEFAULT;
PrivilegesAddFred->Privilege[2].Luid.LowPart = SE_LOCK_MEMORY_PRIVILEGE;
PrivilegesAddFred->Privilege[2].Luid.HighPart = 0;
PrivilegesAddFred->Privilege[2].Attributes =
SE_PRIVILEGE_ENABLED_BY_DEFAULT;
Status = LsaAddPrivilegesToAccount(
AccountHandleFred,
PrivilegesAddFred
);
if (!NT_SUCCESS(Status)) {
DbgPrint("LSA RPC CT - Add privs Fred Acct failed 0x%lx\n", Status);
return FALSE;
}
//
// 1st enumeration of privileges of Fred. There should be three.
//
Status = LsaEnumeratePrivilegesOfAccount(
AccountHandleFred,
&PrivilegesEnumFred
);
if (!NT_SUCCESS(Status)) {
DbgPrint("LSA RPC CT - Enum privs Fred Acct failed 0x%lx\n", Status);
return FALSE;
}
//
// Supersede the first two privileges and add another privilege to
// the Fred account - supersede BACKUP, RESTORE and add
// INCREASE_QUOTA
//
PrivilegesAddFred = RtlAllocateHeap(
RtlProcessHeap(), 0,
sizeof (PRIVILEGE_SET) +
2 * sizeof (LUID_AND_ATTRIBUTES)
);
if (PrivilegesAddFred == NULL) {
DbgPrint("LSA RPC CT - Alloc Mem for PrivilegesAddFred failed 0x%lx\n",
Status);
return FALSE;
}
PrivilegesAddFred->PrivilegeCount = 3;
PrivilegesAddFred->Control = 0;
PrivilegesAddFred->Privilege[0].Luid.LowPart = SE_BACKUP_PRIVILEGE;
PrivilegesAddFred->Privilege[0].Luid.HighPart = 0;
PrivilegesAddFred->Privilege[0].Attributes =
SE_PRIVILEGE_ENABLED;
PrivilegesAddFred->Privilege[1].Luid.LowPart = SE_RESTORE_PRIVILEGE;
PrivilegesAddFred->Privilege[1].Luid.HighPart = 0;
PrivilegesAddFred->Privilege[1].Attributes =
SE_PRIVILEGE_ENABLED;
PrivilegesAddFred->Privilege[2].Luid.LowPart =
SE_INCREASE_QUOTA_PRIVILEGE;
PrivilegesAddFred->Privilege[2].Luid.HighPart = 0;
PrivilegesAddFred->Privilege[2].Attributes =
SE_PRIVILEGE_ENABLED_BY_DEFAULT;
if (PrivilegesAddFred == NULL) {
DbgPrint("LSA RPC CT - Alloc Mem for PrivilegesAddFred failed 0x%lx\n",
Status);
return FALSE;
}
Status = LsaAddPrivilegesToAccount(
AccountHandleFred,
PrivilegesAddFred
);
if (!NT_SUCCESS(Status)) {
DbgPrint("LSA RPC CT - Add privs Fred Acct failed 0x%lx\n", Status);
return FALSE;
}
//
// 2nd enumeration of privileges of Fred. There should be four.
// BACKUP, RESTORE, LOCK_MEMORY and INCREASE_QUOTA
//
Status = LsaEnumeratePrivilegesOfAccount(
AccountHandleFred,
&PrivilegesEnumFred
);
if (!NT_SUCCESS(Status)) {
DbgPrint(
"LSA RPC CT - 2nd Enum privs Fred Acct failed 0x%lx\n",
Status);
return FALSE;
}
//
// Remove the SE_LOCK_MEMORY_PRIVILEGE
//
PrivilegesRemoveFred = RtlAllocateHeap(
RtlProcessHeap(), 0,
sizeof (PRIVILEGE_SET) +
2 * sizeof (LUID_AND_ATTRIBUTES)
);
if (PrivilegesRemoveFred == NULL) {
DbgPrint(
"LSA RPC CT - Alloc Mem for PrivilegesAddFred failed 0x%lx\n",
Status
);
return FALSE;
}
PrivilegesRemoveFred->PrivilegeCount = 1;
PrivilegesRemoveFred->Control = 0;
PrivilegesRemoveFred->Privilege[0].Luid.LowPart = SE_LOCK_MEMORY_PRIVILEGE;
PrivilegesRemoveFred->Privilege[0].Luid.HighPart = 0;
PrivilegesRemoveFred->Privilege[0].Attributes = 0;
Status = LsaRemovePrivilegesFromAccount(
AccountHandleFred,
FALSE,
PrivilegesRemoveFred
);
if (!NT_SUCCESS(Status)) {
DbgPrint("LSA RPC CT - Remove some privs Fred Acct failed 0x%lx\n",
Status);
return FALSE;
}
//
// 3rd enumeration of privileges of Fred. There should be three.
// BACKUP, RESTORE, INCREASE_QUOTA
//
Status = LsaEnumeratePrivilegesOfAccount(
AccountHandleFred,
&PrivilegesEnumFred
);
if (!NT_SUCCESS(Status)) {
DbgPrint(
"LSA RPC CT - 3rd Enum privs Fred Acct failed 0x%lx\n",
Status);
return FALSE;
}
Status = LsaRemovePrivilegesFromAccount(
AccountHandleFred,
TRUE,
NULL
);
if (!NT_SUCCESS(Status)) {
DbgPrint("LSA RPC CT - Remove all privs Fred Acct failed 0x%lx\n",
Status);
return FALSE;
}
//
// 4th enumeration of privileges of Fred. There should be none.
//
Status = LsaEnumeratePrivilegesOfAccount(
AccountHandleFred,
&PrivilegesEnumFred
);
if (!NT_SUCCESS(Status)) {
DbgPrint(
"LSA RPC CT - 4th Enum privs Fred Acct failed 0x%lx\n",
Status);
return FALSE;
}
if (Level == 2) {
Status = LsaAddPrivilegesToAccount(
(LSA_HANDLE) BadAddress,
PrivilegesAddFred
);
Status = LsaAddPrivilegesToAccount(
AccountHandleFred,
(PPRIVILEGE_SET) BadAddress
);
Status = LsaEnumeratePrivilegesOfAccount(
(LSA_HANDLE) BadAddress,
&PrivilegesEnumFred
);
Status = LsaEnumeratePrivilegesOfAccount(
AccountHandleFred,
BadPrivilegeSetAddress
);
Status = LsaRemovePrivilegesFromAccount(
(LSA_HANDLE) BadAddress,
FALSE,
PrivilegesRemoveFred
);
Status = LsaRemovePrivilegesFromAccount(
AccountHandleFred,
FALSE,
(PPRIVILEGE_SET) BadAddress
);
}
return TRUE;
}
BOOLEAN
CtLsaAccountQuotaLimits(
)
/*++
Routine Description:
This function tests the LSA API that manipulate Account Quota Limits.
Arguments:
None.
Return Value:
BOOLEAN - TRUE if successful, FALSE if any failures.
--*/
{
NTSTATUS Status;
BOOLEAN BooleanStatus = TRUE;
DbgPrint("[4] - Test Account Quota Limits API\n");
Status = LsaGetQuotasForAccount(
AccountHandleFred,
&QuotaLimitsGetFred
);
if (!NT_SUCCESS(Status)) {
DbgPrint("LSA RPC CT - 1st Get quotas Fred Acct failed 0x%lx\n",
Status);
return FALSE;
}
QuotaLimitsSetFred.PagedPoolLimit = 0x02000000;
QuotaLimitsSetFred.NonPagedPoolLimit = 0x01000000;
QuotaLimitsSetFred.MinimumWorkingSetSize = 0x03000000;
QuotaLimitsSetFred.MaximumWorkingSetSize = 0x04000000;
QuotaLimitsSetFred.PagefileLimit = 0x05000000;
QuotaLimitsSetFred.TimeLimit.LowPart = 0x06000000;
QuotaLimitsSetFred.TimeLimit.HighPart = 0;
Status = LsaSetQuotasForAccount(
AccountHandleFred,
&QuotaLimitsSetFred
);
if (!NT_SUCCESS(Status)) {
DbgPrint("LSA RPC CT - Set quotas Acct failed 0x%lx\n", Status);
return FALSE;
}
Status = LsaGetQuotasForAccount(
AccountHandleFred,
&QuotaLimitsGetFred
);
if (!NT_SUCCESS(Status)) {
DbgPrint("LSA RPC CT - 2nd Get quotas Fred Acct failed 0x%lx\n",
Status);
return FALSE;
}
if (!CtEqualQuotaLimits(&QuotaLimitsGetFred, &QuotaLimitsSetFred)) {
DbgPrint("One or more quota limits did not match\n");
return FALSE;
}
//
// Bad Addresses passed to Lsa Quota Limit API
//
if (Level == 2) {
Status = LsaGetQuotasForAccount(
(LSA_HANDLE) BadAddress,
&QuotaLimitsGetFred
);
Status = LsaGetQuotasForAccount(
AccountHandleFred,
(PQUOTA_LIMITS) BadAddress
);
Status = LsaSetQuotasForAccount(
(LSA_HANDLE) BadAddress,
&QuotaLimitsSetFred
);
Status = LsaSetQuotasForAccount(
AccountHandleFred,
(PQUOTA_LIMITS) BadAddress
);
//
// Try using the 2nd handle of the Fred account after closure
//
Status = LsaGetQuotasForAccount(
AccountHandleFred2,
&QuotaLimitsGetFred
);
if (NT_SUCCESS(Status)) {
DbgPrint("Using account handle after closure did not fail\n");
BooleanStatus = FALSE;
}
//
// Try using the wrong handle
//
Status = LsaGetQuotasForAccount( PolicyHandle, &QuotaLimitsGetFred );
if (Status != STATUS_INVALID_HANDLE) {
DbgPrint("LSA RPC CT - Using incorrect handle status incorrect\n");
DbgPrint(
"Expected 0x%lx (STATUS_INVALID_HANDLE))\n",
STATUS_INVALID_HANDLE
);
DbgPrint("Got 0x%lx\n", Status);
}
}
return BooleanStatus;
}
BOOLEAN
CtLsaAccountEnumeration(
)
/*++
Routine Description:
This function tests the enumeration of accounts in the LSA
Arguments:
None.
Return Value:
BOOLEAN - TRUE if successful, FALSE if any failures.
--*/
{
NTSTATUS Status;
BOOLEAN BooleanStatus = TRUE;
ULONG Base = 0;
ULONG CountReturned = 0;
ULONG PreferedMaximumLength;
ULONG EnumerationContext = 0;
ULONG EnumNumber = 0;
PLSA_ENUMERATION_INFORMATION EnumerationInformation;
PVOID EnumerationInformationVoid = NULL;
PVOID *BadEnumerationAddress = NULL;
PULONG BadCountReturnedAddress = NULL;
DbgPrint("[5] - Test Account Enumeration API\n");
//
// Enumerate the accounts in the Lsa
//
PreferedMaximumLength = RtlLengthSid(FredSid) +
sizeof(LSA_ENUMERATION_INFORMATION) +
RtlLengthSid(WilmaSid) +
sizeof(LSA_ENUMERATION_INFORMATION);
Status = LsaEnumerateAccounts(
PolicyHandle,
&EnumerationContext,
&EnumerationInformationVoid,
PreferedMaximumLength,
&CountReturned
);
EnumerationInformation =
(PLSA_ENUMERATION_INFORMATION) EnumerationInformationVoid;
if (!NT_SUCCESS(Status)) {
DbgPrint("LSA RPC CT - Enumeration of first two accounts failed\n");
DbgPrint("0x%lx\n", Status);
goto EnumerateAccountsError;
}
if (CountReturned < 1 || CountReturned > 3) {
DbgPrint("LSA_RPC_CT - CountReturned invalid\n");
DbgPrint("expected 1 <= CountReturned <= 3\n");
DbgPrint("got %d\n", CountReturned);
BooleanStatus = FALSE;
}
AccountSidInfo[0].Sid = FredSid;
AccountSidInfo[1].Sid = WilmaSid;
AccountSidInfo[3].Sid = PebblesSid;
AccountSidInfo[2].Sid = DinoSid;
AccountSidInfo[0].SidFound = FALSE;
AccountSidInfo[1].SidFound = FALSE;
AccountSidInfo[2].SidFound = FALSE;
AccountSidInfo[3].SidFound = FALSE;
Base = 0;
EnumNumber = 1;
//
// Now see if the 1st batch of enumerated account Sids returned match those
// expected.
//
for(Index = 0; Index < CountReturned; Index++) {
SidFound = FALSE;
for (SearchIndex = 0; SearchIndex < 4; SearchIndex++) {
if (RtlEqualSid(
AccountSidInfo[SearchIndex].Sid,
EnumerationInformation[Index].Sid
)) {
if (AccountSidInfo[SearchIndex].SidFound) {
DbgPrint(
"Already found Sid with SearchIndex %d\n",
SearchIndex
);
} else {
AccountSidInfo[SearchIndex].SidFound = TRUE;
}
SidFound = TRUE;
break;
}
}
//
// If the enumerated Sid is not found, complain.
//
if (!SidFound) {
DbgPrint(
"Enumeration %d, index %d, Sid not found\n",
EnumNumber,
Index
);
}
}
Base += CountReturned;
EnumNumber++;
CountReturned = 0;
if (EnumerationInformationVoid != NULL) {
Status = LsaFreeMemory(EnumerationInformationVoid);
EnumerationInformationVoid = NULL;
if (!NT_SUCCESS(Status)) {
DbgPrint("LSA RPC CT - Enumerate Accounts");
DbgPrint(" - LsaFreeMemory(EnumerationInformationVoid");
DbgPrint(" failed 0x%lx\n", Status);
BooleanStatus = FALSE;
}
}
PreferedMaximumLength = RtlLengthSid(PebblesSid) +
sizeof(LSA_ENUMERATION_INFORMATION) +
RtlLengthSid(DinoSid) +
sizeof(LSA_ENUMERATION_INFORMATION);
Status = LsaEnumerateAccounts(
PolicyHandle,
&EnumerationContext,
&EnumerationInformationVoid,
PreferedMaximumLength,
&CountReturned
);
EnumerationInformation =
(PLSA_ENUMERATION_INFORMATION) EnumerationInformationVoid;
if (!(NT_SUCCESS(Status) || (Status == STATUS_NO_MORE_ENTRIES))) {
DbgPrint("LSA RPC CT - Enumeration of last two accounts failed\n");
DbgPrint("0x%lx\n", Status);
goto EnumerateAccountsError;
}
if (CountReturned < 1 || CountReturned > 3) {
DbgPrint("LSA_RPC_CT - CountReturned invalid\n");
DbgPrint("expected 1 <= CountReturned <= 3\n");
DbgPrint("got %d\n", CountReturned);
goto EnumerateAccountsError;
}
//
// Now see if the 2nd batch of enumerated account Sids returned match those
// expected.
//
for(Index = 0; Index < CountReturned; Index++) {
SidFound = FALSE;
for (SearchIndex = 0; SearchIndex < 4; SearchIndex++) {
if (RtlEqualSid(
AccountSidInfo[SearchIndex].Sid,
EnumerationInformation[Index].Sid
)) {
if (AccountSidInfo[SearchIndex].SidFound) {
DbgPrint(
"Already found Sid with SearchIndex %d\n",
SearchIndex
);
} else {
AccountSidInfo[SearchIndex].SidFound = TRUE;
}
SidFound = TRUE;
break;
}
}
//
// If the enumerated Sid is not found, complain.
//
if (!SidFound) {
DbgPrint(
"Enumeration %d, index %d, Sid not found\n",
EnumNumber,
Index
);
goto EnumerateAccountsError;
}
}
if (EnumerationInformationVoid != NULL) {
Status = LsaFreeMemory(EnumerationInformationVoid);
EnumerationInformationVoid = NULL;
if (!NT_SUCCESS(Status)) {
DbgPrint("LSA RPC CT - Enumerate Accounts");
DbgPrint(" - LsaFreeMemory(EnumerationInformationVoid");
DbgPrint(" failed 0x%lx\n", Status);
BooleanStatus = FALSE;
}
}
//
// Bad Addresses passed to Lsa Enumerate Accounts API
//
if (Level == 2) {
Status = LsaEnumerateAccounts(
(LSA_HANDLE) BadAddress,
&EnumerationContext,
&EnumerationInformationVoid,
PreferedMaximumLength,
&CountReturned
);
Status = LsaEnumerateAccounts(
PolicyHandle,
(PLSA_ENUMERATION_HANDLE) BadAddress,
&EnumerationInformationVoid,
PreferedMaximumLength,
&CountReturned
);
Status = LsaEnumerateAccounts(
PolicyHandle,
&EnumerationContext,
BadEnumerationAddress,
PreferedMaximumLength,
&CountReturned
);
Status = LsaEnumerateAccounts(
PolicyHandle,
&EnumerationContext,
&EnumerationInformationVoid,
PreferedMaximumLength,
BadCountReturnedAddress
);
}
EnumerateAccountsFinish:
if (EnumerationInformationVoid != NULL) {
Status = LsaFreeMemory(EnumerationInformationVoid);
EnumerationInformationVoid = NULL;
if (!NT_SUCCESS(Status)) {
DbgPrint("LSA RPC CT - Enumerate Accounts");
DbgPrint(" - LsaFreeMemory(EnumerationInformationVoid");
DbgPrint(" failed 0x%lx\n", Status);
BooleanStatus = FALSE;
}
}
return(BooleanStatus);
EnumerateAccountsError:
goto EnumerateAccountsFinish;
}
BOOLEAN
CtLsaAccountSystemAccess(
)
/*++
Routine Description:
This function tests the set & query System Access of accounts in the LSA
Arguments:
None.
Return Value:
BOOLEAN - TRUE if successful, FALSE if any failures.
--*/
{
NTSTATUS Status;
BOOLEAN BooleanStatus = TRUE;
LSA_HANDLE AccountHandleGsaFred = NULL;
LSA_HANDLE AccountHandleSsaFred = NULL;
LSA_HANDLE AccountHandleCGsaFred = NULL;
LSA_HANDLE AccountHandleCSsaFred = NULL;
LSA_HANDLE InvalidHandle = NULL;
LSA_HANDLE PolicyHandle = NULL;
ULONG GetSystemAccessFred = 0;
ULONG SetSystemAccessFred = 0;
ACCESS_MASK ComplAccessRequiredGet;
ACCESS_MASK ComplAccessRequiredSet;
DbgPrint("[6] - Test Account System Access API\n");
//
// Open the Lsa Policy Object
//
Status = LsaOpenPolicy(
SystemName,
&ObjectAttributes,
GENERIC_READ,
&PolicyHandle
);
if (!NT_SUCCESS(Status)) {
DbgPrint(
"LSA RPC CT - Policy object open handle %d failed 0x%lx\n",
Index,
Status
);
}
//
// Open the Fred account for querying system access
//
Status = LsaOpenAccount(
PolicyHandle,
FredSid,
ACCOUNT_VIEW,
&AccountHandleGsaFred
);
if (!NT_SUCCESS(Status)) {
DbgPrint("LSA RPC CT - Open Fred Acct for ACCOUNT_VIEW Access failed 0x%lx\n", Status);
return(FALSE);
}
GetSystemAccessFred = (ULONG) 0xffffffffL;
//
// Query the System Access flags for Fred
//
Status = LsaGetSystemAccessAccount(
AccountHandleGsaFred,
&GetSystemAccessFred
);
if (!NT_SUCCESS(Status)) {
DbgPrint(
"LSA RPC CT - 1st LsaGetSystemAccess.. Fred for ACCOUNT_VIEW Access failed 0x%lx\n",
Status
);
goto AccountSystemAccessError;
}
//
// Since the system access flags have never been set, 0 should be returned.
//
if (GetSystemAccessFred != 0) {
DbgPrint(
"System Access Flags for Fred = 0x%lx, expected 0\n",
GetSystemAccessFred
);
BooleanStatus = FALSE;
}
//
// Open the Fred account for setting system access
//
Status = LsaOpenAccount(
PolicyHandle,
FredSid,
ACCOUNT_ADJUST_SYSTEM_ACCESS,
&AccountHandleSsaFred
);
if (!NT_SUCCESS(Status)) {
DbgPrint("LSA RPC CT - Open Fred Acct for\n");
DbgPrint(" ACCOUNT_ADJUST_SYSTEM_ACCESS failed 0x%lx\n", Status);
goto AccountSystemAccessError;
}
//
// Now set the system access flags for Fred
//
SetSystemAccessFred = POLICY_MODE_ALL;
Status = LsaSetSystemAccessAccount(
AccountHandleSsaFred,
SetSystemAccessFred
);
if (!NT_SUCCESS(Status)) {
DbgPrint(
"LSA RPC CT - LsaSetSystemAccessAccount(Fred) failed 0x%lx\n",
Status
);
goto AccountSystemAccessError;
}
//
// Now query the System Access flags for Fred again
//
GetSystemAccessFred = 0;
Status = LsaGetSystemAccessAccount(
AccountHandleGsaFred,
&GetSystemAccessFred
);
if (!NT_SUCCESS(Status)) {
DbgPrint(
"LSA RPC CT - 1st LsaGetSystemAccess.. Fred for ACCOUNT_VIEW Access failed 0x%lx\n",
Status
);
goto AccountSystemAccessError;
}
//
// The returned System Access Flags should match those set.
//
if (GetSystemAccessFred != SetSystemAccessFred) {
DbgPrint("System Access Flags for Fred mismatch\n");
DbgPrint(
" - Set 0x%lx but returned 0x%lx\n",
SetSystemAccessFred,
GetSystemAccessFred
);
BooleanStatus = FALSE;
}
//
// Try invalid handle (NULL)
//
InvalidHandle = NULL;
Status = LsaGetSystemAccessAccount(
InvalidHandle,
&GetSystemAccessFred
);
if (Status != STATUS_INVALID_HANDLE) {
DbgPrint("Passing NULL handle to LsaGetSystemAccessAccount ");
DbgPrint(" gives incorrect error status code\n");
DbgPrint(
"Expected Ox%lx (STATUS_INVALID_HANDLE), got 0x%lx\n",
STATUS_INVALID_HANDLE,
Status
);
BooleanStatus = FALSE;
}
InvalidHandle = NULL;
Status = LsaSetSystemAccessAccount(
InvalidHandle,
SetSystemAccessFred
);
if (Status != STATUS_INVALID_HANDLE) {
DbgPrint("Passing NULL handle to LsaSetSystemAccessAccount ");
DbgPrint(" gives incorrect error status code\n");
DbgPrint(
"Expected Ox%lx (STATUS_INVALID_HANDLE), got 0x%lx\n",
STATUS_INVALID_HANDLE,
Status
);
BooleanStatus = FALSE;
}
//
// Try invalid handle (handle of another object type)
//
InvalidHandle = PolicyHandle;
Status = LsaGetSystemAccessAccount(
InvalidHandle,
&GetSystemAccessFred
);
if (Status != STATUS_INVALID_HANDLE) {
DbgPrint("Passing wrong handle type to LsaGetSystemAccessAccount ");
DbgPrint(" gives incorrect error status code\n");
DbgPrint(
"Expected Ox%lx (STATUS_INVALID_HANDLE), got 0x%lx\n",
STATUS_INVALID_HANDLE,
Status
);
BooleanStatus = FALSE;
}
Status = LsaSetSystemAccessAccount(
InvalidHandle,
SetSystemAccessFred
);
if (Status != STATUS_INVALID_HANDLE) {
DbgPrint("Passing wrong handle type to LsaSetSystemAccessAccount ");
DbgPrint(" gives incorrect error status code\n");
DbgPrint(
"Expected Ox%lx (STATUS_INVALID_HANDLE), got 0x%lx\n",
STATUS_INVALID_HANDLE,
Status
);
BooleanStatus = FALSE;
}
//
// Try invalid access types
//
//
// Open the Fred account for Complement of access needed to query
// system accesses.
//
ComplAccessRequiredGet = (ACCOUNT_ALL_ACCESS & ~(ACCOUNT_VIEW));
Status = LsaOpenAccount(
PolicyHandle,
FredSid,
ComplAccessRequiredGet,
&AccountHandleCGsaFred
);
if (!NT_SUCCESS(Status)) {
DbgPrint(
"LsaOpenAccount for complement of ACCOUNT_VIEW access failed 0x%lx\n",
Status
);
BooleanStatus = FALSE;
} else {
//
// Now query the System Access flags for Fred. We should get
// STATUS_ACCESS_DENIED.
//
GetSystemAccessFred = 0;
Status = LsaGetSystemAccessAccount(
AccountHandleCGsaFred,
&GetSystemAccessFred
);
if (Status != STATUS_ACCESS_DENIED) {
DbgPrint(
"LSA RPC CT - LsaGetSystemAccessAccount(Fred) returned 0x%lx\n",
Status
);
DbgPrint(
"expected 0x%lx (STATUS_ACCESS_DENIED)\n",
STATUS_ACCESS_DENIED
);
goto AccountSystemAccessError;
}
}
ComplAccessRequiredSet = (ACCOUNT_ALL_ACCESS & ~(ACCOUNT_ADJUST_SYSTEM_ACCESS));
Status = LsaOpenAccount(
PolicyHandle,
FredSid,
ComplAccessRequiredSet,
&AccountHandleCSsaFred
);
if (!NT_SUCCESS(Status)) {
DbgPrint(
"LsaOpenAccount for complement of ACCOUNT_ADJUST_SYSTEM_ACCESS\n"
);
DbgPrint("failed 0x%lx\n", Status);
BooleanStatus = FALSE;
} else {
//
// Now query the System Access flags for Fred. We should get
// STATUS_ACCESS_DENIED.
//
GetSystemAccessFred = 0;
Status = LsaSetSystemAccessAccount(
AccountHandleCSsaFred,
SetSystemAccessFred
);
if (Status != STATUS_ACCESS_DENIED) {
DbgPrint(
"LSA RPC CT - LsaSetSystemAccessAccount(Fred) returned 0x%lx\n",
Status
);
DbgPrint(
"expected 0x%lx (STATUS_ACCESS_DENIED)\n",
STATUS_ACCESS_DENIED
);
goto AccountSystemAccessError;
}
}
AccountSystemAccessFinish:
//
// Close all handles
//
if (AccountHandleGsaFred != NULL) {
Status = LsaClose(AccountHandleGsaFred);
if (!NT_SUCCESS(Status)) {
DbgPrint("LsaClose(AccountHandleGsaFred) failed 0x%lx\n", Status);
BooleanStatus = FALSE;
}
}
if (AccountHandleSsaFred != NULL) {
Status = LsaClose(AccountHandleSsaFred);
if (!NT_SUCCESS(Status)) {
DbgPrint("LsaClose(AccountHandleSsaFred) failed 0x%lx\n", Status);
BooleanStatus = FALSE;
}
}
if (AccountHandleCGsaFred != NULL) {
Status = LsaClose(AccountHandleCGsaFred);
if (!NT_SUCCESS(Status)) {
DbgPrint("LsaClose(AccountHandleCGsaFred failed 0x%lx\n", Status);
BooleanStatus = FALSE;
}
}
if (AccountHandleCSsaFred != NULL) {
Status = LsaClose(AccountHandleCSsaFred);
if (!NT_SUCCESS(Status)) {
DbgPrint("LsaClose(AccountHandleCSsaFred failed 0x%lx\n", Status);
BooleanStatus = FALSE;
}
}
if (PolicyHandle != NULL) {
Status = LsaClose(PolicyHandle);
}
return(BooleanStatus);
AccountSystemAccessError:
BooleanStatus = FALSE;
goto AccountSystemAccessFinish;
}
BOOLEAN
CtLsaAccountDelete(
)
/*++
Routine Description:
This function tests deletion of accounts. First, a simple test is
made to see if we can delete a freshly created account. Next, we
try to delete the accounts created by CtLsaAccountCreate.
Arguments:
None.
Return Value:
BOOLEAN - TRUE if successful, FALSE if any error.
--*/
{
NTSTATUS Status;
BOOLEAN BooleanStatus = TRUE;
DbgPrint("[7] - Test Account Deletion API\n");
//
// First try a simple test. Create a new account called Barney
// to be given DELETE access upon create. Then delete it.
//
//
// Create the Barney Account
//
DesiredAccessBarney = GENERIC_ALL;
Status = LsaCreateAccount(
PolicyHandle,
BarneySid,
DesiredAccessBarney,
&AccountHandleBarney
);
if (!NT_SUCCESS(Status)) {
DbgPrint("LSA RPC CT - Create Barney Acct failed 0x%lx\n", Status);
return FALSE;
}
//
// Delete the Barney account
//
Status = LsaDelete( AccountHandleBarney );
if (!NT_SUCCESS(Status)) {
DbgPrint("LSA RPC CT - Delete Barney Acct failed 0x%lx\n", Status);
return FALSE;
}
//
// Delete the Fred account. This should work since it was opened
// with GENERIC_ALL access.
//
Status = LsaDelete( AccountHandleFred );
if (!NT_SUCCESS(Status)) {
DbgPrint("LSA RPC CT - Delete Fred Acct failed 0x%lx\n", Status);
return FALSE;
}
//
// Delete the Wilma account. This should not work since it was opened
// with GENERIC_READ access.
//
if (DesiredAccessWilma != GENERIC_READ) {
DbgPrint("DesiredAccessWilma should be GENERIC_READ\n");
DbgPrint("Bug in this test program\n");
return FALSE;
}
Status = LsaDelete( AccountHandleWilma );
if (Status != STATUS_ACCESS_DENIED) {
DbgPrint("LSA RPC CT - Delete Wilma Acct should have failed\n");
DbgPrint(" with STATUS_ACCESS_DENIED since handle specifies\n");
DbgPrint("GENERIC_READ access - got 0x%lx\n", Status);
BooleanStatus = FALSE;
}
//
// Now close the handle to Wilma, open another handle with GENERIC_ALL
// access and try to delete the account again.
//
Status = LsaClose(AccountHandleWilma);
if (!NT_SUCCESS(Status)) {
DbgPrint("Close Wilma account failed 0x%lx\n", Status);
}
AccountHandleWilmaOpen = NULL;
Status = LsaOpenAccount(
PolicyHandle,
WilmaSid,
GENERIC_ALL,
&AccountHandleWilmaOpen
);
if (!NT_SUCCESS(Status)) {
DbgPrint(
"LSA RPC CT - Open Wilma Acct for GENERIC_ALL access failed 0x%lx\n",
Status
);
return FALSE;
}
Status = LsaDelete( AccountHandleWilmaOpen );
if (!NT_SUCCESS(Status)) {
DbgPrint("LSA RPC CT - Delete Wilma Acct failed 0x%lx\n", Status);
BooleanStatus = FALSE;
}
//
// Delete the Pebbles account. This should not work since it was opened
// with GENERIC_WRITE access which does not include DELETE.
//
if (DesiredAccessPebbles != GENERIC_WRITE) {
DbgPrint("DesiredAccessPebbles should be GENERIC_WRITE\n");
DbgPrint("Bug in this test program\n");
return FALSE;
}
Status = LsaDelete( AccountHandlePebbles );
if (Status != STATUS_ACCESS_DENIED) {
DbgPrint("LSA RPC CT - Delete Pebbles Acct should have failed\n");
DbgPrint(" with STATUS_ACCESS_DENIED since handle specifies\n");
DbgPrint("GENERIC_READ access - got 0x%lx\n", Status);
BooleanStatus = FALSE;
}
//
// Now close the handle to Pebbles and open another handle with DELETE
// access and try to delete the account again.
//
Status = LsaClose(AccountHandlePebbles);
if (!NT_SUCCESS(Status)) {
DbgPrint("Close Pebbles account failed 0x%lx\n", Status);
}
AccountHandlePebblesOpen = NULL;
Status = LsaOpenAccount(
PolicyHandle,
PebblesSid,
DELETE,
&AccountHandlePebblesOpen
);
if (!NT_SUCCESS(Status)) {
DbgPrint(
"LSA RPC CT - Open Pebbles Acct for DELETE access failed 0x%lx\n",
Status
);
return FALSE;
}
Status = LsaDelete( AccountHandlePebblesOpen );
if (!NT_SUCCESS(Status)) {
DbgPrint("LSA RPC CT - Delete Pebbles Acct failed 0x%lx\n", Status);
BooleanStatus = FALSE;
}
//
// Delete the Dino account. This should not work since it was opened
// with GENERIC_EXECUTE access.
//
if (DesiredAccessDino != GENERIC_EXECUTE) {
DbgPrint("DesiredAccessDino should be GENERIC_EXECUTE\n");
DbgPrint("Bug in this test program\n");
return FALSE;
}
Status = LsaDelete( AccountHandleDino );
if (Status != STATUS_ACCESS_DENIED) {
DbgPrint("LSA RPC CT - Delete Dino Acct failed 0x%lx\n", Status);
BooleanStatus = FALSE;
}
//
// Now close the handle to Dino, open another handle with DELETE
// access and try to delete it again.
//
Status = LsaClose(AccountHandleDino);
if (!NT_SUCCESS(Status)) {
DbgPrint("Close Dino account failed 0x%lx\n", Status);
}
AccountHandleDinoOpen = NULL;
Status = LsaOpenAccount(
PolicyHandle,
DinoSid,
DELETE,
&AccountHandleDinoOpen
);
if (!NT_SUCCESS(Status)) {
DbgPrint(
"LSA RPC CT - Open Dino Acct for DELETE access failed 0x%lx\n",
Status
);
BooleanStatus = FALSE;
}
Status = LsaDelete( AccountHandleDinoOpen );
if (!NT_SUCCESS(Status)) {
DbgPrint("LSA RPC CT - Delete Dino Acct failed 0x%lx\n", Status);
BooleanStatus = FALSE;
}
return TRUE;
}
BOOLEAN
CtLsaTrustedDomainObject(
IN BOOLEAN TrustedClient
)
/*++
Routine Description:
This function tests the Lsa TrustedDomain Object API.
Arguments:
TrustedClient - Specifies whether Trusted Client variations
are to be run additionally. NOTE: These can only be run
with ctlsarpc -lsainit... substituted for lsass.exe
Return Value:
BOOLEAN - TRUE if successful, FALSE if any failures.
--*/
{
NTSTATUS Status;
BOOLEAN BooleanStatus = TRUE;
DbgPrint("********************************************************\n");
DbgPrint("LSA RPC CT - Test Lsa Trusted Domain Object API\n");
DbgPrint("********************************************************\n");
//
// Open a handle to the LSA
//
CtLsaInitObjectAttributes(
&ObjectAttributes,
&SecurityQualityOfService
);
Status = LsaOpenPolicy(
SystemName,
&ObjectAttributes,
GENERIC_ALL,
&PolicyHandle
);
if (!NT_SUCCESS(Status)) {
DbgPrint("LSA RPC CT - Lsa Open failed 0x%lx\n", Status);
return FALSE;
}
//
// Test TrustedDomain creation. Abandon TrustedDomain testing if error.
//
if (!CtLsaTrustedDomainCreate()) {
return FALSE;
}
//
// Test TrustedDomain open and close. Abandon TrustedDomain testing if error.
//
if (!CtLsaTrustedDomainOpenClose()) {
return FALSE;
}
//
// Test TrustedDomain Set and Query Info
//
if (!CtLsaTrustedDomainSetQueryInfo()) {
BooleanStatus = FALSE;
}
//
// Test TrustedDomain enumeration.
//
if (!CtLsaTrustedDomainEnumeration()) {
BooleanStatus = FALSE;
}
//
// Test TrustedDomain deletion.
//
if (!CtLsaTrustedDomainDelete()) {
BooleanStatus = FALSE;
}
return BooleanStatus;
DBG_UNREFERENCED_PARAMETER( TrustedClient );
}
BOOLEAN
CtLsaTrustedDomainCreate(
)
/*++
Routine Description:
This function tests the LSA API that Create TrustedDomains.
Arguments:
None.
Return Value:
BOOLEAN - TRUE if successful, FALSE if any failures.
--*/
{
NTSTATUS Status;
UNICODE_STRING BedrockADomainName;
UNICODE_STRING BedrockBDomainName;
UNICODE_STRING BedrockCDomainName;
UNICODE_STRING BedrockDDomainName;
DbgPrint("[1] - Test TrustedDomain Creation API\n");
RtlInitUnicodeString( &BedrockADomainName, L"BedrockA" );
RtlInitUnicodeString( &BedrockBDomainName, L"BedrockB" );
RtlInitUnicodeString( &BedrockCDomainName, L"BedrockC" );
RtlInitUnicodeString( &BedrockDDomainName, L"BedrockD" );
//
// Create the new Trusted Domains in the LSA Database.
//
DesiredAccessBedrockA = GENERIC_ALL;
CtLsaTrustedDomainSetInfo(
BedrockADomainSid,
&BedrockADomainName,
&TrustedDomainInfoBedrockA
);
Status = LsaCreateTrustedDomain(
PolicyHandle,
&TrustedDomainInfoBedrockA,
DesiredAccessBedrockA,
&TrustedDomainHandleBedrockA
);
if (!NT_SUCCESS(Status)) {
if (Status != STATUS_OBJECT_NAME_EXISTS) {
DbgPrint("LSA RPC CT - Create BedrockA Trusted Domain failed 0x%lx\n", Status);
return FALSE;
}
}
DesiredAccessBedrockB = GENERIC_READ;
CtLsaTrustedDomainSetInfo(
BedrockBDomainSid,
&BedrockBDomainName,
&TrustedDomainInfoBedrockB
);
Status = LsaCreateTrustedDomain(
PolicyHandle,
&TrustedDomainInfoBedrockB,
DesiredAccessBedrockB,
&TrustedDomainHandleBedrockB
);
if (!NT_SUCCESS(Status)) {
DbgPrint("LSA RPC CT - Create BedrockB Trusted Domain failed 0x%lx\n", Status);
return FALSE;
}
DesiredAccessBedrockC = GENERIC_WRITE;
CtLsaTrustedDomainSetInfo(
BedrockCDomainSid,
&BedrockCDomainName,
&TrustedDomainInfoBedrockC
);
Status = LsaCreateTrustedDomain(
PolicyHandle,
&TrustedDomainInfoBedrockC,
DesiredAccessBedrockC,
&TrustedDomainHandleBedrockC
);
if (!NT_SUCCESS(Status)) {
DbgPrint("LSA RPC CT - Create BedrockC Trusted Domain failed 0x%lx\n", Status);
return FALSE;
}
DesiredAccessBedrockD = GENERIC_EXECUTE;
CtLsaTrustedDomainSetInfo(
BedrockDDomainSid,
&BedrockDDomainName,
&TrustedDomainInfoBedrockD
);
Status = LsaCreateTrustedDomain(
PolicyHandle,
&TrustedDomainInfoBedrockD,
DesiredAccessBedrockD,
&TrustedDomainHandleBedrockD
);
if (!NT_SUCCESS(Status)) {
DbgPrint("LSA RPC CT - Create BedrockD Trusted Domain failed 0x%lx\n", Status);
return FALSE;
}
//
// Close the TrustedDomains just created
//
Status = LsaClose(TrustedDomainHandleBedrockA);
if (!NT_SUCCESS(Status)) {
DbgPrint("LSA RPC CT - Close new BedrockA TrustedDomain failed 0x%lx\n",
Status);
return FALSE;
}
Status = LsaClose(TrustedDomainHandleBedrockB);
if (!NT_SUCCESS(Status)) {
DbgPrint("LSA RPC CT - Close new BedrockB TrustedDomain failed 0x%lx\n",
Status);
return FALSE;
}
Status = LsaClose(TrustedDomainHandleBedrockC);
if (!NT_SUCCESS(Status)) {
DbgPrint(
"LSA RPC CT - Close new BedrockC TrustedDomain failed 0x%lx\n",
Status
);
return FALSE;
}
Status = LsaClose(TrustedDomainHandleBedrockD);
if (!NT_SUCCESS(Status)) {
DbgPrint("LSA RPC CT - Close new BedrockD TrustedDomain failed 0x%lx\n",
Status);
return FALSE;
}
return TRUE;
}
BOOLEAN
CtLsaTrustedDomainOpenClose(
)
/*++
Routine Description:
This function tests the LSA API that open and close TrustedDomains.
Arguments:
None.
Return Value:
BOOLEAN - TRUE if successful, FALSE if any failures.
--*/
{
NTSTATUS Status;
BOOLEAN BooleanStatus;
PLSA_HANDLE BadHandleAddress;
DbgPrint("[2] - Test TrustedDomain Open and Close API\n");
//
// Open the TrustedDomains created by CtLsaTrustedDomainCreate
//
Status = LsaOpenTrustedDomain(
PolicyHandle,
BedrockADomainSid,
DesiredAccessBedrockA,
&TrustedDomainHandleBedrockA
);
if (!NT_SUCCESS(Status)) {
DbgPrint("LSA RPC CT - 1st Open BedrockA Trusted Domain failed 0x%lx\n", Status);
return FALSE;
}
Status = LsaOpenTrustedDomain(
PolicyHandle,
BedrockBDomainSid,
DesiredAccessBedrockB,
&TrustedDomainHandleBedrockB
);
if (!NT_SUCCESS(Status)) {
DbgPrint("LSA RPC CT - 1st Open BedrockB Trusted Domain failed 0x%lx\n", Status);
return FALSE;
}
Status = LsaOpenTrustedDomain(
PolicyHandle,
BedrockCDomainSid,
DesiredAccessBedrockC,
&TrustedDomainHandleBedrockC
);
if (!NT_SUCCESS(Status)) {
DbgPrint("LSA RPC CT - 1st Open Pebbles Trusted Domain failed 0x%lx\n", Status);
return FALSE;
}
//
// Open BedrockD TrustedDomain.
// This is a spare call and should be changed in some way.
//
Status = LsaOpenTrustedDomain(
PolicyHandle,
BedrockDDomainSid,
DesiredAccessBedrockD,
&TrustedDomainHandleBedrockD
);
if (!NT_SUCCESS(Status)) {
DbgPrint("LSA RPC CT - 1st Open BedrockD Trusted Domain failed 0x%lx\n", Status);
return FALSE;
}
//
// Now open each TrustedDomain a second time so we have 2 handles to each
// TrustedDomain.
//
Status = LsaOpenTrustedDomain(
PolicyHandle,
BedrockADomainSid,
DesiredAccessBedrockA,
&TrustedDomainHandleBedrockA2
);
if (!NT_SUCCESS(Status)) {
DbgPrint("LSA RPC CT - 2nd Open BedrockA Trusted Domain failed 0x%lx\n", Status);
return FALSE;
}
Status = LsaOpenTrustedDomain(
PolicyHandle,
BedrockBDomainSid,
DesiredAccessBedrockB,
&TrustedDomainHandleBedrockB2
);
if (!NT_SUCCESS(Status)) {
DbgPrint("LSA RPC CT - 2nd Open BedrockB Trusted Domain failed 0x%lx\n", Status);
return FALSE;
}
Status = LsaOpenTrustedDomain(
PolicyHandle,
BedrockCDomainSid,
DesiredAccessBedrockC,
&TrustedDomainHandleBedrockC2
);
if (!NT_SUCCESS(Status)) {
DbgPrint("LSA RPC CT - 2nd Open BedrockC Trusted Domain failed 0x%lx\n", Status);
return FALSE;
}
Status = LsaOpenTrustedDomain(
PolicyHandle,
BedrockDDomainSid,
DesiredAccessBedrockD,
&TrustedDomainHandleBedrockD2
);
if (!NT_SUCCESS(Status)) {
DbgPrint("LSA RPC CT - Open BedrockD Trusted Domain failed 0x%lx\n", Status);
return FALSE;
}
//
// Close the 2nd handles to the TrustedDomains
//
Status = LsaClose( TrustedDomainHandleBedrockA2 );
if (!NT_SUCCESS(Status)) {
DbgPrint("LSA RPC CT - Close BedrockA Trusted Domain hdl2 failed 0x%lx\n", Status);
return FALSE;
}
Status = LsaClose( TrustedDomainHandleBedrockB2 );
if (!NT_SUCCESS(Status)) {
DbgPrint("LSA RPC CT - Close BedrockB Trusted Domain hdl2 failed 0x%lx\n",Status);
return FALSE;
}
Status = LsaClose( TrustedDomainHandleBedrockC2 );
if (!NT_SUCCESS(Status)) {
DbgPrint("LSA RPC CT - Close BedrockC Trusted Domain hdl2 failed 0x%lx\n", Status);
return FALSE;
}
Status = LsaClose( TrustedDomainHandleBedrockD2 );
if (!NT_SUCCESS(Status)) {
DbgPrint("LSA RPC CT - Close BedrockD Trusted Domain hdl2 failed 0x%lx\n", Status);
return FALSE;
}
BooleanStatus = TRUE;
//
// Try to create BedrockA again. We should get STATUS_OBJECT_NAME_COLLISION
//
Status = LsaCreateTrustedDomain(
PolicyHandle,
&TrustedDomainInfoBedrockA,
GENERIC_ALL,
&TrustedDomainHandleBedrockA3
);
if (Status != STATUS_OBJECT_NAME_COLLISION) {
DbgPrint("LSA RPC CT - Create BedrockA Trusted Domain when BedrockA exists\n");
DbgPrint("and LSA_OBJECT_CREATE disposition specified\n");
DbgPrint("Expected 0x%lx (STATUS_OBJECT_NAME_COLLISION)\n",
STATUS_OBJECT_NAME_COLLISION);
DbgPrint("Got 0x%lx\n", Status);
BooleanStatus = FALSE;
}
return BooleanStatus;
if (Level == 2) {
//
// LsaOpenTrustedDomain with bad addresses
//
Status = LsaOpenTrustedDomain(
PolicyHandle,
BedrockADomainSid,
DesiredAccessBedrockA,
BadHandleAddress
);
//
// Lsa Close with bad address
//
Status = LsaClose( (LSA_HANDLE) BadAddress );
}
}
BOOLEAN
CtLsaTrustedDomainSetQueryInfo(
)
/*++
Routine Description:
This function tests the LsaSetInformationTrustedDomain and
LsaQueryInfoTrustedDomain API.
Arguments:
None
Return Value:
BOOLEAN - TRUE if test is successful, else FALSE
--*/
{
BOOLEAN BooleanStatus = TRUE;
DbgPrint("[3] - Test TrustedDomain Set and Query Info API\n");
BooleanStatus &= CtLsaTrustedDomainAccountInfo();
BooleanStatus &= CtLsaTrustedDomainControllersInfo();
BooleanStatus &= CtLsaTrustedDomainPosixOffsetInfo();
return(BooleanStatus);
}
BOOLEAN
CtLsaTrustedDomainAccountInfo()
{
BOOLEAN BooleanStatus = TRUE;
TRUSTED_DOMAIN_NAME_INFO TrustedDomainNameInfo;
//
// Setup sample Trusted Account Name Info
//
RtlInitUnicodeString(
&TrustedDomainNameInfo.Name,
L"TRUSTEDACCOUNT1"
);
BooleanStatus = CtLsaTrustedDomainSetQuerySub(
TrustedDomainNameInformation,
&TrustedDomainNameInfo
);
return(BooleanStatus);
}
BOOLEAN
CtLsaTrustedDomainControllersInfo()
{
BOOLEAN BooleanStatus = TRUE;
ULONG Controller;
UNICODE_STRING Names[CT_TRUSTED_CONTROLLER_COUNT];
PWSTR Strings[CT_TRUSTED_CONTROLLER_COUNT] = {
L"\\CONTROLLERA",
L"\\CONTROLLERB",
L"\\CONTROLLERC",
L"\\CONTROLLERD"
};
TRUSTED_CONTROLLERS_INFO TrustedControllersInfo;
//
// Setup sample Trusted Controllers Info
//
TrustedControllersInfo.Entries = CT_TRUSTED_CONTROLLER_COUNT;
for (Controller = 0;
Controller < CT_TRUSTED_CONTROLLER_COUNT;
Controller++) {
RtlInitUnicodeString( &Names[Controller], Strings[Controller] );
}
TrustedControllersInfo.Names = Names;
BooleanStatus = CtLsaTrustedDomainSetQuerySub(
TrustedControllersInformation,
&TrustedControllersInfo
);
return(BooleanStatus);
}
BOOLEAN
CtLsaTrustedDomainPosixOffsetInfo()
{
BOOLEAN BooleanStatus = TRUE;
TRUSTED_POSIX_OFFSET_INFO TrustedPosixOffsetInfo;
//
// Setup sample Trusted Posix Offset Info
//
TrustedPosixOffsetInfo.Offset = CT_TRUSTED_POSIX_OFFSET;
BooleanStatus = CtLsaTrustedDomainSetQuerySub(
TrustedPosixOffsetInformation,
&TrustedPosixOffsetInfo
);
return(BooleanStatus);
}
BOOLEAN
CtLsaTrustedDomainSetQuerySub(
IN TRUSTED_INFORMATION_CLASS InformationClass,
IN PVOID TrustedDomainInformation
)
{
NTSTATUS Status;
BOOLEAN BooleanStatus = TRUE;
OBJECT_ATTRIBUTES ObjectAttributes;
SECURITY_QUALITY_OF_SERVICE SecurityQualityOfService;
LSA_HANDLE TrustedDomainHandleSet = NULL;
LSA_HANDLE TrustedDomainHandleQuery = NULL;
PVOID ReturnedTrustedDomainInformation;
ACCESS_MASK DesiredAccess;
LSA_HANDLE PolicyHandle = NULL;
ACCESS_MASK RequiredAccessSetTrustedDomain[TrustedPosixOffsetInformation+1] =
{
0,
0, // TrustedDomainNameInformation can't be set
TRUSTED_SET_CONTROLLERS,
TRUSTED_SET_POSIX
};
ACCESS_MASK RequiredAccessQueryTrustedDomain[TrustedPosixOffsetInformation+1] =
{
0,
TRUSTED_QUERY_DOMAIN_NAME,
TRUSTED_QUERY_CONTROLLERS,
TRUSTED_QUERY_POSIX
};
//
// Open a handle to the LSA
//
CtLsaInitObjectAttributes(
&ObjectAttributes,
&SecurityQualityOfService
);
Status = LsaOpenPolicy(
SystemName,
&ObjectAttributes,
GENERIC_ALL,
&PolicyHandle
);
if (!NT_SUCCESS(Status)) {
DbgPrint("LSA RPC CT - Lsa Open failed 0x%lx\n", Status);
goto TrustedSetQuerySubError;
}
DbgPrint("...Testing information class %d\n", InformationClass);
//
// Open a handle to the TrustedDomain Object with the access required for
// setting the given TrustedDomain Information Class. If the Class
// is not settable via LsaSetInformationTrustedDomain(), ie requires
// a trusted client, the call is expected to fail even if we open
// the TrustedDomain Object with GENERIC_ALL.
//
if (CtLsaTrustedDomainSetInfoAllowed(InformationClass)) {
DesiredAccess = RequiredAccessSetTrustedDomain[InformationClass];
} else {
DesiredAccess = GENERIC_ALL;
}
Status = LsaOpenTrustedDomain(
PolicyHandle,
BedrockADomainSid,
DesiredAccess,
&TrustedDomainHandleSet
);
if (!NT_SUCCESS(Status)) {
DbgPrint(
"LSA RPC CT - TrustedDomain object open handle failed 0x%lx\n",
Status
);
BooleanStatus = FALSE;
}
//
// Set the TrustedDomain Information for the specified class
//
try {
Status = LsaSetInformationTrustedDomain(
TrustedDomainHandleSet,
InformationClass,
TrustedDomainInformation
);
} except (EXCEPTION_EXECUTE_HANDLER) {
DbgPrint("Lsa CT RPC - Access Violation: CtLsaTrustedDomainSetQuerySub\n");
DbgPrint(" within LsaSetInformationTrustedDomain call 1\n");
BooleanStatus = FALSE;
}
if (!BooleanStatus) {
goto TrustedSetQuerySubError;
}
//
// If setting of the InformationClass via LsaSetInformationTrustedDomain()
// is allowed, we expect STATUS_SUCCESS, otherwise we expect
// STATUS_INVALID_PARAMETER.
//
if (CtLsaTrustedDomainSetInfoAllowed(InformationClass)) {
if (!NT_SUCCESS(Status)) {
BooleanStatus = FALSE;
DbgPrint(
"LsaSetInformationTrustedDomain - Class %d failed 0x%lx\n",
InformationClass,
Status
);
BooleanStatus = FALSE;
}
} else {
//
// Information Class may not be set via LsaSetInformationTrustedDomain
// We expect STATUS_INVALID_PARAMETER.
//
if (Status != STATUS_INVALID_PARAMETER) {
DbgPrint("LsaSetInformationTrustedDomain - Attempt to set ");
DbgPrint("prohibited Information Class should have\n");
DbgPrint(
"failed 0x%lx\n (STATUS_INVALID_PARAMETER)",
STATUS_INVALID_PARAMETER
);
DbgPrint("instead returned 0x%lx\n", Status);
BooleanStatus = FALSE;
}
}
Status = LsaClose(TrustedDomainHandleSet);
TrustedDomainHandleSet = NULL;
//
// Now open a handle to the TrustedDomain Object with the access required for
// querying the given TrustedDomain Information Class. If the Class
// is not queryable via LsaQueryInformationTrustedDomain(), ie requires
// a trusted client, the call is expected to fail even if we open
// the TrustedDomain Object with GENERIC_ALL.
//
if (CtLsaTrustedDomainQueryInfoAllowed(InformationClass)) {
DesiredAccess = RequiredAccessQueryTrustedDomain[InformationClass];
} else {
DesiredAccess = GENERIC_ALL;
}
Status = LsaOpenTrustedDomain(
PolicyHandle,
BedrockADomainSid,
DesiredAccess,
&TrustedDomainHandleQuery
);
if (!NT_SUCCESS(Status)) {
DbgPrint(
"LSA RPC CT - TrustedDomain object open handle failed 0x%lx\n",
Status
);
goto TrustedSetQuerySubError;
}
//
// Now query the TrustedDomain Information set
//
try {
Status = LsaQueryInfoTrustedDomain(
TrustedDomainHandleQuery,
InformationClass,
&ReturnedTrustedDomainInformation
);
} except (EXCEPTION_EXECUTE_HANDLER) {
DbgPrint("Lsa CT RPC - Access Violation: CtLsaTrustedDomainSetQuerySub\n");
DbgPrint(" within LsaQueryInformationTrustedDomain call 1\n");
BooleanStatus = FALSE;
}
if (!BooleanStatus) {
goto TrustedSetQuerySubError;
}
//
// If querying of the InformationClass via LsaQueryInformationTrustedDomain()
// is allowed, we expect STATUS_SUCCESS, otherwise we expect
// STATUS_INVALID_PARAMETER.
//
if (CtLsaTrustedDomainQueryInfoAllowed(InformationClass)) {
if (!NT_SUCCESS(Status)) {
BooleanStatus = FALSE;
DbgPrint(
"LsaQueryInformationTrustedDomain - Class %d failed 0x%lx\n",
InformationClass,
Status
);
BooleanStatus = FALSE;
}
} else {
//
// Information Class may not be queried via LsaQueryInformationTrustedDomain
// We expect STATUS_INVALID_PARAMETER.
//
if (Status != STATUS_INVALID_PARAMETER) {
DbgPrint("LsaQueryInformationTrustedDomain - Attempt to query ");
DbgPrint("prohibited Information Class should have\n");
DbgPrint(
"failed 0x%lx\n (STATUS_INVALID_PARAMETER)",
STATUS_INVALID_PARAMETER
);
DbgPrint("instead returned 0x%lx\n", Status);
BooleanStatus = FALSE;
}
}
//
// If set and query are both allowed for the Information Class, they
// should both have worked. In this case, compare the returned TrustedDomain
// information with that set
//
if (CtLsaTrustedDomainSetInfoAllowed(InformationClass) &&
CtLsaTrustedDomainQueryInfoAllowed(InformationClass)) {
BooleanStatus &= CtLsaTrustedDomainInfoClassCompare(
InformationClass,
TrustedDomainInformation,
ReturnedTrustedDomainInformation
);
}
if (ReturnedTrustedDomainInformation != NULL) {
Status = LsaFreeMemory(ReturnedTrustedDomainInformation);
ReturnedTrustedDomainInformation = NULL;
if (!NT_SUCCESS(Status)) {
DbgPrint("LSA RPC CT - Query Info Trusted Domain");
DbgPrint(" - LsaFreeMemory(ReturnedTrustedDomainInformation)");
DbgPrint(" failed 0x%lx\n", Status);
BooleanStatus = FALSE;
}
}
Status = LsaClose(TrustedDomainHandleQuery);
TrustedDomainHandleQuery = NULL;
//
// Now open a handle to the TrustedDomain Object with all accesses except the
// access required for setting the given TrustedDomain Information Class.
// If the TrustedDomain Information Class cannot be set via public API,
// open the handle instead with TRUSTED_ALL_ACCESS.
//
if (CtLsaTrustedDomainSetInfoAllowed(InformationClass)) {
DesiredAccess =
(TRUSTED_ALL_ACCESS & ~RequiredAccessSetTrustedDomain[InformationClass]);
} else {
DesiredAccess = GENERIC_ALL;
}
Status = LsaOpenTrustedDomain(
PolicyHandle,
BedrockADomainSid,
DesiredAccess,
&TrustedDomainHandleSet
);
if (!NT_SUCCESS(Status)) {
DbgPrint(
"LSA RPC CT - TrustedDomain object open handle failed 0x%lx\n",
Status
);
goto TrustedSetQuerySubError;
}
//
// Attempt to set the TrustedDomain Information for the specified class
// using the handle opened above. This handle has either the
// complement of the accesses required (if the class is settable
// via LsaSetInformationTrustedDomain()) or TrustedDomain_ALL_ACCESS. In the
// former case, we should get STATUS_ACCESS_DENIED back from
// LsaSetInformationTrustedDomain(), in the latter case, STATUS_INVALID_PARAMETER.
//
try {
Status = LsaSetInformationTrustedDomain(
TrustedDomainHandleSet,
InformationClass,
TrustedDomainInformation
);
} except (EXCEPTION_EXECUTE_HANDLER) {
DbgPrint("Lsa CT RPC - Access Violation: CtLsaTrustedDomainSetQuerySub\n");
DbgPrint(" within LsaSetInformationTrustedDomain call 2\n");
BooleanStatus = FALSE;
}
//
// If setting of the InformationClass via LsaSetInformationTrustedDomain()
// is allowed, we expect STATUS_ACCESS_DENIED since we specified the
// complement of the access required (relative to TrustedDomain_ALL_ACCESS).
// Otherwise we expect STATUS_INVALID_PARAMETER.
//
if (CtLsaTrustedDomainSetInfoAllowed(InformationClass)) {
if (Status != STATUS_ACCESS_DENIED) {
DbgPrint("LsaSetInformationTrustedDomain Class");
DbgPrint(
" %d access mask 0x%lx should have failed 0x%lx (STATUS_ACCESS_DENIED)\n",
InformationClass,
DesiredAccess,
STATUS_ACCESS_DENIED
);
DbgPrint(
"since the required access for setting info is 0x%lx\n",
RequiredAccessSetTrustedDomain[InformationClass]
);
DbgPrint(" but instead returned 0x%lx\n", Status);
BooleanStatus = FALSE;
}
} else {
//
// Information Class may not be set via LsaSetInformationTrustedDomain
// We expect STATUS_INVALID_PARAMETER.
//
if (Status != STATUS_INVALID_PARAMETER) {
DbgPrint("LsaSetInformationTrustedDomain - Attempt to set ");
DbgPrint("prohibited Information Class should have\n");
DbgPrint(
"failed 0x%lx\n (STATUS_INVALID_PARAMETER)",
STATUS_INVALID_PARAMETER
);
DbgPrint("instead returned 0x%lx\n", Status);
BooleanStatus = FALSE;
}
}
Status = LsaClose(TrustedDomainHandleSet);
TrustedDomainHandleSet = NULL;
//
// Now open a handle to the TrustedDomain Object with all accesses except the
// access required for querying the given TrustedDomain Information Class.
// If the TrustedDomain Information Class cannot be queried via public API,
// open the handle instead with TrustedDomain_ALL_ACCESS.
//
if (CtLsaTrustedDomainQueryInfoAllowed(InformationClass)) {
DesiredAccess =
(TRUSTED_ALL_ACCESS & ~RequiredAccessQueryTrustedDomain[InformationClass]);
} else {
DesiredAccess = GENERIC_ALL;
}
Status = LsaOpenTrustedDomain(
PolicyHandle,
BedrockADomainSid,
DesiredAccess,
&TrustedDomainHandleQuery
);
if (!NT_SUCCESS(Status)) {
DbgPrint(
"LSA RPC CT - TrustedDomain object open handle failed 0x%lx\n",
Status
);
goto TrustedSetQuerySubError;
}
try {
//
// Now query the TrustedDomain Information set. This should fail
// STATUS_ACCESS_DENIED
//
Status = LsaQueryInfoTrustedDomain(
TrustedDomainHandleQuery,
InformationClass,
&ReturnedTrustedDomainInformation
);
} except (EXCEPTION_EXECUTE_HANDLER) {
DbgPrint("Lsa CT RPC - Access Violation: CtLsaTrustedDomainSetQuerySub\n");
DbgPrint(" within LsaQueryInformationTrustedDomain call 2\n");
BooleanStatus = FALSE;
}
//
// If querying of the InformationClass via LsaQueryInformationTrustedDomain()
// is allowed, we expect STATUS_ACCESS_DENIED since we specified the
// complement of the access required (relative to TrustedDomain_ALL_ACCESS).
// Otherwise we expect STATUS_INVALID_PARAMETER.
//
if (CtLsaTrustedDomainQueryInfoAllowed(InformationClass)) {
if (Status != STATUS_ACCESS_DENIED) {
DbgPrint("LsaQueryInfoTrustedDomain Class");
DbgPrint(
" %d access mask 0x%lx should have failed 0x%lx (STATUS_ACCESS_DENIED)\n",
InformationClass,
DesiredAccess,
STATUS_ACCESS_DENIED
);
DbgPrint(
"since the required access for querying info is 0x%lx\n",
RequiredAccessQueryTrustedDomain[InformationClass]
);
DbgPrint(" but instead returned 0x%lx\n", Status);
BooleanStatus = FALSE;
}
} else {
//
// Information Class may not be queried via LsaQueryInformationTrustedDomain
// We expect STATUS_INVALID_PARAMETER.
//
if (Status != STATUS_INVALID_PARAMETER) {
DbgPrint("LsaQueryInfoTrustedDomain - Attempt to query ");
DbgPrint("prohibited Information Class should have\n");
DbgPrint(
"failed 0x%lx\n (STATUS_INVALID_PARAMETER)",
STATUS_INVALID_PARAMETER
);
DbgPrint("instead returned 0x%lx\n", Status);
BooleanStatus = FALSE;
}
}
Status = LsaClose(TrustedDomainHandleQuery);
TrustedDomainHandleQuery = NULL;
TrustedSetQuerySubFinish:
if (ReturnedTrustedDomainInformation != NULL) {
Status = LsaFreeMemory(ReturnedTrustedDomainInformation);
ReturnedTrustedDomainInformation = NULL;
if (!NT_SUCCESS(Status)) {
DbgPrint("LSA RPC CT - Query Info Trusted Domain");
DbgPrint(" - LsaFreeMemory(ReturnedTrustedDomainInformation)");
DbgPrint(" failed 0x%lx\n", Status);
BooleanStatus = FALSE;
}
}
if (PolicyHandle != NULL) {
Status = LsaClose(PolicyHandle);
}
return(BooleanStatus);
TrustedSetQuerySubError:
BooleanStatus = FALSE;
goto TrustedSetQuerySubFinish;
}
BOOLEAN
CtLsaTrustedDomainInfoClassCompare(
IN TRUSTED_INFORMATION_CLASS InformationClass,
IN PVOID TrustedDomainInformation1,
IN PVOID TrustedDomainInformation2
)
/*++
Routine Description:
This function compares two sets of TrustedDomain Information for a known
Information Class.
Arguments:
InformationClass - Specifies a TrustedDomain Information Class
TrustedDomainInformation1 - First comparand. TrustedDomain Information for the
given information class.
TrustedDomainInformation2 - Second comparand. TrustedDomain Information for the
given information class.
Return Values:
BOOLEAN - TRUE if TrustedDomain information sets are equal , else FALSE
--*/
{
BOOLEAN BooleanStatus = TRUE;
ULONG Controller;
ULONG Entries;
// PTRUSTED_DOMAIN_NAME_INFO TrustedDomainNameInfo1;
PTRUSTED_CONTROLLERS_INFO TrustedControllersInfo1;
PTRUSTED_POSIX_OFFSET_INFO TrustedPosixOffsetInfo1;
// PTRUSTED_DOMAIN_NAME_INFO TrustedDomainNameInfo2;
PTRUSTED_CONTROLLERS_INFO TrustedControllersInfo2;
PTRUSTED_POSIX_OFFSET_INFO TrustedPosixOffsetInfo2;
//
// Switch on Information Class
//
switch (InformationClass) {
case TrustedDomainNameInformation:
/* This test will be enabled for trusted callers only
TrustedDomainNameInfo1 = (PTRUSTED_DOMAIN_NAME_INFO) TrustedDomainInfo1;
TrustedDomainNameInfo2 = (PTRUSTED_DOMAIN_NAME_INFO) TrustedDomainInfo2;
if (!RtlEqualUnicodeString(
&TrustedDomainNameInfo1,
&TrustedDomainNameInfo2,
FALSE
)) {
DbgPrint("TrustedDomainNameInfo - Name mismatch\n");
BooleanStatus = FALSE;
}
*/
break;
case TrustedControllersInformation:
TrustedControllersInfo1 = (PTRUSTED_CONTROLLERS_INFO) TrustedDomainInformation1;
TrustedControllersInfo2 = (PTRUSTED_CONTROLLERS_INFO) TrustedDomainInformation2;
//
// First compare the number of entries
//
if (TrustedControllersInfo1->Entries !=
TrustedControllersInfo2->Entries) {
DbgPrint("TrustedControllersInfo - Entries mismatch\n");
DbgPrint(
".. expected %d, got %d\n",
TrustedControllersInfo1->Entries,
TrustedControllersInfo2->Entries
);
BooleanStatus = FALSE;
}
Entries = TrustedControllersInfo1->Entries;
//
// Now compare each of the Trusted Controller names
//
for (Controller = 0; Controller < Entries; Controller++) {
if (!RtlEqualUnicodeString(
&TrustedControllersInfo1->Names[Controller],
&TrustedControllersInfo2->Names[Controller],
FALSE
)) {
DbgPrint("Trusted Controller Name mismatch\n");
DbgPrint(".. name number %d\n", Controller);
DbgPrint("No further names compared\n");
BooleanStatus = FALSE;
break;
}
}
break;
case TrustedPosixOffsetInformation:
TrustedPosixOffsetInfo1 = (PTRUSTED_POSIX_OFFSET_INFO) TrustedDomainInformation1;
TrustedPosixOffsetInfo2 = (PTRUSTED_POSIX_OFFSET_INFO) TrustedDomainInformation2;
//
// Compare the Posix Offset with the value set.
//
if (TrustedPosixOffsetInfo1->Offset != TrustedPosixOffsetInfo2->Offset) {
DbgPrint("Trusted Posix Offset Info - Mismatch on Offset\n");
DbgPrint(
".. expected %d, got %d\n",
TrustedPosixOffsetInfo1->Offset,
TrustedPosixOffsetInfo2->Offset
);
BooleanStatus = FALSE;
}
break;
default:
BooleanStatus = FALSE;
DbgPrint(
"Bug in test program - Invalid Information Class %d\n",
InformationClass
);
break;
}
return(BooleanStatus);
}
BOOLEAN
CtLsaTrustedDomainQueryInfoAllowed(
IN TRUSTED_INFORMATION_CLASS InformationClass
)
/*++
Routine Description:
This function determines whether querying of a TrustedDomain Information Class
is allowed via LsaQueryInformationTrustedDomain. Note that all TrustedDomain
Information Classes may be queried via (to be implemented) trusted
clients to private API.
Arguments:
InformationClass - The TrustedDomain Information Class to be checked (assumed
valid).
Return Value:
BOOLEAN - TRUE if the information class can be queried via
LsaQueryInformationTrustedDomain() else FALSE.
--*/
{
//
// Range check the InformationClass parameter.
//
if ((InformationClass < TrustedDomainNameInformation) ||
(InformationClass > TrustedPosixOffsetInformation)) {
DbgPrint("WARNING! CtLsaTrustedDomainQueryInfoAllowed:\n");
DbgPrint(
" InformationClass %d is invalid - check caller\n",
InformationClass
);
return(FALSE);
}
//
// Currently all Information Classes may be queried via
// LsaQueryInfoTrustedDomain(). Place any future restrictions
// on what may be queried here.
//
return(TRUE);
}
BOOLEAN
CtLsaTrustedDomainSetInfoAllowed(
IN TRUSTED_INFORMATION_CLASS InformationClass
)
/*++
Routine Description:
This function determines whether setting of a TrustedDomain Information Class
is allowed via LsaSetInformationTrustedDomain. Note that all TrustedDomain
Information Classes may be set via (to be implemented) trusted
clients to private API.
Arguments:
InformationClass - The TrustedDomain Information Class to be checked (assumed
valid).
Return Value:
BOOLEAN - TRUE idf the information class can be set via
LsaSetInformationTrustedDomain() else FALSE.
--*/
{
//
// Range check the InformationClass parameter.
//
if ((InformationClass < TrustedDomainNameInformation) ||
(InformationClass > TrustedPosixOffsetInformation)) {
DbgPrint("WARNING! CtLsaTrustedDomainSetInfoAllowed:\n");
DbgPrint(
" InformationClass %d is invalid - check caller\n",
InformationClass
);
return(FALSE);
}
//
// Check if this Information Class can be set via
// LsaSetInformationTrustedDomain().
//
if (InformationClass == TrustedDomainNameInformation) {
return(FALSE);
}
return(TRUE);
}
BOOLEAN
CtLsaTrustedDomainEnumeration(
)
/*++
Routine Description:
This function tests the enumeration of TrustedDomains in the LSA
Arguments:
None.
Return Value:
BOOLEAN - TRUE if successful, FALSE if any failures.
--*/
{
NTSTATUS Status = STATUS_SUCCESS;
BOOLEAN BooleanStatus = TRUE;
ULONG Base = 0;
ULONG CountReturned = 0;
ULONG PreferedMaximumLength;
ULONG EnumerationContext = 0;
ULONG EnumNumber = 0;
ULONG EnumIndex;
ULONG Index;
PLSA_TRUST_INFORMATION EnumerationInformation;
PVOID EnumerationInformationVoid = NULL;
PVOID *BadEnumerationAddress = NULL;
PULONG BadCountReturnedAddress = NULL;
ULONG CallNumber;
CT_LSA_SINGLE_CALL_ENUM_INFO EnumerationInformations[ 20 ];
DbgPrint("[4] - Test TrustedDomain Enumeration API\n");
//
// Enumerate the TrustedDomains in the Lsa. Set the Prefered Maximum
// Length od data returned to a low value to cause as many subsequent
// calls to the LsaEnumerateTrustedDomains API as possible.
//
PreferedMaximumLength = 1;
CallNumber = 1;
Status = STATUS_SUCCESS;
while(NT_SUCCESS(Status)) {
Status = LsaEnumerateTrustedDomains(
PolicyHandle,
&EnumerationContext,
&EnumerationInformationVoid,
PreferedMaximumLength,
&CountReturned
);
EnumerationInformations[ EnumNumber ].EnumInfoReturned =
EnumerationInformationVoid;
EnumerationInformations[ EnumNumber ].CountReturned = CountReturned;
if (!NT_SUCCESS(Status)) {
break;
}
CallNumber++;
}
if (!NT_SUCCESS(Status)) {
if (Status != STATUS_NO_MORE_ENTRIES) {
DbgPrint(
"LSA RPC CT - Enumeration of TrustedDomains failed\n"
"Call number %d to LsaEnumerateTrustedDomains returned 0x%lx\n",
CallNumber,
Status
);
return FALSE;
}
}
TrustedDomainSidInfo[0].Sid = BedrockADomainSid;
TrustedDomainSidInfo[1].Sid = BedrockBDomainSid;
TrustedDomainSidInfo[3].Sid = BedrockCDomainSid;
TrustedDomainSidInfo[2].Sid = BedrockDDomainSid;
TrustedDomainSidInfo[0].SidFound = FALSE;
TrustedDomainSidInfo[1].SidFound = FALSE;
TrustedDomainSidInfo[2].SidFound = FALSE;
TrustedDomainSidInfo[3].SidFound = FALSE;
//
// Now see if we found all of the TrustedDomain Sids we were looking for.
//
for (EnumIndex = 0; EnumIndex < EnumNumber; EnumIndex++) {
CountReturned = EnumerationInformations[ EnumIndex ].CountReturned;
EnumerationInformation = (PLSA_TRUST_INFORMATION)
EnumerationInformations[ EnumIndex ].EnumInfoReturned;
for( Index = 0; Index < CountReturned; Index++ ) {
SidFound = FALSE;
for ( SearchIndex = 0; SearchIndex < 4; SearchIndex++ ) {
if (RtlEqualSid(
TrustedDomainSidInfo[SearchIndex].Sid,
EnumerationInformation[Index].Sid
)) {
if (TrustedDomainSidInfo[SearchIndex].SidFound) {
DbgPrint(
"Already found Sid with SearchIndex %d\n",
SearchIndex
);
} else {
TrustedDomainSidInfo[SearchIndex].SidFound = TRUE;
}
SidFound = TRUE;
break;
}
}
}
}
//
// Now check that all of the Sids were found.
//
for (SearchIndex = 0; SearchIndex < 4; SearchIndex++ ) {
if (!TrustedDomainSidInfo[ SearchIndex ].SidFound ) {
DbgPrint(
"LSA RPC CT - Enumeration of TrustedDomains failed\n"
"Trusted Domain Sid number %d was not found",
SearchIndex
);
BooleanStatus = FALSE;
break;
}
}
if (!BooleanStatus) {
return(FALSE);
}
//
// Bad Addresses passed to Lsa Enumerate TrustedDomains API
//
if (Level == 2) {
Status = LsaEnumerateTrustedDomains(
(LSA_HANDLE) BadAddress,
&EnumerationContext,
&EnumerationInformationVoid,
PreferedMaximumLength,
&CountReturned
);
Status = LsaEnumerateTrustedDomains(
PolicyHandle,
(PLSA_ENUMERATION_HANDLE) BadAddress,
&EnumerationInformationVoid,
PreferedMaximumLength,
&CountReturned
);
Status = LsaEnumerateTrustedDomains(
PolicyHandle,
&EnumerationContext,
BadEnumerationAddress,
PreferedMaximumLength,
&CountReturned
);
Status = LsaEnumerateTrustedDomains(
PolicyHandle,
&EnumerationContext,
&EnumerationInformationVoid,
PreferedMaximumLength,
BadCountReturnedAddress
);
}
return(BooleanStatus);
}
BOOLEAN
CtLsaTrustedDomainDelete(
)
/*++
Routine Description:
This function tests deletion of TrustedDomains. First, a simple test is
made to see if we can delete a freshly created TrustedDomain. Next, we
try to delete the TrustedDomains created by CtLsaTrustedDomainCreate.
Arguments:
None.
Return Value:
BOOLEAN - TRUE if successful, FALSE if any error.
--*/
{
NTSTATUS Status;
BOOLEAN BooleanStatus = TRUE;
UNICODE_STRING BedrockEDomainName;
PSID BedrockEDomainSid = BedrockDomainSid;
DbgPrint("[5] - Test TrustedDomain Deletion API\n");
//
// First try a simple test. Create a new TrustedDomain called BedrockE
// to be given DELETE access upon create. Then delete it.
//
RtlInitUnicodeString( &BedrockEDomainName, L"BedrockE" );
DesiredAccessBedrockE = DELETE;
CtLsaTrustedDomainSetInfo(
BedrockEDomainSid,
&BedrockEDomainName,
&TrustedDomainInfoBedrockE
);
Status = LsaCreateTrustedDomain(
PolicyHandle,
&TrustedDomainInfoBedrockE,
DesiredAccessBedrockE,
&TrustedDomainHandleBedrockE
);
if (!NT_SUCCESS(Status)) {
DbgPrint("LSA RPC CT - Create BedrockE Trusted Domain failed 0x%lx\n", Status);
return FALSE;
}
//
// Delete the BedrockE TrustedDomain
//
Status = LsaDelete( TrustedDomainHandleBedrockE );
if (!NT_SUCCESS(Status)) {
DbgPrint("LSA RPC CT - Delete BedrockE Trusted Domain failed 0x%lx\n", Status);
return FALSE;
}
//
// Delete the BedrockA TrustedDomain. This should work since it was opened
// with GENERIC_ALL access.
//
Status = LsaDelete( TrustedDomainHandleBedrockA );
if (!NT_SUCCESS(Status)) {
DbgPrint("LSA RPC CT - Delete BedrockA Trusted Domain failed 0x%lx\n", Status);
return FALSE;
}
//
// Delete the BedrockB TrustedDomain. This should not work since it was opened
// with GENERIC_READ access.
//
if (DesiredAccessBedrockB != GENERIC_READ) {
DbgPrint("DesiredAccessBedrockB should be GENERIC_READ\n");
DbgPrint("Bug in this test program\n");
return FALSE;
}
Status = LsaDelete( TrustedDomainHandleBedrockB );
if (Status != STATUS_ACCESS_DENIED) {
DbgPrint("LSA RPC CT - Delete BedrockB Trusted Domain should have failed\n");
DbgPrint(" with STATUS_ACCESS_DENIED since handle specifies\n");
DbgPrint("GENERIC_READ access - got 0x%lx\n", Status);
BooleanStatus = FALSE;
}
//
// Now close the handle to BedrockB, open another handle with GENERIC_ALL
// access and try to delete the TrustedDomain again.
//
Status = LsaClose(TrustedDomainHandleBedrockB);
if (!NT_SUCCESS(Status)) {
DbgPrint("Close BedrockB TrustedDomain failed 0x%lx\n", Status);
}
TrustedDomainHandleBedrockBOpen = NULL;
Status = LsaOpenTrustedDomain(
PolicyHandle,
BedrockBDomainSid,
GENERIC_ALL,
&TrustedDomainHandleBedrockBOpen
);
if (!NT_SUCCESS(Status)) {
DbgPrint(
"LSA RPC CT - Open BedrockB Trusted Domain for GENERIC_ALL access failed 0x%lx\n",
Status
);
return FALSE;
}
Status = LsaDelete( TrustedDomainHandleBedrockBOpen );
if (!NT_SUCCESS(Status)) {
DbgPrint("LSA RPC CT - Delete BedrockB Trusted Domain failed 0x%lx\n", Status);
BooleanStatus = FALSE;
}
//
// Delete the BedrockC TrustedDomain. This should not work since it was opened
// with GENERIC_WRITE access which does not include DELETE.
//
if (DesiredAccessBedrockC != GENERIC_WRITE) {
DbgPrint("DesiredAccessBedrockC should be GENERIC_WRITE\n");
DbgPrint("Bug in this test program\n");
return FALSE;
}
Status = LsaDelete( TrustedDomainHandleBedrockC );
if (Status != STATUS_ACCESS_DENIED) {
DbgPrint("LSA RPC CT - Delete BedrockC Trusted Domain should have failed\n");
DbgPrint(" with STATUS_ACCESS_DENIED since handle specifies\n");
DbgPrint("GENERIC_READ access - got 0x%lx\n", Status);
BooleanStatus = FALSE;
}
//
// Now close the handle to BedrockC and open another handle with DELETE
// access and try to delete the TrustedDomain again.
//
Status = LsaClose(TrustedDomainHandleBedrockC);
if (!NT_SUCCESS(Status)) {
DbgPrint("Close BedrockC TrustedDomain failed 0x%lx\n", Status);
}
TrustedDomainHandleBedrockCOpen = NULL;
Status = LsaOpenTrustedDomain(
PolicyHandle,
BedrockCDomainSid,
DELETE,
&TrustedDomainHandleBedrockCOpen
);
if (!NT_SUCCESS(Status)) {
DbgPrint(
"LSA RPC CT - Open BedrockC Trusted Domain for DELETE access failed 0x%lx\n",
Status
);
return FALSE;
}
Status = LsaDelete( TrustedDomainHandleBedrockCOpen );
if (!NT_SUCCESS(Status)) {
DbgPrint("LSA RPC CT - Delete BedrockC Trusted Domain failed 0x%lx\n", Status);
BooleanStatus = FALSE;
}
//
// Delete the BedrockD TrustedDomain. This should not work since it was opened
// with GENERIC_EXECUTE access.
//
if (DesiredAccessBedrockD != GENERIC_EXECUTE) {
DbgPrint("DesiredAccessBedrockD should be GENERIC_EXECUTE\n");
DbgPrint("Bug in this test program\n");
return FALSE;
}
Status = LsaDelete( TrustedDomainHandleBedrockD );
if (Status != STATUS_ACCESS_DENIED) {
DbgPrint("LSA RPC CT - Delete BedrockD Trusted Domain failed 0x%lx\n", Status);
BooleanStatus = FALSE;
}
//
// Now close the handle to BedorckD, open another handle with DELETE
// access and try to delete it again.
//
Status = LsaClose(TrustedDomainHandleBedrockD);
if (!NT_SUCCESS(Status)) {
DbgPrint("Close BedrockD TrustedDomain failed 0x%lx\n", Status);
}
TrustedDomainHandleBedrockDOpen = NULL;
Status = LsaOpenTrustedDomain(
PolicyHandle,
BedrockDDomainSid,
DELETE,
&TrustedDomainHandleBedrockDOpen
);
if (!NT_SUCCESS(Status)) {
DbgPrint(
"LSA RPC CT - Open BedrockD Trusted Domain for DELETE access failed 0x%lx\n",
Status
);
BooleanStatus = FALSE;
}
Status = LsaDelete( TrustedDomainHandleBedrockDOpen );
if (!NT_SUCCESS(Status)) {
DbgPrint("LSA RPC CT - Delete BedrockD Trusted Domain failed 0x%lx\n", Status);
BooleanStatus = FALSE;
}
return TRUE;
}
VOID
CtLsaTrustedDomainSetInfo(
IN PSID DomainSid,
IN PUNICODE_STRING DomainName,
OUT PLSA_TRUST_INFORMATION TrustedDomainInfo
)
{
TrustedDomainInfo->Name = *DomainName;
TrustedDomainInfo->Sid = DomainSid;
}
BOOLEAN
CtLsaSecretObject(
IN BOOLEAN TrustedClient
)
/*++
Routine Description:
This function tests the Lsa Secret Object API.
Arguments:
TrustedClient - Specifies whether Trusted Client variations
are to be run additionally. NOTE: These can only be run
with ctlsarpc -lsainit... substituted for lsass.exe
Return Value:
BOOLEAN - TRUE if successful, FALSE if any failures.
--*/
{
NTSTATUS Status;
BOOLEAN BooleanStatus = TRUE;
BOOLEAN BooleanStatusDelete = TRUE;
BOOLEAN SecretsCreated = FALSE;
DbgPrint("********************************************************\n");
DbgPrint("LSA RPC CT - Test Lsa Secret Object API\n");
DbgPrint("********************************************************\n");
//
// Open a handle to the LSA
//
CtLsaInitObjectAttributes(
&ObjectAttributes,
&SecurityQualityOfService
);
Status = LsaOpenPolicy(
SystemName,
&ObjectAttributes,
GENERIC_ALL,
&PolicyHandle
);
if (!NT_SUCCESS(Status)) {
DbgPrint("LSA RPC CT - Lsa Open failed 0x%lx\n", Status);
goto SecretObjectError;
}
//
// Cleanup secrets from last run
//
if (!CtLsaSecretCleanup()) {
DbgPrint("LSA RPC CT - Pre-test Secret cleanup failed\n");
}
//
// Test Secret creation. Abandon Secret testing if error.
//
if (!CtLsaSecretCreate()) {
goto SecretObjectError;
}
SecretsCreated = TRUE;
//
// Test Secret open and close. Abandon Secret testing if error.
//
if (!CtLsaSecretOpenClose()) {
goto SecretObjectError;
}
//
// Test Secret Set and Query Value
//
if (!CtLsaSecretSetQueryValue()) {
BooleanStatus = FALSE;
}
//
// Test Secret Enumeration (Only Trusted Callers can do this)
//
if (TrustedClient) {
if (!CtLsaSecretEnumeration()) {
BooleanStatus = FALSE;
}
}
//
// Test Secret Set Times (only Trusted Callers can do this)
//
if (TrustedClient) {
if (!CtLsaSecretSetTimes()) {
BooleanStatus = FALSE;
}
}
//
// Test Secret deletion.
//
if (!CtLsaSecretDelete()) {
BooleanStatusDelete = FALSE;
goto SecretObjectError;
}
SecretsCreated = FALSE;
SecretObjectFinish:
//
// Cleanup secrets from last run
//
if (!CtLsaSecretCleanup()) {
DbgPrint("LSA RPC CT - Pre-test Secret cleanup failed\n");
}
return BooleanStatus;
SecretObjectError:
BooleanStatus = FALSE;
goto SecretObjectFinish;
}
BOOLEAN
CtLsaSecretCreate(
)
/*++
Routine Description:
This function tests the LSA API that Create Secrets.
Arguments:
None.
Return Value:
BOOLEAN - TRUE if successful, FALSE if any failures.
--*/
{
NTSTATUS Status;
DbgPrint("[1] - Test Secret Creation API\n");
//
// Set up Secret information for Secrets to be created.
//
Status = CtSecretSetInfo(
"Fred",
"Fred secret current value",
"Fred secret old value",
&SecretInfoFred
);
if (!NT_SUCCESS(Status)) {
DbgPrint(
"LSA RPC CT - CtSecretSetInfo for Fred failed 0x%lx\n",
Status
);
return FALSE;
}
Status = CtSecretSetInfo(
"Wilma",
"Wilma secret current value",
"Wilma secret old value",
&SecretInfoWilma
);
if (!NT_SUCCESS(Status)) {
DbgPrint(
"LSA RPC CT - CtSecretSetInfo for Wilma failed 0x%lx\n",
Status
);
return FALSE;
}
Status = CtSecretSetInfo(
"Dino",
"Dino secret current value",
"Dino secret old value",
&SecretInfoDino
);
if (!NT_SUCCESS(Status)) {
DbgPrint(
"LSA RPC CT - CtSecretSetInfo for Dino failed 0x%lx\n",
Status
);
return FALSE;
}
Status = CtSecretSetInfo(
"Pebbles",
"Pebbles secret current value",
"Pebbles secret old value",
&SecretInfoPebbles
);
if (!NT_SUCCESS(Status)) {
DbgPrint(
"LSA RPC CT - CtSecretSetInfo for Pebbles failed 0x%lx\n",
Status
);
return FALSE;
}
//
// Create the new Secrets in the LSA Database.
//
DesiredAccessFred = GENERIC_ALL;
Status = LsaCreateSecret(
PolicyHandle,
&(SecretInfoFred.SecretName),
DesiredAccessFred,
&SecretHandleFred
);
if (!NT_SUCCESS(Status)) {
DbgPrint("LSA RPC CT - Create Fred Secret failed 0x%lx\n", Status);
return FALSE;
}
DesiredAccessWilma = GENERIC_READ;
Status = LsaCreateSecret(
PolicyHandle,
&(SecretInfoWilma.SecretName),
DesiredAccessWilma,
&SecretHandleWilma
);
if (!NT_SUCCESS(Status)) {
DbgPrint("LSA RPC CT - Create Wilma Secret failed 0x%lx\n", Status);
return FALSE;
}
DesiredAccessPebbles = GENERIC_WRITE;
Status = LsaCreateSecret(
PolicyHandle,
&(SecretInfoPebbles.SecretName),
DesiredAccessPebbles,
&SecretHandlePebbles
);
if (!NT_SUCCESS(Status)) {
DbgPrint("LSA RPC CT - Create Pebbles Secret failed 0x%lx\n", Status);
return FALSE;
}
DesiredAccessDino = GENERIC_EXECUTE;
Status = LsaCreateSecret(
PolicyHandle,
&(SecretInfoDino.SecretName),
DesiredAccessDino,
&SecretHandleDino
);
if (!NT_SUCCESS(Status)) {
DbgPrint("LSA RPC CT - Create Dino Secret failed 0x%lx\n", Status);
return FALSE;
}
//
// Close the Secrets just created
//
Status = LsaClose(SecretHandleFred);
if (!NT_SUCCESS(Status)) {
DbgPrint("LSA RPC CT - Close new Fred Secret failed 0x%lx\n",
Status);
return FALSE;
}
Status = LsaClose(SecretHandleWilma);
if (!NT_SUCCESS(Status)) {
DbgPrint("LSA RPC CT - Close new Wilma Secret failed 0x%lx\n",
Status);
return FALSE;
}
Status = LsaClose(SecretHandlePebbles);
if (!NT_SUCCESS(Status)) {
DbgPrint(
"LSA RPC CT - Close new Pebbles Secret failed 0x%lx\n",
Status
);
return FALSE;
}
Status = LsaClose(SecretHandleDino);
if (!NT_SUCCESS(Status)) {
DbgPrint("LSA RPC CT - Close new Dino Secret failed 0x%lx\n",
Status);
return FALSE;
}
return TRUE;
}
BOOLEAN
CtLsaSecretOpenClose(
)
/*++
Routine Description:
This function tests the LSA API that open and close Secrets.
Arguments:
None.
Return Value:
BOOLEAN - TRUE if successful, FALSE if any failures.
--*/
{
NTSTATUS Status;
BOOLEAN BooleanStatus;
PLSA_HANDLE BadSecretHandleAddress = NULL;
DbgPrint("[2] - Test Secret Open and Close API\n");
//
// Open the Secrets created by CtLsaSecretCreate
//
Status = LsaOpenSecret(
PolicyHandle,
&(SecretInfoFred.SecretName),
DesiredAccessFred,
&SecretHandleFred
);
if (!NT_SUCCESS(Status)) {
DbgPrint("LSA RPC CT - 1st Open Fred Secret failed 0x%lx\n", Status);
return FALSE;
}
Status = LsaOpenSecret(
PolicyHandle,
&(SecretInfoWilma.SecretName),
DesiredAccessWilma,
&SecretHandleWilma
);
if (!NT_SUCCESS(Status)) {
DbgPrint("LSA RPC CT - 1st Open Wilma Secret failed 0x%lx\n", Status);
return FALSE;
}
Status = LsaOpenSecret(
PolicyHandle,
&(SecretInfoPebbles.SecretName),
DesiredAccessPebbles,
&SecretHandlePebbles
);
if (!NT_SUCCESS(Status)) {
DbgPrint("LSA RPC CT - 1st Open Pebbles Secret failed 0x%lx\n", Status);
return FALSE;
}
Status = LsaOpenSecret(
PolicyHandle,
&(SecretInfoDino.SecretName),
DesiredAccessDino,
&SecretHandleDino
);
if (!NT_SUCCESS(Status)) {
DbgPrint("LSA RPC CT - 1st Open Dino Secret failed 0x%lx\n", Status);
return FALSE;
}
//
// Now open each Secret a second time so we have 2 handles to each
// Secret.
//
Status = LsaOpenSecret(
PolicyHandle,
&(SecretInfoFred.SecretName),
DesiredAccessFred,
&SecretHandleFred2
);
if (!NT_SUCCESS(Status)) {
DbgPrint("LSA RPC CT - 2nd Open Fred Secret failed 0x%lx\n", Status);
return FALSE;
}
Status = LsaOpenSecret(
PolicyHandle,
&(SecretInfoWilma.SecretName),
DesiredAccessWilma,
&SecretHandleWilma2
);
if (!NT_SUCCESS(Status)) {
DbgPrint("LSA RPC CT - 2nd Open Wilma Secret failed 0x%lx\n", Status);
return FALSE;
}
Status = LsaOpenSecret(
PolicyHandle,
&(SecretInfoPebbles.SecretName),
DesiredAccessPebbles,
&SecretHandlePebbles2
);
if (!NT_SUCCESS(Status)) {
DbgPrint("LSA RPC CT - 2nd Open Pebbles Secret failed 0x%lx\n", Status);
return FALSE;
}
Status = LsaOpenSecret(
PolicyHandle,
&(SecretInfoDino.SecretName),
DesiredAccessDino,
&SecretHandleDino2
);
if (!NT_SUCCESS(Status)) {
DbgPrint("LSA RPC CT - 2nd Open Dino Secret failed 0x%lx\n", Status);
return FALSE;
}
//
// Close the 2nd handles to the Secrets
//
Status = LsaClose( SecretHandleFred2 );
if (!NT_SUCCESS(Status)) {
DbgPrint("LSA RPC CT - Close Fred Secret hdl2 failed 0x%lx\n", Status);
return FALSE;
}
Status = LsaClose( SecretHandleWilma2 );
if (!NT_SUCCESS(Status)) {
DbgPrint("LSA RPC CT - Close Wilma Secret hdl2 failed 0x%lx\n",Status);
return FALSE;
}
Status = LsaClose( SecretHandlePebbles2 );
if (!NT_SUCCESS(Status)) {
DbgPrint("LSA RPC CT - Close Pebbles Secret hdl2 failed 0x%lx\n", Status);
return FALSE;
}
Status = LsaClose( SecretHandleDino2 );
if (!NT_SUCCESS(Status)) {
DbgPrint("LSA RPC CT - Close Dino Secret hdl2 failed 0x%lx\n", Status);
return FALSE;
}
BooleanStatus = TRUE;
//
// Try to create Fred again. We
// should get STATUS_OBJECT_NAME_COLLISION
//
DesiredAccessFred = GENERIC_ALL;
Status = LsaCreateSecret(
PolicyHandle,
&(SecretInfoFred.SecretName),
DesiredAccessFred,
&SecretHandleFred3
);
if (Status != STATUS_OBJECT_NAME_COLLISION) {
DbgPrint("LSA RPC CT - Create Fred Secret when Fred exists\n");
DbgPrint("Expected 0x%lx (STATUS_OBJECT_NAME_COLLISION)\n",
STATUS_OBJECT_NAME_COLLISION);
DbgPrint("Got 0x%lx\n", Status);
BooleanStatus = FALSE;
}
return BooleanStatus;
if (Level == 2) {
//
// LsaOpenSecret with bad addresses
//
Status = LsaOpenSecret(
PolicyHandle,
(PUNICODE_STRING) BadAddress,
DesiredAccessFred,
&SecretHandleFred
);
Status = LsaOpenSecret(
PolicyHandle,
&(SecretInfoFred.SecretName),
DesiredAccessFred,
BadSecretHandleAddress
);
}
return(BooleanStatus);
}
BOOLEAN
CtLsaSecretSetQueryValue(
)
/*++
Routine Description:
This function tests the Setting and Querying of Secret Values.
Arguments:
None.
Return Value:
BOOLEAN - TRUE if successful, FALSE if any error.
--*/
{
NTSTATUS Status;
BOOLEAN BooleanStatus = TRUE;
LARGE_INTEGER FredCurrentValueSetTime;
LARGE_INTEGER FredOldValueSetTime;
LARGE_INTEGER FredCurrentValueSetTime2;
LARGE_INTEGER FredOldValueSetTime2;
DbgPrint("[3] - Test Secret Set and Query Value API\n");
//
// Query Secret Values for Fred before any set.
//
Status = LsaQuerySecret(
SecretHandleFred,
&(SecretInfoFred.ReturnedCurrentValue),
&FredCurrentValueSetTime,
&(SecretInfoFred.ReturnedOldValue),
&FredOldValueSetTime
);
if (!NT_SUCCESS(Status)) {
DbgPrint("LsaQuerySecret for Fred before values set failed 0x%lx\n", Status);
BooleanStatus = FALSE;
}
//
// Since the Secret Values for Fred have never been set, we
// should have NULLs for them
//
if (SecretInfoFred.ReturnedCurrentValue != NULL) {
DbgPrint("LsaQuerySecret for Fred did not return\n");
DbgPrint("NULL for CurrentValue when Current Value\n");
DbgPrint("has never been set\n");
BooleanStatus = FALSE;
}
if (SecretInfoFred.ReturnedOldValue != NULL) {
DbgPrint("LsaQuerySecret for Fred did not return\n");
DbgPrint("NULL for OldValue when Old Value\n");
DbgPrint("has never been set\n");
BooleanStatus = FALSE;
}
//
// Set Secret Values for Fred.
//
Status = LsaSetSecret(
SecretHandleFred,
&(SecretInfoFred.CurrentValue),
&(SecretInfoFred.OldValue)
);
if (!NT_SUCCESS(Status)) {
DbgPrint("LsaSetSecret for Fred failed 0x%lx\n", Status);
return(FALSE);
}
//
// Query Secret Values for Fred after Set.
//
Status = LsaQuerySecret(
SecretHandleFred,
&(SecretInfoFred.ReturnedCurrentValue),
&FredCurrentValueSetTime2,
&(SecretInfoFred.ReturnedOldValue),
&FredOldValueSetTime2
);
if (!NT_SUCCESS(Status)) {
DbgPrint("LsaQuerySecret for Fred failed 0x%lx\n", Status);
return(FALSE);
}
//
// Compare returned Current Value of Fred Secret with original.
//
if (!RtlEqualUnicodeString(
&(SecretInfoFred.CurrentValue),
SecretInfoFred.ReturnedCurrentValue,
FALSE
)) {
DbgPrint("LsaSetSecret - LsaQuerySecret value mismatch\n");
DbgPrint("... returned Current Value of Fred Secret incorrect\n");
BooleanStatus = FALSE;
}
//
// Free the memory for the returned Current Value of Fred
//
Status = LsaFreeMemory(SecretInfoFred.ReturnedCurrentValue);
if (!NT_SUCCESS(Status)) {
DbgPrint("LsaFreeMemory for Fred Secret Query 1 Current Value\n");
DbgPrint("failed 0x%lx\n", Status);
BooleanStatus = FALSE;
}
SecretInfoFred.ReturnedCurrentValue = NULL;
//
// Compare returned Old Value of Fred Secret with original.
//
if (!RtlEqualUnicodeString(
&(SecretInfoFred.OldValue),
SecretInfoFred.ReturnedOldValue,
FALSE
)) {
DbgPrint("LsaSetSecret - LsaQuerySecret value mismatch\n");
DbgPrint("... returned Old Value of Fred Secret incorrect\n");
BooleanStatus = FALSE;
}
//
// Free the memory for the returned Old Value of Fred
//
Status = LsaFreeMemory(SecretInfoFred.ReturnedOldValue);
if (!NT_SUCCESS(Status)) {
DbgPrint("LsaFreeMemory for Fred Secret Query 1 Old Value\n");
DbgPrint("failed 0x%lx\n", Status);
BooleanStatus = FALSE;
}
SecretInfoFred.ReturnedOldValue = NULL;
//
// Query Secret Values for Fred (no creation timestamp info wanted).
//
Status = LsaQuerySecret(
SecretHandleFred,
&(SecretInfoFred.ReturnedCurrentValue),
NULL,
&(SecretInfoFred.ReturnedOldValue),
NULL
);
if (!NT_SUCCESS(Status)) {
DbgPrint("LsaQuerySecret for Fred failed 0x%lx\n", Status);
return(FALSE);
}
//
// Compare Returned Current Value of Fred Secret with original.
//
if (!RtlEqualUnicodeString(
&(SecretInfoFred.CurrentValue),
SecretInfoFred.ReturnedCurrentValue,
FALSE
)) {
DbgPrint("LsaSetSecret - LsaQuerySecret value mismatch\n");
BooleanStatus = FALSE;
}
//
// Free the memory for the returned Current Value of Fred
//
Status = LsaFreeMemory(SecretInfoFred.ReturnedCurrentValue);
if (!NT_SUCCESS(Status)) {
DbgPrint("LsaFreeMemory for Fred Secret Query 2 Current Value\n");
DbgPrint("failed 0x%lx\n", Status);
BooleanStatus = FALSE;
}
SecretInfoFred.ReturnedCurrentValue = NULL;
//
// Compare returned Old Value of Fred Secret with original.
//
if (!RtlEqualUnicodeString(
&(SecretInfoFred.OldValue),
SecretInfoFred.ReturnedOldValue,
FALSE
)) {
DbgPrint("LsaSetSecret - LsaQuerySecret value mismatch\n");
DbgPrint("... returned Old Value of Fred Secret incorrect\n");
BooleanStatus = FALSE;
}
//
// Free the memory for the returned Old Value of Fred
//
Status = LsaFreeMemory(SecretInfoFred.ReturnedOldValue);
if (!NT_SUCCESS(Status)) {
DbgPrint("LsaFreeMemory for Fred Secret Query 2 Old Value\n");
DbgPrint("failed 0x%lx\n", Status);
BooleanStatus = FALSE;
}
SecretInfoFred.ReturnedOldValue = NULL;
//
// Set NULL Secret Values for Fred.
//
Status = LsaSetSecret(
SecretHandleFred,
NULL,
NULL
);
if (!NT_SUCCESS(Status)) {
DbgPrint("LsaSetSecret (NULL values) for Fred failed 0x%lx\n", Status);
return(FALSE);
}
//
// Query Secret Values for Fred after Set.
//
Status = LsaQuerySecret(
SecretHandleFred,
&(SecretInfoFred.ReturnedCurrentValue),
&FredCurrentValueSetTime2,
&(SecretInfoFred.ReturnedOldValue),
&FredOldValueSetTime2
);
if (!NT_SUCCESS(Status)) {
DbgPrint("LsaQuerySecret (NULL Values) for Fred failed 0x%lx\n", Status);
return(FALSE);
}
//
// Verify that values returned are NULL.
//
if (SecretInfoFred.ReturnedCurrentValue != NULL) {
DbgPrint("LsaQuerySecret - Returned Current Value should be NULL\n");
BooleanStatus = FALSE;
}
if (SecretInfoFred.ReturnedOldValue != NULL) {
DbgPrint("LsaQuerySecret - Returned Old Value should be NULL\n");
BooleanStatus = FALSE;
}
return(BooleanStatus);
}
BOOLEAN
CtLsaSecretEnumeration(
)
/*++
Routine Description:
This function tests the enumeration of Secrets in the LSA. Note that
Secret enumeration may only be performed by Trusted Clients.
Arguments:
None.
Return Value:
BOOLEAN - TRUE if successful, FALSE if any failures.
--*/
{
NTSTATUS Status = STATUS_SUCCESS;
BOOLEAN BooleanStatus = TRUE;
ULONG Base = 0;
ULONG CountReturned = 0;
ULONG PreferedMaximumLength;
ULONG EnumerationContext = 0;
ULONG EnumNumber = 0;
ULONG EnumIndex;
ULONG Index;
PUNICODE_STRING EnumerationInformation;
PVOID EnumerationInformationVoid = NULL;
PVOID *BadEnumerationAddress = NULL;
PULONG BadCountReturnedAddress = NULL;
LSAPR_HANDLE TrustedPolicyHandle = NULL;
CT_LSA_SINGLE_CALL_ENUM_INFO EnumerationInformations[ 20 ];
DbgPrint("[4] - Test Secret Enumeration (Trusted Callers) API\n");
//
// First open a Trusted Handle to the LSA.
//
Status = LsaIOpenPolicyTrusted( &TrustedPolicyHandle );
if (!NT_SUCCESS(Status)) {
DbgPrint(
"LSA RPC CT - Enumeration of Secrets failed\n"
"LsaIOpenPolicyTrusted call %d returned 0x%lx\n",
"... no more enumerations attempted\n",
EnumNumber,
Status
);
goto EnumerateSecretsError;
}
//
// Enumerate the Secrets in the Lsa. Set the Prefered Maximum
// Length od data returned to a low value to cause as many subsequent
// calls to the LsaEnumerateSecrets API as possible.
//
PreferedMaximumLength = 1;
EnumNumber = 0;
Status = STATUS_SUCCESS;
while(NT_SUCCESS(Status)) {
Status = LsaIEnumerateSecrets(
TrustedPolicyHandle,
&EnumerationContext,
&EnumerationInformationVoid,
PreferedMaximumLength,
&CountReturned
);
EnumerationInformations[ EnumNumber ].EnumInfoReturned =
EnumerationInformationVoid;
EnumerationInformations[ EnumNumber ].CountReturned = CountReturned;
if (!NT_SUCCESS(Status)) {
if (Status != STATUS_NO_MORE_ENTRIES) {
DbgPrint(
"LSA RPC CT - Enumeration of Secrets failed\n"
"LsaIEnumerateSecrets call %d returned 0x%lx\n",
"... no more enumerations attempted\n",
EnumNumber,
Status
);
break;
}
}
EnumNumber++;
}
if (!NT_SUCCESS(Status)) {
if (Status != STATUS_NO_MORE_ENTRIES) {
DbgPrint(
"LSA RPC CT - Enumeration of Secrets failed\n"
"Call number %d to LsaEnumerateSecrets returned 0x%lx\n",
EnumNumber,
Status
);
goto EnumerateSecretsError;
}
}
SecretNameInfo[0].Name = FredName;
SecretNameInfo[1].Name = WilmaName;
SecretNameInfo[3].Name = PebblesName;
SecretNameInfo[2].Name = DinoName;
SecretNameInfo[0].NameFound = FALSE;
SecretNameInfo[1].NameFound = FALSE;
SecretNameInfo[2].NameFound = FALSE;
SecretNameInfo[3].NameFound = FALSE;
//
// Scan all of the enumeration information returned and lookup
// each Secret Name returned in the SecretNameInfo array. If the
// name is found, set the NameFound flag in the array entry. Also,
// check for duplicates.
//
for (EnumIndex = 0; EnumIndex < EnumNumber; EnumIndex++) {
CountReturned = EnumerationInformations[ EnumIndex ].CountReturned;
EnumerationInformation = (PUNICODE_STRING)
EnumerationInformations[ EnumIndex ].EnumInfoReturned;
for( Index = 0; Index < CountReturned; Index++ ) {
//
// Search for this Secret Name in the SecretNameInfo array.
// If found, set NameFound, else ignore (there may be other
// Secret objects not involved in this test).
//
for ( SearchIndex = 0; SearchIndex < 4; SearchIndex++ ) {
if (RtlEqualUnicodeString(
&SecretNameInfo[SearchIndex].Name,
&EnumerationInformation[Index],
TRUE
)) {
if (SecretNameInfo[SearchIndex].NameFound) {
DbgPrint(
"Already found Sid with SearchIndex %d\n",
SearchIndex
);
} else {
SecretNameInfo[SearchIndex].NameFound = TRUE;
}
break;
}
}
}
}
//
// We've scanned all of the returned Secret Names. Now check that all
// of the Names were found.
//
for (SearchIndex = 0; SearchIndex < 4; SearchIndex++ ) {
if ( !SecretNameInfo[ SearchIndex ].NameFound ) {
DbgPrint(
"LSA RPC CT - Enumeration of Secrets failed\n"
"Secret number %d was not found",
SearchIndex
);
BooleanStatus = FALSE;
break;
}
}
if (!BooleanStatus) {
return(FALSE);
}
//
// Bad Addresses passed to Lsa Enumerate Secrets API
//
if (Level == 2) {
Status = LsaIEnumerateSecrets(
(LSA_HANDLE) BadAddress,
&EnumerationContext,
&EnumerationInformationVoid,
PreferedMaximumLength,
&CountReturned
);
Status = LsaIEnumerateSecrets(
PolicyHandle,
(PLSA_ENUMERATION_HANDLE) BadAddress,
&EnumerationInformationVoid,
PreferedMaximumLength,
&CountReturned
);
Status = LsaIEnumerateSecrets(
PolicyHandle,
&EnumerationContext,
BadEnumerationAddress,
PreferedMaximumLength,
&CountReturned
);
Status = LsaIEnumerateSecrets(
PolicyHandle,
&EnumerationContext,
&EnumerationInformationVoid,
PreferedMaximumLength,
BadCountReturnedAddress
);
}
EnumerateSecretsFinish:
//
// If necessary, close the TrustedPolicyHandle.
//
if (TrustedPolicyHandle != NULL) {
Status = LsarClose( &TrustedPolicyHandle );
TrustedPolicyHandle = NULL;
if (!NT_SUCCESS(Status)) {
DbgPrint(
"LSA RPC CT - Enumeration of Secrets failed\n"
"LsaClose on TrustedPolicyHandle returned 0x%lx\n",
Status
);
goto EnumerateSecretsError;
}
}
return(BooleanStatus);
EnumerateSecretsError:
BooleanStatus = FALSE;
goto EnumerateSecretsFinish;
}
BOOLEAN
CtLsaSecretSetTimes(
)
/*++
Routine Description:
This function tests the setting of Secret Current and Old Value
Set Times. Only Trusted Callers can do this.
Arguments:
None.
Return Value:
BOOLEAN - TRUE if successful, FALSE if any error.
--*/
{
NTSTATUS Status;
BOOLEAN BooleanStatus = TRUE;
LSAPR_HANDLE TrustedPolicyHandle = NULL;
LSAPR_HANDLE TrustedSecretHandleFred = NULL;
LARGE_INTEGER FredCurrentValueSetTime;
LARGE_INTEGER FredOldValueSetTime;
LARGE_INTEGER SystemTime;
DbgPrint("[5] - Test Secret Set Times API\n");
//
// First open a Trusted Handle to the LSA.
//
Status = LsaIOpenPolicyTrusted( &TrustedPolicyHandle );
if (!NT_SUCCESS(Status)) {
DbgPrint(
"LSA RPC CT - Set Times for Secret Values failed\n"
"LsaIOpenPolicyTrusted returned 0x%lx\n",
Status
);
goto SetTimesSecretError;
}
//
// Now open a handle to Fred. This handle will be trusted by
// inheritance from the TrustedPolicyhandle.
//
Status = LsarOpenSecret(
TrustedPolicyHandle,
(PLSAPR_UNICODE_STRING) &FredName,
(ACCESS_MASK) 0,
&TrustedSecretHandleFred
);
if (!NT_SUCCESS(Status)) {
DbgPrint(
"LSA RPC CT - Set Times for Secret Values failed\n"
"LsarOpenSecret call returned 0x%lx\n",
Status
);
goto SetTimesSecretError;
}
//
// Now query the current time
//
Status = NtQuerySystemTime(&SystemTime);
if (!NT_SUCCESS(Status)) {
DbgPrint(
"LSA RPC CT - Set Times for Secret Values failed\n"
"NtQuerySystemTime() returned 0x%lx\n",
Status
);
goto SetTimesSecretError;
}
//
// Now change the times that the Fred Secret Values were set.
//
Status = LsaISetTimesSecret( TrustedSecretHandleFred, &SystemTime, &SystemTime );
if (!NT_SUCCESS(Status)) {
DbgPrint(
"LSA RPC CT - Set Times for Secret Values failed\n"
"LsaiSetTimesSecret() returned 0x%lx\n",
Status
);
goto SetTimesSecretError;
}
//
// Now Query Secret Values for Fred.
//
FredCurrentValueSetTime.LowPart = 0;
FredCurrentValueSetTime.HighPart = 0;
FredOldValueSetTime.LowPart = 0;
FredOldValueSetTime.HighPart = 0;
Status = LsarQuerySecret(
TrustedSecretHandleFred,
NULL,
&FredCurrentValueSetTime,
NULL,
&FredOldValueSetTime
);
if (!NT_SUCCESS(Status)) {
DbgPrint(
"LSA RPC CT - Set Times for Secret Values failed\n"
"LsarQuerySecret for Fred returned 0x%lx\n",
Status
);
goto SetTimesSecretError;
}
//
// Now compare the returned Current and Old Value Set Times with
// the SystemTime.
//
if (!( FredCurrentValueSetTime.QuadPart == SystemTime.QuadPart )) {
DbgPrint(
"LSA RPC CT - Set Times for Secret Values failed\n"
"Mismatch on CurrentValueSetTime\n ",
Status
);
goto SetTimesSecretError;
}
if (!( FredOldValueSetTime.QuadPart == SystemTime.QuadPart )) {
DbgPrint(
"LSA RPC CT - Set Times for Secret Values failed\n"
"Mismatch on OldValueSetTime\n ",
Status
);
goto SetTimesSecretError;
}
SetTimesSecretFinish:
//
// If necessary, close the Fred Secret Handle.
//
if (TrustedSecretHandleFred != NULL) {
Status = LsarClose( &TrustedSecretHandleFred );
TrustedSecretHandleFred = NULL;
if (!NT_SUCCESS(Status)) {
DbgPrint(
"LSA RPC CT - Set Times for Secret Values failed\n"
"LsaClose on TrustedFredSecretHandle returned 0x%lx\n",
Status
);
goto SetTimesSecretError;
}
}
//
// If necessary, close the TrustedPolicyHandle.
//
if (TrustedPolicyHandle != NULL) {
Status = LsarClose( &TrustedPolicyHandle );
TrustedPolicyHandle = NULL;
if (!NT_SUCCESS(Status)) {
DbgPrint(
"LSA RPC CT - Set Times for Secret Values failed\n"
"LsaClose on TrustedPolicyHandle returned 0x%lx\n",
Status
);
goto SetTimesSecretError;
}
}
return(BooleanStatus);
SetTimesSecretError:
BooleanStatus = FALSE;
goto SetTimesSecretFinish;
}
BOOLEAN
CtLsaSecretDelete(
)
/*++
Routine Description:
This function tests deletion of Secrets. First, a simple test is
made to see if we can delete a freshly created Secret. Next, we
try to delete the Secrets created by CtLsaSecretCreate.
Arguments:
None.
Return Value:
BOOLEAN - TRUE if successful, FALSE if any error.
--*/
{
NTSTATUS Status;
BOOLEAN BooleanStatus = TRUE;
DbgPrint("[6] - Test Secret Deletion API\n");
//
// First try a simple test. Create a new Secret called Barney
// to be given DELETE access upon create. Then delete it.
//
//
// Set up Secret information for Barney Secret to be created.
//
Status = CtSecretSetInfo(
"Barney",
"Barney secret current value",
"Barney secret old value",
&SecretInfoBarney
);
if (!NT_SUCCESS(Status)) {
DbgPrint(
"LSA RPC CT - CtSecretSetInfo for Barney failed 0x%lx\n",
Status
);
return FALSE;
}
//
// Create the Barney Secret
//
Status = LsaCreateSecret(
PolicyHandle,
&(SecretInfoBarney.SecretName),
DELETE,
&SecretHandleBarney
);
if (!NT_SUCCESS(Status)) {
DbgPrint("LSA RPC CT - Create Barney Secret failed 0x%lx\n", Status);
return FALSE;
}
//
// Delete the Barney Secret
//
Status = LsaDelete( SecretHandleBarney );
if (!NT_SUCCESS(Status)) {
DbgPrint("LSA RPC CT - Delete Barney Secret failed 0x%lx\n", Status);
return FALSE;
}
//
// Delete the Fred Secret. This should work since it was opened
// with GENERIC_ALL access.
//
if (DesiredAccessFred != GENERIC_ALL) {
DbgPrint("DesiredAccessFred should be GENERIC_ALL \n");
DbgPrint("Bug in this test program\n");
return FALSE;
}
Status = LsaDelete( SecretHandleFred );
if (!NT_SUCCESS(Status)) {
DbgPrint("LSA RPC CT - Delete Fred Secret failed 0x%lx\n", Status);
return FALSE;
}
//
// Delete the Wilma Secret. This should not work since it was opened
// with GENERIC_READ access.
//
if (DesiredAccessWilma != GENERIC_READ) {
DbgPrint("DesiredAccessWilma should be GENERIC_READ\n");
DbgPrint("Bug in this test program\n");
return FALSE;
}
Status = LsaDelete( SecretHandleWilma );
if (Status != STATUS_ACCESS_DENIED) {
DbgPrint("LSA RPC CT - Delete Wilma Secret should have failed\n");
DbgPrint(" with STATUS_ACCESS_DENIED since handle specifies\n");
DbgPrint("GENERIC_READ access - got 0x%lx\n", Status);
BooleanStatus = FALSE;
}
//
// Now close the handle to Wilma, open another handle with GENERIC_ALL
// access and try to delete the Secret again.
//
Status = LsaClose(SecretHandleWilma);
if (!NT_SUCCESS(Status)) {
DbgPrint("Close Secret account failed 0x%lx\n", Status);
}
SecretHandleWilmaOpen = NULL;
Status = LsaOpenSecret(
PolicyHandle,
&(SecretInfoWilma.SecretName),
DELETE,
&SecretHandleWilmaOpen
);
if (!NT_SUCCESS(Status)) {
DbgPrint(
"LSA RPC CT - Open Wilma Secret for DELETE failed 0x%lx\n",
Status
);
return FALSE;
}
Status = LsaDelete( SecretHandleWilmaOpen );
if (!NT_SUCCESS(Status)) {
DbgPrint("LSA RPC CT - Delete Wilma Secret failed 0x%lx\n", Status);
BooleanStatus = FALSE;
}
//
// Delete the Pebbles Secret. This should not work since it was opened
// with GENERIC_WRITE access which does not include DELETE.
//
if (DesiredAccessPebbles != GENERIC_WRITE) {
DbgPrint("DesiredAccessPebbles should be GENERIC_WRITE\n");
DbgPrint("Bug in this test program\n");
return FALSE;
}
Status = LsaDelete( SecretHandlePebbles );
if (Status != STATUS_ACCESS_DENIED) {
DbgPrint("LSA RPC CT - Delete Pebbles Secret should have failed\n");
DbgPrint(" with STATUS_ACCESS_DENIED since handle specifies\n");
DbgPrint("GENERIC_WRITE access - got 0x%lx\n", Status);
BooleanStatus = FALSE;
}
//
// Now close the handle to Pebbles, open another handle with DELETE
// access and try to delete the Secret again.
//
Status = LsaClose(SecretHandlePebbles);
if (!NT_SUCCESS(Status)) {
DbgPrint("Close Pebbles Secret account failed 0x%lx\n", Status);
}
SecretHandlePebblesOpen = NULL;
Status = LsaOpenSecret(
PolicyHandle,
&(SecretInfoPebbles.SecretName),
DELETE,
&SecretHandlePebblesOpen
);
if (!NT_SUCCESS(Status)) {
DbgPrint(
"LSA RPC CT - Open Pebbles Secret for DELETE failed 0x%lx\n",
Status
);
return FALSE;
}
Status = LsaDelete( SecretHandlePebblesOpen );
if (!NT_SUCCESS(Status)) {
DbgPrint("LSA RPC CT - Delete Wilma Secret failed 0x%lx\n", Status);
BooleanStatus = FALSE;
}
//
// Delete the Dino Secret. This should not work since it was opened
// with GENERIC_EXECUTE access.
//
if (DesiredAccessDino != GENERIC_EXECUTE) {
DbgPrint("DesiredAccessDino should be GENERIC_EXECUTE\n");
DbgPrint("Bug in this test program\n");
return FALSE;
}
Status = LsaDelete( SecretHandleDino );
if (Status != STATUS_ACCESS_DENIED) {
DbgPrint("LSA RPC CT - Delete Dino Secret should have failed\n");
DbgPrint(" with STATUS_ACCESS_DENIED since handle specifies\n");
DbgPrint("GENERIC_WRITE access - got 0x%lx\n", Status);
BooleanStatus = FALSE;
}
//
// Now close the handle to Dino, open another handle with DELETE
// access and try to delete the Secret again.
//
Status = LsaClose(SecretHandleDino);
if (!NT_SUCCESS(Status)) {
DbgPrint("Close Dino Secret account failed 0x%lx\n", Status);
}
SecretHandleDinoOpen = NULL;
Status = LsaOpenSecret(
PolicyHandle,
&(SecretInfoDino.SecretName),
DELETE,
&SecretHandleDinoOpen
);
if (!NT_SUCCESS(Status)) {
DbgPrint(
"LSA RPC CT - Open Dino Secret for DELETE failed 0x%lx\n",
Status
);
return FALSE;
}
Status = LsaDelete( SecretHandleDinoOpen );
if (!NT_SUCCESS(Status)) {
DbgPrint("LSA RPC CT - Delete Dino Secret failed 0x%lx\n", Status);
BooleanStatus = FALSE;
}
return(BooleanStatus);
}
BOOLEAN
CtLsaSecretCleanup(
)
/*++
Routine Description:
This function cleans up any secrets created by the Secret tests.
No failures are reported.
Arguments:
None.
Return Value:
BOOLEAN - TRUE if successful, FALSE if any error.
--*/
{
NTSTATUS Status;
BOOLEAN BooleanStatus = TRUE;
LSA_HANDLE SecretHandleBarneyOpen = NULL;
//
// Close the handle to Barney (if any), open another handle with DELETE
// access and try to delete the Secret again.
//
if (SecretHandleBarney != NULL) {
Status = LsaClose(SecretHandleBarney);
SecretHandleBarney = NULL;
}
//
// Open new handle to Barney with DELETE access
//
SecretHandleBarneyOpen = NULL;
Status = LsaOpenSecret(
PolicyHandle,
&(SecretInfoBarney.SecretName),
DELETE,
&SecretHandleBarneyOpen
);
if (NT_SUCCESS(Status)) {
Status = LsaDelete( SecretHandleBarneyOpen );
SecretHandleBarneyOpen = NULL;
}
//
// Close the handle to Fred (if any), open another handle with DELETE
// access and try to delete the Secret again.
//
if (SecretHandleFred != NULL) {
Status = LsaClose(SecretHandleFred);
SecretHandleFred = NULL;
}
//
// Open new handle to Fred with DELETE access
//
SecretHandleFredOpen = NULL;
Status = LsaOpenSecret(
PolicyHandle,
&(SecretInfoFred.SecretName),
DELETE,
&SecretHandleFredOpen
);
if (NT_SUCCESS(Status)) {
Status = LsaDelete( SecretHandleFredOpen );
SecretHandleFredOpen = NULL;
}
//
// Close the handle to Wilma (if any), open another handle with DELETE
// access and try to delete the Secret again.
//
if (SecretHandleWilma != NULL) {
Status = LsaClose(SecretHandleWilma);
SecretHandleWilma = NULL;
}
//
// Open new handle to Wilma with DELETE access
//
SecretHandleWilmaOpen = NULL;
Status = LsaOpenSecret(
PolicyHandle,
&(SecretInfoWilma.SecretName),
DELETE,
&SecretHandleWilmaOpen
);
if (NT_SUCCESS(Status)) {
Status = LsaDelete( SecretHandleWilmaOpen );
SecretHandleWilmaOpen = NULL;
}
//
// Close the handle to Pebbles (if any), open another handle with DELETE
// access and try to delete the Secret again.
//
if (SecretHandlePebbles != NULL) {
Status = LsaClose(SecretHandlePebbles);
SecretHandlePebbles = NULL;
}
//
// Open new handle to Pebbles with DELETE access
//
SecretHandlePebblesOpen = NULL;
Status = LsaOpenSecret(
PolicyHandle,
&(SecretInfoPebbles.SecretName),
DELETE,
&SecretHandlePebblesOpen
);
if (NT_SUCCESS(Status)) {
Status = LsaDelete( SecretHandlePebblesOpen );
SecretHandlePebblesOpen = NULL;
}
//
// Close the handle to Dino (if any), open another handle with DELETE
// access and try to delete the Secret again.
//
if (SecretHandleDino != NULL) {
Status = LsaClose(SecretHandleDino);
SecretHandleDino = NULL;
}
//
// Open new handle to Dino with DELETE access
//
SecretHandleDinoOpen = NULL;
Status = LsaOpenSecret(
PolicyHandle,
&(SecretInfoDino.SecretName),
DELETE,
&SecretHandleDinoOpen
);
if (NT_SUCCESS(Status)) {
Status = LsaDelete( SecretHandleDinoOpen );
SecretHandleDinoOpen = NULL;
}
return(BooleanStatus);
}
NTSTATUS
CtSecretSetInfo(
IN PUCHAR SecretNameText,
IN PUCHAR CurrentValueText,
IN PUCHAR OldValueText,
OUT PCT_SECRET_INFO SecretInformation
)
/*++
Routine Description:
This function sets up the Secret information for a new Secret
prior to creation.
Arguments:
SecretNameText - Pointer ASCIIZ Secret Name.
CurrentValueText - Pointer to ASCIIZ Current Value
OldValueText - Pointer to ASCIIZ Old Value
SecretInformation - Pointer to structure that will be set to
contain above secret information in form needed by LsaSetSecret()
or returned by LsaQuerySecret.
Return Value:
NTSTATUS - Standard Nt Result Code
--*/
{
NTSTATUS Status = STATUS_SUCCESS;
ANSI_STRING AnsiString;
//
// Convert the Secret name to Unicode
//
RtlInitString(&AnsiString, SecretNameText);
Status = RtlAnsiStringToUnicodeString(
&(SecretInformation->SecretName),
&AnsiString,
TRUE
);
if (!NT_SUCCESS(Status)) {
return(Status);
}
//
// Convert the Current Value to Unicode
//
RtlInitString(&AnsiString, CurrentValueText);
Status = RtlAnsiStringToUnicodeString(
&(SecretInformation->CurrentValue),
&AnsiString,
TRUE
);
if (!NT_SUCCESS(Status)) {
return(Status);
}
//
// Convert the Old value to Unicode
//
RtlInitString(&AnsiString, OldValueText);
Status = RtlAnsiStringToUnicodeString(
&(SecretInformation->OldValue),
&AnsiString,
TRUE
);
return(Status);
}
BOOLEAN
CtLsaGeneralAPI(
IN OPTIONAL PUNICODE_STRING WorkstationName
)
/*++
Routine Description:
This function tests the General Policy Database API
Parameters:
WorkstationName - Specifies the name of the target workstation. If
NULL or a NULL string is specified, the workstation is the local
machine.
Return Values:
BOOLEAN - True if test successful, else FALSE
--*/
{
BOOLEAN BooleanStatus = TRUE;
DbgPrint("********************************************************\n");
DbgPrint("LSA RPC CT - Test Lsa Policy General API \n");
DbgPrint("********************************************************\n");
//
// Test Set and Query Security object
//
if (!CtLsaGeneralSetQuerySecurityObject( WorkstationName )) {
goto GeneralAPIError;
}
//
// Test Privilege Enumeration
//
if (!CtLsaGeneralEnumeratePrivileges( WorkstationName )) {
goto GeneralAPIError;
}
GeneralAPIFinish:
return( BooleanStatus );
GeneralAPIError:
BooleanStatus = FALSE;
goto GeneralAPIFinish;
}
BOOLEAN
CtLsaLookupSids(
IN PUNICODE_STRING WorkstationName
)
/*++
Routine Description:
This function tests the LsaLookupSids API.
Parameters:
None.
Return Values:
BOOLEAN - True if test successful, else FALSE.
--*/
{
NTSTATUS Status;
BOOLEAN BooleanStatus = TRUE;
ULONG Count;
PLSA_TRANSLATED_NAME Names = NULL;
PLSA_REFERENCED_DOMAIN_LIST ReferencedDomains = NULL;
LSAP_WELL_KNOWN_SID_INDEX SidIndex;
PLSAP_WELL_KNOWN_SID_ENTRY WellKnownSidEntry = NULL;
PLSA_TRUST_INFORMATION ReturnedTrustInformation = NULL;
OBJECT_ATTRIBUTES ObjectAttributes;
OBJECT_ATTRIBUTES SamObjectAttributes;
SECURITY_QUALITY_OF_SERVICE SecurityQualityOfService;
LSA_HANDLE PolicyHandle = NULL;
PCT_UNKNOWN_SID_ENTRY UnknownSidEntry = NULL;
PSID Sids[LsapDummyLastSidIndex];
CT_UNKNOWN_SID_ENTRY UnknownSids[4];
UNICODE_STRING BuiltInDomainName;
PSID BuiltInDomainSid = NULL;
UNICODE_STRING AccountDomainName;
PSID AccountDomainSid = NULL;
PSID *AccountDomainGroupSids = NULL;
UNICODE_STRING PDAccountDomainName;
PSID PDAccountDomainSid = NULL;
PSID *PDAccountDomainGroupSids = NULL;
LSA_HANDLE PDPolicyHandle = NULL;
PSAM_RID_ENUMERATION AliasEnumerationBuffer = NULL;
PSAM_RID_ENUMERATION GroupEnumerationBuffer = NULL;
PPOLICY_ACCOUNT_DOMAIN_INFO PolicyAccountDomainInfo;
PPOLICY_PRIMARY_DOMAIN_INFO PolicyPrimaryDomainInfo;
PTRUSTED_CONTROLLERS_INFO TrustedControllersInfo;
PSID TrustedDomainSid = NULL;
LSA_HANDLE TrustedDomainHandle = NULL;
LSA_HANDLE PDTrustedDomainHandle = NULL;
PPOLICY_ACCOUNT_DOMAIN_INFO PolicyPDAccountDomainInfo;
UNICODE_STRING PDControllerName;
DbgPrint("[1] - Test General Sid Lookup\n");
//
// Open a handle to the target Workstation's Policy Object so that we can obtain
// information from it and also so that we can use it for looking up.
// Sids
//
CtLsaInitObjectAttributes(
&ObjectAttributes,
&SecurityQualityOfService
);
PolicyHandle = NULL;
Status = LsaOpenPolicy(
WorkstationName,
&ObjectAttributes,
POLICY_LOOKUP_NAMES | POLICY_VIEW_LOCAL_INFORMATION,
&PolicyHandle
);
if (!NT_SUCCESS(Status)) {
DbgPrint(
"LSA RPC CT - Lookup Sids Test failed\n"
"LsaOpenPolicy failed 0x%lx\n",
Status
);
goto LookupSidsError;
}
//
// Variation (1) - Lookup all of the Well Known Sids
//
DbgPrint("... [1] - Lookup all of the Well Known Sids\n");
// Using the table of Well Known Sids, construct an array containing all
// of the Well Known Sids in the format needed by LsaLookupSids() and
// look them all up.
//
for (SidIndex = LsapNullSidIndex;
SidIndex < LsapDummyLastSidIndex;
SidIndex++) {
//
// Copy the next Well Known Sid from the table of Well Known Sids.
//
Sids[SidIndex] = WellKnownSids[SidIndex].Sid;
}
Count = (ULONG) LsapDummyLastSidIndex - LsapWorldSidIndex;
ReferencedDomains = NULL;
Names = NULL;
Status = LsaLookupSids(
PolicyHandle,
Count,
&Sids[LsapWorldSidIndex],
&ReferencedDomains,
&Names
);
if (Status != STATUS_SUCCESS) {
DbgPrint(
"LSA RPC CT - Lookup all Well Known Sids failed 0x%lx\n",
Status
);
goto LookupSidsError;
}
//
// Verify that a names array has been returned.
//
if (Names == NULL) {
DbgPrint(
"LSA RPC CT - Lookup Well Known Sids\n"
"... no Names array returned\n"
);
goto LookupSidsError;
}
//
// Now compare the information returned with that contained in the
// table of Well Known Sids. We will omit name checking for
// those Well Know Known Sids which have configurable names.
//
for (SidIndex = 0,
WellKnownSidEntry = &WellKnownSids[LsapWorldSidIndex];
SidIndex < (LsapDummyLastSidIndex - LsapWorldSidIndex);
SidIndex++, WellKnownSidEntry++) {
try {
//
// Verify that the Sid Name Use is correct.
//
if (Names[SidIndex].Use != WellKnownSidEntry->Use) {
DbgPrint(
"LSA RPC CT - Lookup Well Known Sid %d mismatch on Use\n"
"... expected Use code %d, got %d\n",
SidIndex,
WellKnownSidEntry->Use,
Names[SidIndex].Use
);
BooleanStatus = FALSE;
}
//
// Verify that the translation of the Sid to a Name is correct
// for those non-Domain Sids that have Well Known Names. Skip
// this check for those with configurable names. Domain Sids
// are checked later.
//
if (WellKnownSidEntry->Use != SidTypeDomain) {
//
// If the Name field in the Well Known Sid Table entry
// has a 0 length (excepting Domain Sids), the Name is
// configurable and we should skip this check.
//
if (WellKnownSidEntry->Name.Length != 0) {
if (!RtlEqualUnicodeString(
&Names[SidIndex].Name,
&WellKnownSidEntry->Name,
FALSE)) {
DbgPrint(
"LSA RPC CT - Lookup Well Known Sid %d mismatch on name\n",
SidIndex
);
BooleanStatus = FALSE;
}
}
}
//
// Verify that the Referenced Domain Index is as expected.
// This should be non-negative for all identified Sids
// because we return descriptive information in the
// Trust Information in place of a Domain Name for well
// well known Sids that are not Domain Sids.
//
if (Names[SidIndex].DomainIndex < 0) {
DbgPrint("LSA RPC CT - Lookup Well Known Sids\n");
DbgPrint(".. negative Domain Index returned");
DbgPrint(" for Sid %d\n", SidIndex);
BooleanStatus = FALSE;
} else {
//
// The DomainIndex is non negative. Verify that a Referenced
// Domain List has been returned. Then check that the
// Referenced Entry contains the correct Trust Information.
//
if (ReferencedDomains == NULL) {
DbgPrint(
"LSA RPC CT - Lookup all well known Sids failed\n"
"... Referenced Domain List NULL but Well Known\n"
".. Sid %d specifies a non negative index\n",
SidIndex
);
BooleanStatus = FALSE;
} else {
//
// A Referenced Domain List was returned. Check out the
// Trust Information.
//
ReturnedTrustInformation =
(ReferencedDomains->Domains) + (Names[SidIndex].DomainIndex);
BooleanStatus = CtLsaGeneralVerifyTrustInfo(
ReturnedTrustInformation,
WellKnownSidEntry
);
}
}
} except (EXCEPTION_EXECUTE_HANDLER) {
Status = GetExceptionCode();
DbgPrint(
"LSA RPC CT - Lookup Well Known Sids failed\n"
"Access violation accessing returned\n"
".. information from LsaLookupSids\n"
);
BooleanStatus = FALSE;
}
break;
}
if (!BooleanStatus) {
DbgPrint("LSA RPC CT - Lookup Well Known Sids failed\n");
}
//
// Variation (2) - Lookup the Alias Sids in the Built-In Sam Domain
//
DbgPrint(
"... [2] - Lookup Alias Account Sids present in Workstation's\n"
"..........Built-in SAM Domain\n"
);
CtLsaInitObjectAttributes(
&SamObjectAttributes,
&SecurityQualityOfService
);
RtlInitUnicodeString( &BuiltInDomainName, L"BUILTIN" );
if (!CtLsaLookupSidsInSamDomain(
WorkstationName,
WorkstationName,
&BuiltInDomainName,
CT_SAM_ALIAS
)) {
goto LookupSidsError;
}
//
// Variation [3] - Lookup the Group Sids contained in the Workstation's
// SAM Account Domain
//
// First, obtain the Name and Sid of the SAM Account Domain from the
// Workstation's LSA Policy Object.
//
DbgPrint(
"... [3] - Lookup User and Group Account Sids present in Workstation's\n"
"..........SAM Account Domain\n"
);
Status = LsaQueryInformationPolicy(
PolicyHandle,
PolicyAccountDomainInformation,
(PVOID *) &PolicyAccountDomainInfo
);
if (!NT_SUCCESS(Status)) {
DbgPrint(
"LSA RPC CT - General Sid Lookup in Workstation SAM Account Domain failed\n"
"... LsaQueryInformationPolicy for Account Domain Name/Sid returned 0x%lx\n",
Status
);
goto LookupSidsError;
}
AccountDomainName = PolicyAccountDomainInfo->DomainName;
CtLsaInitObjectAttributes(
&SamObjectAttributes,
&SecurityQualityOfService
);
if (!CtLsaLookupSidsInSamDomain(
WorkstationName,
WorkstationName,
&AccountDomainName,
CT_SAM_USER
)) {
goto LookupSidsError;
}
if (!CtLsaLookupSidsInSamDomain(
WorkstationName,
WorkstationName,
&AccountDomainName,
CT_SAM_GROUP
)) {
goto LookupSidsError;
}
//
// Variation [4] - Lookup the Group Sids contained in the Primary Domain's
// SAM Account Domain
//
// We need to obtain the Name of a Primary Domain Controller so that
// we can connect to the LSA Policy Object and SAM Servers there.
// To get this takes several steps -
//
// * Query the Workstation Policy object to get the Sid of the Primary
// Domain.
//
// * Use the primary Domain Sid to open the Trusted Domain object
// for the Primary Domain.
//
// * Query the Trusted Controller List from the TD object.
//
// * Select the name of the first (or any) Controller on the list
// to open the LSA and SAM objects.
//
// Obtain the Sid of the Workstation's Primary Domain from the
// Policy Object.
//
DbgPrint(
"... [4] - Lookup User and Group Account Sids present in Workstation's\n"
"..........Primary Domain SAM Account Domain\n"
);
Status = LsaQueryInformationPolicy(
PolicyHandle,
PolicyPrimaryDomainInformation,
(PVOID *) &PolicyPrimaryDomainInfo
);
if (!NT_SUCCESS(Status)) {
DbgPrint(
"LSA RPC CT - General Sid Lookup in Primary Domain SAM Account Domain failed\n"
"... LsaQueryInformationPolicy for Primary Domain Name/Sid returned 0x%lx\n",
Status
);
goto LookupSidsError;
}
//
// If the Primary Domain Sid is NULL, return an error.
//
if (PolicyPrimaryDomainInfo->Sid == NULL) {
DbgPrint(
"LSA RPC CT - General Sid Lookup in Primary Domain SAM Account Domain failed\n"
"... LsaQueryInformationPolicy for Primary Domain Name/Sid returned NULL Sid\n"
);
goto LookupSidsError;
}
//
// Now open the Trusted Domain object corresponding to the
// Primary Domain Sid.
//
Status = LsaOpenTrustedDomain(
PolicyHandle,
PolicyPrimaryDomainInfo->Sid,
TRUSTED_QUERY_CONTROLLERS,
&TrustedDomainHandle
);
if (!NT_SUCCESS(Status)) {
DbgPrint(
"LSA RPC CT - General Sid Lookup in Primary Domain SAM Account Domain failed\n"
"... LsaOpenTrustedDomain for Primary Domain Trusted Object returned 0x%lx\n",
Status
);
goto LookupSidsError;
}
//
// Now query the Primary Domain's Controller List
//
Status = LsaQueryInfoTrustedDomain(
TrustedDomainHandle,
TrustedControllersInformation,
(PVOID *) &TrustedControllersInfo
);
if (!NT_SUCCESS(Status)) {
DbgPrint(
"LSA RPC CT - General Sid Lookup in Primary Domain SAM Account Domain failed\n"
"... LsaQueryInfoTrustedDomain for Primary Domain Ctrlrs 0x%lx\n",
Status
);
goto LookupSidsError;
}
//
// If no Trusted Controllers were returned, return an error.
//
if (TrustedControllersInfo->Entries == 0) {
DbgPrint(
"LSA RPC CT - General Sid Lookup in Primary Domain SAM Account Domain failed\n"
"... no PD Controllers returned\n",
Status
);
goto LookupSidsError;
}
//
// Now open a handle to the Lsa Policy Object for the first
// controller on the list.
//
CtLsaInitObjectAttributes(
&ObjectAttributes,
&SecurityQualityOfService
);
PDPolicyHandle = NULL;
Status = LsaOpenPolicy(
&TrustedControllersInfo->Names[0],
&ObjectAttributes,
POLICY_LOOKUP_NAMES | POLICY_VIEW_LOCAL_INFORMATION,
&PDPolicyHandle
);
if (!NT_SUCCESS(Status)) {
DbgPrint(
"LSA RPC CT - General Sid Lookup in Primary Domain SAM Account Domain failed\n"
"... LsaOpenPolicy for PD LSA returned 0x%lx\n",
Status
);
goto LookupSidsError;
}
//
// Obtain the Name and Sid of the SAM Account Domain from the
// Primary Domain's LSA Policy Object.
//
Status = LsaQueryInformationPolicy(
PDPolicyHandle,
PolicyAccountDomainInformation,
(PVOID *) &PolicyPDAccountDomainInfo
);
if (!NT_SUCCESS(Status)) {
DbgPrint(
"LSA RPC CT - General Sid Lookup in Primary Domain SAM Account Domain failed\n"
"... LsaQueryInformationPolicy for Account Domain Name/Sid returned 0x%lx\n",
Status
);
goto LookupSidsError;
}
//
// Now Lookup the Group and User accounts in the SAM Account object
// on this Domain Controller for the Primary Domain.
//
PDAccountDomainName = PolicyPDAccountDomainInfo->DomainName;
PDControllerName = TrustedControllersInfo->Names[0];
if (!CtLsaLookupSidsInSamDomain(
WorkstationName,
&PDControllerName,
&PDAccountDomainName,
CT_SAM_USER
)) {
goto LookupSidsError;
}
if (!CtLsaLookupSidsInSamDomain(
WorkstationName,
&PDControllerName,
&PDAccountDomainName,
CT_SAM_GROUP
)) {
goto LookupSidsError;
}
//
// Variation (5) - Lookup Group and User account Sids in a Domain
// controller for a Domain that is trusted by the workstation's
// Primary Domain.
//
DbgPrint(
"... [5] - Lookup User and Group Account Sids present in Workstation's\n"
"..........Primary Domain Trusted Domain SAM Account Domain\n"
);
DbgPrint("..... Test TBS\n");
//
// Variation (6) - Lookup some completely unknown Sids.
//
DbgPrint("... [5] - Lookup Unknown Sids\n");
BooleanStatus = CtLsaGeneralInitUnknownSid(
FredSid,
&UnknownSids[0],
FALSE
);
if (!BooleanStatus) {
goto LookupSidsError;
}
BooleanStatus = CtLsaGeneralInitUnknownSid(
WilmaSid,
&UnknownSids[1],
FALSE
);
if (!BooleanStatus) {
goto LookupSidsError;
}
BooleanStatus = CtLsaGeneralInitUnknownSid(
PebblesSid,
&UnknownSids[2],
FALSE
);
if (!BooleanStatus) {
goto LookupSidsError;
}
BooleanStatus = CtLsaGeneralInitUnknownSid(
DinoSid,
&UnknownSids[3],
FALSE
);
if (!BooleanStatus) {
goto LookupSidsError;
}
ReferencedDomains = NULL;
Names = NULL;
Count = 4;
//
// Construct an array containing the unknown Sids.
//
for (SidIndex = 0;
SidIndex < 4;
SidIndex++) {
//
// Copy the next Unknown Sid
//
Sids[SidIndex] = UnknownSids[SidIndex].Sid;
}
Status = LsaLookupSids(
PolicyHandle,
Count,
Sids,
&ReferencedDomains,
&Names
);
if (Status != STATUS_SUCCESS) {
DbgPrint(
"LSA RPC CT - Lookup Unknown Sids failed 0x%lx\n",
Status
);
goto LookupSidsError;
}
//
// Now compare the information returned with that contained in the
// table of Unknown Sids.
//
for (SidIndex = 0, UnknownSidEntry = UnknownSids;
SidIndex < 4;
SidIndex++, UnknownSidEntry++) {
try {
//
// Verify that the Sid Name Use is correct. We should
// have SidTypeUnknown in all cases.
//
if (Names[SidIndex].Use != SidTypeUnknown) {
DbgPrint(
"LSA RPC CT - Lookup Unknown Sids failed\n"
"... Unknown Sid %d mismatch on Use\n",
"... expected Use code %d (SidTypeUnknown), got %d\n",
SidIndex,
SidTypeUnknown,
Names[SidIndex].Use
);
BooleanStatus = FALSE;
}
//
// Verify that the translation of the Sid to a Name is correct.
// For an Unknown Sid, the translation is a Unicode representation
// of the Relative Id (if the Sid's Domain is known) or the
// full Sid (if the Sid's Domain is unknown.
//
if (!RtlEqualUnicodeString(
&Names[SidIndex].Name,
&UnknownSidEntry->Name,
FALSE)) {
DbgPrint(
"LSA RPC CT - Lookup Unknown Sids failed\n"
"... Unknown Sid %d mismatch on name\n",
SidIndex
);
BooleanStatus = FALSE;
}
//
// Verify that the Referenced Domain Index is as expected.
// This should be non-negative for all identified Sids
// because we return descriptive information in the
// Trust Information in place of a Domain Name for well
// well known Sids that are not Domain Sids.
//
if (!UnknownSids[SidIndex].DomainKnown) {
if (Names[SidIndex].DomainIndex >= 0) {
DbgPrint(
"LSA RPC CT - Lookup Unknown Sids failed\n"
"... Incorrect DomainIndex returned\n"
".. for Sid %d\n"
".. non-neg value returned when domain unknown\n",
SidIndex
);
BooleanStatus = FALSE;
}
} else {
//
// Domain is expected to be known.
//
if (Names[SidIndex].DomainIndex < 0) {
DbgPrint(
"LSA RPC CT - Lookup Unknown Sids failed\n"
"... Incorrect DomainIndex returned\n"
"... for Sid %d\n"
"... Negative value returned when domain known\n",
SidIndex
);
BooleanStatus = FALSE;
}
//
// The DomainIndex is non negative. Verify that a Referenced
// Domain List has been returned. Then check that the
// Referenced Entry contains the correct Trust Information.
//
if (BooleanStatus) {
if (ReferencedDomains == NULL) {
DbgPrint(
"LSA RPC CT - Lookup Unknown Sids failed\n"
".. Referenced Domains List NULL\n"
);
BooleanStatus = FALSE;
} else {
//
// A Referenced Domain List was returned. Check out the
// Trust Information.
//
ReturnedTrustInformation =
(ReferencedDomains->Domains) + (Names[SidIndex].DomainIndex);
BooleanStatus = CtLsaGeneralVerifyTrustInfo(
ReturnedTrustInformation,
WellKnownSidEntry
);
}
}
}
} except (EXCEPTION_EXECUTE_HANDLER) {
Status = GetExceptionCode();
DbgPrint(
"LSA RPC CT - Lookup Unknown Sids failed\n"
"... Access violation accessing returned\n"
"... information from lookup of all well known Sids\n"
);
BooleanStatus = FALSE;
}
if (!BooleanStatus) {
DbgPrint(".. no further Sid output compared\n");
break;
}
}
LookupSidsFinish:
//
// If necessary, free the ReferencedDomains array.
//
if (ReferencedDomains != NULL) {
Status = LsaFreeMemory(ReferencedDomains);
ReferencedDomains = NULL;
if (!NT_SUCCESS(Status)) {
DbgPrint(
"LSA RPC CT - General Sids Lookup failed\n"
"... LsaFreeMemory(ReferencedDomains) returned 0x%lx\n",
Status
);
BooleanStatus = FALSE;
}
}
//
// If necessary, free the Names array.
//
if (Names != NULL) {
Status = LsaFreeMemory(Names);
Names = NULL;
if (!NT_SUCCESS(Status)) {
DbgPrint(
"LSA RPC CT - General Sids Lookup failed\n"
"... LsaFreeMemory(Names) returned 0x%lx\n",
Status
);
BooleanStatus = FALSE;
}
}
//
// If necessary, close the TrustedDomainHandle.
//
if (TrustedDomainHandle != NULL) {
Status = LsaClose( TrustedDomainHandle );
TrustedDomainHandle = NULL;
}
//
// If necessary, close the Policy handle to the LSA object on the
// PDC.
//
if (PDPolicyHandle != NULL) {
Status = LsaClose(PDPolicyHandle);
PDPolicyHandle = NULL;
if (!NT_SUCCESS(Status)) {
DbgPrint(
"LSA RPC CT - General Sids Lookup failed\n"
"... LsaClose(PDPolicyHandle) returned 0x%lx\n",
Status
);
BooleanStatus = FALSE;
}
}
//
// If necessary, close the LSA Policy Handle for the Workstation.
//
if (PolicyHandle != NULL) {
Status = LsaClose(PolicyHandle);
PolicyHandle = NULL;
if (!NT_SUCCESS(Status)) {
DbgPrint(
"LSA RPC CT - General Sids Lookup failed\n"
"... LsaClose(PolicyHandle) returned 0x%lx\n",
Status
);
BooleanStatus = FALSE;
}
}
return(BooleanStatus);
LookupSidsError:
goto LookupSidsFinish;
}
BOOLEAN
CtLsaLookupSidsInSamDomain(
IN OPTIONAL PUNICODE_STRING WorkstationName,
IN PUNICODE_STRING DomainControllerName,
IN PUNICODE_STRING SamDomainName,
IN CT_SAM_ACCOUNT_TYPE SamAccountType
)
/*++
Routine Description:
This function enumerates all the SAM accounts of a specified type
in a specified SAM domain on a specified target system. The system
must be one of the following:
o The Workstation itself.
o A Domain Controller for the Primary Domain of the Workstation.
o A Domain Controller for one of the Trusted Domains of the
Workstation.
Having enumerated the accounts, the function then performs
an LsaLookupSids call via the specified Workstation to lookup all of
these account Sids, and then compares the returned information
with that expected.
Arguments:
WorkstationName - Specifies a Workstation Name. The name may be
the NULL string, which means the current system.
DomainControllerName - Specifies the name of a target Domain Controller
for (the Workstation's Primary Domain or one of its Trusted
Domains.
SamDomainName - Specifies the name of the SAM Domain. This is either
the BUILTIN Domain or the name of the Accounts Domain.
SamAccountType - Specifies the type of SAM account to be enumerated
and looked up.
Return Values:
BOOLEAN - TRUE if successful, else FALSE.
--*/
{
NTSTATUS Status;
BOOLEAN BooleanStatus = TRUE;
SAM_HANDLE SamServerHandle = NULL;
SAM_HANDLE SamDomainHandle = NULL;
OBJECT_ATTRIBUTES SamObjectAttributes;
OBJECT_ATTRIBUTES LsaObjectAttributes;
PSID SamDomainSid = NULL;
PSAM_RID_ENUMERATION EnumerationBuffer = NULL;
PSID *AccountSids = NULL;
ULONG AccountSidsLength;
PLSA_REFERENCED_DOMAIN_LIST ReferencedDomains = NULL;
PLSA_TRANSLATED_NAME Names = NULL;
ULONG RidIndex;
ULONG UserAccountControl;
LSA_HANDLE PolicyHandle = NULL;
UNICODE_STRING TmpDomainControllerName;
//
// Connect to the SAM server.
//
Status = SamConnect(
DomainControllerNameCopy,
&SamServerHandle,
SAM_SERVER_LOOKUP_DOMAIN,
&SamObjectAttributes
);
if (!NT_SUCCESS(Status)) {
DbgPrint(
"LSA RPC CT - General Sid Lookup in SAM Domain failed\n"
"... SamConnect returned 0x%lx\n",
Status
);
goto LookupSidsInSamDomainError;
}
//
// Lookup the Named Domain in the Sam Server to get its Sid.
//
Status = SamLookupDomainInSamServer(
SamServerHandle,
SamDomainName,
&SamDomainSid
);
if (!NT_SUCCESS(Status)) {
DbgPrint(
"LSA RPC CT - General Sid Lookup in SAM Domain failed\n"
"... SamLookupDomainInSamServer returned 0x%lx\n",
Status
);
goto LookupSidsInSamDomainError;
}
//
// Open the Domain
//
Status = SamOpenDomain(
SamServerHandle,
DOMAIN_LIST_ACCOUNTS,
SamDomainSid,
&SamDomainHandle
);
if (!NT_SUCCESS(Status)) {
DbgPrint(
"LSA RPC CT - General Sid Lookup in SAM Domain failed\n"
"... SamOpenDomain returned 0x%lx\n",
Status
);
goto LookupSidsInSamDomainError;
}
//
// Enumerate the accounts of the specified type in the specified SAM Domain
//
CountReturned = 0;
EnumerationContext = 0;
EnumerationBuffer = NULL;
PreferedMaximumLength = 512;
switch (SamAccountType) {
case CT_SAM_ALIAS:
Status = SamEnumerateAliasesInDomain(
SamDomainHandle,
&EnumerationContext,
(PVOID *) &EnumerationBuffer,
PreferedMaximumLength,
&CountReturned
);
if (!NT_SUCCESS(Status)) {
DbgPrint(
"LSA RPC CT - General Sid Lookup in SAM Domain failed\n"
"... SamEnumerateAliasInDomain returned 0x%lx\n",
Status
);
BooleanStatus = FALSE;
}
break;
case CT_SAM_GROUP:
Status = SamEnumerateGroupsInDomain(
SamDomainHandle,
&EnumerationContext,
(PVOID *) &EnumerationBuffer,
PreferedMaximumLength,
&CountReturned
);
if (!NT_SUCCESS(Status)) {
DbgPrint(
"LSA RPC CT - General Sid Lookup in SAM Domain failed\n"
"... SamEnumerateGroupsInDomain returned 0x%lx\n",
Status
);
BooleanStatus = FALSE;
}
break;
case CT_SAM_USER:
UserAccountControl = 0;
Status = SamEnumerateUsersInDomain(
SamDomainHandle,
&EnumerationContext,
UserAccountControl,
(PVOID *) &EnumerationBuffer,
PreferedMaximumLength,
&CountReturned
);
if (!NT_SUCCESS(Status)) {
DbgPrint(
"LSA RPC CT - General Sid Lookup in SAM Domain failed\n"
"... SamEnumerateUsersInDomain returned 0x%lx\n",
Status
);
BooleanStatus = FALSE;
}
break;
}
if (!BooleanStatus) {
goto LookupSidsInSamDomainError;
}
if (CountReturned == 0) {
DbgPrint(
"LSA RPC CT - General Sid Lookup in SAM Domain failed\n"
"... SamEnumerate<AccountType>Domain returned no Ids\n"
);
goto LookupSidsInSamDomainError;
}
//
// Now construct the Account Sids from the Rids just enumerated.
// We prepend the Sam Domain Sid to the Rids.
//
AccountSidsLength = CountReturned * sizeof ( PSID );
AccountSids = (PSID *) LocalAlloc( LMEM_FIXED, AccountSidsLength );
if (AccountSids == 0) {
DbgPrint(
"LSA RPC CT - General Sid Lookup in SAM Domain failed\n"
"... Unable to allocate memory for Built In Domain Alias Sids\n"
);
goto LookupSidsInSamDomainError;
}
RtlZeroMemory( AccountSids, AccountSidsLength );
for (RidIndex = 0; RidIndex < CountReturned; RidIndex++) {
if (!CtLsaGeneralBuildSid(
&(AccountSids[ RidIndex ]),
SamDomainSid,
EnumerationBuffer[ RidIndex ].RelativeId
)) {
DbgPrint(
"LSA RPC CT - General Sid Lookup in SAM Domain failed\n"
"... not enough memory to build Sid from DomainSid and Rid\n"
);
BooleanStatus = FALSE;
break;
}
}
if (!BooleanStatus) {
goto LookupSidsInSamDomainError;
}
//
// Now Lookup these Account Sids via LsaLookupSids specifying the
// Workstation. First, we need to open a handle to the workstation's
// Policy object.
//
CtLsaInitObjectAttributes(
&LsaObjectAttributes,
&SecurityQualityOfService
);
PolicyHandle = NULL;
Status = LsaOpenPolicy(
WorkstationName,
&LsaObjectAttributes,
POLICY_LOOKUP_NAMES,
&PolicyHandle
);
if (!NT_SUCCESS(Status)) {
DbgPrint(
"LSA RPC CT - Lookup Sids in Sam Domain failed\n"
"LsaOpenPolicy for Workstation returned 0x%lx\n",
Status
);
goto LookupSidsInSamDomainError;
}
ReferencedDomains = NULL;
Names = NULL;
Status = LsaLookupSids(
PolicyHandle,
CountReturned,
AccountSids,
&ReferencedDomains,
&Names
);
if (Status != STATUS_SUCCESS) {
DbgPrint(
"LSA RPC CT - General Sid Lookup in SAM Domain failed\n"
"... LsaLookupSids returned 0x%lx\n",
Status
);
goto LookupSidsInSamDomainError;
}
//
// Verify that a ReferencedDomains structure has been returned.
//
if (ReferencedDomains == NULL) {
DbgPrint(
"LSA RPC CT - General Sid Lookup in SAM Domain failed\n"
"... no ReferencedDomains structure returned\n");
goto LookupSidsInSamDomainError;
}
//
// Verify that a Names array has been returned.
//
if (Names == NULL) {
DbgPrint(
"LSA RPC CT - General Sid Lookup in SAM Domain failed\n"
"... no Names array returned\n"
);
goto LookupSidsInSamDomainError;
}
//
// Finally, compare the Names returned from SAM directly with the
// names returned from LsaLookupSids.
//
for ( RidIndex = 0; RidIndex < CountReturned; RidIndex++ ) {
if (!RtlEqualUnicodeString(
&EnumerationBuffer[ RidIndex].Name,
&Names[ RidIndex ].Name,
TRUE
)) {
DbgPrint(
"LSA RPC CT - General Sid Lookup in SAM Domain failed\n"
"... mismatch on name for Sid %d\n",
RidIndex
);
DbgPrint("... no further names compared\n");
goto LookupSidsInSamDomainError;
}
}
LookupSidsInSamDomainFinish:
//
// If necessary, close the SAM Domain Handle for the Workstation.
//
if (SamDomainHandle != NULL) {
Status = SamCloseHandle( SamDomainHandle);
SamDomainHandle = NULL;
if (!NT_SUCCESS(Status)) {
DbgPrint(
"LSA RPC CT - General Sid Lookup in SAM Domain failed\n"
"... SamCloseHandle ( Sam Domain Handle ) returned 0x%lx\n",
Status
);
goto LookupSidsInSamDomainError;
}
}
//
// If necessary, disconnect from the SAM Server.
//
if (SamServerHandle != NULL) {
Status = SamCloseHandle( SamServerHandle );
SamServerHandle = NULL;
if (!NT_SUCCESS(Status)) {
DbgPrint(
"LSA RPC CT - General Sid Lookup in SAM Domain failed\n"
"... SamCloseHandle( Sam Server Handle ) returned 0x%lx\n",
Status
);
goto LookupSidsInSamDomainError;
}
}
//
// If necessary, close the LSA handle to the Workstation's Policy object.
//
if (PolicyHandle != NULL) {
Status = LsaClose( PolicyHandle );
PolicyHandle = NULL;
if (!NT_SUCCESS(Status)) {
DbgPrint(
"LSA RPC CT - General Sid Lookup in SAM Domain failed\n"
"... LsaClose( Policy Server Handle ) returned 0x%lx\n",
Status
);
goto LookupSidsInSamDomainError;
}
}
return( BooleanStatus );
LookupSidsInSamDomainError:
BooleanStatus = FALSE;
goto LookupSidsInSamDomainFinish;
}
BOOLEAN
CtLsaLookupNames(
IN OPTIONAL PUNICODE_STRING WorkstationName
)
/*++
Routine Description:
This function tests the LsaLookupNames API.
Parameters:
WorkstationName - Specifies the name of the Workstation. If NULL or
a NULL string is specified, the workstation is the local machine.
Return Values:
BOOLEAN - True if test successful, else FALSE.
--*/
{
NTSTATUS Status;
BOOLEAN BooleanStatus = TRUE;
ULONG Count;
PLSA_REFERENCED_DOMAIN_LIST ReferencedDomains;
LSAP_WELL_KNOWN_SID_INDEX NameIndex;
PLSAP_WELL_KNOWN_SID_ENTRY WellKnownSidEntry;
PLSA_TRUST_INFORMATION ReturnedTrustInformation;
OBJECT_ATTRIBUTES ObjectAttributes;
SECURITY_QUALITY_OF_SERVICE SecurityQualityOfService;
LSA_HANDLE PolicyHandle = NULL;
LSA_HANDLE PDPolicyHandle = NULL;
LSA_HANDLE TrustedDomainHandle = NULL;
ULONG ExpectedRid;
PLSA_TRANSLATED_SID Sids = NULL;
CT_UNKNOWN_NAME_ENTRY UnknownNameInfo[CT_UNKNOWN_NAME_COUNT];
UCHAR SubAuthorityCount;
UNICODE_STRING BuiltInDomainName;
UNICODE_STRING AccountDomainName;
UNICODE_STRING PDAccountDomainName;
UNICODE_STRING InputNames[LsapDummyLastSidIndex];
PPOLICY_ACCOUNT_DOMAIN_INFO PolicyAccountDomainInfo = NULL;
PPOLICY_ACCOUNT_DOMAIN_INFO PolicyPDAccountDomainInfo = NULL;
PPOLICY_PRIMARY_DOMAIN_INFO PolicyPrimaryDomainInfo = NULL;
PTRUSTED_CONTROLLERS_INFO TrustedControllersInfo = NULL;
UNICODE_STRING UnknownNames[CT_UNKNOWN_NAME_COUNT];
PCT_UNKNOWN_NAME_ENTRY UnknownNameEntry = NULL;
DbgPrint("[2] - Test General Name Lookup\n");
//
// Open a handle to the Policy Object
//
CtLsaInitObjectAttributes(
&ObjectAttributes,
&SecurityQualityOfService
);
PolicyHandle = NULL;
Status = LsaOpenPolicy(
WorkstationName,
&ObjectAttributes,
POLICY_LOOKUP_NAMES | POLICY_VIEW_LOCAL_INFORMATION,
&PolicyHandle
);
if (!NT_SUCCESS(Status)) {
DbgPrint(
"LSA RPC CT - Policy object open handle %d failed 0x%lx\n",
Index,
Status
);
return FALSE;
}
//
// Variation [1] - Lookup all of the Well Known Names
//
DbgPrint("... [1] - Lookup all of the Well Known Names\n");
// Using the table of Well Known Sids/Names, construct an array containing all
// of the Well Known Names in the format needed by LsaLookupNames() and
// look them all up.
//
for (NameIndex = LsapNullSidIndex;
NameIndex < LsapDummyLastSidIndex;
NameIndex++) {
//
// Copy the next Well Known Name from the table of Well Known Names.
//
InputNames[NameIndex] = WellKnownSids[NameIndex].Name;
}
Count = (ULONG) LsapDummyLastSidIndex - LsapWorldSidIndex;
ReferencedDomains = NULL;
Sids = NULL;
Status = LsaLookupNames(
PolicyHandle,
Count,
&InputNames[LsapWorldSidIndex],
&ReferencedDomains,
&Sids
);
//
// Not all of the well known Sids have Well Known Names, so we should
// get STATUS_SOME_NOT_MAPPED back.
if (Status != STATUS_SOME_NOT_MAPPED) {
DbgPrint(
"LSA RPC CT - Lookup all Well Known Names returned 0x%lx\n",
"... expected 0x%lx (STATUS_SOME_NOT_MAPPED)\n",
"[ The unmapped Names are NULL names, one name for\n"
" each Well Known Sid that does not have a Well Known Name ]\n",
Status,
STATUS_SOME_NOT_MAPPED
);
goto LookupNamesError;
}
//
// Verify that a Sids array has been returned.
//
if (Sids == NULL) {
DbgPrint(
"LSA RPC CT - Lookup Well Known Names\n"
"... no Sids array returned\n"
);
goto LookupNamesError;
}
//
// Now compare the information returned with that contained in the
// table of Well Known Names.
//
for (NameIndex = 0,
WellKnownSidEntry = &WellKnownSids[LsapWorldSidIndex];
NameIndex < (LsapDummyLastSidIndex - LsapWorldSidIndex);
NameIndex++, WellKnownSidEntry++) {
try {
//
// If this entry in the Well Known Sids table has a Well Known
// Name, check the output from LsaLookupNames.
//
if (WellKnownSidEntry->Name.Length != 0) {
//
// Verify that the Sid Name Use is correct.
//
if (Sids[NameIndex].Use != WellKnownSidEntry->Use) {
DbgPrint(
"LSA RPC CT - Lookup Well Known Name %d mismatch on Use\n"
"... expected Use code %d, got %d\n",
NameIndex,
WellKnownSidEntry->Use,
Sids[NameIndex].Use
);
BooleanStatus = FALSE;
}
//
// Verify that the Referenced Domain Index is as expected.
// and validate the Trust Information. The Referenced Domain
// index should be non-negative for all identified Names
// because we return descriptive information in the
// Trust Information in place of a Domain Name for well
// well known Names that are not Domain Names.
//
if (Sids[NameIndex].DomainIndex < 0) {
DbgPrint("LSA RPC CT - Lookup Well Known Names\n");
DbgPrint(".. negative Domain Index returned");
DbgPrint(" for Name %d\n", NameIndex);
BooleanStatus = FALSE;
} else {
//
// The DomainIndex is non negative. Verify that a Referenced
// Domain List has been returned. Then check that the
// Referenced Entry contains the correct Trust Information.
//
if (ReferencedDomains == NULL) {
DbgPrint(
"LSA RPC CT - Lookup all well known Names failed\n"
"... Referenced Domain List NULL but Well Known\n"
".. Name %d specifies a non negative index\n",
NameIndex
);
BooleanStatus = FALSE;
} else {
//
// A Referenced Domain List was returned. Check out the
// Trust Information.
//
ReturnedTrustInformation =
(ReferencedDomains->Domains) + (Sids[NameIndex].DomainIndex);
BooleanStatus = CtLsaGeneralVerifyTrustInfo(
ReturnedTrustInformation,
WellKnownSidEntry
);
}
}
} else {
//
// This entry has no Well Known Name. We should get
// SidTypeUnknown back in the Translated Sids info.
//
if (Sids[NameIndex].Use != SidTypeUnknown) {
DbgPrint(
"LSA RPC CT - Lookup Well Known Names failed\n"
"Use SidTypeUnknown expected for NULL Name %d\n",
NameIndex
);
BooleanStatus = FALSE;
}
}
} except (EXCEPTION_EXECUTE_HANDLER) {
Status = GetExceptionCode();
DbgPrint(
"LSA RPC CT - Lookup Well Known Names failed\n"
"Access violation accessing returned\n"
".. information from LsaLookupNames\n"
);
BooleanStatus = FALSE;
}
if (!BooleanStatus) {
DbgPrint("... no further Name output compared\n");
break;
}
//
// If the Sid is not the Sid of a Domain and the Sid has a well
// known name, verify that the RelativeId returned matches that
// expected. First, compute the Relative Id expected from the Well
// Known Sid Entry.
//
if (WellKnownSidEntry->Use != SidTypeDomain) {
if (WellKnownSidEntry->Name.Length != 0) {
SubAuthorityCount = *RtlSubAuthorityCountSid( WellKnownSidEntry-> Sid);
ExpectedRid = *RtlSubAuthoritySid(
WellKnownSidEntry->Sid,
SubAuthorityCount - 1
);
if (Sids[NameIndex].RelativeId != ExpectedRid) {
BooleanStatus = FALSE;
break;
}
}
} else {
//
// The Sid is the Sid of a Domain. Verify that the correct
// Trust Information has been returned.
//
// TBS
}
}
if (!BooleanStatus) {
goto LookupNamesError;
}
//
// Variation [2] - Lookup the Alias Names in the Built-In Sam Domain
//
DbgPrint(
"... [2] - Lookup Alias Account Names present in Workstation's\n"
"..........Built-in SAM Domain\n"
);
RtlInitUnicodeString( &BuiltInDomainName, L"BUILTIN" );
//
// Enumerate the Aliases in the Built-in Sam Domain, convert them to
// names and then Lookup those Names via LsaLookupNames.
//
if (!CtLsaLookupNamesInSamDomain(
WorkstationName,
WorkstationName,
&BuiltInDomainName,
CT_SAM_ALIAS
)) {
goto LookupNamesError;
}
//
// Variation [3] - Lookup the User and Group Names contained in the Workstation's
// SAM Account Domain
//
// First, obtain the Name and Name of the SAM Account Domain from the
// Workstation's LSA Policy Object.
//
DbgPrint(
"... [3] - Lookup User and Group Account Names present in Workstation's\n"
"..........SAM Account Domain\n"
);
Status = LsaQueryInformationPolicy(
PolicyHandle,
PolicyAccountDomainInformation,
(PVOID *) &PolicyAccountDomainInfo
);
if (!NT_SUCCESS(Status)) {
DbgPrint(
"LSA RPC CT - General Name Lookup in Workstation SAM Account Domain failed\n"
"... LsaQueryInformationPolicy for Account Domain Name/Name returned 0x%lx\n",
Status
);
goto LookupNamesError;
}
AccountDomainName = PolicyAccountDomainInfo->DomainName;
//
// Enumerate the Users in the Account Domain, convert them to
// names and then Lookup those Names via LsaLookupNames.
//
if (!CtLsaLookupNamesInSamDomain(
WorkstationName,
WorkstationName,
&AccountDomainName,
CT_SAM_USER
)) {
goto LookupNamesError;
}
//
// Enumerate the Groups in the Account Domain, convert them to
// names and then Lookup those Names via LsaLookupNames.
//
if (!CtLsaLookupNamesInSamDomain(
WorkstationName,
WorkstationName,
&AccountDomainName,
CT_SAM_GROUP
)) {
goto LookupNamesError;
}
//
// Variation [4] - Lookup the User and Group Names contained in the Primary Domain's
// SAM Account Domain
//
DbgPrint(
"... [4] - Lookup User and Group Account Names present in Workstation's\n"
"..........Primary Domain's SAM Account Domain\n"
);
//
// We need to obtain the Name of a Primary Domain Controller so that
// we can connect to the LSA Policy Object and SAM Servers there.
// To get this takes several steps -
//
// * Query the Workstation Policy object to get the Name of the Primary
// Domain.
//
// * Use the primary Domain Name to open the Trusted Domain object
// for the Primary Domain.
//
// * Query the Trusted Controller List from the TD object.
//
// * Select the name of the first (or any) Controller on the list
// to open the LSA and SAM objects.
//
// Obtain the Name of the Workstation's Primary Domain from the
// Policy Object.
//
Status = LsaQueryInformationPolicy(
PolicyHandle,
PolicyPrimaryDomainInformation,
(PVOID *) &PolicyPrimaryDomainInfo
);
if (!NT_SUCCESS(Status)) {
DbgPrint(
"LSA RPC CT - General Name Lookup in Primary Domain SAM Account Domain failed\n"
"... LsaQueryInformationPolicy for Primary Domain Name/Name returned 0x%lx\n",
Status
);
goto LookupNamesError;
}
//
// If the Primary Domain Name is NULL, return an error.
//
if (PolicyPrimaryDomainInfo->Name.Buffer == NULL) {
DbgPrint(
"LSA RPC CT - General Name Lookup in Primary Domain SAM Account Domain failed\n"
"... LsaQueryInformationPolicy for Primary Domain Name/Name returned NULL Name\n"
);
goto LookupNamesError;
}
//
// Now open the Trusted Domain object corresponding to the
// Primary Domain Name.
//
Status = LsaOpenTrustedDomain(
PolicyHandle,
PolicyPrimaryDomainInfo->Sid,
TRUSTED_QUERY_CONTROLLERS,
&TrustedDomainHandle
);
if (!NT_SUCCESS(Status)) {
DbgPrint(
"LSA RPC CT - General Name Lookup in Primary Domain SAM Account Domain failed\n"
"... LsaOpenTrustedDomain for Primary Domain Trusted Object returned 0x%lx\n",
Status
);
goto LookupNamesError;
}
//
// Now query the Primary Domain's Controller List
//
Status = LsaQueryInfoTrustedDomain(
TrustedDomainHandle,
TrustedControllersInformation,
(PVOID *) &TrustedControllersInfo
);
if (!NT_SUCCESS(Status)) {
DbgPrint(
"LSA RPC CT - General Name Lookup in Primary Domain SAM Account Domain failed\n"
"... LsaQueryInfoTrustedDomain for Primary Domain Ctrlrs 0x%lx\n",
Status
);
goto LookupNamesError;
}
//
// If no Trusted Controllers were returned, return an error.
//
if (TrustedControllersInfo->Entries == 0) {
DbgPrint(
"LSA RPC CT - General Name Lookup in Primary Domain SAM Account Domain failed\n"
"... no PD Controllers returned\n",
Status
);
goto LookupNamesError;
}
//
// Now open a handle to the Lsa Policy Object for the first
// controller on the list.
//
CtLsaInitObjectAttributes(
&ObjectAttributes,
&SecurityQualityOfService
);
PDPolicyHandle = NULL;
Status = LsaOpenPolicy(
&TrustedControllersInfo->Names[0],
&ObjectAttributes,
POLICY_LOOKUP_NAMES | POLICY_VIEW_LOCAL_INFORMATION,
&PDPolicyHandle
);
if (!NT_SUCCESS(Status)) {
DbgPrint(
"LSA RPC CT - General Name Lookup in Primary Domain SAM Account Domain failed\n"
"... LsaOpenPolicy for PD LSA returned 0x%lx\n",
Status
);
goto LookupNamesError;
}
//
// Obtain the Name and Sid of the SAM Account Domain from the
// Primary Domain's LSA Policy Object.
//
Status = LsaQueryInformationPolicy(
PDPolicyHandle,
PolicyAccountDomainInformation,
(PVOID *) &PolicyPDAccountDomainInfo
);
if (!NT_SUCCESS(Status)) {
DbgPrint(
"LSA RPC CT - General Name Lookup in Primary Domain SAM Account Domain failed\n"
"... LsaQueryInformationPolicy for Account Domain Name/Name returned 0x%lx\n",
Status
);
goto LookupNamesError;
}
PDAccountDomainName = PolicyPDAccountDomainInfo->DomainName;
//
// Enumerate the Users in the Account Domain located on a controller
// for the primary Domain, and then Lookup those Names via LsaLookupNames.
//
if (!CtLsaLookupNamesInSamDomain(
WorkstationName,
&TrustedControllersInfo->Names[0],
&PDAccountDomainName,
CT_SAM_USER
)) {
goto LookupNamesError;
}
//
// Enumerate the Groups in the Account Domain, convert them to
// names and then Lookup those Names via LsaLookupNames.
//
if (!CtLsaLookupNamesInSamDomain(
WorkstationName,
&TrustedControllersInfo->Names[0],
&PDAccountDomainName,
CT_SAM_GROUP
)) {
goto LookupNamesError;
}
//
// Variation [5] - Lookup Names of Groups and Users in the SAM Account Domain of
// a Controller for one of the Trusted Domains
//
DbgPrint(
"... [5] - Lookup User and Group Account Names present in Workstation's\n"
"..........Primary Domain Trusted Domain SAM Account Domain\n"
);
// TBS
//
// Variation (6) - Lookup some completely unknown isolated Names.
//
DbgPrint("... [6] - Lookup Unknown Names\n");
CtLsaGeneralInitUnknownName(
&FredName,
NULL,
NULL,
&UnknownNameInfo[0],
FALSE
);
CtLsaGeneralInitUnknownName(
&WilmaName,
NULL,
NULL,
&UnknownNameInfo[1],
FALSE
);
CtLsaGeneralInitUnknownName(
&PebblesName,
&BedrockCDomainName,
BedrockCDomainSid,
&UnknownNameInfo[2],
FALSE
);
CtLsaGeneralInitUnknownName(
&DinoName,
&BedrockDDomainName,
BedrockDDomainSid,
&UnknownNameInfo[3],
FALSE
);
ReferencedDomains = NULL;
Count = 4;
//
// Construct an array containing the unknown Names.
//
for (NameIndex = 0;
NameIndex < 4;
NameIndex++) {
//
// Copy the next Unknown Name
//
UnknownNames[NameIndex] = UnknownNameInfo[NameIndex].Name;
}
Status = LsaLookupNames(
PolicyHandle,
Count,
UnknownNames,
&ReferencedDomains,
&Sids
);
if (Status != STATUS_SUCCESS) {
DbgPrint(
"LSA RPC CT - Lookup Unknown Names failed 0x%lx\n",
Status
);
goto LookupNamesError;
}
//
// Now compare the information returned with that contained in the
// table of Unknown Names.
//
for (NameIndex = 0, UnknownNameEntry = UnknownNameInfo;
NameIndex < 4;
NameIndex++, UnknownNameEntry++) {
try {
//
// Verify that the Name Name Use is correct. We should
// have NameTypeUnknown in all cases.
//
if (Sids[NameIndex].Use != SidTypeUnknown) {
DbgPrint(
"LSA RPC CT - Lookup Unknown Names failed\n"
"... Unknown Name %d Use incorrect\n",
"... expected Use code %d (SidTypeUnknown), got %d\n",
NameIndex,
SidTypeUnknown,
Sids[NameIndex].Use
);
BooleanStatus = FALSE;
}
//
// Verify that the Referenced Domain Index is as expected.
// This should be non-negative for all identified Names
// because we return descriptive information in the
// Trust Information in place of a Domain Name for well
// well known Names that are not Domain Names.
//
if (!UnknownNameInfo[NameIndex].DomainKnown) {
if (Sids[NameIndex].DomainIndex >= 0) {
DbgPrint(
"LSA RPC CT - Lookup Unknown Names failed\n"
"... Incorrect DomainIndex returned\n"
".. for Name %d\n"
".. non-neg value returned when domain unknown\n",
NameIndex
);
BooleanStatus = FALSE;
}
} else {
//
// Domain is expected to be known.
//
if (Sids[NameIndex].DomainIndex < 0) {
DbgPrint(
"LSA RPC CT - Lookup Unknown Names failed\n"
"... Incorrect DomainIndex returned\n"
"... for Name %d\n"
"... Negative value returned when domain known\n",
NameIndex
);
BooleanStatus = FALSE;
}
//
// The DomainIndex is non negative. Verify that a Referenced
// Domain List has been returned. Then check that the
// Referenced Entry contains the correct Trust Information.
//
if (BooleanStatus) {
if (ReferencedDomains == NULL) {
DbgPrint(
"LSA RPC CT - Lookup Unknown Names failed\n"
".. Referenced Domains List NULL\n"
);
BooleanStatus = FALSE;
} else {
//
// A Referenced Domain List was returned. Check out the
// Trust Information.
//
ReturnedTrustInformation =
(ReferencedDomains->Domains) + (Sids[NameIndex].DomainIndex);
/*
NOTE - This test is TBS
BooleanStatus = CtLsaGeneralVerifyNameTrustInfo(
ReturnedTrustInformation,
UnknownNameInfo + NameIndex;
)
*/
}
}
}
} except (EXCEPTION_EXECUTE_HANDLER) {
Status = GetExceptionCode();
DbgPrint(
"LSA RPC CT - Lookup Unknown Names failed\n"
"... Access violation accessing returned\n"
"... information from lookup of all well known Names\n"
);
BooleanStatus = FALSE;
}
if (!BooleanStatus) {
DbgPrint(".. no further Sid output compared\n");
break;
}
}
LookupNamesFinish:
//
// If necessary, free the ReferencedDomains array.
//
if (ReferencedDomains != NULL) {
Status = LsaFreeMemory(ReferencedDomains);
ReferencedDomains = NULL;
if (!NT_SUCCESS(Status)) {
DbgPrint(
"LSA RPC CT - General Names Lookup failed\n"
"... LsaFreeMemory(ReferencedDomains) returned 0x%lx\n",
Status
);
BooleanStatus = FALSE;
}
}
//
// If necessary, free the Sids array.
//
if (Sids != NULL) {
Status = LsaFreeMemory(Sids);
Sids = NULL;
if (!NT_SUCCESS(Status)) {
DbgPrint(
"LSA RPC CT - General Names Lookup failed\n"
"... LsaFreeMemory(Sids) returned 0x%lx\n",
Status
);
BooleanStatus = FALSE;
}
}
//
// If necessary, close the TrustedDomainHandle.
//
if (TrustedDomainHandle != NULL) {
Status = LsaClose( TrustedDomainHandle );
TrustedDomainHandle = NULL;
}
//
// If necessary, close the Policy handle to the LSA object on the
// PDC.
//
if (PDPolicyHandle != NULL) {
Status = LsaClose(PDPolicyHandle);
PDPolicyHandle = NULL;
if (!NT_SUCCESS(Status)) {
DbgPrint(
"LSA RPC CT - General Names Lookup failed\n"
"... LsaClose(PDPolicyHandle) returned 0x%lx\n",
Status
);
BooleanStatus = FALSE;
}
}
//
// If necessary, close the LSA Policy Handle for the Workstation.
//
if (PolicyHandle != NULL) {
Status = LsaClose(PolicyHandle);
PolicyHandle = NULL;
if (!NT_SUCCESS(Status)) {
DbgPrint(
"LSA RPC CT - General Names Lookup failed\n"
"... LsaClose(PolicyHandle) returned 0x%lx\n",
Status
);
BooleanStatus = FALSE;
}
}
return(BooleanStatus);
LookupNamesError:
BooleanStatus = FALSE;
goto LookupNamesFinish;
}
BOOLEAN
CtLsaLookupNamesInSamDomain(
IN OPTIONAL PUNICODE_STRING WorkstationName,
IN PUNICODE_STRING DomainControllerName,
IN PUNICODE_STRING SamDomainName,
IN CT_SAM_ACCOUNT_TYPE SamAccountType
)
/*++
Routine Description:
This function enumerates all the SAM accounts of a specified type
in a specified SAM domain on a specified target system. The system
must be one of the following:
o The Workstation itself.
o A Domain Controller for the Primary Domain of the Workstation.
o A Domain Controller for one of the Trusted Domains of the
Workstation.
Having enumerated the accounts, the function then performs
an LsaLookupNames call via the specified Workstation to lookup all of
these account names, and then compares the returned information
with that expected.
Arguments:
WorkstationName - Specifies a Workstation Name. The name may be
the NULL string, which means the current system.
DomainControllerName - Specifies the name of a target Domain Controller
for (the Workstation's Primary Domain or one of its Trusted
Domains.
SamDomainName - Specifies the name of the SAM Domain. This is either
the BUILTIN Domain or the name of the Accounts Domain.
SamAccountType - Specifies the type of SAM account to be enumerated
and looked up.
Return Values:
BOOLEAN - TRUE if successful, else FALSE.
--*/
{
NTSTATUS Status;
BOOLEAN BooleanStatus = TRUE;
SAM_HANDLE SamServerHandle = NULL;
SAM_HANDLE SamDomainHandle = NULL;
OBJECT_ATTRIBUTES SamObjectAttributes;
OBJECT_ATTRIBUTES LsaObjectAttributes;
SECURITY_QUALITY_OF_SERVICE SecurityQualityOfService;
PSID SamDomainSid = NULL;
ULONG CountReturned;
ULONG EnumerationContext;
PSAM_RID_ENUMERATION EnumerationBuffer = NULL;
ULONG PreferedMaximumLength;
ULONG RidIndex;
ULONG NameIndex;
ULONG UserAccountControl;
LSA_HANDLE PolicyHandle = NULL;
PUNICODE_STRING SamDomainAccountNames = NULL;
ULONG SamDomainAccountNamesLength;
PLSA_REFERENCED_DOMAIN_LIST ReferencedDomains = NULL;
PLSA_TRANSLATED_SID Sids = NULL;
PSID_NAME_USE Uses = NULL;
PULONG RelativeIds = NULL;
ULONG RelativeIdsLength;
PUNICODE_STRING ThrowawayNames = NULL;
LONG ConstantDomainIndex;
LONG DomainIndex;
//
// Setup Object Attributes for connecting to SAM on the specified
// DomainController.
//
CtLsaInitObjectAttributes(
&SamObjectAttributes,
&SecurityQualityOfService
);
//
// Connect to the SAM server.
//
Status = SamConnect(
DomainControllerName,
&SamServerHandle,
SAM_SERVER_LOOKUP_DOMAIN,
&SamObjectAttributes
);
if (!NT_SUCCESS(Status)) {
DbgPrint(
"LSA RPC CT - General Name Lookup in SAM Built in Domain failed\n"
"... SamConnect returned 0x%lx\n",
Status
);
goto LookupNamesInSamDomainError;
}
//
// Lookup the SAM Domain by its name.
//
Status = SamLookupDomainInSamServer(
SamServerHandle,
SamDomainName,
&SamDomainSid
);
if (!NT_SUCCESS(Status)) {
DbgPrint(
"LSA RPC CT - General Name Lookup in SAM Domain failed\n"
"... SamLookupDomainInSamServer returned 0x%lx\n",
Status
);
goto LookupNamesInSamDomainError;
}
//
// Verify that a Domain Sid has been returned.
//
if (SamDomainSid == NULL) {
DbgPrint(
"LSA RPC CT - General Alias Name Lookup in SAM Domain failed\n"
".. no DomainSid returned\n"
);
goto LookupNamesInSamDomainError;
}
//
// Open the SAM Domain
//
Status = SamOpenDomain(
SamServerHandle,
DOMAIN_LIST_ACCOUNTS | DOMAIN_LOOKUP,
SamDomainSid,
&SamDomainHandle
);
if (!NT_SUCCESS(Status)) {
DbgPrint(
"LSA RPC CT - General Alias Name Lookup in SAM Domain failed\n"
"... SamOpenDomain returned 0x%lx\n",
Status
);
goto LookupNamesInSamDomainError;
}
//
// Enumerate the accounts of the specified type the SAM Domain
//
CountReturned = 0;
EnumerationContext = 0;
EnumerationBuffer = NULL;
PreferedMaximumLength = 512;
switch (SamAccountType) {
case CT_SAM_ALIAS:
Status = SamEnumerateAliasesInDomain(
SamDomainHandle,
&EnumerationContext,
(PVOID *) &EnumerationBuffer,
PreferedMaximumLength,
&CountReturned
);
if (!NT_SUCCESS(Status)) {
DbgPrint(
"LSA RPC CT - General Alias Name Lookup in SAM Domain failed\n"
"... SamEnumerateAliasInDomain returned 0x%lx\n",
Status
);
}
break;
case CT_SAM_GROUP:
Status = SamEnumerateGroupsInDomain(
SamDomainHandle,
&EnumerationContext,
(PVOID *) &EnumerationBuffer,
PreferedMaximumLength,
&CountReturned
);
if (!NT_SUCCESS(Status)) {
DbgPrint(
"LSA RPC CT - General Group Name Lookup in SAM Domain failed\n"
"... SamEnumerateGroupsInDomain returned 0x%lx\n",
Status
);
}
break;
case CT_SAM_USER:
UserAccountControl = 0;
Status = SamEnumerateUsersInDomain(
SamDomainHandle,
&EnumerationContext,
UserAccountControl,
(PVOID *) &EnumerationBuffer,
PreferedMaximumLength,
&CountReturned
);
if (!NT_SUCCESS(Status)) {
DbgPrint(
"LSA RPC CT - General User Name Lookup in SAM Domain failed\n"
"... SamEnumerateUsersInDomain returned 0x%lx\n",
Status
);
}
break;
}
if (!NT_SUCCESS(Status)) {
goto LookupNamesInSamDomainError;
}
if (CountReturned == 0) {
DbgPrint(
"LSA RPC CT - General Name Lookup in SAM Domain failed\n"
"... SamEnumerate<AccountType>InDomain returned no Alias Ids\n"
);
goto LookupNamesInSamDomainError;
}
//
// Verify that an EnumerationBuffer has been returned.
//
if (EnumerationBuffer == NULL) {
DbgPrint(
"LSA RPC CT - General Alias Name Lookup in SAM Built in Domain failed\n"
"... no EnumerationBuffer structure returned\n"
);
goto LookupNamesInSamDomainError;
}
//
// Construct an array of account names to be looked up.
//
SamDomainAccountNamesLength = CountReturned * sizeof ( UNICODE_STRING );
SamDomainAccountNames = LocalAlloc( (UINT) LMEM_FIXED, (UINT) SamDomainAccountNamesLength );
if (SamDomainAccountNames == 0) {
DbgPrint(
"LSA RPC CT - General Name Lookup in SAM Domain failed\n"
"... Unable to allocate memory for Sam Domain Account Names\n"
);
goto LookupNamesInSamDomainError;
}
//
// Fish the account names out of the Enumeration Buffer returned by
// SamEnumerateIdsInDomain.
//
for ( NameIndex = 0; NameIndex < CountReturned; NameIndex++ ) {
if (EnumerationBuffer[ NameIndex].Name.Length == 0) {
DbgPrint(
"LSA RPC CT - Lookup Names in Sam Domain failed\n"
"SamEnumerateIdsInDomain returned 0 length Unicode Name\n",
"for id %d\n",
NameIndex
);
BooleanStatus = FALSE;
break;
}
if (EnumerationBuffer[ NameIndex].Name.Buffer == NULL) {
DbgPrint(
"LSA RPC CT - Lookup Names in Sam Domain failed\n"
"SamEnumerateIdsInDomain returned NULL Unicode Name Buffer\n",
"for id %d\n",
NameIndex
);
BooleanStatus = FALSE;
break;
}
SamDomainAccountNames[NameIndex].Buffer = EnumerationBuffer[ NameIndex].Name.Buffer;
SamDomainAccountNames[NameIndex].Length = EnumerationBuffer[ NameIndex].Name.Length;
SamDomainAccountNames[NameIndex].MaximumLength = EnumerationBuffer[ NameIndex].Name.MaximumLength;
}
if (!BooleanStatus) {
goto LookupNamesInSamDomainError;
}
//
// Now Lookup these account names via LsaLookupNames specifying the
// Workstation. First, we need to open its Policy object.
//
CtLsaInitObjectAttributes(
&LsaObjectAttributes,
&SecurityQualityOfService
);
PolicyHandle = NULL;
Status = LsaOpenPolicy(
WorkstationName,
&LsaObjectAttributes,
POLICY_LOOKUP_NAMES,
&PolicyHandle
);
if (!NT_SUCCESS(Status)) {
DbgPrint(
"LSA RPC CT - Lookup Sids in Sam Domain failed\n"
"LsaOpenPolicy for Workstation returned 0x%lx\n",
Status
);
goto LookupNamesInSamDomainError;
}
ReferencedDomains = NULL;
Sids = NULL;
Status = LsaLookupNames(
PolicyHandle,
CountReturned,
SamDomainAccountNames,
&ReferencedDomains,
&Sids
);
if (Status != STATUS_SUCCESS) {
DbgPrint(
"LSA RPC CT - General Name Lookup in SAM Domain\n"
"... LsaLookupNames failed 0x%lx\n",
Status
);
goto LookupNamesInSamDomainError;
}
//
// Verify that a ReferencedDomains structure has been returned.
//
if (ReferencedDomains == NULL) {
DbgPrint(
"LSA RPC CT - General Name Lookup in SAM Domain failed\n"
"... no ReferencedDomains structure returned\n");
goto LookupNamesInSamDomainError;
}
//
// Verify that a Sids array has been returned.
//
if (Sids == NULL) {
DbgPrint(
"LSA RPC CT - General Name Lookup in SAM Domain failed\n"
"... no Sids array returned\n"
);
goto LookupNamesInSamDomainError;
}
//
// Compare the Account Rids returned from SAM directly with the
// Sid translation info returned from LsaLookupNames.
//
for ( RidIndex = 0; RidIndex < CountReturned; RidIndex++ ) {
if (EnumerationBuffer[ RidIndex ].RelativeId !=
Sids[ RidIndex ].RelativeId) {
DbgPrint(
"LSA RPC CT - General Name Lookup in SAM Domain failed\n"
"... mismatch on RelativeId number %d\n"
"... expected 0x%lx, got 0x%lx\n",
RidIndex,
EnumerationBuffer[ RidIndex ].RelativeId,
Sids[ RidIndex ].RelativeId
);
BooleanStatus = FALSE;
break;
}
}
if (!BooleanStatus) {
goto LookupNamesInSamDomainError;
}
//
// Construct an array of the Relative Ids returned by
// SamEnumerate<AccountType>InDomain. We will look them up
// to obtain their Uses.
//
RelativeIdsLength = CountReturned * sizeof( ULONG );
RelativeIds = LocalAlloc( (UINT) LMEM_FIXED, (UINT) RelativeIdsLength);
if (RelativeIds == NULL) {
DbgPrint(
"LSA RPC CT - General Name Lookup in SAM Domain failed\n"
"... Unable to allocate memory for Rid array\n"
);
goto LookupNamesInSamDomainError;
}
for (RidIndex = 0; RidIndex < CountReturned; RidIndex++) {
RelativeIds[ RidIndex ] = EnumerationBuffer[ RidIndex ].RelativeId;
}
//
// Now lookup the RelativeIds in the Sam Domain and get their Uses.
//
Status = SamLookupIdsInDomain(
SamDomainHandle,
CountReturned,
RelativeIds,
&ThrowawayNames,
&Uses
);
if (!NT_SUCCESS(Status)) {
DbgPrint(
"LSA RPC CT - General Name Lookup in SAM Domain failed\n"
"... SamLookupIdsInDomain returned 0x%lx\n",
Status
);
goto LookupNamesInSamDomainError;
}
if (ThrowawayNames == NULL) {
DbgPrint(
"LSA RPC CT - General Name Lookup in SAM Domain failed\n"
"... SamLookupIdsInDomain returned NULL Uames array\n",
Status
);
goto LookupNamesInSamDomainError;
}
if (Uses == NULL) {
DbgPrint(
"LSA RPC CT - General Name Lookup in SAM Domain failed\n"
"... SamLookupIdsInDomain returned NULL Uses array\n",
Status
);
goto LookupNamesInSamDomainError;
}
//
// Now compare the Uses returned from SAM with the Uses returned from
// LsaLookupNames.
//
for (RidIndex = 0; RidIndex < CountReturned; RidIndex++) {
if (Uses[ RidIndex] != Sids[ RidIndex].Use) {
DbgPrint(
"LSA RPC CT - General Name Lookup in SAM Account Domain failed\n"
"... mismatch on Use returned for Name %d\n"
"... expected %d, got %d\n"
".. no further Use values compared\n",
(ULONG) Uses[ RidIndex ],
(ULONG) Sids[RidIndex].Use
);
BooleanStatus = FALSE;
break;
}
}
if (!BooleanStatus) {
goto LookupNamesInSamDomainError;
}
//
// Finally, verify the Trust Information entry for this domain and
// check that each Sid translation structure references that domain.
//
try {
//
// First, load the Domain Index returned in the first Sid
// Translation structure and verify that it is non-negative.
//
ConstantDomainIndex = Sids[ 0 ].DomainIndex;
if (ConstantDomainIndex < 0) {
DbgPrint(
"LSA RPC CT - General Name Lookup in SAM Account Domain failed\n"
"... negative DomainIndex Returned\n"
"... no further Domain Indices checked\n"
);
BooleanStatus = FALSE;
}
//
// Now verify that the referenced Domain List structure returned
// contains the correct Trust Information.
//
if (!RtlEqualSid(
SamDomainSid,
ReferencedDomains->Domains[ ConstantDomainIndex ].Sid
)) {
DbgPrint(
"LSA RPC CT - General Name Lookup in SAM Account Domain failed\n"
"... Incorrect Sid in the single ReferencedDomainList entry\n"
"... Sid should match Sid of the SAM Domain we're searching\n"
);
BooleanStatus = FALSE;
}
if (!RtlEqualUnicodeString(
SamDomainName,
&ReferencedDomains->Domains[ ConstantDomainIndex].Name,
TRUE)) {
DbgPrint(
"LSA RPC CT - General Name Lookup in SAM Account Domain failed\n"
"... Incorrect name in the single ReferencedDomainList entry\n"
"... name should match name of SAM domain we're searching\n"
);
BooleanStatus = FALSE;
}
if (BooleanStatus) {
for (RidIndex = 0; RidIndex < CountReturned; RidIndex++) {
DomainIndex = Sids[ RidIndex ].DomainIndex;
//
// First verify that a non-negative Domain Index was returned.
//
if (DomainIndex < 0) {
DbgPrint(
"LSA RPC CT - General Name Lookup in SAM Account Domain failed\n"
"... negative DomainIndex Returned\n"
"... no further Domain Indices checked\n"
);
BooleanStatus = FALSE;
break;
}
if (DomainIndex != ConstantDomainIndex) {
DbgPrint(
"LSA RPC CT - General Name Lookup in SAM Account Domain failed\n"
"... all domain indices not the same\n"
"... for ids all in the same SAM domain\n"
"... no further Domain Indices checked\n"
);
BooleanStatus = FALSE;
break;
}
}
}
} except( EXCEPTION_EXECUTE_HANDLER ) {
DbgPrint(
"LSA RPC CT - General Name Lookup in SAM Account Domain failed\n"
"... access violation when examining output\n"
);
BooleanStatus = FALSE;
}
if (!BooleanStatus) {
goto LookupNamesInSamDomainError;
}
LookupNamesInSamDomainFinish:
//
// If necessary, close the SAM Built In Domain Handle for the Workstation.
//
if (SamDomainHandle != NULL) {
Status = SamCloseHandle( SamDomainHandle);
SamDomainHandle = NULL;
}
if (!NT_SUCCESS(Status)) {
DbgPrint(
"LSA RPC CT - General Name Lookup in SAM Account Domain failed\n"
"... SamCloseHandle( SamDomainHandle returned 0x%lx\n",
Status
);
goto LookupNamesInSamDomainError;
}
//
// If necessary, disconnect from the Workstation's SAM Server.
//
if (SamServerHandle != NULL) {
Status = SamCloseHandle( SamServerHandle );
SamServerHandle = NULL;
if (!NT_SUCCESS(Status)) {
DbgPrint(
"LSA RPC CT - General Name Lookup in SAM Account Domain failed\n"
"... SamCloseHandle returned 0x%lx\n",
Status
);
goto LookupNamesInSamDomainError;
}
}
//
// If necessary, close the LSA handle to the Workstation's Policy object.
//
if (PolicyHandle != NULL) {
Status = LsaClose( PolicyHandle );
PolicyHandle = NULL;
if (!NT_SUCCESS(Status)) {
DbgPrint(
"LSA RPC CT - General Name Lookup in SAM Account Domain failed\n"
"... LsaClose( PolicyHandle ) returned 0x%lx\n",
Status
);
goto LookupNamesInSamDomainError;
}
}
return(BooleanStatus);
LookupNamesInSamDomainError:
BooleanStatus = FALSE;
goto LookupNamesInSamDomainFinish;
}
BOOLEAN
CtLsaLookupConfigure(
IN OPTIONAL PUNICODE_STRING WorkstationName,
IN OPTIONAL PUNICODE_STRING PrimaryDomainName,
IN PSID PrimaryDomainSid,
IN PUNICODE_STRING PrimaryDomainCtrlrNames,
IN ULONG PrimaryDomainCtrlrCount,
IN OPTIONAL PUNICODE_STRING TrustedDomainNames,
IN PSID *TrustedDomainSids,
IN ULONG TrustedDomainCount,
IN PUNICODE_STRING TrustedDomainCtrlrNames,
IN ULONG TrustedDomainCtrlrTotal,
IN PULONG TrustedDomainCtrlrCounts
)
/*++
Routine Description:
This function configures the LSA and SAM Databases for multiple
machines for a Sid or Name Lookup Test. These machines may
be combined into one if desired. The machines are setup to
represent the following:
- A Workstation
- One or more Primary Domain Controllers
- One or more Trusted Domain Controllers
Arguments:
WorkstationName - Pointer to name of the workstation.
PrimaryDomainName - Pointer to Unicode String containing name
of the Primary Domain (if any) for the Workstation. If NULL
is specified, no Primary Domain will be set up. If a zero
length Unicode name is specified, a default Primary Domain name
will be used.
PrimaryDomainSid - Pointer to Sid for the Primary Domain.
PrimaryDomainCtrlrNames - Pointer to array of Unicode Strings
specifying the names of machines that form the set of Controllers
for the Primary Domain. The first of these is set to be the
Primary Controller, the remainder are the Backup Controllers.
PrimaryDomainCtrlrCount - Count of Domain Controllers provided
in PrimaryDomainCtrlrNames.
TrustedDomainNames - Pointer to array of Unicode Strings containing
names of Domains that are Trusted by the Primary Domain for
authentication.
TrustedDomainSids - Pointer to an array of Sids for the Trusted Domains.
TrustedDomainCount - Count of Trusted Domain Names provided on
the TrustedDomainNames parameter.
TrustedDomainCtrlrNames - Pointer to array of Unicode Strings containing
the names of machines that are to act as Primary or Backup Domain
Controllers for the Trusted Domains specified on TrustedDomainNames.
This array is subdivided into subarrays, there being one subarray
corresponding to each TrustedDomainNames entry. Each subarray
contains the name of the Primary Controller followed by the names
of the Backup Domain Controllers for the Trusted Domain it describes.
The size of the subarray for TrustedDomain n is in element n of the
TrustedDomainCtrlrCounts array.
TrustedDomainCtrlrTotal - Count of the total number of Domain
Controllers provided in TrustedDomainCtrlrNames.
TrustedDomainCtrlrCounts - Pointer to array in which the nth element
contains the number of Domain Controllers for Trusted Domain n.
Return Values:
BOOLEAN - TRUE if the configuration was successful, else FALSE.
--*/
{
BOOLEAN BooleanStatus = FALSE;
PULONG RelativeId = NULL;
PSID Sid = NULL;
//
// Print out the configuration specified on the ctlsarpc command line.
//
if (!CtLsaLookupPrintConfiguration(
WorkstationName,
PrimaryDomainName,
PrimaryDomainCtrlrNames,
PrimaryDomainCtrlrCount,
TrustedDomainNames,
TrustedDomainCount,
TrustedDomainCtrlrNames,
TrustedDomainCtrlrCounts
)) {
goto LookupConfigureError;
}
//
// Configure the Workstation. We store information about the Primary
// Domain and its list of Domain Controllers in the LSA Database.
//
if (!CtLsaLookupConfigureWksta(
WorkstationName,
PrimaryDomainName,
PrimaryDomainSid,
PrimaryDomainCtrlrNames,
PrimaryDomainCtrlrCount
)) {
goto LookupConfigureError;
}
//
// Configure the Primary Domain Primary and Backup Controller (if any).
// machines. For each Controller, we have to set its LSA Database
// Primary Domain and Trusted Domain information.
//
if (PrimaryDomainName != NULL && PrimaryDomainName->Buffer != NULL) {
if (!CtLsaLookupConfigurePDC(
PrimaryDomainName,
PrimaryDomainSid,
PrimaryDomainCtrlrNames,
PrimaryDomainCtrlrCount,
TrustedDomainNames,
TrustedDomainSids,
TrustedDomainCount,
TrustedDomainCtrlrNames,
TrustedDomainCtrlrTotal,
TrustedDomainCtrlrCounts
)) {
goto LookupConfigureError;
}
}
//
// Configure each of the Trusted Domain Controllers (if any).
// Skip if the obnly Trusted Domain is the Primary Domain.
//
if (TrustedDomainCount > 1) {
if (!CtLsaGeneraLookupConfigureTDC(
TrustedDomainNames,
TrustedDomainSids,
TrustedDomainCount,
TrustedDomainCtrlrNames,
TrustedDomainCtrlrTotal,
TrustedDomainCtrlrCounts
)) {
goto LookupConfigureError;
}
}
BooleanStatus = TRUE;
LookupConfigureFinish:
return(BooleanStatus);
LookupConfigureError:
BooleanStatus = FALSE;
goto LookupConfigureFinish;
}
VOID
CtLsaGeneralInitUnknownName(
IN PUNICODE_STRING Name,
IN OPTIONAL PUNICODE_STRING DomainName,
IN OPTIONAL PSID DomainSid,
OUT PCT_UNKNOWN_NAME_ENTRY UnknownNameInfo,
IN BOOLEAN DomainKnown
)
/*++
Routine Description:
This function sets up information for an Unknown Name. The Name may be
completely unknown, or its DomainName may be recognizable.
Arguments:
Name - Pointer to the terminal part of the name, i.e. without any
Domain Name prefix.
DomainName - Optional pointer to Domain Name.
DomainSid - Optional pointer to Domain Sid.
UnknownNameInfo - Pointer to structure that will receive the Name,
Domain Name, Domain Sid information.
DomainKnown - Indicates whether the optional Domain Name and Domain Sid
are known. Here "known" means that they are one of the following
domains:
The Workstation's SAM BUILTIN or Accounts Domains
The Workstation's Primary Domain's SAM Accounts Domain
The SAM Accounts Domain on any Domain that is Trusted by the
Workstation's Primary Domain.
Return Values:
None.
--*/
{
//
// Just copy the supplied information to the UnknownNameInfo structure.
//
UnknownNameInfo->Name = *Name;
if (DomainName != NULL) {
UnknownNameInfo->DomainName = *DomainName;
} else {
UnknownNameInfo->DomainName.Buffer = NULL;
UnknownNameInfo->DomainName.Length = 0;
UnknownNameInfo->DomainName.MaximumLength = 0;
}
UnknownNameInfo->DomainSid = DomainSid;
UnknownNameInfo->DomainKnown = DomainKnown;
}
BOOLEAN
CtLsaLookupConfigureWksta(
IN PUNICODE_STRING WorkstationName,
IN PUNICODE_STRING PrimaryDomainName,
IN PUNICODE_STRING PrimaryDomainSid,
IN PUNICODE_STRING PrimaryDomainCtrlrNames,
IN ULONG PrimaryDomainCtrlrCount
)
/*++
Routine Description:
This function configures a Workstation's Policy Database by storing
information defining the Workstation's Primary Domain and list
of that domain's Domain Controllers.
Arguments:
WorkstationName - Pointer to Unicode Name of the target workstation
(\\machinename).
PrimaryDomainName - Pointer to Unicode String containing name
of the Primary Domain (if any) for the Workstation. If NULL
is specified, no Primary Domain will be set up. If a zero
length Unicode name is specified, a default Primary Domain name
will be used.
PrimaryDomainSid - Pointer to the Sid of the Primary Domain.
PrimaryDomainCtrlrNames - Pointer to array of Unicode Strings
specifying the names of machines that form the set of Controllers
for the Primary Domain. The first of these is set to be the
Primary Controller, the remainder are the Backup Controllers.
PrimaryDomainCtrlrCount - Count of Domain Controllers provided
in PrimaryDomainCtrlrNames.
Return Values:
BOOLEAN - TRUE if configuration successful, else FALSE.
--*/
{
NTSTATUS Status;
BOOLEAN BooleanStatus;
OBJECT_ATTRIBUTES ObjectAttributes;
SECURITY_QUALITY_OF_SERVICE SecurityQualityOfService;
LSA_HANDLE PolicyHandle;
POLICY_ACCOUNT_DOMAIN_INFO PolicyAccountDomainInfo;
POLICY_PRIMARY_DOMAIN_INFO PolicyPrimaryDomainInfo;
LSA_HANDLE PrimaryDomainHandle = NULL;
LSA_HANDLE TrustedDomainHandle = NULL;
LSA_TRUST_INFORMATION PrimaryDomainTrustInformation;
TRUSTED_CONTROLLERS_INFO PrimaryDomainTrustedCtrlrsInfo;
if (WorkstationName == NULL || WorkstationName->Length == 0) {
DbgPrint("LSA RPC CT - Configuring Workstation (Local Machine)\n");
} else {
DbgPrint("LSA RPC CT - Configuring Workstation %Z\n", WorkstationName);
}
//
// Open a handle to the Workstation's Policy Database.
//
CtLsaInitObjectAttributes(
&ObjectAttributes,
&SecurityQualityOfService
);
PolicyHandle = NULL;
Status = LsaOpenPolicy(
WorkstationName,
&ObjectAttributes,
POLICY_TRUST_ADMIN | POLICY_SERVER_ADMIN,
&PolicyHandle
);
if (!NT_SUCCESS(Status)) {
DbgPrint(
"LSA RPC CT - Lookup Sid/Name Test Configuration failed\n"
"... (Configuring the Workstation)\n"
"... Policy object open handle for Wksta failed 0x%lx\n",
Status
);
goto LookupConfigureWkstaError;
}
//
// Now configure the SAM Account Domain Name. This is set equal
// to the fixed name "ACCOUNTS" as we assume that the target
// Workstation is configured as a Workstation, not a Server, i.e.
// that the Product Type is Win-NT. The Sid of this domain is
// configurable, so for this test configuration, we supply one that we
// generate ourselves.
//
RtlInitUnicodeString(
&PolicyAccountDomainInfo.DomainName,
L"ACCOUNTS"
);
PolicyAccountDomainInfo.DomainSid = AccountDomainSid;
Status = LsaSetInformationPolicy(
PolicyHandle,
PolicyAccountDomainInformation,
&PolicyAccountDomainInfo
);
if (!NT_SUCCESS(Status)) {
DbgPrint(
"LSA RPC CT - Lookup Sid/Name Test configuration failed\n"
"... (Configuring the Workstation)\n"
".. LsaSetInformationPolicy for Account Domain failed "
"0x%lx\n",
Status
);
goto LookupConfigureWkstaError;
}
//
// Now set the Name and Sid for the workstation's Primary Domain.
//
PolicyPrimaryDomainInfo.Name = *PrimaryDomainName;
PolicyPrimaryDomainInfo.Sid = PrimaryDomainSid;
Status = LsaSetInformationPolicy(
PolicyHandle,
PolicyPrimaryDomainInformation,
&PolicyPrimaryDomainInfo
);
if (!NT_SUCCESS(Status)) {
DbgPrint(
"LSA RPC CT - Lookup Sid/Name Test Configuration failed\n"
"... (Configuring the Workstation)\n"
".. LsaSetInformationPolicy setting Primary Domain failed 0x%lx\n",
Status
);
goto LookupConfigureWkstaError;
}
//
// Create a TrustedDomain object for the Primary Domain.
//
PrimaryDomainTrustInformation.Name = *PrimaryDomainName;
PrimaryDomainTrustInformation.Sid = PrimaryDomainSid;
PrimaryDomainTrustedCtrlrsInfo.Entries = PrimaryDomainCtrlrCount;
PrimaryDomainTrustedCtrlrsInfo.Names = PrimaryDomainCtrlrNames;
Status = CtLsaLookupConfigureTrustedDomain(
PolicyHandle,
&PrimaryDomainTrustInformation,
&PrimaryDomainTrustedCtrlrsInfo
);
if (!NT_SUCCESS(Status)) {
goto LookupConfigureWkstaError;
}
BooleanStatus = TRUE;
LookupConfigureWkstaFinish:
return(BooleanStatus);
LookupConfigureWkstaError:
BooleanStatus = FALSE;
goto LookupConfigureWkstaFinish;
}
BOOLEAN
CtLsaLookupConfigurePDC(
IN PUNICODE_STRING PrimaryDomainName,
IN PSID PrimaryDomainSid,
IN PUNICODE_STRING PrimaryDomainCtrlrNames,
IN ULONG PrimaryDomainCtrlrCount,
IN PUNICODE_STRING TrustedDomainNames,
IN PSID *TrustedDomainSids,
IN ULONG TrustedDomainCount,
IN PUNICODE_STRING TrustedDomainCtrlrNames,
IN ULONG TrustedDomainCtrlrTotal,
IN PULONG TrustedDomainCtrlrCounts
)
/*++
Routine Description:
This function configures the Policy Database for a set of machines
so that they represent Domain Controllers for the Primary Domain
of a Workstation. For each Controller, the Policy Lsa Server Role
information is set and the name of the SAM Account domain is set to
the name of the Primary Domain. In addition, a Trusted Domain Object is
created for the Primary Domain and it is initilaized with the list
of Controllers.
Arguments:
PrimaryDomainName - Pointer to Unicode String containing name
of the Primary Domain (if any) for the Workstation. If NULL
is specified, no Primary Domain will be set up. If a zero
length Unicode name is specified, a default Primary Domain name
will be used.
PrimaryDomainSid - Pointer to the Sid of the Primary Domain.
PrimaryDomainCtrlrNames - Pointer to array of Unicode Strings
specifying the names of machines that form the set of Controllers
for the Primary Domain. The first of these is set to be the
Primary Controller, the remainder are the Backup Controllers.
PrimaryDomainCtrlrCount - Count of Domain Controllers provided
in PrimaryDomainCtrlrNames.
TrustedDomainNames - Pointer to array of Unicode Strings containing
names of Domains that are Trusted by the Primary Domain for
authentication.
TrustedDomainSids - Pointer to an array of TrustedDomainCount Sids
for the TrustedDomains
TrustedDomainCount - Count of Trusted Domain Names/Sids provided on
the TrustedDomainNames/Sids parameters.
TrustedDomainCtrlrNames - Pointer to array of Unicode Strings containing
the names of machines that are to act as Primary or Backup Domain
Controllers for the Trusted Domains specified on TrustedDomainNames.
This array is subdivided into subarrays, there being one subarray
corresponding to each TrustedDomainNames entry. Each subarray
contains the name of the Primary Controller followed by the names
of the Backup Domain Controllers for the Trusted Domain it describes.
The size of the subarray for TrustedDomain n is in element n of the
TrustedDomainCtrlrCounts array.
TrustedDomainCtrlrTotal - Count of the total number of Domain
Controllers provided in TrustedDomainCtrlrNames.
TrustedDomainCtrlrCounts - Pointer to array in which the nth element
contains the number of Domain Controllers for Trusted Domain n.
Return Values:
BOOLEAN - TRUE if configuration successful, else FALSE.
--*/
{
NTSTATUS Status;
BOOLEAN BooleanStatus;
ULONG DomainControllerIndex;
LSA_HANDLE TrustedDomainHandle = NULL;
POLICY_LSA_SERVER_ROLE PolicyLsaServerRoleInfo;
OBJECT_ATTRIBUTES ObjectAttributes;
SECURITY_QUALITY_OF_SERVICE SecurityQualityOfService;
LSA_HANDLE PolicyHandle;
ULONG FirstDomainCtrlrIndex;
POLICY_ACCOUNT_DOMAIN_INFO PolicyAccountDomainInfo;
ULONG DomainNumber;
LSA_TRUST_INFORMATION DomainTrustInformation;
TRUSTED_CONTROLLERS_INFO DomainTrustedCtrlrsInfo;
LSA_TRUST_INFORMATION PrimaryDomainTrustInformation;
TRUSTED_CONTROLLERS_INFO PrimaryDomainTrustedCtrlrsInfo;
//
// Iterate over the set of Domain Controllers for the Primary Domain.
//
for (DomainControllerIndex = 0;
DomainControllerIndex < PrimaryDomainCtrlrCount;
DomainControllerIndex++) {
//
// Select the Policy Lsa Server Role. This is Primary for the
// first controller for a Domain, backup for all others.
//
PolicyLsaServerRoleInfo = PolicyServerRoleBackup;
if (DomainControllerIndex == 0) {
PolicyLsaServerRoleInfo = PolicyServerRolePrimary;
DbgPrint(
"LSA RPC CT - Configuring %Z as Primary Controller"
" for Primary Domain\n",
&PrimaryDomainCtrlrNames[DomainControllerIndex]
);
} else {
DbgPrint(
"LSA RPC CT - Configuring %Z as Backup Controller"
" for Primary Domain\n",
&PrimaryDomainCtrlrNames[DomainControllerIndex]
);
}
//
// Open a handle to the Policy Object for the next
// Domain Controller for the Primary Domain.
//
CtLsaInitObjectAttributes(
&ObjectAttributes,
&SecurityQualityOfService
);
PolicyHandle = NULL;
Status = LsaOpenPolicy(
&PrimaryDomainCtrlrNames[DomainControllerIndex],
&ObjectAttributes,
POLICY_TRUST_ADMIN | POLICY_SERVER_ADMIN,
&PolicyHandle
);
if (!NT_SUCCESS(Status)) {
DbgPrint(
"LSA RPC CT - Lookup Sid/Name Test Configuration failed\n"
"... (Configuring the Primary Domain Controllers)\n"
"LSA RPC CT - Policy object open handle %d failed 0x%lx\n",
Status
);
}
//
// Now set the Server Role.
//
Status = LsaSetInformationPolicy(
PolicyHandle,
PolicyLsaServerRoleInformation,
&PolicyLsaServerRoleInfo
);
if (!NT_SUCCESS(Status)) {
DbgPrint(
"LSA RPC CT - Lookup Sid/Name Test configuration failed\n"
"... (Configuring the Primary Domain Controllers)\n"
".. LsaSetInformationPolicy for Server Role failed 0x%lx\n",
Status
);
break;
}
//
// Now configure the SAM Account Domain Name. This is set equal
// to the Primary Domain Name.
//
PolicyAccountDomainInfo.DomainName = *PrimaryDomainName;
PolicyAccountDomainInfo.DomainSid = PrimaryDomainSid;
Status = LsaSetInformationPolicy(
PolicyHandle,
PolicyAccountDomainInformation,
&PolicyAccountDomainInfo
);
if (!NT_SUCCESS(Status)) {
DbgPrint(
"LSA RPC CT - Lookup Sid/Name Test configuration failed\n"
"... (Configuring the Primary Domain Controllers)\n"
".. LsaSetInformationPolicy for Account Domain failed "
"0x%lx\n",
Status
);
break;
}
//
// Now create a Trusted Domain Object for the Primary Domain.
//
PrimaryDomainTrustInformation.Name = *PrimaryDomainName;
PrimaryDomainTrustInformation.Sid = PrimaryDomainSid;
PrimaryDomainTrustedCtrlrsInfo.Entries = PrimaryDomainCtrlrCount;
PrimaryDomainTrustedCtrlrsInfo.Names = PrimaryDomainCtrlrNames;
Status = CtLsaLookupConfigureTrustedDomain(
PolicyHandle,
&PrimaryDomainTrustInformation,
&PrimaryDomainTrustedCtrlrsInfo
);
if (!NT_SUCCESS(Status)) {
break;
}
}
if (!NT_SUCCESS(Status)) {
goto LookupConfigurePDCError;
}
//
// For each of the other Trusted Domains (if any), create a Trusted Domain object
// and store the Controller Information within it.
//
//
// Set index to skip past TDC's for Primary Domain.
//
FirstDomainCtrlrIndex = TrustedDomainCtrlrCounts[0];
for (DomainNumber = 1; DomainNumber < TrustedDomainCount; DomainNumber++) {
DomainTrustInformation.Name = TrustedDomainNames[DomainNumber];
DomainTrustInformation.Sid = TrustedDomainSids[DomainNumber];
DomainTrustedCtrlrsInfo.Entries = TrustedDomainCtrlrCounts[DomainNumber];
DomainTrustedCtrlrsInfo.Names =
&TrustedDomainCtrlrNames[FirstDomainCtrlrIndex];
Status = CtLsaLookupConfigureTrustedDomain(
PolicyHandle,
&DomainTrustInformation,
&DomainTrustedCtrlrsInfo
);
if (!NT_SUCCESS(Status)) {
break;
}
//
// Obtain the index of the first Domain Controller for the next
// domain by adding in the count of controllers in the domain
// just dealt with.
//
FirstDomainCtrlrIndex += TrustedDomainCtrlrCounts[ DomainNumber ];
if (FirstDomainCtrlrIndex > TrustedDomainCtrlrTotal) {
DbgPrint(
"LSA RPC CT Lookup Sids/Names Test Configuration failed\n"
"... Trusted Domain Ctrlr Total less than sum of\n"
"... Trusted Domain Ctrlr Counts\n"
);
Status = STATUS_INVALID_PARAMETER;
break;
}
}
if (!NT_SUCCESS(Status)) {
goto LookupConfigurePDCError;
}
BooleanStatus = TRUE;
LookupConfigurePDCFinish:
return(BooleanStatus);
LookupConfigurePDCError:
BooleanStatus = FALSE;
goto LookupConfigurePDCFinish;
}
NTSTATUS
CtLsaLookupConfigureTrustedDomain(
IN LSA_HANDLE PolicyHandle,
IN PLSA_TRUST_INFORMATION TrustedDomainInformation,
IN PTRUSTED_CONTROLLERS_INFO TrustedControllersInfo
)
/*++
Routine Description:
This function creates a Trusted Domain object (if necessary) and
initializes it with a Domain Name, Sid and Trusted Controller List.
Arguments:
PolicyHandle - Handle to LSA Policy Object. This handle must have
POLICY_TRUST_ADMIN access granted.
TrustedDomainInformation - Pointer to Trust Information for the Domain
consisting of the Unicode Domain Name and Sid.
TrustedControllersInfo - Pointer to list of Trusted Controller Names.
Return Values:
NTSTATUS - Standard Nt Result Code
Status returned by LsaCreateTrustedDomain or
LsaSetInformationTrustedDomain.
--*/
{
NTSTATUS Status;
LSA_HANDLE TrustedDomainHandle = NULL;
ULONG ControllerNumber;
DbgPrint(
"... Configuring Trusted Domain %Z\n",
&TrustedDomainInformation->Name
);
Status = LsaCreateTrustedDomain(
PolicyHandle,
TrustedDomainInformation,
TRUSTED_SET_CONTROLLERS,
&TrustedDomainHandle
);
if (!NT_SUCCESS(Status)) {
if (Status != STATUS_OBJECT_NAME_COLLISION) {
DbgPrint(
"LSA RPC CT - Lookup Sid/Name Test configuration failed\n"
"... (Configuring the Primary Domain Controllers)\n"
".. LsaCreateTrustedDomain failed 0x%lx\n",
Status
);
goto LookupConfigureTrustedDomainError;
} else {
//
// Open the existing Trusted Domain object with the given Sid.
//
Status = LsaOpenTrustedDomain(
PolicyHandle,
TrustedDomainInformation->Sid,
TRUSTED_SET_CONTROLLERS,
&TrustedDomainHandle
);
if (!NT_SUCCESS(Status)) {
DbgPrint(
"LSA RPC CT - Lookup Sid/Name Test configuration failed\n"
"... (Configuring the Primary Domain Controllers)\n"
".. LsaOpenTrustedDomain failed 0x%lx\n",
Status
);
goto LookupConfigureTrustedDomainError;
}
}
}
//
// Print out the names of all the controllers.
//
for (ControllerNumber = 0;
ControllerNumber < TrustedControllersInfo->Entries;
ControllerNumber ++
) {
DbgPrint(
"...... Trusted Controller %d - %Z\n",
ControllerNumber,
&TrustedControllersInfo->Names[ControllerNumber]
);
}
//
// Setup info for this Trusted Domain.
//
Status = LsaSetInformationTrustedDomain(
TrustedDomainHandle,
TrustedControllersInformation,
TrustedControllersInfo
);
if (!NT_SUCCESS(Status)) {
DbgPrint(
"LSA RPC CT - Lookup Sids/Name Test configuration failed\n"
"... (Configuring the Primary Domain Controllers)\n"
"... LsaSetInformationTrustedDomain for Domain Ctrlrs failed 0x%lx\n",
Status
);
goto LookupConfigureTrustedDomainError;
}
//
// Close the Trusted Domain Handle
//
Status = LsaClose( TrustedDomainHandle );
TrustedDomainHandle = NULL;
if (!NT_SUCCESS(Status)) {
DbgPrint(
"LSA RPC CT - Lookup Sid/Name Test configuration failed\n"
"... (Configuring the Primary Domain Controllers)\n"
"... LsaClose for TrustedDomain object failed 0x%lx\n",
Status
);
goto LookupConfigureTrustedDomainError;
}
LookupConfigureTrustedDomainFinish:
//
// If necessary, close the Trusted Domain object handle
//
if (TrustedDomainHandle != NULL) {
Status = LsaClose( TrustedDomainHandle );
TrustedDomainHandle = NULL;
if (!NT_SUCCESS(Status)) {
DbgPrint(
"LSA RPC CT - Lookup Sid/Name Test configuration failed\n"
"... (Configuring the Primary Domain Controllers)\n"
"... LsaClose for TrustedDomain object failed 0x%lx\n",
Status
);
goto LookupConfigureTrustedDomainError;
}
}
return(Status);
LookupConfigureTrustedDomainError:
goto LookupConfigureTrustedDomainFinish;
}
BOOLEAN
CtLsaGeneraLookupConfigureTDC(
IN PUNICODE_STRING TrustedDomainNames,
IN PSID *TrustedDomainSids,
IN ULONG TrustedDomainCount,
IN PUNICODE_STRING TrustedDomainCtrlrNames,
IN ULONG TrustedDomainCtrlrTotal,
IN PULONG TrustedDomainCtrlrCounts
)
/*++
Routine Description:
This function configures the Policy Databases for all of the machines
that are to act as Trusted Domain Controllers. For each machine,
the Policy Lsa Server Role Info is set to Primary or Backup.
TrustedDomainNames - Pointer to array of Unicode Strings containing
names of Domains that are Trusted by the Primary Domain for
authentication.
TrustedDomainSids - Pointer to an array of TrustedDomainCount Sids
for the TrustedDomains
TrustedDomainCount - Count of Trusted Domain Names/Sids provided on
the TrustedDomainNames/Sids parameters.
TrustedDomainCtrlrNames - Pointer to array of Unicode Strings containing
the names of machines that are to act as Primary or Backup Domain
Controllers for the Trusted Domains specified on TrustedDomainNames.
This array is subdivided into subarrays, there being one subarray
corresponding to each Trusted Domain Controller. Each subarray
contains the name of the Primary Controller followed by the names
of the Backup Domain Controllers for the Trusted Domain it describes.
The size of the subarray for TrustedDomain n is in element n of the
TrustedDomainCtrlrCounts array.
TrustedDomainCtrlrTotal - Total number of Domain Controllers provided
in TrustedDomainCtrlrNames.
TrustedDomainCtrlrCounts - Pointer to array in which the nth element
contains the number of Domain Controllers for Trusted Domain n.
Return Values:
BOOLEAN - TRUE if configuration successful, else FALSE.
--*/
{
NTSTATUS Status;
BOOLEAN BooleanStatus;
ULONG DomainControllerIndex;
OBJECT_ATTRIBUTES ObjectAttributes;
SECURITY_QUALITY_OF_SERVICE SecurityQualityOfService;
LSA_HANDLE PolicyHandle;
ULONG DomainNumber;
ULONG DomainControllerNumber;
POLICY_LSA_SERVER_ROLE PolicyLsaServerRoleInfo;
POLICY_ACCOUNT_DOMAIN_INFO PolicyAccountDomainInfo;
//
// Scan the list of Domain Controllers. For each one, open its
// Policy Object and set the Policy Lsa Server Role Information.
//
DomainNumber = 0;
DomainControllerIndex = 0;
for (DomainControllerIndex = 0;
DomainControllerIndex < TrustedDomainCtrlrTotal;
DomainControllerIndex++) {
//
// If there are no Domain Controllers for this domain, skip.
//
while ((TrustedDomainCtrlrCounts[DomainNumber] == 0) &&
(DomainNumber < TrustedDomainCount)) {
DomainNumber++;
}
//
// If all Domains have been dealt with, break out.
//
if (DomainNumber >= TrustedDomainCount) {
break;
}
//
// If the Count of Controllers for the current domain has been
// exceeded, this Controller is for the next domain. Reset the
// Controller Number to 0.
//
if (DomainControllerNumber >= TrustedDomainCtrlrCounts[ DomainNumber ]) {
DomainControllerNumber = 0;
}
//
// Select the Policy Lsa Server Role. This is Primary for the
// first controller for a Domain, backup for all others.
//
PolicyLsaServerRoleInfo = PolicyServerRoleBackup;
if (DomainControllerNumber == 0) {
PolicyLsaServerRoleInfo = PolicyServerRolePrimary;
}
//
// Open a handle to the Policy Object
//
CtLsaInitObjectAttributes(
&ObjectAttributes,
&SecurityQualityOfService
);
PolicyHandle = NULL;
Status = LsaOpenPolicy(
&TrustedDomainCtrlrNames[DomainControllerIndex],
&ObjectAttributes,
POLICY_TRUST_ADMIN | POLICY_SERVER_ADMIN,
&PolicyHandle
);
if (!NT_SUCCESS(Status)) {
DbgPrint(
"LSA RPC CT - Lookup Sid/Name Test configuration failed\n"
"... (Configuring the Trusted Domain Controllers)\n"
"... Policy object open handle %d failed 0x%lx\n",
Status
);
}
//
// Now set the Server Role.
//
Status = LsaSetInformationPolicy(
PolicyHandle,
PolicyLsaServerRoleInformation,
&PolicyLsaServerRoleInfo
);
if (!NT_SUCCESS(Status)) {
DbgPrint(
"LSA RPC CT - Lookup configuration failed\n"
"... (Configuring the Trusted Domain Controllers)\n"
"... LsaSetInformationPolicy for Server Role failed 0x%lx\n",
Status
);
break;
}
//
// Now configure the SAM Account Domain Name. This is set equal
// to the Trusted Domain Name.
//
RtlInitUnicodeString(
&PolicyAccountDomainInfo.DomainName,
TrustedDomainNames[DomainNumber].Buffer
);
PolicyAccountDomainInfo.DomainSid = TrustedDomainSids[DomainNumber];
Status = LsaSetInformationPolicy(
PolicyHandle,
PolicyAccountDomainInformation,
&PolicyAccountDomainInfo
);
if (!NT_SUCCESS(Status)) {
DbgPrint(
"LSA RPC CT - Lookup Sid/Name Test configuration failed\n"
"... (Configuring the Trusted Domain Controllers)\n"
"... LsaSetInformationPolicy for Account Domain failed 0x%lx\n",
Status
);
break;
}
}
if (!NT_SUCCESS(Status)) {
goto LookupConfigureTDCError;
}
BooleanStatus = TRUE;
LookupConfigureTDCFinish:
return(BooleanStatus);
LookupConfigureTDCError:
BooleanStatus = FALSE;
goto LookupConfigureTDCFinish;
}
BOOLEAN
CtLsaLookupPrintConfiguration(
IN PUNICODE_STRING WorkstationName,
IN PUNICODE_STRING PrimaryDomainName,
IN PUNICODE_STRING PrimaryDomainCtrlrNames,
IN ULONG PrimaryDomainCtrlrCount,
IN PUNICODE_STRING TrustedDomainNames,
IN ULONG TrustedDomainCount,
IN PUNICODE_STRING TrustedDomainCtrlrNames,
IN PULONG TrustedDomainCtrlrCounts
)
/*++
Routine Description:
This function prints out the configuration specified on the ctlsarpc
command line.
Arguments:
WorkstationName - Pointer to name of the workstation.
PrimaryDomainName - Pointer to Unicode String containing name
of the Primary Domain (if any) for the Workstation. If NULL
is specified, no Primary Domain will be set up. If a zero
length Unicode name is specified, a default Primary Domain name
will be used.
PrimaryDomainSid - Pointer to Sid for the Primary Domain.
PrimaryDomainCtrlrNames - Pointer to array of Unicode Strings
specifying the names of machines that form the set of Controllers
for the Primary Domain. The first of these is set to be the
Primary Controller, the remainder are the Backup Controllers.
PrimaryDomainCtrlrCount - Count of Domain Controllers provided
in PrimaryDomainCtrlrNames.
TrustedDomainNames - Pointer to array of Unicode Strings containing
names of Domains that are Trusted by the Primary Domain for
authentication.
TrustedDomainCount - Count of Trusted Domain Names provided on
the TrustedDomainNames parameter.
TrustedDomainCtrlrNames - Pointer to array of Unicode Strings containing
the names of machines that are to act as Primary or Backup Domain
Controllers for the Trusted Domains specified on TrustedDomainNames.
This array is subdivided into subarrays, there being one subarray
corresponding to each TrustedDomainNames entry. Each subarray
contains the name of the Primary Controller followed by the names
of the Backup Domain Controllers for the Trusted Domain it describes.
The size of the subarray for TrustedDomain n is in element n of the
TrustedDomainCtrlrCounts array.
TrustedDomainCtrlrTotal - Count of the total number of Domain
Controllers provided in TrustedDomainCtrlrs.
TrustedDomainCtrlrCounts - Pointer to array in which the nth element
contains the number of Domain Controllers for Trusted Domain n.
Return Values:
BOOLEAN - TRUE if successful, else FALSE.
--*/
{
BOOLEAN BooleanStatus = TRUE;
ULONG ControllerNumber;
ULONG FirstCtrlrNumber;
ULONG DomainNumber;
DbgPrint("LSA RPC CT - Configuring machines for Lookup Sid/Names tests\n");
//
// Print Configuration Summary
//
DbgPrint(
"**************************************************************\n"
" Configuration Summary \n"
"**************************************************************\n"
"\n"
);
if (WorkstationName->Buffer != NULL) {
DbgPrint("Workstation: %Z\n\n", WorkstationName);
} else {
DbgPrint("Workstation: Local Machine\n\n");
}
if (PrimaryDomainName->Buffer != NULL) {
DbgPrint("Primary Domain: %Z\n", PrimaryDomainName);
for (ControllerNumber = 0;
ControllerNumber < PrimaryDomainCtrlrCount;
ControllerNumber++) {
DbgPrint(
"... Controller %d - %Z\n",
ControllerNumber,
&PrimaryDomainCtrlrNames[ControllerNumber]
);
}
DbgPrint("\n");
if (TrustedDomainCount == 1) {
DbgPrint("No Trusted Domains other than Primary Domain\n");
} else if (TrustedDomainCount > 1) {
ASSERT (PrimaryDomainCtrlrCount == TrustedDomainCtrlrCounts[0]);
FirstCtrlrNumber = TrustedDomainCtrlrCounts[0];
for (DomainNumber = 1;
DomainNumber < TrustedDomainCount;
DomainNumber++) {
DbgPrint(
"Trusted Domain %d: %Z\n",
DomainNumber,
&TrustedDomainNames[DomainNumber]
);
for (ControllerNumber = 0;
ControllerNumber < TrustedDomainCtrlrCounts[DomainNumber];
ControllerNumber++) {
DbgPrint(
"... Controller %d: %Z\n",
ControllerNumber,
&TrustedDomainCtrlrNames[ControllerNumber + FirstCtrlrNumber]
);
}
FirstCtrlrNumber += TrustedDomainCtrlrCounts[DomainNumber];
}
} else {
DbgPrint(
"LSA RPC CT - Configuration failed "
" - no trusted domain controllers\n"
);
BooleanStatus = FALSE;
}
} else {
DbgPrint("Workstation is Standalone\n");
}
DbgPrint(
"\n**************************************************************\n"
);
if (!BooleanStatus) {
goto LookupPrintConfigurationError;
}
LookupPrintConfigurationFinish:
return(BooleanStatus);
LookupPrintConfigurationError:
BooleanStatus = FALSE;
goto LookupPrintConfigurationFinish;
}
BOOLEAN
CtLsaGeneralConstructSids(
OUT PSID *AccountDomainSid,
OUT PSID *PrimaryDomainSid,
OUT PSID **TrustedDomainSids,
IN ULONG TrustedDomainCount
)
/*++
Routine Description:
This function constructs a hardwired set of Sids, for an array
of Trusted Domains. The first of these Sids is for the Primary
Domain that trusts these Trusted Domains.
Arguments:
AccountDomainSid - Receives a pointer to the Account Domain Sid.
PrimaryDomainSid - Receives a pointer to the Primary Domain Sid.
This is always the same as the first Trusted Domain Sid.
TrustedDomainSids - Receives a pointer to an array of pointers to
Sids, which will be used as Trusted Domain Sids.
TrustedDomainCount - Count of Trusted Domain Sids needed including
the primary Domain Sid.
Return Value:
TRUE if successful, else FALSE.
--*/
{
NTSTATUS Status;
BOOLEAN BooleanStatus = FALSE;
ULONG SidLength;
ULONG SidNumber;
PULONG RelativeId = NULL;
PSID OutputPrimaryDomainSid = NULL;
PSID *OutputDomainSids = NULL;
PSID Sid = NULL;
//
// Allocate memory for the array of Sids.
//
OutputDomainSids = (PSID *) LocalAlloc( LMEM_FIXED,
sizeof (PSID) * (TrustedDomainCount + 1)
);
Status = STATUS_INSUFFICIENT_RESOURCES;
if (OutputDomainSids == NULL) {
goto GeneralConstructSidsError;
}
//
// Generate the first of the Sids. This is the Account Domain Sid.
//
SidLength = RtlLengthSid(LsapBuiltInDomainSid);
Sid = LocalAlloc( (UINT) LMEM_FIXED, (UINT) SidLength );
Status = STATUS_INSUFFICIENT_RESOURCES;
if (Sid == NULL) {
DbgPrint("LSA RPC CT - Out of memory during Sid setup\n");
goto GeneralConstructSidsError;
}
//
// Make a copy of the Sid used for generating the Sids. We just
// select the Built-In Domain Sid. We will be generating Sids
// for the Primary and Trusted Domains with consecutive Rids
// starting with a hardwired Rid for the Primary Domain Sid. The
// Rids do not need to be consecutive, it is just easy to generate
// an array of distinct Sids that way. First copy our template
// Sid.
//
Status = RtlCopySid(
SidLength,
Sid,
LsapBuiltInDomainSid
);
if (!NT_SUCCESS(Status)) {
DbgPrint("LSA RPC CT RtlCopySid failed 0x%lx\n", Status);
goto GeneralConstructSidsError;
}
RelativeId = RtlSubAuthoritySid(
Sid,
*RtlSubAuthorityCountSid(Sid) - (UCHAR) 1
);
*RelativeId = CT_ACCOUNT_DOMAIN_RID;
for (SidNumber = 0; SidNumber < (TrustedDomainCount + 1); SidNumber++) {
OutputDomainSids[SidNumber] = LocalAlloc( (UINT) LMEM_FIXED, (UINT) SidLength );
Status = RtlCopySid(
SidLength,
OutputDomainSids[SidNumber],
Sid
);
if (!NT_SUCCESS(Status)) {
DbgPrint("LSA RPC CT RtlCopySid failed 0x%lx\n", Status);
break;
}
(*RelativeId)++;
}
if (!NT_SUCCESS(Status)) {
goto GeneralConstructSidsError;
}
*TrustedDomainSids = (OutputDomainSids + 1);
*AccountDomainSid = OutputDomainSids[0];
*PrimaryDomainSid = OutputDomainSids[1];
BooleanStatus = TRUE;
GeneralConstructSidsFinish:
return(BooleanStatus);
GeneralConstructSidsError:
BooleanStatus = FALSE;
goto GeneralConstructSidsFinish;
}
BOOLEAN
CtLsaGeneralSetQuerySecurityObject(
IN OPTIONAL PUNICODE_STRING WorkstationName
)
/*++
Routine Description:
This function tests the LsaSetSecurityObject and LsaQuerySecurityObject
API.
Parameters:
WorkstationName = Optional pointer to Unicode String specifying the
name of the target workstation.
Return Values:
BOOLEAN - True if test successful, else FALSE.
--*/
{
NTSTATUS Status;
BOOLEAN BooleanStatus = TRUE;
LSA_HANDLE PolicyHandle = NULL;
LSA_HANDLE SecretHandleRubble = NULL;
CT_SECRET_INFO SecretInfoRubble;
OBJECT_ATTRIBUTES ObjectAttributes;
SECURITY_QUALITY_OF_SERVICE SecurityQualityOfService;
PSECURITY_DESCRIPTOR ExistingSecurityDescriptor = NULL;
PSECURITY_DESCRIPTOR UpdatedSecurityDescriptor = NULL;
PACL Dacl = NULL;
PSID UpdatedOwnerSid = NULL;
DbgPrint("[1] - Test Set/Query Security Object API\n");
//
// First open a Handle to the LSA.
//
CtLsaInitObjectAttributes(
&ObjectAttributes,
&SecurityQualityOfService
);
Status = LsaOpenPolicy(
WorkstationName,
&ObjectAttributes,
POLICY_VIEW_LOCAL_INFORMATION | POLICY_CREATE_SECRET,
&PolicyHandle
);
if (!NT_SUCCESS(Status)) {
DbgPrint(
"LSA RPC CT - Set/Query Security Object Test failed\n"
"LsaOpenPolicy returned 0x%lx\n",
Status
);
goto SetQuerySecurityObjectError;
}
//
// Create a new Secret called Rubble. We will Set and Query
// Security on this object and then delete it. First, set up Secret
// information for the Rubble Secret to be created.
//
Status = CtSecretSetInfo(
"Rubble",
"Rubble secret current value",
"Rubble secret old value",
&SecretInfoRubble
);
if (!NT_SUCCESS(Status)) {
DbgPrint(
"LSA RPC CT - Set/Query Security Object Test failed\n"
"LSA RPC CT - CtSecretSetInfo for Rubble returned 0x%lx\n",
Status
);
goto SetQuerySecurityObjectError;
}
//
// Create the Rubble Secret
//
Status = LsaCreateSecret(
PolicyHandle,
&(SecretInfoRubble.SecretName),
DELETE | WRITE_OWNER | WRITE_DAC | READ_CONTROL,
&SecretHandleRubble
);
if (!NT_SUCCESS(Status)) {
DbgPrint(
"LSAP RPC CT - Set/Query Security Object test failed\n"
"LSA RPC CT - Create Rubble Secret failed 0x%lx\n",
Status
);
goto SetQuerySecurityObjectError;
}
//
// First, try to assign DOMAIN_ALIAS_ADMINS as owner. This should
// work.
//
Status = CtLsaSetQuerySecurityObjectSub( SecretHandleRubble, LsapAliasAdminsSid );
if (!NT_SUCCESS(Status)) {
DbgPrint(
"LSAP RPC CT - Set/Query Security Object test failed\n"
"LsaSetSecurityObject with DOMAIN_ALIAS_ADMINS's Sid as owner\n"
"returned 0x%lx\n",
Status
);
goto SetQuerySecurityObjectError;
}
//
// Next, try to assign WORLD as owner. We should get back
// STATUS_INVALID_OWNER becuae this well known group is not
// assignable as an owner.
//
Status = CtLsaSetQuerySecurityObjectSub( SecretHandleRubble, LsapWorldSid );
if (Status != STATUS_INVALID_OWNER) {
DbgPrint(
"LSAP RPC CT - Set/Query Security Object test failed\n"
"LsaSetSecurityObject with WORLD Sid as owner returned 0x%lx\n"
"... expected 0x%lx (STATUS_INVALID_OWNER) since WORLD\n"
".. is not assignable as an owner.\n",
Status,
STATUS_INVALID_OWNER
);
goto SetQuerySecurityObjectError;
}
SetQuerySecurityObjectFinish:
//
// If necessary, Delete the Rubble Secret.
//
if (SecretHandleRubble != NULL) {
Status = LsaDelete( SecretHandleRubble );
SecretHandleRubble = NULL;
if (!NT_SUCCESS(Status)) {
DbgPrint(
"LSAP RPC CT - Set/Query Security Object test failed\n"
"LSA RPC CT - Delete Rubble Secret failed 0x%lx\n",
Status
);
goto SetQuerySecurityObjectError;
}
}
//
// If necessary, close the handle to the Policy Object.
//
if (PolicyHandle != NULL) {
Status = LsaClose( PolicyHandle );
PolicyHandle = NULL;
if (!NT_SUCCESS( Status )) {
DbgPrint(
"LSA RPC CT - Set/Query Security Object Test failed\n"
"LsaClose on Policy Handle returned 0x%lx\n",
Status
);
goto SetQuerySecurityObjectError;
}
}
return(BooleanStatus);
SetQuerySecurityObjectError:
BooleanStatus = FALSE;
goto SetQuerySecurityObjectFinish;
}
NTSTATUS
CtLsaSetQuerySecurityObjectSub(
IN LSA_HANDLE ObjectHandle,
IN PSID NewOwnerSid
)
/*++
Routine Description:
This function tests the LsaSet/QuerySecurityObject API by attempting
to change the owner of the object and DACL in the SD.
Arguments:
Objecthandle - Handle to an LSA Object.
NewOwnerSid - The SID of the new owner. Note that the assignment
of this Sid is expected to fail if it is not included in the
client's token or is the Sid of a group that is non-assignable
as owner.
Return Values:
NTSTATUS - Standard Nt Result Code.
Replies back from called routines.
--*/
{
NTSTATUS Status;
BOOLEAN BooleanStatus = TRUE;
PSECURITY_DESCRIPTOR ExistingSecurityDescriptor = NULL;
PSECURITY_DESCRIPTOR UpdatedSecurityDescriptor = NULL;
SECURITY_DESCRIPTOR ModificationSecurityDescriptor;
SECURITY_INFORMATION QuerySecurityInformation;
SECURITY_INFORMATION SetSecurityInformation;
PACL Dacl = NULL;
ULONG DaclLength;
PSID UpdatedOwnerSid = NULL;
BOOLEAN UpdatedOwnerDefaulted;
//
// Query the existing Security on the object.
//
QuerySecurityInformation = DACL_SECURITY_INFORMATION |
OWNER_SECURITY_INFORMATION;
Status = LsaQuerySecurityObject(
ObjectHandle,
QuerySecurityInformation,
&ExistingSecurityDescriptor
);
if (!NT_SUCCESS(Status)) {
DbgPrint(
"LSA RPC CT - Set/Query Security Object Test failed\n"
"LsaQuerySecurityObject (existing security) returned 0x%lx\n",
Status
);
goto SetQuerySecurityObjectSubError;
}
if (ExistingSecurityDescriptor == NULL) {
DbgPrint(
"LSA RPC CT - Set/Query Security Object Test failed\n"
"LsaQuerySecurityObject (existing security) returned a NULL"
" Security Descriptor\n",
Status
);
goto SetQuerySecurityObjectSubError;
}
//
// Now modify the Security on the object. Specifically, we will
// assign ownership to the designated NewOwnerSid and we will modify the
// DACL on the object to grant SECRET_WRITE access to that Sid.
//
Status = RtlCreateSecurityDescriptor(
&ModificationSecurityDescriptor,
SECURITY_DESCRIPTOR_REVISION
);
if (!NT_SUCCESS(Status)) {
DbgPrint(
"LSA RPC CT - Set/Query Security Object Test failed\n"
"RtlCreateSecurityDescriptor (modification SD) returned a NULL"
" Security Descriptor\n",
Status
);
goto SetQuerySecurityObjectSubError;
}
Status = RtlSetOwnerSecurityDescriptor (
&ModificationSecurityDescriptor,
NewOwnerSid,
FALSE
);
if (!NT_SUCCESS(Status)) {
DbgPrint(
"LSA RPC CT - Set/Query Security Object Test failed\n"
"RtlSetOwnerSecurityDescriptor (modification SD) returned a NULL"
" Security Descriptor\n",
Status
);
goto SetQuerySecurityObjectSubError;
}
//
// Calculate length of DACL required. It will hold one Access Allowed
// ACE for the Sid. The size of the DACL is the size of the ACL header
// plus the size of the ACE minus a redundant ULONG built into the header.
//
DaclLength = sizeof (ACL) - sizeof (ULONG) +
sizeof (ACCESS_ALLOWED_ACE ) +
RtlLengthSid( NewOwnerSid );
Dacl = RtlAllocateHeap( RtlProcessHeap(), 0, DaclLength );
Status = RtlCreateAcl( Dacl, DaclLength, ACL_REVISION );
if (!NT_SUCCESS(Status)) {
goto SetQuerySecurityObjectSubError;
}
//
// Now add the Access Allowed ACE for the group to the object's DACL.
//
Status = RtlAddAccessAllowedAce(
Dacl,
ACL_REVISION,
SECRET_WRITE,
NewOwnerSid
);
if (!NT_SUCCESS(Status)) {
goto SetQuerySecurityObjectSubError;
}
//
// Hook the DACL to the Security Descriptor.
//
Status = RtlSetDaclSecurityDescriptor (
&ModificationSecurityDescriptor,
TRUE,
Dacl,
FALSE
);
if (!NT_SUCCESS(Status)) {
goto SetQuerySecurityObjectSubError;
}
SetSecurityInformation = DACL_SECURITY_INFORMATION |
OWNER_SECURITY_INFORMATION;
Status = LsaSetSecurityObject(
ObjectHandle,
SetSecurityInformation,
&ModificationSecurityDescriptor
);
if (!NT_SUCCESS(Status)) {
goto SetQuerySecurityObjectSubError;
}
//
// Query the updated Security on the object.
//
QuerySecurityInformation = DACL_SECURITY_INFORMATION |
OWNER_SECURITY_INFORMATION;
Status = LsaQuerySecurityObject(
ObjectHandle,
QuerySecurityInformation,
&UpdatedSecurityDescriptor
);
if (!NT_SUCCESS(Status)) {
DbgPrint(
"LSA RPC CT - Set/Query Security Object Test failed\n"
"LsaQuerySecurityObject (updated security) returned 0x%lx\n",
Status
);
goto SetQuerySecurityObjectSubError;
}
if (UpdatedSecurityDescriptor == NULL) {
DbgPrint(
"LSA RPC CT - Set/Query Security Object Test failed\n"
"LsaQuerySecurityObject (updated security) returned a NULL"
" Security Descriptor\n",
Status
);
goto SetQuerySecurityObjectSubError;
}
//
// Verify that the updated owner returned matches that set.
//
UpdatedOwnerDefaulted = FALSE;
Status = RtlGetOwnerSecurityDescriptor(
UpdatedSecurityDescriptor,
&UpdatedOwnerSid,
&UpdatedOwnerDefaulted
);
if (!NT_SUCCESS(Status)) {
DbgPrint(
"LSA RPC CT - Set/Query Security Object Test failed\n"
"RtlGetOwnerSecurityDescriptor (updated security) returned 0x%lx\n",
Status
);
goto SetQuerySecurityObjectSubError;
}
if (UpdatedOwnerDefaulted) {
DbgPrint(
"LSA RPC CT - Set/Query Security Object Test failed\n"
"RtlGetOwnerSecurityDescriptor (updated security) returned\n"
"UpdatedOwnerDefaulted as TRUE\n",
Status
);
BooleanStatus = FALSE;
}
if (UpdatedOwnerSid == NULL) {
DbgPrint(
"LSA RPC CT - Set/Query Security Object Test failed\n"
"RtlGetOwnerSecurityDescriptor (updated security) returned\n"
" a NULL owner Sid\n",
Status
);
goto SetQuerySecurityObjectSubError;
}
if (!RtlValidSid( UpdatedOwnerSid)) {
DbgPrint(
"LSA RPC CT - Set/Query Security Object Test failed\n"
"RtlGetOwnerSecurityDescriptor (updated security) returned\n"
" an invalid owner Sid\n",
Status
);
goto SetQuerySecurityObjectSubError;
}
if (!RtlEqualSid( UpdatedOwnerSid, NewOwnerSid)) {
DbgPrint(
"LSA RPC CT - Set/Query Security Object Test failed\n"
"Updated Owner Sid does not match NewOwnerSid\n",
Status
);
goto SetQuerySecurityObjectSubError;
}
SetQuerySecurityObjectSubFinish:
//
// If necessary, free the Dacl.
//
if (Dacl != NULL) {
RtlFreeHeap( RtlProcessHeap(), 0, Dacl );
Dacl = NULL;
}
//
// If necessary, free the queried Existing Security Descriptor.
//
if ( ExistingSecurityDescriptor != NULL ) {
LsaFreeMemory( ExistingSecurityDescriptor );
ExistingSecurityDescriptor = NULL;
}
//
// If necessary, free the queried Updated Security Descriptor.
//
if ( UpdatedSecurityDescriptor != NULL ) {
LsaFreeMemory( UpdatedSecurityDescriptor );
UpdatedSecurityDescriptor = NULL;
}
return(Status);
SetQuerySecurityObjectSubError:
if (NT_SUCCESS(Status)) {
Status = STATUS_UNSUCCESSFUL;
}
goto SetQuerySecurityObjectSubFinish;
}
BOOLEAN
CtLsaGeneralEnumeratePrivileges(
IN OPTIONAL PUNICODE_STRING WorkstationName
)
/*++
Routine Description:
This function tests the LsaEnumeratePrivileges API.
Arguments:
WorkstationName - Specifies the name of the target Workstation whose
Policy Object wil be accessed.
Return Values:
BOOLEAN - TRUE if successful, else FALSE
--*/
{
NTSTATUS Status;
BOOLEAN BooleanStatus = TRUE;
ULONG CountReturned;
ULONG TotalCountReturned;
ULONG EnumerationContext;
ULONG PreferedMaximumLength;
LSA_HANDLE PolicyHandle = NULL;
PPOLICY_PRIVILEGE_DEFINITION Privileges = NULL;
OBJECT_ATTRIBUTES ObjectAttributes;
SECURITY_QUALITY_OF_SERVICE SecurityQualityOfService;
ULONG EnumerationCount;
ULONG OriginalEnumerationContext;
DbgPrint("[2] - Test Enumerate Privileges API\n");
//
// First open a Handle to the LSA.
//
CtLsaInitObjectAttributes( &ObjectAttributes, &SecurityQualityOfService );
Status = LsaOpenPolicy(
WorkstationName,
&ObjectAttributes,
POLICY_VIEW_LOCAL_INFORMATION | POLICY_CREATE_SECRET,
&PolicyHandle
);
if (!NT_SUCCESS(Status)) {
DbgPrint(
"LSA RPC CT - Set/Query Security Object Test failed\n"
"LsaOpenPolicy returned 0x%lx\n",
Status
);
goto EnumeratePrivilegesError;
}
EnumerationCount = 0;
EnumerationContext = 0;
TotalCountReturned = 0;
CountReturned = 0x0fffffffL;
PreferedMaximumLength = 1;
while (NT_SUCCESS(Status)) {
CountReturned = 0x0fffffffL;
OriginalEnumerationContext = EnumerationContext;
Status = LsaEnumeratePrivileges(
PolicyHandle,
&EnumerationContext,
&Privileges,
PreferedMaximumLength,
&CountReturned
);
if (!NT_SUCCESS(Status)) {
if (OriginalEnumerationContext <
SE_MAX_WELL_KNOWN_PRIVILEGE - SE_MIN_WELL_KNOWN_PRIVILEGE + 1) {
DbgPrint(
"LSA RPC CT - Enumerate Privileges Test failed\n"
"LsaEnumeratePrivileges returned 0x%lx\n",
Status
);
BooleanStatus = FALSE;
} else {
if (Status != STATUS_NO_MORE_ENTRIES) {
DbgPrint(
"LSA RPC CT - Enumerate Privileges Test failed\n"
"LsaEnumeratePrivileges returned 0x%lx\n"
".. expected 0x%lx (STATUS_NO_MORE_ENTRIES)\n",
STATUS_NO_MORE_ENTRIES,
Status
);
BooleanStatus = FALSE;
}
}
break;
}
//
// A success status was returned. Only STATUS_SUCCESS or
// STATUS_MORE_ENTRIES are allowed.
//
if ((Status != STATUS_SUCCESS) && (Status != STATUS_MORE_ENTRIES)) {
DbgPrint(
"LSA RPC CT - Enumerate Privileges Test failed\n"
"LsaEnumeratePrivileges returned 0x%lx\n",
Status
);
break;
}
//
// Check EnumerationContext and CountReturned.
//
TotalCountReturned += CountReturned;
if (EnumerationContext != TotalCountReturned) {
DbgPrint(
"LSA RPC CT - Enumerate Privileges Test failed\n"
"EnumerationContext does not match TotalCountReturned\n"
"EnumerationContext = %d, TotalCountReturned = %d\n",
EnumerationContext,
TotalCountReturned
);
goto EnumeratePrivilegesError;
}
EnumerationCount++;
}
if (EnumerationCount == 0) {
DbgPrint(
"LSA RPC CT - Enumerate Privileges Test failed\n"
"No enumerations took place\n"
);
goto EnumeratePrivilegesError;
}
EnumeratePrivilegesFinish:
//
// If necessary, free the memory allocated for the Privileges
//
if (Privileges == NULL) {
Status = LsaFreeMemory( Privileges );
Privileges = NULL;
if (!NT_SUCCESS(Status)) {
DbgPrint(
"LSA RPC CT - Enumerate Privileges Test failed\n"
"LsaFreeMemory for Privileges buffer returned 0x%lx\n",
Status
);
goto EnumeratePrivilegesError;
}
}
//
// If necessary, close the handle to the Policy Object.
//
if (PolicyHandle != NULL) {
Status = LsaClose( PolicyHandle );
PolicyHandle = NULL;
if (!NT_SUCCESS(Status)) {
DbgPrint(
"LSA RPC CT - Enumerate Privileges Test failed\n"
"LsaClose on Policy Handle returned 0x%lx\n",
Status
);
goto EnumeratePrivilegesError;
}
}
return(BooleanStatus);
EnumeratePrivilegesError:
BooleanStatus = FALSE;
goto EnumeratePrivilegesFinish;
}
BOOLEAN
CtLsaGeneralInitUnknownSid(
IN PSID Sid,
OUT PCT_UNKNOWN_SID_ENTRY UnknownSidInfo,
IN BOOLEAN DomainKnown
)
/*++
Routine Description:
This function initializes information about an Unknown Sid.
Arguments:
Sid - Pointer to the unknown Sid.
UnknownSidInfo - Pointer to entry for unknown Sid info to be filled in.
DomainKnown - TRUE if the domain is known, else FALSE.
Return Values:
BOOLEAN - TRUE if successful, else FALSE.
--*/
{
ULONG LengthRequiredDomainSid;
UCHAR SubAuthorityCountSid;
NTSTATUS Status;
UnknownSidInfo->Sid = Sid;
//
// If the domain is known, store its Sid, and, for the name of the
// Sid, store the RelativeId converted to Unicode.
//
if (DomainKnown) {
UnknownSidInfo->DomainKnown = TRUE;
//
// Construct the Domain Sid by making a copy of the
// Sid and decrementing its SubAuthorityCount. Store
// pointer to the Domain Sid in the Trust Information.
//
SubAuthorityCountSid = *(RtlSubAuthorityCountSid(Sid));
LengthRequiredDomainSid = RtlLengthRequiredSid( SubAuthorityCountSid-1);
UnknownSidInfo->Sid = TstAllocatePool(PagedPool, LengthRequiredDomainSid);
if (UnknownSidInfo->Sid == NULL) {
return(FALSE);
}
RtlMoveMemory(
UnknownSidInfo->Sid,
Sid,
LengthRequiredDomainSid
);
(*(RtlSubAuthorityCountSid(Sid)))--;
//
// Convert the Relative Id to a Unicode Name and store in
// the Translation.
//
Status = CtLsaGeneralSidToLogicalNameObject(
Sid,
&UnknownSidInfo->Name
);
if (!NT_SUCCESS(Status)) {
DbgPrint("LSA RPC CT - Lookup Sids - failed to allocate memory\n");
DbgPrint("for unknown Sid's Relative id in Unicode Form\n");
return(FALSE);
}
} else {
//
// The Domain is not expected to be known. In this case, the
// Domain Sid and name are undefined and the whole Sid is
// converted to character form.
//
UnknownSidInfo->DomainKnown = FALSE;
Status = CtRtlConvertSidToUnicodeString(
Sid,
&UnknownSidInfo->Name
);
if (!NT_SUCCESS(Status)) {
return(FALSE);
}
}
return(TRUE);
}
BOOLEAN
CtEqualQuotaLimits(
IN PQUOTA_LIMITS QuotaLimits1,
IN PQUOTA_LIMITS QuotaLimits2
)
/*++
Routine Description:
This function compares two sets of quota limits to see if they are
equal. For each mismatch found a diagnostic message is printed.
Arguments:
QuotaLimits1 - Pointer to first comparand.
QuotaLimits2 - Pointer to second comparand.
Return Value:
BOOLEAN - TRUE if all fields match, else FALSE.
--*/
{
BOOLEAN EqualStatus = TRUE;
//
// Compare the quota limits with those set
//
if (QuotaLimits1->PagedPoolLimit !=
QuotaLimits2->PagedPoolLimit) {
DbgPrint("Quota Limit Paged Pool mismatch\n");
DbgPrint(
"Set 0x%lx, Returned 0x%lx\n",
(QuotaLimits2->PagedPoolLimit),
(QuotaLimits1->PagedPoolLimit)
);
EqualStatus = FALSE;
}
if (QuotaLimits1->NonPagedPoolLimit !=
QuotaLimits2->NonPagedPoolLimit) {
DbgPrint("Quota Limit Non-Paged Pool mismatch\n");
DbgPrint(
"Set 0x%lx, Returned 0x%lx\n",
(QuotaLimits2->NonPagedPoolLimit),
(QuotaLimits1->NonPagedPoolLimit)
);
EqualStatus = FALSE;
}
if (QuotaLimits1->MinimumWorkingSetSize !=
QuotaLimits2->MinimumWorkingSetSize) {
DbgPrint("Quota Limit Min Working SetSize mismatch\n");
DbgPrint(
"Set 0x%lx, Returned 0x%lx\n",
(QuotaLimits2->MinimumWorkingSetSize),
(QuotaLimits1->MinimumWorkingSetSize)
);
EqualStatus = FALSE;
}
if (QuotaLimits1->MaximumWorkingSetSize !=
QuotaLimits2->MaximumWorkingSetSize) {
DbgPrint("Quota Limit Max Working Set Size mismatch\n");
DbgPrint(
"Set 0x%lx, Returned 0x%lx\n",
(QuotaLimits2->MaximumWorkingSetSize),
(QuotaLimits1->MaximumWorkingSetSize)
);
EqualStatus = FALSE;
}
if (QuotaLimits1->PagefileLimit !=
QuotaLimits2->PagefileLimit) {
DbgPrint("Quota Limit Pagefile Limit mismatch\n");
DbgPrint(
"Set 0x%lx, Returned 0x%lx\n",
(QuotaLimits2->PagefileLimit),
(QuotaLimits1->PagefileLimit)
);
EqualStatus = FALSE;
}
if (QuotaLimits1->TimeLimit.LowPart !=
QuotaLimits2->TimeLimit.LowPart) {
DbgPrint("Quota Limit Time Limit mismatch\n");
DbgPrint(
"Set 0x%lx, Returned 0x%lx\n",
(QuotaLimits2->TimeLimit.LowPart),
(QuotaLimits1->TimeLimit.LowPart)
);
EqualStatus = FALSE;
}
return EqualStatus;
}
VOID
CtLsaInitObjectAttributes(
IN POBJECT_ATTRIBUTES ObjectAttributes,
IN PSECURITY_QUALITY_OF_SERVICE SecurityQualityOfService
)
/*++
Routine Description:
This function initializes the given Object Attributes structure, including
Security Quality Of Service. Memory must be allcated for both
ObjectAttributes and Security QOS by the caller.
Arguments:
ObjectAttributes - Pointer to Object Attributes to be initialized.
SecurityQualityOfService - Pointer to Security QOS to be initialized.
Return Value:
None.
--*/
{
SecurityQualityOfService->Length = sizeof(SECURITY_QUALITY_OF_SERVICE);
SecurityQualityOfService->ImpersonationLevel = SecurityImpersonation;
SecurityQualityOfService->ContextTrackingMode = SECURITY_DYNAMIC_TRACKING;
SecurityQualityOfService->EffectiveOnly = FALSE;
//
// Set up the object attributes prior to opening the LSA.
//
InitializeObjectAttributes(
ObjectAttributes,
NULL,
0L,
NULL,
NULL
);
//
// The InitializeObjectAttributes macro presently stores NULL for
// the SecurityQualityOfService field, so we must manually copy that
// structure for now.
//
ObjectAttributes->SecurityQualityOfService = SecurityQualityOfService;
}
BOOLEAN
CtLsaVariableInitialization()
/*++
Routine Description:
This function initializes the global variables specific to the security
test environment.
Arguments:
None.
Return Value:
TRUE if variables successfully initialized.
FALSE if not successfully initialized.
--*/
{
ULONG SidWithZeroSubAuthorities;
ULONG SidWithOneSubAuthority;
ULONG SidWithThreeSubAuthorities;
ULONG SidWithFourSubAuthorities;
SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;
SID_IDENTIFIER_AUTHORITY BedrockAuthority = BEDROCK_AUTHORITY;
SID_IDENTIFIER_AUTHORITY BedrockAAuthority = BEDROCKA_AUTHORITY;
SID_IDENTIFIER_AUTHORITY BedrockBAuthority = BEDROCKB_AUTHORITY;
SID_IDENTIFIER_AUTHORITY BedrockCAuthority = BEDROCKC_AUTHORITY;
SID_IDENTIFIER_AUTHORITY BedrockDAuthority = BEDROCKD_AUTHORITY;
SID_IDENTIFIER_AUTHORITY BedrockEAuthority = BEDROCKE_AUTHORITY;
//
// The following SID sizes need to be allocated
//
SidWithZeroSubAuthorities = RtlLengthRequiredSid( 0 );
SidWithOneSubAuthority = RtlLengthRequiredSid( 1 );
SidWithThreeSubAuthorities = RtlLengthRequiredSid( 3 );
SidWithFourSubAuthorities = RtlLengthRequiredSid( 4 );
//
// Allocate SIDs specific to the Component Tests. These relate to the
// Bedrock domains.
//
BedrockDomainSid = (PSID)TstAllocatePool(PagedPool,SidWithThreeSubAuthorities);
BedrockADomainSid = (PSID)TstAllocatePool(PagedPool,SidWithThreeSubAuthorities);
BedrockBDomainSid = (PSID)TstAllocatePool(PagedPool,SidWithThreeSubAuthorities);
BedrockCDomainSid = (PSID)TstAllocatePool(PagedPool,SidWithThreeSubAuthorities);
BedrockDDomainSid = (PSID)TstAllocatePool(PagedPool,SidWithThreeSubAuthorities);
BedrockEDomainSid = (PSID)TstAllocatePool(PagedPool,SidWithThreeSubAuthorities);
FredSid = (PSID)TstAllocatePool(PagedPool,SidWithFourSubAuthorities);
WilmaSid = (PSID)TstAllocatePool(PagedPool,SidWithFourSubAuthorities);
PebblesSid = (PSID)TstAllocatePool(PagedPool,SidWithFourSubAuthorities);
DinoSid = (PSID)TstAllocatePool(PagedPool,SidWithFourSubAuthorities);
BarneySid = (PSID)TstAllocatePool(PagedPool,SidWithFourSubAuthorities);
BettySid = (PSID)TstAllocatePool(PagedPool,SidWithFourSubAuthorities);
BambamSid = (PSID)TstAllocatePool(PagedPool,SidWithFourSubAuthorities);
FlintstoneSid = (PSID)TstAllocatePool(PagedPool,SidWithFourSubAuthorities);
RubbleSid = (PSID)TstAllocatePool(PagedPool,SidWithFourSubAuthorities);
AdultSid = (PSID)TstAllocatePool(PagedPool,SidWithFourSubAuthorities);
ChildSid = (PSID)TstAllocatePool(PagedPool,SidWithFourSubAuthorities);
NeandertholSid = (PSID)TstAllocatePool(PagedPool,SidWithFourSubAuthorities);
RtlInitializeSid( BedrockDomainSid, &BedrockAuthority, 3 );
*(RtlSubAuthoritySid( BedrockDomainSid, 0)) = BEDROCK_SUBAUTHORITY_0;
*(RtlSubAuthoritySid( BedrockDomainSid, 1)) = BEDROCK_SUBAUTHORITY_1;
*(RtlSubAuthoritySid( BedrockDomainSid, 2)) = BEDROCK_SUBAUTHORITY_2;
RtlInitializeSid( BedrockADomainSid, &BedrockAAuthority, 3 );
*(RtlSubAuthoritySid( BedrockADomainSid, 0)) = BEDROCKA_SUBAUTHORITY_0;
*(RtlSubAuthoritySid( BedrockADomainSid, 1)) = BEDROCKA_SUBAUTHORITY_1;
*(RtlSubAuthoritySid( BedrockADomainSid, 2)) = BEDROCKA_SUBAUTHORITY_2;
RtlInitializeSid( BedrockBDomainSid, &BedrockBAuthority, 3 );
*(RtlSubAuthoritySid( BedrockBDomainSid, 0)) = BEDROCKB_SUBAUTHORITY_0;
*(RtlSubAuthoritySid( BedrockBDomainSid, 1)) = BEDROCKB_SUBAUTHORITY_1;
*(RtlSubAuthoritySid( BedrockBDomainSid, 2)) = BEDROCKB_SUBAUTHORITY_2;
RtlInitializeSid( BedrockCDomainSid, &BedrockCAuthority, 3 );
*(RtlSubAuthoritySid( BedrockCDomainSid, 0)) = BEDROCKC_SUBAUTHORITY_0;
*(RtlSubAuthoritySid( BedrockCDomainSid, 1)) = BEDROCKC_SUBAUTHORITY_1;
*(RtlSubAuthoritySid( BedrockCDomainSid, 2)) = BEDROCKC_SUBAUTHORITY_2;
RtlInitializeSid( BedrockDDomainSid, &BedrockDAuthority, 3 );
*(RtlSubAuthoritySid( BedrockDDomainSid, 0)) = BEDROCKD_SUBAUTHORITY_0;
*(RtlSubAuthoritySid( BedrockDDomainSid, 1)) = BEDROCKD_SUBAUTHORITY_1;
*(RtlSubAuthoritySid( BedrockDDomainSid, 2)) = BEDROCKD_SUBAUTHORITY_2;
RtlInitializeSid( BedrockEDomainSid, &BedrockEAuthority, 3 );
*(RtlSubAuthoritySid( BedrockEDomainSid, 0)) = BEDROCKE_SUBAUTHORITY_0;
*(RtlSubAuthoritySid( BedrockEDomainSid, 1)) = BEDROCKE_SUBAUTHORITY_1;
*(RtlSubAuthoritySid( BedrockEDomainSid, 2)) = BEDROCKE_SUBAUTHORITY_2;
RtlCopySid( SidWithFourSubAuthorities, FredSid, BedrockDomainSid);
*(RtlSubAuthorityCountSid( FredSid )) += 1;
*(RtlSubAuthoritySid( FredSid, 3)) = FRED_RID;
RtlCopySid( SidWithFourSubAuthorities, WilmaSid, BedrockDomainSid);
*(RtlSubAuthorityCountSid( WilmaSid )) += 1;
*(RtlSubAuthoritySid( WilmaSid, 3)) = WILMA_RID;
RtlCopySid( SidWithFourSubAuthorities, PebblesSid, BedrockDomainSid);
*(RtlSubAuthorityCountSid( PebblesSid )) += 1;
*(RtlSubAuthoritySid( PebblesSid, 3)) = PEBBLES_RID;
RtlCopySid( SidWithFourSubAuthorities, DinoSid, BedrockDomainSid);
*(RtlSubAuthorityCountSid( DinoSid )) += 1;
*(RtlSubAuthoritySid( DinoSid, 3)) = DINO_RID;
RtlCopySid( SidWithFourSubAuthorities, BarneySid, BedrockDomainSid);
*(RtlSubAuthorityCountSid( BarneySid )) += 1;
*(RtlSubAuthoritySid( BarneySid, 3)) = BARNEY_RID;
RtlCopySid( SidWithFourSubAuthorities, BettySid, BedrockDomainSid);
*(RtlSubAuthorityCountSid( BettySid )) += 1;
*(RtlSubAuthoritySid( BettySid, 3)) = BETTY_RID;
RtlCopySid( SidWithFourSubAuthorities, BambamSid, BedrockDomainSid);
*(RtlSubAuthorityCountSid( BambamSid )) += 1;
*(RtlSubAuthoritySid( BambamSid, 3)) = BAMBAM_RID;
RtlCopySid( SidWithFourSubAuthorities, FlintstoneSid, BedrockDomainSid);
*(RtlSubAuthorityCountSid( FlintstoneSid )) += 1;
*(RtlSubAuthoritySid( FlintstoneSid, 3)) = FLINTSTONE_RID;
RtlCopySid( SidWithFourSubAuthorities, RubbleSid, BedrockDomainSid);
*(RtlSubAuthorityCountSid( RubbleSid )) += 1;
*(RtlSubAuthoritySid( RubbleSid, 3)) = RUBBLE_RID;
RtlCopySid( SidWithFourSubAuthorities, AdultSid, BedrockDomainSid);
*(RtlSubAuthorityCountSid( AdultSid )) += 1;
*(RtlSubAuthoritySid( AdultSid, 3)) = ADULT_RID;
RtlCopySid( SidWithFourSubAuthorities, ChildSid, BedrockDomainSid);
*(RtlSubAuthorityCountSid( ChildSid )) += 1;
*(RtlSubAuthoritySid( ChildSid, 3)) = CHILD_RID;
RtlCopySid( SidWithFourSubAuthorities, NeandertholSid, BedrockDomainSid);
*(RtlSubAuthorityCountSid( NeandertholSid )) += 1;
*(RtlSubAuthoritySid( NeandertholSid, 3)) = NEANDERTHOL_RID;
//
// Initialize the names of the Bedrock Domain inhabitants.
//
RtlInitUnicodeString( &BedrockDomainName, L"Bedrock");
RtlInitUnicodeString( &BedrockADomainName, L"BedrockA");
RtlInitUnicodeString( &BedrockBDomainName, L"BedrockB");
RtlInitUnicodeString( &BedrockCDomainName, L"BedrockC");
RtlInitUnicodeString( &BedrockDDomainName, L"BedrockD");
RtlInitUnicodeString( &BedrockEDomainName, L"BedrockE");
RtlInitUnicodeString( &FredName, L"Fred");
RtlInitUnicodeString( &WilmaName, L"Wilma");
RtlInitUnicodeString( &PebblesName, L"Pebbles");
RtlInitUnicodeString( &DinoName, L"Dino");
RtlInitUnicodeString( &BarneyName, L"Barney");
RtlInitUnicodeString( &BettyName, L"Betty");
RtlInitUnicodeString( &BambamName, L"Bambam");
RtlInitUnicodeString( &FlintstoneName, L"Flintstone");
RtlInitUnicodeString( &RubbleName, L"Rubble");
RtlInitUnicodeString( &AdultName, L"Adult");
RtlInitUnicodeString( &ChildName, L"Child");
RtlInitUnicodeString( &NeandertholName, L"Neanderthol");
return TRUE;
}
NTSTATUS
CtLsaGeneralSidToLogicalNameObject(
IN PSID Sid,
OUT PUNICODE_STRING LogicalName
)
/*++
Routine Description:
This function generates the Logical Name (Internal LSA Database Name)
of an object from its Sid. Currently, only the Relative Id (lowest
sub-authority) is used due to Registry and hence Lsa Database limits
on name components to 8 characters. The Rid is extracted and converted
to an 8-digit Unicode Integer.
Arguments:
Sid - Pointer to the Sid to be looked up. It is the caller's
responsibility to ensure that the Sid has valid syntax.
LogicalName - Pointer to a Unicode String structure that will receive
the Logical Name. Note that memory for the string buffer in this
Unicode String will be allocated by this routine if successful. The
caller must free this memory after use by calling RtlFreeUnicodeString.
Return Value:
NTSTATUS - Standard Nt Status code
STATUS_INSUFFICIENT_RESOURCES - Insufficient system resources
to allocate buffer for Unicode String name.
--*/
{
NTSTATUS Status;
ULONG Rid;
UCHAR SubAuthorityCount;
UCHAR RidNameBufferAnsi[9];
ANSI_STRING CharacterSidAnsi;
//
// First, verify that the given Sid is valid
//
if (!RtlValidSid( Sid )) {
return STATUS_INVALID_PARAMETER;
}
//
// Sid is valid. If however, the SubAuthorityCount is zero,
// we cannot have a Rid so return error.
//
SubAuthorityCount = ((PLSAPR_SID) Sid)->SubAuthorityCount;
if (SubAuthorityCount == 0) {
return STATUS_INVALID_PARAMETER;
}
//
// Sid has at least one subauthority. Get the lowest subauthority
// (i.e. the Rid).
//
Rid = ((PLSAPR_SID) Sid)->SubAuthority[SubAuthorityCount - 1];
//
// Now convert the Rid to an 8-digit numeric character string
//
Status = RtlIntegerToChar( Rid, 16, -8, RidNameBufferAnsi );
//
// Need to add null terminator to string
//
RidNameBufferAnsi[8] = 0;
//
// Initialize an ANSI string structure with the converted name.
//
RtlInitString( &CharacterSidAnsi, RidNameBufferAnsi );
//
// Convert the ANSI string structure to Unicode form
//
Status = RtlAnsiStringToUnicodeString(
LogicalName,
&CharacterSidAnsi,
TRUE
);
if (!NT_SUCCESS(Status)) {
Status = STATUS_INSUFFICIENT_RESOURCES;
}
return Status;
}
BOOLEAN
CtLsaGeneralVerifyTrustInfo(
IN PLSA_TRUST_INFORMATION TrustInformation,
IN PLSAP_WELL_KNOWN_SID_ENTRY WellKnownSidEntry
)
/*++
Routine Description:
This function verifies that Trust Information given for a Well Known
Sid or Name is correct.
Parameters:
TrustInformation - Pointer to Trust Information.
WellKnownSidEntry - Pointer to entry in the table of Well Known Sids.
Return Values:
BOOLEAN - TRUE if Trust Information is correct, else FALSE.
--*/
{
BOOLEAN BooleanStatus = TRUE;
LSA_TRUST_INFORMATION ExpectedTrustInformation;
ExpectedTrustInformation.Name = WellKnownSidEntry->DomainName;
//
// Compare the Domain Names (or descriptive text)
//
if ((ExpectedTrustInformation.Name.Buffer != NULL) &&
(ExpectedTrustInformation.Name.Length != 0)) {
if (TrustInformation->Name.Buffer == NULL) {
DbgPrint(".. NULL Domain Name Unicode Buffer returned\n");
BooleanStatus = FALSE;
} else if (!RtlEqualUnicodeString(
&TrustInformation->Name,
&ExpectedTrustInformation.Name,
FALSE
)) {
DbgPrint(".. mismatch on Domain Name or text\n");
BooleanStatus = FALSE;
}
}
//
// Compare the Domain Sids in the Trust Information. First
// we need to derive the expected Domain or Prefix Sid by
// making a copy of the original Sid and decrementing the
// SubAuthorityCount (non-Domain Sids) or just copying the
// Sid (domain sids).
//
if (WellKnownSidEntry->Use == SidTypeDomain) {
ExpectedTrustInformation.Sid = WellKnownSidEntry->Sid;
} else {
ExpectedTrustInformation.Sid =
TstAllocatePool(
PagedPool,
RtlLengthSid(WellKnownSidEntry->Sid)
);
if (ExpectedTrustInformation.Sid == NULL) {
DbgPrint("LSA RPC CT - Failed to allocate memory\n");
return(FALSE);
}
//
// Copy the Sid and decrement the SubAuthorityCount..
//
RtlMoveMemory(
ExpectedTrustInformation.Sid,
WellKnownSidEntry->Sid,
RtlLengthSid(WellKnownSidEntry->Sid)
);
(*RtlSubAuthorityCountSid( ExpectedTrustInformation.Sid ))--;
}
//
// Now compare the Sid returned in the TrustInformation.
//
if (!RtlEqualSid(
TrustInformation->Sid,
ExpectedTrustInformation.Sid
)) {
DbgPrint(".. mismatch on Sid or text\n");
BooleanStatus = FALSE;
}
//
// If necessary, free the memory allocated for the Domain Sid.
//
if (WellKnownSidEntry->Use != SidTypeDomain) {
if (ExpectedTrustInformation.Sid != NULL) {
TstDeallocatePool( ExpectedTrustInformation.Sid );
}
}
return(BooleanStatus);
}
BOOLEAN
CtLsaGeneralBuildSid(
PSID *Sid,
PSID DomainSid,
ULONG RelativeId
)
/*++
Routine Description:
This function builds a Sid from a Domain Sid and a RelativeId.
Arguments:
Sid - Receives a pointer to the constructed Sid.
DomainSid - Points to a Domain Sid
RelativeId - Contains a Relative Id.
Return Values:
BOOLEAN - TRUE if successful, else FALSE.
--*/
{
PSID OutputSid = NULL;
ULONG OutputSidLength;
UCHAR SubAuthorityCount;
SubAuthorityCount = *RtlSubAuthorityCountSid( DomainSid ) + (UCHAR) 1;
OutputSidLength = RtlLengthRequiredSid( SubAuthorityCount );
OutputSid = LocalAlloc( (UINT) LMEM_FIXED, (UINT) OutputSidLength );
if (OutputSid == NULL) {
return(FALSE);
}
RtlMoveMemory( OutputSid, DomainSid, OutputSidLength - sizeof (ULONG));
(*RtlSubAuthorityCountSid( OutputSid ))++;
(*RtlSubAuthoritySid( OutputSid, SubAuthorityCount - (UCHAR) 1)) = RelativeId;
*Sid = OutputSid;
return(TRUE);
}
NTSTATUS
CtRtlConvertSidToUnicodeString(
IN PSID Sid,
OUT PUNICODE_STRING UnicodeString
)
/*++
Routine Description:
This function converts a Sid to Text format.
Arguments:
Sid - Pointer to Sid.
UnicodeString - Pointer to Output Unicode String.
Return Values:
NTSTATUS - Standard Nt Result Code
STATUS_SUCCESS - The call completed successfully
STATUS_INSUFFICIENT_RESOURCES - Insufficient system resources
such as memory, to complete the call.
WARNING! This is a temporary hack.
--*/
{
NTSTATUS Status;
UCHAR Buffer[256];
UCHAR String[256];
UCHAR i;
ULONG Tmp;
PISID iSid = (PISID)Sid; // pointer to opaque structure
ANSI_STRING AnsiString;
sprintf(Buffer, "S-%u-", (USHORT)iSid->Revision );
lstrcpyA((LPSTR) String, (LPCSTR) Buffer);
if ( (iSid->IdentifierAuthority.Value[0] != 0) ||
(iSid->IdentifierAuthority.Value[1] != 0) ){
sprintf(Buffer, "0x%02hx%02hx%02hx%02hx%02hx%02hx",
(USHORT)iSid->IdentifierAuthority.Value[0],
(USHORT)iSid->IdentifierAuthority.Value[1],
(USHORT)iSid->IdentifierAuthority.Value[2],
(USHORT)iSid->IdentifierAuthority.Value[3],
(USHORT)iSid->IdentifierAuthority.Value[4],
(USHORT)iSid->IdentifierAuthority.Value[5] );
lstrcatA((LPSTR) String, (LPCSTR) Buffer);
} else {
Tmp = (ULONG)iSid->IdentifierAuthority.Value[5] +
(ULONG)(iSid->IdentifierAuthority.Value[4] << 8) +
(ULONG)(iSid->IdentifierAuthority.Value[3] << 16) +
(ULONG)(iSid->IdentifierAuthority.Value[2] << 24);
sprintf(Buffer, "%lu", Tmp);
lstrcatA((LPSTR) String, (LPCSTR) Buffer);
}
for (i=0;i<iSid->SubAuthorityCount ;i++ ) {
sprintf(Buffer, "-%lu", iSid->SubAuthority[i]);
lstrcatA((LPSTR) String, (LPCSTR) Buffer);
}
//
// Convert the string to a Unicode String
//
RtlInitString(&AnsiString, (PSZ) String);
Status = RtlAnsiStringToUnicodeString( UnicodeString, &AnsiString, TRUE);
return(Status);
}
VOID
lsassmain ()
{
//
// Do the following:
//
// Initialize the RPC server
//
// Initialize LSA (this starts the RPC server)
//
// Pause for installation if necessary
//
// Initialize SAM
//
// Initialize the service-controller service
// dispatcher.
//
NTSTATUS Status = STATUS_SUCCESS;
//
// Initialize the LSA.
// If unsuccessful, we must exit with status so that the SM knows
// something has gone wrong.
//
Status = LsapInitLsa();
if (!NT_SUCCESS(Status)) {
goto Cleanup;
}
//
// Initialize SAM
//
Status = SamIInitialize();
//
// Initialize the service dispatcher.
//
// Note : we initialize the service dispatcher even when the sam
// service is not started, this will make the service controller
// starts successfully when the netlogon service is installed.
//
Status = ServiceInit();
if (!NT_SUCCESS(Status)) {
goto Cleanup;
}
Cleanup:
DbgPrint("ctlsarpc - LSA initialized, set Ct breakpoints now\n");
DbgBreakPoint();
// NtTerminateThread( NtCurrentThread(), Status );
}