15306 lines
382 KiB
C
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 );
|
|
}
|