summaryrefslogtreecommitdiffstats
path: root/private/lsa/server/ctlsarpc.c
diff options
context:
space:
mode:
Diffstat (limited to 'private/lsa/server/ctlsarpc.c')
-rw-r--r--private/lsa/server/ctlsarpc.c15305
1 files changed, 15305 insertions, 0 deletions
diff --git a/private/lsa/server/ctlsarpc.c b/private/lsa/server/ctlsarpc.c
new file mode 100644
index 000000000..484c50bdc
--- /dev/null
+++ b/private/lsa/server/ctlsarpc.c
@@ -0,0 +1,15305 @@
+
+/*++
+
+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 );
+}