From e611b132f9b8abe35b362e5870b74bce94a1e58e Mon Sep 17 00:00:00 2001 From: Adam Date: Sat, 16 May 2020 20:51:50 -0700 Subject: initial commit --- private/lsa/uclient/crclient.c | 112 ++ private/lsa/uclient/ctlkacct.c | 378 ++++ private/lsa/uclient/ctlklsa.c | 579 ++++++ private/lsa/uclient/ctreg.c | 807 ++++++++ private/lsa/uclient/ctsamdb.c | 213 +++ private/lsa/uclient/lsaclip.h | 25 + private/lsa/uclient/lsaudll.def | 11 + private/lsa/uclient/makefile | 6 + private/lsa/uclient/rpcapi.c | 3797 ++++++++++++++++++++++++++++++++++++++ private/lsa/uclient/rpcapi2.c | 3316 +++++++++++++++++++++++++++++++++ private/lsa/uclient/rpcbind.c | 102 + private/lsa/uclient/rpcclimm.c | 103 ++ private/lsa/uclient/runsamdb.cmd | 4 + private/lsa/uclient/sources | 44 + private/lsa/uclient/tgetsid.c | 211 +++ private/lsa/uclient/tlookup.c | 249 +++ private/lsa/uclient/tsecomm.c | 136 ++ private/lsa/uclient/tsevars.c | 447 +++++ 18 files changed, 10540 insertions(+) create mode 100644 private/lsa/uclient/crclient.c create mode 100644 private/lsa/uclient/ctlkacct.c create mode 100644 private/lsa/uclient/ctlklsa.c create mode 100644 private/lsa/uclient/ctreg.c create mode 100644 private/lsa/uclient/ctsamdb.c create mode 100644 private/lsa/uclient/lsaclip.h create mode 100644 private/lsa/uclient/lsaudll.def create mode 100644 private/lsa/uclient/makefile create mode 100644 private/lsa/uclient/rpcapi.c create mode 100644 private/lsa/uclient/rpcapi2.c create mode 100644 private/lsa/uclient/rpcbind.c create mode 100644 private/lsa/uclient/rpcclimm.c create mode 100644 private/lsa/uclient/runsamdb.cmd create mode 100644 private/lsa/uclient/sources create mode 100644 private/lsa/uclient/tgetsid.c create mode 100644 private/lsa/uclient/tlookup.c create mode 100644 private/lsa/uclient/tsecomm.c create mode 100644 private/lsa/uclient/tsevars.c (limited to 'private/lsa/uclient') diff --git a/private/lsa/uclient/crclient.c b/private/lsa/uclient/crclient.c new file mode 100644 index 000000000..087bf1284 --- /dev/null +++ b/private/lsa/uclient/crclient.c @@ -0,0 +1,112 @@ +/*++ + +Copyright (c) 1991 Microsoft Corporation + +Module Name: + + crclient.c + +Abstract: + + Local Security Authority - Client Cipher Routines + + These routines interface the LSA client side with the Cipher + Routines. They perform RPC-style memory allocation. + +Author: + + Scott Birrell (ScottBi) December 13, 1991 + +Environment: + +Revision History: + +--*/ + +#include + + +NTSTATUS +LsapCrClientGetSessionKey( + IN LSA_HANDLE ObjectHandle, + OUT PLSAP_CR_CIPHER_KEY *SessionKey + ) + +/*++ + +Routine Description: + + This function obtains the Session Key, allocates an Cipher Key + structure and returns the key. + +Arguments: + + ObjectHandle - Handle from an LsaOpen call. + + SessionKey - Receives a pointer to a structure containing the + Session Key in which the memory has been allocated via + MIDL_user_allocate(). + +Return Value: + + NTSTATUS - Standard Nt Result Code + + STATUS_INSUFFICIENT_RESOURCES - Insufficient system resources + (e.g memory) to complete the call. +--*/ + +{ + NTSTATUS Status = STATUS_SUCCESS; + PLSAP_CR_CIPHER_KEY OutputSessionKey = NULL; + ULONG OutputSessionKeyBufferLength; + + // + // Allocate memory for the Session Key buffer and LSAP_CR_CIPHER_KEY + // structure. + // + + OutputSessionKeyBufferLength = sizeof (USER_SESSION_KEY); + + Status = STATUS_INSUFFICIENT_RESOURCES; + + OutputSessionKey = MIDL_user_allocate( + OutputSessionKeyBufferLength + + sizeof (LSAP_CR_CIPHER_KEY) + ); + + if (OutputSessionKey == NULL) { + + goto ClientGetSessionKeyError; + } + + // + // Fill in the Cipher key structure, making the buffer point to + // just beyond the header. + // + + OutputSessionKey->Length = OutputSessionKeyBufferLength; + OutputSessionKey->MaximumLength = OutputSessionKeyBufferLength; + OutputSessionKey->Buffer = (PUCHAR) (OutputSessionKey + 1); + + Status = RtlGetUserSessionKeyClient( + ObjectHandle, + (PUSER_SESSION_KEY) OutputSessionKey->Buffer + ); + + if (!NT_SUCCESS(Status)) { + + goto ClientGetSessionKeyError; + } + + +ClientGetSessionKeyFinish: + + *SessionKey = OutputSessionKey; + return(Status); + +ClientGetSessionKeyError: + + goto ClientGetSessionKeyFinish; +} + + diff --git a/private/lsa/uclient/ctlkacct.c b/private/lsa/uclient/ctlkacct.c new file mode 100644 index 000000000..8d8b95ed1 --- /dev/null +++ b/private/lsa/uclient/ctlkacct.c @@ -0,0 +1,378 @@ +/*++ + +Copyright (c) 1992 Microsoft Corporation + +Module Name: + + ctlkacct.c + +Abstract: + + Local Security Authority Subsystem - Short CT for Win 32 LookupAccountName/Sid + + This is a small test that simply calls the Win 32 LookupAccountName/Sid + API once. + +Usage: + + ctlkacct \\ServerName AccountName + +Building Instructions: + + nmake UMTEST=ctlkacc UMTYPE=console + +Author: + + Scott Birrell (ScottBi) July 20, 1992 + [ Adapted from a test written by TimF, not completely to Nt standards ] + +Environment: + +Revision History: + +--*/ + +#include +#include + + +VOID +DumpSID( + IN PSID s + ); + +#define LSA_WIN_STANDARD_BUFFER_SIZE 0x000000200L + +VOID _CRTAPI1 +main(argc, argv) +int argc; +char **argv; +{ + char SidFromLookupName[LSA_WIN_STANDARD_BUFFER_SIZE]; + char RefDFromLookupName[LSA_WIN_STANDARD_BUFFER_SIZE]; + DWORD cbSidFromLookupName, cchRefDFromLookupName; + SID_NAME_USE UseFromLookupName; + + DWORD cchNameFromLookupSid; + char NameFromLookupSid[LSA_WIN_STANDARD_BUFFER_SIZE]; + char RefDFromLookupSid[LSA_WIN_STANDARD_BUFFER_SIZE]; + DWORD cchRefDFromLookupSid; + SID_NAME_USE UseFromLookupSid; + BOOL BoolStatus = TRUE; + DWORD LastError; + + if (argc != 3) { + + printf("usage: ctlkacct <(char *)SystemName> <(char *)AccountName>\n"); + return(0); + } + + cbSidFromLookupName = 0; + cchRefDFromLookupName = 0; + + BoolStatus = LookupAccountName(argv[1], + argv[2], + (PSID)SidFromLookupName, + &cbSidFromLookupName, + RefDFromLookupName, + &cchRefDFromLookupName, + &UseFromLookupName + ); + + if (BoolStatus) { + + printf( + "LookupAccountName() with zero buffer sizes returned TRUE\n" + ); + } + + // + // Get the Last Error (in DOS errorcode from). + // + + LastError = GetLastError(); + + if (LastError != ERROR_INSUFFICIENT_BUFFER) { + + printf( + "Unexpected Last Error %d returned from LookupAccountName\n" + "Expected %d (ERROR_INSUFFICIENT_BUFFER)\n", + LastError + ); + } + + // + // Now call LookupAccountName() again, using the buffer sizes returned. + // + + BoolStatus = LookupAccountName(argv[1], + argv[2], + (PSID)SidFromLookupName, + &cbSidFromLookupName, + RefDFromLookupName, + &cchRefDFromLookupName, + &UseFromLookupName + ); + + if (!BoolStatus) { + + printf( + "LookupAccountName failed - \n" + "LastError = %d\n", + GetLastError() + ); + + return(0); + } + + /* + * Print information returned by LookupAccountName + */ + + printf( + "*********************************************\n" + "Information returned by LookupAccountName\n" + "*********************************************\n\n" + ); + + printf( "Sid = " ); + DumpSID((PSID) SidFromLookupName); + printf( + "Size of Sid = %d\n", + cbSidFromLookupName + ); + + printf( + "Referenced Domain Name = %s\n" + "Size of Referenced Domain Name = %d\n", + RefDFromLookupName, + cchRefDFromLookupName + ); + + printf("Name Use = "); + + switch (UseFromLookupName) { + + case SidTypeUser: + + printf("SidTypeUser\n"); + break; + + case SidTypeGroup: + + printf("SidTypeGroup\n"); + break; + + case SidTypeDomain: + + printf("SidTypeDomain\n"); + break; + + case SidTypeAlias: + + printf("SidTypeAlias\n"); + break; + + case SidTypeWellKnownGroup: + + printf("SidTypeWellKnownGroup\n"); + break; + + case SidTypeDeletedAccount: + + printf("SidTypeDeletedAccount\n"); + break; + + case SidTypeInvalid: + + printf("SidTypeInvalid\n"); + break; + + case SidTypeUnknown: + + printf("SidTypeUnknown\n"); + break; + + default: + + break; + + } + + cchNameFromLookupSid = 0; + cchRefDFromLookupSid = 0; + + // + // Now lookup the Sid we just obtained and see if we get the name back. + // First, provide zero buffer sizes so that we get the sizes needed + // returned. + // + + cchNameFromLookupSid = 0; + cchRefDFromLookupSid = 0; + + BoolStatus = LookupAccountSid(argv[1], + (PSID) SidFromLookupName, + NameFromLookupSid, + &cchNameFromLookupSid, + RefDFromLookupSid, + &cchRefDFromLookupSid, + &UseFromLookupSid + ); + + if (BoolStatus) { + + printf("LookupAccountSid() with zero buffer sizes returned TRUE\n"); + } + + // + // Get the Last Error (in DOS errorcode from). + // + + LastError = GetLastError(); + + if (LastError != ERROR_INSUFFICIENT_BUFFER) { + + printf( + "Unexpected Last Error %d returned from LookupAccountSid\n" + "Expected %d (ERROR_INSUFFICIENT_BUFFER)\n", + LastError + ); + } + + // + // Now call LookupAccountSid() again, using the buffer sizes obtained + // from the previous call. + // + + if (!LookupAccountSid(argv[1], + (PSID) SidFromLookupName, + NameFromLookupSid, + &cchNameFromLookupSid, + RefDFromLookupSid, + &cchRefDFromLookupSid, + &UseFromLookupSid + )) { + + printf( + "LookupAccountSid failed\n" + "LastError = %d\n", + GetLastError() + ); + + return(0); + } + + /* + * Print information returned by LookupAccountSid + */ + + printf( + "*********************************************\n" + "Information returned by LookupAccountSid\n" + "*********************************************\n\n" + ); + + printf( + "Account Name = %s\n" + "Account Name Size (chars) = %d\n" + "Referenced Domain Name = %s\n" + "Referenced Domain Size (chars) = %d\n", + NameFromLookupSid, + cchNameFromLookupSid, + RefDFromLookupSid, + cchRefDFromLookupSid + ); + + printf("Sid Use = "); + + switch (UseFromLookupSid) { + + case SidTypeUser: + + printf("SidTypeUser\n"); + break; + + case SidTypeGroup: + + printf("SidTypeGroup\n"); + break; + + case SidTypeDomain: + + printf("SidTypeDomain\n"); + break; + + case SidTypeAlias: + + printf("SidTypeAlias\n"); + break; + + case SidTypeWellKnownGroup: + + printf("SidTypeWellKnownGroup\n"); + break; + + case SidTypeDeletedAccount: + + printf("SidTypeDeletedAccount\n"); + break; + + case SidTypeInvalid: + + printf("SidTypeInvalid\n"); + break; + + case SidTypeUnknown: + + printf("SidTypeUnknown\n"); + break; + + default: + + break; + } + + return(0); +} + + +VOID +DumpSID( + IN PSID s + ) + +{ + static char b[128]; + + SID_IDENTIFIER_AUTHORITY *a; + ULONG id = 0, i; + + try { + + b[0] = '\0'; + + a = GetSidIdentifierAuthority(s); + + sprintf(b, "s-0x1-%02x%02x%02x%02x%02x%02x", a -> Value[0], + a -> Value[1], a -> Value[2], a -> Value[3], a -> + Value[4], a -> Value[5]); + + for (i = 0; i < *GetSidSubAuthorityCount(s); i++) { + + sprintf(b, "%s-0x%lx", b, *GetSidSubAuthority(s, i)); + } + + printf("%s\n", b); + + } except (EXCEPTION_EXECUTE_HANDLER) { + + if (*b) { + + printf("%s", b); + } + + printf("\n", s); + } +} + diff --git a/private/lsa/uclient/ctlklsa.c b/private/lsa/uclient/ctlklsa.c new file mode 100644 index 000000000..fc6b79d50 --- /dev/null +++ b/private/lsa/uclient/ctlklsa.c @@ -0,0 +1,579 @@ +/*++ + +Copyright (c) 1992 Microsoft Corporation + +Module Name: + + ctlklsa.c + +Abstract: + + Local Security Authority Subsystem - Short CT for Lsa LookupAccountName/Sid + + This is a small test that simply calls the LsaLookupName/Sid API once. + +Usage: + + ctlklsa \\ServerName [-p] -a AccountName ... AccountName + + -p - pause before name and sid lookup operation + -a - start of list of account names + + +Building Instructions: + + nmake UMTEST=ctlklsa UMTYPE=console + +Author: + + +Environment: + +Revision History: + +--*/ + +#include "lsaclip.h" + + +VOID +DumpSID( + IN PSID s + ); + +VOID +CtPause( + ); + +#define LSA_WIN_STANDARD_BUFFER_SIZE 0x000000200L + +VOID _CRTAPI1 +main(argc, argv) +int argc; +char **argv; +{ + NTSTATUS + Status = STATUS_SUCCESS, + SidStatus; + + ULONG + Index, + ArgCount = (ULONG) argc, + DomainIndex, + NameIndex, + NameCount, + DomainSidLength; + + ANSI_STRING + NamesAnsi[ LSA_WIN_STANDARD_BUFFER_SIZE], + SystemNameAnsi; + + UNICODE_STRING + Names[ LSA_WIN_STANDARD_BUFFER_SIZE], + SystemName; + + PUNICODE_STRING + DomainName; + + PSID + Sid = NULL, + *Sids = NULL; + + SECURITY_QUALITY_OF_SERVICE + SecurityQualityOfService; + + OBJECT_ATTRIBUTES + ObjectAttributes; + + LSA_HANDLE + PolicyHandle; + + PLSA_REFERENCED_DOMAIN_LIST + ReferencedDomains = NULL, + ReferencedSidsDomains = NULL; + + PLSA_TRANSLATED_SID + TranslatedSids = NULL; + + PLSA_TRANSLATED_NAME + TranslatedNames = NULL; + + UCHAR + SubAuthorityCount; + + BOOLEAN + Pause = FALSE, + DoLookupSids = TRUE; + + if (argc < 4) { + + printf("usage: ctlkacct [-p] -a [ ...]\n\n"); + printf(" -p - pause before name and sid lookup operations\n"); + printf(" -a - start of list of account names\n\n"); + printf("example:\n"); + printf(" ctlklsa \\\\jimk -p -a interactive \"domain guests\" administrators\n\n"); + return; + } + + NameIndex = 0; + + // + // Capture argument 1, the Server Name + // + + RtlInitString( &SystemNameAnsi, (PUCHAR) argv[1] ); + + Status = RtlAnsiStringToUnicodeString( + &SystemName, + &SystemNameAnsi, + TRUE + ); + + if (!NT_SUCCESS(Status)) { + + goto MainError; + } + + for (Index = 2; Index < ArgCount; Index++) { + + if (strncmp(argv[Index], "-p", 2) == 0) { + + // + // The caller wants a pause before each lookup call. + // + + Pause = TRUE; + } else if (strncmp(argv[Index], "-a", 2) == 0) { + + Index++; + + while (Index < ArgCount) { + + if (strncmp(argv[Index], "-", 1) == 0) { + + Index--; + break; + } + + // + // Capture the Account Name as a Unicode String. + // + + RtlInitString( &NamesAnsi[ NameIndex ], argv[Index] ); + + Status = RtlAnsiStringToUnicodeString( + &Names[ NameIndex ], + &NamesAnsi[ NameIndex ], + TRUE + ); + + if (!NT_SUCCESS(Status)) { + + break; + } + + NameIndex++; + Index++; + } + + if (Index == ArgCount) { + + break; + } + } + } + + if (!NT_SUCCESS(Status)) { + + goto MainError; + } + + NameCount = NameIndex; + + 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; + + // + // Open the LSA Policy Database for the target system. This is the + // starting point for the Name Lookup operation. + // + + Status = LsaOpenPolicy( + &SystemName, + &ObjectAttributes, + POLICY_LOOKUP_NAMES, + &PolicyHandle + ); + + if (!NT_SUCCESS(Status)) { + + goto MainError; + } + + if (Pause) { + + printf( "\n\n..... Pausing before name lookup \n "); + CtPause( ); + } + + + // + // Attempt to translate the Names to Sids. + // + + Status = LsaLookupNames( + PolicyHandle, + NameCount, + Names, + &ReferencedDomains, + &TranslatedSids + ); + + if (!NT_SUCCESS(Status)) { + + goto MainError; + } + + // + // Build the Sids from the output. + // + + Sids = (PSID *) LocalAlloc( 0, NameCount * sizeof (PSID) ); + + + if (Sids == NULL) { + + Status = STATUS_INSUFFICIENT_RESOURCES; + goto MainError; + } + + + for (NameIndex = 0; NameIndex < NameCount; NameIndex++) { + + if (TranslatedSids[NameIndex].Use == SidTypeUnknown) { + + Sids[NameIndex] = NULL; + DoLookupSids = FALSE; + + } else { + DomainIndex = TranslatedSids[NameIndex].DomainIndex; + + DomainSidLength = RtlLengthSid( + ReferencedDomains->Domains[DomainIndex].Sid + ); + + + + Sid = (PSID) LocalAlloc( (UINT) 0, (UINT) (DomainSidLength + sizeof(ULONG)) ); + + if (Sid == NULL) { + printf(" ** ERROR - couldn't allocate heap !!\n"); + return; + } + + RtlMoveMemory( + Sid, + ReferencedDomains->Domains[DomainIndex].Sid, + DomainSidLength + ); + + if (TranslatedSids[NameIndex].Use != SidTypeDomain) { + + (*RtlSubAuthorityCountSid( Sid ))++; + SubAuthorityCount = *RtlSubAuthorityCountSid( Sid ); + *RtlSubAuthoritySid(Sid,SubAuthorityCount - (UCHAR) 1) = + TranslatedSids[NameIndex].RelativeId; + } + + Sids[NameIndex] = Sid; + } + } + + + // + // Pause before SID lookup... + // + + if (!DoLookupSids) { + printf("\n\n Unknown Name causing sid lookup to be skipped\n"); + } else { + if (Pause) { + + printf( "\n\n..... Pausing before SID lookup \n "); + CtPause(); + } + + // + // Now translate the Sids back to Names + // + + SidStatus = LsaLookupSids( + PolicyHandle, + NameCount, + (PSID *) Sids, + &ReferencedSidsDomains, + &TranslatedNames + ); + } + + /* + * Print information returned by LookupAccountName + */ + + + printf( + "*********************************************\n" + "Information returned by LookupAccountName\n" + "*********************************************\n\n" + ); + + for (NameIndex = 0; NameIndex < NameCount; NameIndex++) { + + + printf(" Name looked up: *%wZ*\n", &Names[NameIndex]); + + printf(" Use = "); + + switch (TranslatedSids[NameIndex].Use) { + + case SidTypeUser: + + printf("SidTypeUser\n"); + break; + + case SidTypeGroup: + + printf("SidTypeGroup\n"); + break; + + case SidTypeDomain: + + printf("SidTypeDomain\n"); + break; + + case SidTypeAlias: + + printf("SidTypeAlias\n"); + break; + + case SidTypeWellKnownGroup: + + printf("SidTypeWellKnownGroup\n"); + break; + + case SidTypeDeletedAccount: + + printf("SidTypeDeletedAccount\n"); + break; + + case SidTypeInvalid: + + printf("SidTypeInvalid\n"); + break; + + case SidTypeUnknown: + + printf("SidTypeUnknown\n\n"); + break; + + default: + + printf("Hmmm - something unusual came back !!!! \n\n"); + break; + + } + + if (TranslatedSids[NameIndex].Use != SidTypeUnknown) { + + printf(" Sid = " ); + DumpSID((PSID) Sids[NameIndex]); + + DomainIndex = TranslatedSids[NameIndex].DomainIndex; + DomainName = &ReferencedDomains->Domains[ DomainIndex ].Name; + + printf(" Referenced Domain Name = *%wZ*\n\n", DomainName ); + } + } + + + if (DoLookupSids) { + printf( + "*********************************************\n" + "Information returned by LookupAccountSid\n" + "*********************************************\n\n" + ); + + if (!NT_SUCCESS(SidStatus)) { + printf(" Sid lookup failed. Status 0x%lx\n" + " Dumping sids that were being looked up...\n", + SidStatus); + } + + for (NameIndex = 0; NameIndex < NameCount; NameIndex++) { + + + printf(" Sid = " ); + DumpSID((PSID) Sids[NameIndex]); + + if (NT_SUCCESS(SidStatus)) { + + printf(" Sid Use = "); + + switch (TranslatedNames[NameIndex].Use) { + + case SidTypeUser: + + printf("SidTypeUser\n"); + break; + + case SidTypeGroup: + + printf("SidTypeGroup\n"); + break; + + case SidTypeDomain: + + printf("SidTypeDomain\n"); + break; + + case SidTypeAlias: + + printf("SidTypeAlias\n"); + break; + + case SidTypeWellKnownGroup: + + printf("SidTypeWellKnownGroup\n"); + break; + + case SidTypeDeletedAccount: + + printf("SidTypeDeletedAccount\n"); + break; + + case SidTypeInvalid: + + printf("SidTypeInvalid\n"); + break; + + case SidTypeUnknown: + + printf("SidTypeUnknown\n"); + break; + + default: + + printf("Hmmm - unexpected value !!!\n"); + break; + } + + DomainIndex = TranslatedNames[NameIndex].DomainIndex; + DomainName = &ReferencedSidsDomains->Domains[ DomainIndex ].Name; + if (TranslatedNames[NameIndex].Use == SidTypeDomain) { + printf( + " Domain Name = *%wZ*\n\n", + DomainName + ); + } else { + printf( + " Account Name = *%wZ*\n" + " Referenced Domain Name = *%wZ*\n\n", + &TranslatedNames[NameIndex].Name, + DomainName + ); + } + } + } + } + + +MainFinish: + + return; + +MainError: + + printf("Error: status = 0x%lx\n", Status); + + goto MainFinish; +} + + +VOID +DumpSID( + IN PSID s + ) + +{ + SID_IDENTIFIER_AUTHORITY + *a; + + ULONG + id = 0, + i; + + BOOLEAN + PrintValue = FALSE; + + try { + + + a = GetSidIdentifierAuthority(s); + + printf("s-1-"); + + for (i=0; i<5; i++) { + if ((a->Value[i] != 0) || PrintValue) { + printf("%02x", a->Value[i]); + PrintValue = TRUE; + } + } + printf("%02x", a->Value[5]); + + + for (i = 0; i < (ULONG) *GetSidSubAuthorityCount(s); i++) { + + printf("-0x%lx", *GetSidSubAuthority(s, i)); + } + + + } except (EXCEPTION_EXECUTE_HANDLER) { + + printf("\n", s); + } + printf("\n"); +} + +VOID +CtPause( + ) +{ + CHAR + IgnoreInput[300]; + + printf("Press to continue . . ."); + gets( &IgnoreInput[0] ); + return; +} diff --git a/private/lsa/uclient/ctreg.c b/private/lsa/uclient/ctreg.c new file mode 100644 index 000000000..edf6a5acb --- /dev/null +++ b/private/lsa/uclient/ctreg.c @@ -0,0 +1,807 @@ +/*++ + +Copyright (c) 1991 Microsoft Corporation + +Module Name: + + ctreg.c + +Abstract: + + Configuration Registry component test + + Needs to move from here + +Author: + + Scott Birrell (ScottBi) June 5, 1991 + +Environment: + +Revision History: + +--*/ + + +#include +#include +#include + + +#define CT_REG_INITIAL_KEY_COUNT 8L +#define CT_REG_INITIAL_LEVEL_COUNT 4L +#define CT_REG_KEY_VALUE_MAX_LENGTH 0x00000100L + +// +// List of initial Registry keys to be set up. The list must be +// kept so that moving linearly through it visits key nodes with top +// to bottom key traversal taking precedence over left-to-right. +// + +typedef struct _CT_TEST_REGISTRY_KEY { + ULONG KeyLevel; + PUCHAR KeyName; + ULONG KeyValueType; + PUCHAR KeyValue; + ULONG KeyValueLengthToQuery; + ULONG KeyValueLengthToSet; + NTSTATUS ExpectedStatus; + HANDLE KeyHandle; + HANDLE ParentKeyHandle; +} CT_TEST_REGISTRY_KEY, *PCT_TEST_REGISTRY_KEY; + +CT_TEST_REGISTRY_KEY RegistryKeys[ CT_REG_INITIAL_KEY_COUNT ]; + +UCHAR KeyValue[CT_REG_KEY_VALUE_MAX_LENGTH]; +ULONG KeyValueLengthToQuery; +ULONG KeyValueType; +LARGE_INTEGER LastWriteTime; + +HANDLE ParentKeyHandle[CT_REG_INITIAL_LEVEL_COUNT + 1] = + { NULL, NULL, NULL, NULL, NULL }; + +VOID +InitTestKey( + IN ULONG KeyNumber, + IN ULONG KeyLevel, + IN PUCHAR KeyName, + IN ULONG KeyNameLength, + IN ULONG KeyValueType, + IN PUCHAR KeyValue, + IN ULONG KeyValueLengthToQuery, + IN ULONG KeyValueLengthToSet, + IN NTSTATUS ExpectedStatus + ); + + +VOID +CtRegExamineResult( + IN ULONG KeyNumber, + IN ULONG KeyValueType, + IN PUCHAR KeyValue, + IN ULONG KeyValueLength, + IN NTSTATUS ReturnedStatus + ); + + +VOID +CtCreateSetQueryKey(); + +VOID +CtOpenMakeTempCloseKey(); + + +VOID +main () +{ + CtCreateSetQueryKey(); + + CtOpenMakeTempCloseKey(); + +} + + + + +VOID +CtCreateSetQueryKey( + ) + +/*++ + +Routine Description: + + This function tests the RtlpNtOpenKey RtlpNtCreateKey and NtClose API. + +Arguments: + + None. + +Return Value: + + None. + +--*/ + +{ + NTSTATUS Status; + + // + // Set up a test hierarchy of keys + // + + ULONG KeyNumber; + ULONG ZeroLength; + STRING Name; + UNICODE_STRING UnicodeName; + OBJECT_ATTRIBUTES ObjectAttributes; + + ZeroLength = 0L; + + DbgPrint("Start of Create, Set, Query Registry Key Test\n"); + + // + // Initialize the test array. I did it this way because a statically + // initialized table is harder to read. + // + + InitTestKey( + 0, + 0, + "\\Registry\\RLM", + sizeof ("\\Registry\\RLM"), + 0, + "Level 0 - RLM", + sizeof ("\\Registry\\RLM") - 1, + sizeof ("\\Registry\\RLM") - 1, + STATUS_SUCCESS + ); + + InitTestKey( + 1, + 1, + "Test", + sizeof ("Test"), + 1, + "Keyname Test - this value too big", + 6, + sizeof ("Keyname Test - this value too big") -1, + STATUS_BUFFER_OVERFLOW + ); + + InitTestKey( + 2, + 2, + "SubTestA", + sizeof("SubTestA"), + 2, + "Keyname SubTestA - value small", + 30, + sizeof ("Keyname SubTestA - value small") - 1, + STATUS_SUCCESS + ); + + + InitTestKey( + 3, + 3, + "SSTestA", + sizeof("SSTestA"), + 3, + "Keyname SSTestA - zero length buffer", + 30, + sizeof("Keyname SSTestA - zero length buffer") - 1, + STATUS_BUFFER_OVERFLOW + ); + + InitTestKey( + 4, + 3, + "SSTestB", + sizeof("SSTestB"), + 4, + "Keyname SSTestB - value exact fit", + sizeof ("Keyname SSTestB - value exact fit") -1, + sizeof ("Keyname SSTestB - value exact fit") -1, + STATUS_SUCCESS + ); + + InitTestKey( + 5, + 3, + "SSTestC", + sizeof("SSTestC"), + 5, + "Keyname SSTestC - value small", + 40, + sizeof ("Keyname SSTestC - value small") -1, + STATUS_SUCCESS + ); + + InitTestKey( + 6, + 3, + "SSTestD", + sizeof("SSTestD"), + 6, + "Keyname SSTestD - value small", + 40, + sizeof ("Keyname SSTestD - value small") -1, + STATUS_SUCCESS + ); + + InitTestKey( + 7, + 3, + "SSTestE", + sizeof("SSTestD"), + 0, + "Keyname SSTestD - no value set", + 40, + 0, + STATUS_SUCCESS + ); + + DbgPrint("Start of Registry Test\n"); + + // + // Create all of the initial test registry keys + // + + + for (KeyNumber = 0; KeyNumber < CT_REG_INITIAL_KEY_COUNT; KeyNumber++) { + + RtlInitString( + &Name, + RegistryKeys[KeyNumber].KeyName + ); + + Status = RtlAnsiStringToUnicodeString( + &UnicodeName, + &Name, + TRUE ); + + if (!NT_SUCCESS(Status)) { + DbgPrint("Security: Registry Init Ansi to Unicode failed 0x%lx\n", + Status); + return; + } + + InitializeObjectAttributes( + &ObjectAttributes, + &UnicodeName, + OBJ_CASE_INSENSITIVE, + ParentKeyHandle[RegistryKeys[KeyNumber].KeyLevel], + NULL + ); + + // + // Remember the Parent Key handle + // + + RegistryKeys[KeyNumber].ParentKeyHandle = + ParentKeyHandle[RegistryKeys[KeyNumber].KeyLevel]; + + // + // Create the key if it does not already exist. If key does exist, + // continue trying to create all of the other keys needed (for now). + // Store the returned key handle as the parent key handle for the + // next higher (child) level. + // + + Status = RtlpNtCreateKey( + &RegistryKeys[KeyNumber].KeyHandle, + (KEY_READ | KEY_WRITE), + &ObjectAttributes, + 0L, // No options + NULL, // Default provider + NULL + ); + + // + // Save the Key's handle as the next level's parent handle. + // + + ParentKeyHandle[RegistryKeys[KeyNumber].KeyLevel + 1] = + RegistryKeys[KeyNumber].KeyHandle; + + // + // Free the memory allocated for the Unicode name + // + + RtlFreeUnicodeString( &UnicodeName ); + + if (NT_SUCCESS(Status) || Status == STATUS_OBJECT_NAME_COLLISION) { + + // + // Set the key's value unless the length to set is zero. + // + + if (RegistryKeys[KeyNumber].KeyValueLengthToSet != 0) { + + Status=RtlpNtSetValueKey( + ParentKeyHandle[RegistryKeys[KeyNumber].KeyLevel+1], + RegistryKeys[KeyNumber].KeyValueType, + RegistryKeys[KeyNumber].KeyValue, + RegistryKeys[KeyNumber].KeyValueLengthToSet + ); + } + + // + // Read the key's value back + // + + KeyValueLengthToQuery = + RegistryKeys[KeyNumber].KeyValueLengthToQuery; + + Status = RtlpNtQueryValueKey( + ParentKeyHandle[RegistryKeys[KeyNumber].KeyLevel + 1], + &KeyValueType, + KeyValue, + &KeyValueLengthToQuery, + &LastWriteTime + ); + + // + // Verify that the expected KeyValue, KeyLength and Status + // were returned. + // + + CtRegExamineResult( + KeyNumber, + KeyValueType, + KeyValue, + KeyValueLengthToQuery, + Status + ); + + // + // Test null pointer cases don't crash NtQueryValueKey + // + + Status = RtlpNtQueryValueKey( + ParentKeyHandle[RegistryKeys[KeyNumber].KeyLevel + 1], + NULL, // No type + KeyValue, + &KeyValueLengthToQuery, + &LastWriteTime + ); + + Status = RtlpNtQueryValueKey( + ParentKeyHandle[RegistryKeys[KeyNumber].KeyLevel + 1], + &KeyValueType, + NULL, // No value + &KeyValueLengthToQuery, + &LastWriteTime + ); + + Status = RtlpNtQueryValueKey( + ParentKeyHandle[RegistryKeys[KeyNumber].KeyLevel + 1], + &KeyValueType, + KeyValue, + NULL, // No length + &LastWriteTime + ); + + Status = RtlpNtQueryValueKey( + ParentKeyHandle[RegistryKeys[KeyNumber].KeyLevel + 1], + &KeyValueType, + KeyValue, + &ZeroLength, // Zero length + &LastWriteTime + ); + + Status = RtlpNtQueryValueKey( + ParentKeyHandle[RegistryKeys[KeyNumber].KeyLevel + 1], + &KeyValueType, + KeyValue, + &KeyValueLengthToQuery, + NULL // No time + ); + // + // Test null pointer cases don't crash NtSetValueKey + // + + Status = RtlpNtSetValueKey( + ParentKeyHandle[RegistryKeys[KeyNumber].KeyLevel+1], + RegistryKeys[KeyNumber].KeyValueType, + NULL, // No value, setting type only + RegistryKeys[KeyNumber].KeyValueLengthToSet + ); + } else { + + DbgPrint( + "Key number %d creation failed 0x%lx\n", + KeyNumber, + Status + ); + } + } + + // + // Close all the keys in the table + // + + for (KeyNumber = 0; KeyNumber < CT_REG_INITIAL_KEY_COUNT; KeyNumber++) { + + Status = NtClose( + RegistryKeys[KeyNumber].KeyHandle + ); + + if (!NT_SUCCESS(Status)) { + + DbgPrint("Closing KeyNumber %d failed 0x%lx\n", Status); + } + } + + DbgPrint("End of Create, Set, Query Registry Key Test\n"); +} + + +VOID +CtRegExamineResult( + IN ULONG KeyNumber, + IN ULONG KeyValueType, + IN PUCHAR KeyValue, + IN ULONG KeyValueLengthReturned, + IN NTSTATUS ReturnedStatus + ) + +{ + ULONG KeyValueLengthToCompare; + + // + // Check the status. If bad, skip the other checks. + // + + if (ReturnedStatus != RegistryKeys[KeyNumber].ExpectedStatus) { + + DbgPrint( + "KeyNumber %d: RtlpNtQueryValueKey returned 0x%lx, expected 0x%lx\n", + KeyNumber, + ReturnedStatus, + RegistryKeys[KeyNumber].ExpectedStatus + ); + + } else { + + // + // Check that the Key Type is as expected. + // + + + if (KeyValueType != RegistryKeys[KeyNumber].KeyValueType) { + + DbgPrint( + "KeyNumber %d: RtlpNtQueryValueKey returned KeyValueType 0x%lx, \ + expected 0x%lx\n", + KeyNumber, + KeyValueType, + RegistryKeys[KeyNumber].KeyValueType + ); + + } + + // + // Check that the Key Length is as expected. + // + + + if (KeyValueLengthReturned != + RegistryKeys[KeyNumber].KeyValueLengthToSet) { + + DbgPrint( + "KeyNumber %d: RtlpNtQueryValueKey returned ValLength 0x%lx, \ + expected 0x%lx\n", + KeyNumber, + KeyValueLengthReturned, + RegistryKeys[KeyNumber].KeyValueLengthToSet + ); + + } + + // + // Check that the Key Value is as expected. Distinguish between + // Buffer truncated cases and regular cases. + // + + if (RegistryKeys[KeyNumber].KeyValueLengthToSet != 0L) { + + // + // Determine the length of returned key value to compare. This is + // the min of the set length and and the size of the return + // buffer. + // + + KeyValueLengthToCompare = + RegistryKeys[KeyNumber].KeyValueLengthToSet; + + if (KeyValueLengthToCompare > + RegistryKeys[KeyNumber].KeyValueLengthToQuery) { + + KeyValueLengthToCompare = + RegistryKeys[KeyNumber].KeyValueLengthToQuery; + } + + + if (strncmp( + KeyValue, + RegistryKeys[KeyNumber].KeyValue, + KeyValueLengthToCompare + ) != 0) { + + // + // Output approriate error message. Message contains + // "truncated.." if key value should have been truncated + // + + if (RegistryKeys[KeyNumber].KeyValueLengthToSet > + RegistryKeys[KeyNumber].KeyValueLengthToQuery) { + + DbgPrint( + "KeyNumber %d: RtlpNtQueryValueKey returned KeyValue %s, \ + expected %s truncated to %d characters\n", + KeyNumber, + KeyValue, + RegistryKeys[KeyNumber].KeyValue, + RegistryKeys[KeyNumber].KeyValueLengthToQuery + ); + + } else { + + DbgPrint( + "KeyNumber %d: RtlpNtQueryValueKey returned KeyValue %s, \ + expected %s\n", + KeyNumber, + KeyValue, + RegistryKeys[KeyNumber].KeyValue + ); + } + } + } + } +} + + + + +VOID +CtOpenMakeTempCloseKey() + +/*++ + +Routine Description: + + This function tests NtDeleteKey by deleting the CT configuration + +Arguments: + + None. + +Return Value: + + None + +--*/ + +{ + ULONG KeyNumber; + ULONG KeyLevel; + STRING Name; + UNICODE_STRING UnicodeName; + NTSTATUS Status; + OBJECT_ATTRIBUTES ObjectAttributes; + + // + // Open all of the initial test registry keys for write and delete + // access, set, query and delete each key. + // + + DbgPrint("Start of Open Make Temp and Close Delete Registry Key Test\n"); + + // + // First, set all of the Parent handles to NULL + // + + for (KeyNumber = 0; KeyNumber < CT_REG_INITIAL_KEY_COUNT; KeyNumber++) { + + RegistryKeys[KeyNumber].ParentKeyHandle = NULL; + } + + for (KeyLevel = 0; KeyLevel < CT_REG_INITIAL_LEVEL_COUNT; KeyLevel++) { + + ParentKeyHandle[KeyLevel] = NULL; + } + + for (KeyNumber = 0; KeyNumber < CT_REG_INITIAL_KEY_COUNT; KeyNumber++) { + + RtlInitString( + &Name, + RegistryKeys[KeyNumber].KeyName + ); + + Status = RtlAnsiStringToUnicodeString( + &UnicodeName, + &Name, + TRUE ); + + if (!NT_SUCCESS(Status)) { + DbgPrint("Security: Registry Init Ansi to Unicode failed 0x%lx\n", + Status); + return; + } + + InitializeObjectAttributes( + &ObjectAttributes, + &UnicodeName, + OBJ_CASE_INSENSITIVE, + ParentKeyHandle[RegistryKeys[KeyNumber].KeyLevel], + NULL + ); + + // + // Open the key and store the returned key handle as the parent key + // handle for the next higher (child) level. + // + + Status = RtlpNtOpenKey( + &RegistryKeys[KeyNumber].KeyHandle, + (KEY_READ | KEY_WRITE | DELETE), + &ObjectAttributes, + 0L // No options + ); + + if (!NT_SUCCESS(Status)) { + + DbgPrint( + "NtOpenKey - KeyNumber %d failed 0x%lx\n", + KeyNumber, + Status + ); + } + + // + // Save the Key's handle as the next level's parent handle. + // + + ParentKeyHandle[RegistryKeys[KeyNumber].KeyLevel + 1] = + RegistryKeys[KeyNumber].KeyHandle; + + // + // Free the memory allocated for the Unicode name + // + + RtlFreeUnicodeString( &UnicodeName ); + + if (NT_SUCCESS(Status) || Status == STATUS_OBJECT_NAME_COLLISION) { + + // + // Set the key's value unless the length to set is zero. + // + + if (RegistryKeys[KeyNumber].KeyValueLengthToSet != 0) { + + Status=RtlpNtSetValueKey( + ParentKeyHandle[RegistryKeys[KeyNumber].KeyLevel+1], + RegistryKeys[KeyNumber].KeyValueType, + RegistryKeys[KeyNumber].KeyValue, + RegistryKeys[KeyNumber].KeyValueLengthToSet + ); + } + + // + // Read the key's value back + // + + KeyValueLengthToQuery = + RegistryKeys[KeyNumber].KeyValueLengthToQuery; + + Status = RtlpNtQueryValueKey( + ParentKeyHandle[RegistryKeys[KeyNumber].KeyLevel + 1], + &KeyValueType, + KeyValue, + &KeyValueLengthToQuery, + &LastWriteTime + ); + + // + // Verify that the expected KeyValue, KeyLength and Status + // were returned. + // + + CtRegExamineResult( + KeyNumber, + KeyValueType, + KeyValue, + KeyValueLengthToQuery, + Status + ); + + } else { + + DbgPrint( + "Key number %d open failed 0x%lx\n", + KeyNumber, + Status + ); + } + } + + // + // Make Temporary and Close all the keys in the table + // + + for (KeyNumber = CT_REG_INITIAL_KEY_COUNT-1; KeyNumber != 0L; KeyNumber--) { + + Status = RtlpNtMakeTemporaryKey( RegistryKeys[KeyNumber].KeyHandle ); + + if (!NT_SUCCESS(Status)) { + + DbgPrint( + "Making Temporary KeyNumber %d failed 0x%lx\n", + KeyNumber, + Status + ); + } + + Status = NtClose( + RegistryKeys[KeyNumber].KeyHandle + ); + + if (!NT_SUCCESS(Status)) { + + DbgPrint( + "Closing KeyNumber %d failed 0x%lx\n", + KeyNumber, + Status + ); + } + } + + DbgPrint("End of Open Mk Temp and Close Registry Key Test\n"); +} + + +VOID +InitTestKey( + IN ULONG KeyNumber, + IN ULONG KeyLevel, + IN PUCHAR KeyName, + IN ULONG KeyNameLength, + IN ULONG KeyValueType, + IN PUCHAR KeyValue, + IN ULONG KeyValueLengthToQuery, + IN ULONG KeyValueLengthToSet, + IN NTSTATUS ExpectedStatus + ) + +/*++ + +Routine Description: + + This function initializes an entry in the array of test keys + +Arguments: + + TBS. + +Return Value: + +--*/ + +{ + RegistryKeys[KeyNumber].KeyLevel = KeyLevel; + RegistryKeys[KeyNumber].KeyName = KeyName; + RegistryKeys[KeyNumber].KeyValueType = KeyValueType; + RegistryKeys[KeyNumber].KeyValue = KeyValue; + RegistryKeys[KeyNumber].KeyValueLengthToSet = KeyValueLengthToSet; + RegistryKeys[KeyNumber].KeyValueLengthToQuery = KeyValueLengthToQuery; + RegistryKeys[KeyNumber].ExpectedStatus = ExpectedStatus; + RegistryKeys[KeyNumber].KeyHandle = NULL; + RegistryKeys[KeyNumber].ParentKeyHandle = NULL; + + + DBG_UNREFERENCED_PARAMETER (KeyNameLength); +} + + diff --git a/private/lsa/uclient/ctsamdb.c b/private/lsa/uclient/ctsamdb.c new file mode 100644 index 000000000..68e690cd2 --- /dev/null +++ b/private/lsa/uclient/ctsamdb.c @@ -0,0 +1,213 @@ + +/*++ + +Copyright (c) 1991 Microsoft Corporation + +Module Name: + + ctsamdb.c + +Abstract: + + CT for loading a SAM Accounts Database + + This test creates a number of users in the local SAM Database + + To build this test: + + cd \nt\private\lsa\uclient + nmake UMTYPE=console UMTEST=ctsamdb + + To run this test: + + 1. Build lsasrv.dll with LSA_SAM_ACCOUNTS_DOMAIN_TEST flag + enabled in file \nt\private\lsa\server\dbp.h + + 2. On your test system, replace lsasrv.dll in \nt\system32 and reboot. + + 3. Type ctsamdb n to load SAM Database with n users + + 4. Type ctsamdb -1 to delete the users you created. + +Author: + + Scott Birrell (ScottBi) October 19, 1992 + +Environment: + +Revision History: + +--*/ + +#include "lsaclip.h" + + +///////////////////////////////////////////////////////////////////////////// +// // +// LSA Component Test for RPC API - main program // +// // +///////////////////////////////////////////////////////////////////////////// + + +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; +} + +VOID _CRTAPI1 +main (argc, argv) +int argc; +char **argv; + +{ + NTSTATUS Status = STATUS_SUCCESS; + UNICODE_STRING NumberOfAccounts; + ANSI_STRING NumberOfAccountsAnsi; + OBJECT_ATTRIBUTES ObjectAttributes; + SECURITY_QUALITY_OF_SERVICE SecurityQualityOfService; + LSA_HANDLE PolicyHandle; + + if (argc != 2) { + + printf("\n"); + printf("Instructions for using SAM Accounts Domain Test Load\n"); + printf("----------------------------------------------------\n"); + printf("\n\n"); + printf("This program can be used to create n users in a SAM\n"); + printf("Accounts domain, or update user information in a domain.\n"); + printf("Usernames and other information are pseudo-randomized\n"); + printf("and Relative Ids begin at 4096, to avoid conflict with\n"); + printf("existing installed accounts\n"); + printf("\n"); + printf("NOTE: \\\\popcorn\\public\\scottbi\\runsamdb temporarily\n"); + printf("contains 340-compatible x86 versions of the four files\n"); + printf("described in steps 1. 2. and 3 below.\n"); + printf("\n"); + printf("1. Replace lsasrv.dll with one compiled with the\n"); + printf(" LSA_SAM_ACCOUNTS_DOMAIN_TEST #define enabled\n"); + printf(" in file lsa\\server\\dbpolicy.c.\n"); + printf("\n"); + printf("2. Replace samsrv.dll with one containing chads\n"); + printf(" mondo level SamSetInformationUser changes.\n"); + printf("\n"); + printf("3. Copy runsamdb.cmd and ctsamdb.exe to a directory\n"); + printf(" on your path\n"); + printf("\n"); + printf("4. Reboot system with debugger enabled. Debugger terminal\n"); + printf(" will display a message for each 100 users created\n"); + printf(" plus the time taken to create the last 100 users.\n"); + printf(" If any attempt is made to create an existing user,\n"); + printf(" or a user that conflicts with an existing account, the\n"); + printf(" total number of occurrences of these to date is displayed.\n"); + printf("\n"); + printf("5. To load a SAM database with n > 0 users, type:\n"); + printf("\n"); + printf(" runsamdb n\n"); + printf("\n"); + printf("6. To update the SAM database with identical information\n"); + printf(" to that loaded, repeat the command in 5.\n"); + printf("\n"); + printf("7. To delete the users you created, type\n"); + printf("\n"); + printf(" runsamdb -1\n"); + printf("\n"); + printf("8. Existing accounts not created by the test will not\n"); + printf(" normally be affected.\n"); + printf("\n"); + printf("9. To repeat these instructions, type\n"); + printf("\n"); + printf(" runsamdb\n"); + return; + } + + RtlInitAnsiString( &NumberOfAccountsAnsi, argv[1] ); + RtlAnsiStringToUnicodeString( + &NumberOfAccounts, + &NumberOfAccountsAnsi, + TRUE + ); + + CtLsaInitObjectAttributes( + &ObjectAttributes, + &SecurityQualityOfService + ); + + // + // Open a handle to the local Policy Object. Use a benign access + // mask, because we won't check it. + // + + Status = LsaOpenPolicy( + NULL, + &ObjectAttributes, + POLICY_VIEW_LOCAL_INFORMATION, + &PolicyHandle + ); + + if (!NT_SUCCESS(Status)) { + + printf("LSA RPC CT - LsaOpenPolicy failed 0x%lx\n", Status); + return; + } + + // + // Use an information class in LsaSetInformationPolicy() that can't be + // specified normally on a set operation. + // + + Status = LsaSetInformationPolicy( + PolicyHandle, + PolicyPdAccountInformation, + &NumberOfAccounts + ); + + Status = LsaClose( PolicyHandle ); +} diff --git a/private/lsa/uclient/lsaclip.h b/private/lsa/uclient/lsaclip.h new file mode 100644 index 000000000..0e56e32e2 --- /dev/null +++ b/private/lsa/uclient/lsaclip.h @@ -0,0 +1,25 @@ +/*++ + +Copyright (c) 1991 Microsoft Corporation + +Module Name: + + lsaclip.h + +Abstract: + + LSA - Client Side private includes + +Author: + + Scott Birrell (ScottBi) January 23, 1992 + +Environment: + +Revision History: + +--*/ + +#include +#include "lsarpc_c.h" +#include diff --git a/private/lsa/uclient/lsaudll.def b/private/lsa/uclient/lsaudll.def new file mode 100644 index 000000000..c598f1057 --- /dev/null +++ b/private/lsa/uclient/lsaudll.def @@ -0,0 +1,11 @@ +LIBRARY LSAUDLL + +DESCRIPTION 'Local Security Authority User-Mode Client Library' + +EXPORTS + +; +; Scott Birrell (ScottBi) Febreary 14, 1992 +; +; Exported Public RPC Services +; diff --git a/private/lsa/uclient/makefile b/private/lsa/uclient/makefile new file mode 100644 index 000000000..6ee4f43fa --- /dev/null +++ b/private/lsa/uclient/makefile @@ -0,0 +1,6 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the components of NT OS/2 +# +!INCLUDE $(NTMAKEENV)\makefile.def diff --git a/private/lsa/uclient/rpcapi.c b/private/lsa/uclient/rpcapi.c new file mode 100644 index 000000000..2169a078c --- /dev/null +++ b/private/lsa/uclient/rpcapi.c @@ -0,0 +1,3797 @@ + +/*++ + +Copyright (c) 1989 Microsoft Corporation + +Module Name: + + rpcapi.c + +Abstract: + + This module contains the routines for the LSA API that use RPC. The + routines in this module are merely wrappers that work as follows: + + o Client program calls LsaFoo in this module + o LsaFoo calls RPC client stub interface routine LsapFoo with + similar parameters. Some parameters are translated from types + (e.g structures containing PVOIDs or certain kinds of variable length + parameters such as pointers to SID's) that are not specifiable on an + RPC interface, to specifiable form. + o RPC client stub LsapFoo calls interface specific marshalling routines + and RPC runtime to marshal parameters into a buffer and send them over + to the server side of the LSA. + o Server side calls RPC runtime and interface specific unmarshalling + routines to unmarshal parameters. + o Server side calls worker LsapFoo to perform API function. + o Server side marshals response/output parameters and communicates these + back to client stub LsapFoo + o LsapFoo exits back to LsaFoo which returns to client program. + +Author: + + Scott Birrell (ScottBi) April 24, 1991 + +Revision History: + +--*/ + +#include "lsaclip.h" + +// +// The following limit on the maximum number of Sids or Names is tentative, +// so it is not being published. +// + +#define LSAP_DB_TRIAL_MAXIMUM_SID_COUNT ((ULONG) 0x00005000L) +#define LSAP_DB_TRIAL_MAXIMUM_NAME_COUNT ((ULONG) 0x00005000L) + + +// +// Functions private to this module +// + +NTSTATUS +LsapApiReturnResult( + IN ULONG ExceptionCode + ); + +//////////////////////////////////////////////////////////////////////////// +// // +// Local Security Policy Administration API function prototypes // +// // +//////////////////////////////////////////////////////////////////////////// + +NTSTATUS +LsaOpenPolicy( + IN PUNICODE_STRING SystemName OPTIONAL, + IN POBJECT_ATTRIBUTES ObjectAttributes, + IN ACCESS_MASK DesiredAccess, + IN OUT PLSA_HANDLE PolicyHandle + ) + +/*++ + +Routine Description: + + To administer the Local Security Policy of a local or remote system, + this API must be called to establish a session with that system's + Local Security Authority (LSA) subsystem. This API connects to + the LSA of the target system and opens the object representing + the target system's Local Security Policy database. A handle to + the object is returned. This handle must be used on all subsequent API + calls to administer the Local Security Policy information for the + target system. + +Arguments: + + SystemName - Name of the target system to be administered. + Administration of the local system is assumed if NULL is specified. + + ObjectAttributes - Pointer to the set of attributes to use for this + connection. The security Quality Of Service information is used and + normally should provide Security Identification level of + impersonation. Some operations, however, require Security + Impersonation level of impersonation. + + DesiredAccess - This is an access mask indicating accesses being + requested for the LSA Subsystem's LSA Database. These access types + are reconciled with the Discretionary Access Control List of the + target LsaDatabase object to determine whether the + accesses will be granted or denied. + + PolicyHandle - Receives a handle to be used in future requests to + access the Local Security Policy of the target system. This handle + represents both the handle to the LsaDatabase object and + the RPC Context Handle for the connection to the target LSA + susbsystem. + + +Return Values: + + NTSTATUS - Standard Nt Result Code + + STATUS_ACCESS_DENIED - Caller does not have access to the target + system's LSA Database, or does not have other desired accesses. + +--*/ + +{ + NTSTATUS Status = STATUS_SUCCESS; + PLSAPR_SERVER_NAME ServerName = NULL; + USHORT NullTerminatedServerNameLength; + + RpcTryExcept { + + // + // Get the Server Name as a Unicode String buffer. Set it to + // NULL (i.e. local machine) if a zero length or NULL Unicode String + // structure us passed. If a non NULL server name is given, we must + // ensure that it is terminated with a NULL wide character. Allocate + // a buffer that is one wide character longer than the server name + // buffer, copy the server name to that buffer and append a trailing + // NULL wide character. + // + + if (ARGUMENT_PRESENT(SystemName) && + (SystemName->Buffer != NULL) && + (SystemName->Length > 0)) { + + NullTerminatedServerNameLength = SystemName->Length + (USHORT) sizeof (WCHAR); + + ServerName = MIDL_user_allocate( NullTerminatedServerNameLength ); + + if (ServerName != NULL) { + + RtlZeroMemory( ServerName, NullTerminatedServerNameLength ); + + RtlMoveMemory( + ServerName, + SystemName->Buffer, + SystemName->Length + ); + + } else { + + Status = STATUS_INSUFFICIENT_RESOURCES; + } + } + + if (NT_SUCCESS(Status)) { + + *PolicyHandle = NULL; + + ObjectAttributes->RootDirectory = NULL; + + Status = LsarOpenPolicy2( + ServerName, + (PLSAPR_OBJECT_ATTRIBUTES) ObjectAttributes, + DesiredAccess, + (PLSAPR_HANDLE) PolicyHandle + ); + } + + } RpcExcept( EXCEPTION_EXECUTE_HANDLER ) { + + Status = LsapApiReturnResult(I_RpcMapWin32Status(RpcExceptionCode())); + + } RpcEndExcept; + + // + // If the open failed because the new API doesn't exist, try the + // old one. + // + + if ((Status == RPC_NT_UNKNOWN_IF) || + (Status == RPC_NT_PROCNUM_OUT_OF_RANGE)) { + + RpcTryExcept { + ASSERT(*PolicyHandle == NULL); + ASSERT(ObjectAttributes->RootDirectory == NULL); + + Status = LsarOpenPolicy( + ServerName, + (PLSAPR_OBJECT_ATTRIBUTES) ObjectAttributes, + DesiredAccess, + (PLSAPR_HANDLE) PolicyHandle + ); + + + } RpcExcept( EXCEPTION_EXECUTE_HANDLER ) { + + Status = LsapApiReturnResult(I_RpcMapWin32Status(RpcExceptionCode())); + + } RpcEndExcept; + + } + + // + // If necessary, free the NULL-terminated server name buffer. + // + + if (ServerName != NULL) { + + MIDL_user_free( ServerName ); + } + + return Status; +} + + +NTSTATUS +LsaQueryInformationPolicy( + IN LSA_HANDLE PolicyHandle, + IN POLICY_INFORMATION_CLASS InformationClass, + OUT PVOID *Buffer + ) + +/*++ + +Routine Description: + + The LsaQueryInformationPolicy API obtains information from the Policy + object. The caller must have access appropriate to the information + being requested (see InformationClass parameter). + +Arguments: + + PolicyHandle - Handle from an LsaOpenPolicy call. + + InformationClass - Specifies the information to be returned. The + Information Classes and accesses required are as follows: + + Information Class Required Access Type + + PolicyAuditLogInformation POLICY_VIEW_AUDIT_INFORMATION + PolicyAuditEventsInformation POLICY_VIEW_AUDIT_INFORMATION + PolicyPrimaryDomainInformation POLICY_VIEW_LOCAL_INFORMATION + PolicyAccountDomainInformation POLICY_VIEW_LOCAL_INFORMATION + PolicyPdAccountInformation POLICY_GET_PRIVATE_INFORMATION + PolicyLsaServerRoleInformation POLICY_VIEW_LOCAL_INFORMATION + PolicyReplicaSourceInformation POLICY_VIEW_LOCAL_INFORMATION + PolicyDefaultQuotaInformation POLICY_VIEW_LOCAL_INFORMATION + + Buffer - receives a pointer to the buffer returned comtaining the + requested information. This buffer is allocated by this service + and must be freed when no longer needed by passing the returned + value to LsaFreeMemory(). + +Return Value: + + NTSTATUS - Standard Nt Result Code + + STATUS_ACCESS_DENIED - Caller does not have the appropriate + access to complete the operation. + + Others TBS +--*/ + +{ + NTSTATUS Status; + + PLSAPR_POLICY_INFORMATION PolicyInformation = NULL; + + RpcTryExcept { + + // + // Call the Client Stub for LsaQueryInformationPolicy. + // + + Status = LsarQueryInformationPolicy( + (LSAPR_HANDLE) PolicyHandle, + InformationClass, + &PolicyInformation + ); + + // + // Return pointer to Policy Information for the given class, or NULL. + // + + *Buffer = PolicyInformation; + + } RpcExcept( EXCEPTION_EXECUTE_HANDLER ) { + + // + // If memory was allocated for the returned Policy Information, + // free it. + // + + if (PolicyInformation != NULL) { + + MIDL_user_free(PolicyInformation); + } + + Status = LsapApiReturnResult(I_RpcMapWin32Status(RpcExceptionCode())); + + } RpcEndExcept; + + + return Status; +} + + +NTSTATUS +LsaSetInformationPolicy( + IN LSA_HANDLE PolicyHandle, + IN POLICY_INFORMATION_CLASS InformationClass, + IN PVOID Buffer + ) + +/*++ + +Routine Description: + + The LsaSetInformationPolicy API modifies information in the Policy Object. + The caller must have access appropriate to the information to be changed + in the Policy Object, see the InformationClass parameter. + +Arguments: + + PolicyHandle - Handle from an LsaOpenPolicy call. + + InformationClass - Specifies the type of information being changed. + The information types and accesses required to change them are as + follows: + + PolicyAuditLogInformation POLICY_AUDIT_LOG_ADMIN + PolicyAuditEventsInformation POLICY_SET_AUDIT_REQUIREMENTS + PolicyPrimaryDomainInformation POLICY_TRUST_ADMIN + PolicyAccountDomainInformation POLICY_TRUST_ADMIN + PolicyPdAccountInformation Not settable by this API + PolicyLsaServerRoleInformation POLICY_SERVER_ADMIN + PolicyReplicaSourceInformation POLICY_SERVER_ADMIN + PolicyDefaultQuotaInformation POLICY_SET_DEFAULT_QUOTA_LIMITS + + Buffer - Points to a structure containing the information appropriate + to the information type specified by the InformationClass parameter. + +Return Value: + + NTSTATUS - Standard Nt Result Code + + STATUS_ACCESS_DENIED - Caller does not have the appropriate access + to complete the operation. + + Others TBS +--*/ + +{ + NTSTATUS Status; + + RpcTryExcept { + + // + // Call the Client Stub for LsaSetInformationPolicy. + // + + Status = LsarSetInformationPolicy( + (LSAPR_HANDLE) PolicyHandle, + InformationClass, + (PLSAPR_POLICY_INFORMATION) Buffer + ); + + } RpcExcept( EXCEPTION_EXECUTE_HANDLER ) { + + Status = LsapApiReturnResult(I_RpcMapWin32Status(RpcExceptionCode())); + + } RpcEndExcept; + + return Status; +} + + +NTSTATUS +LsaClearAuditLog( + IN LSA_HANDLE PolicyHandle + ) + +/*++ + +Routine Description: + + This function clears the Audit Log. Caller must have POLICY_AUDIT_LOG_ADMIN + access to the Policy Object to perform this operation. + +Arguments: + + PolicyHandle - handle from an LsaOpenPolicy call. + +Return Values: + + NTSTATUS - Standard Nt Result Code. + + STATUS_SUCCESS - The call completed successfully. + + STATUS_ACCESS_DENIED - Caller does not have the required access + to perform the operation. + + STATUS_INSUFFICIENT_RESOURCES - Insufficient system resources, + such as memory, to complete the call. + + STATUS_INVALID_HANDLE - PolicyHandle is not a valid handle to + a Policy Object. +--*/ + +{ + NTSTATUS Status; + + RpcTryExcept { + + // + // Call the Client Stub for LsaClearAuditLog. + // + + Status = LsarClearAuditLog( + (LSAPR_HANDLE) PolicyHandle + ); + + } RpcExcept( EXCEPTION_EXECUTE_HANDLER ) { + + Status = LsapApiReturnResult(I_RpcMapWin32Status(RpcExceptionCode())); + + } RpcEndExcept; + + return(Status); +} + + + +NTSTATUS +LsaLookupPrivilegeValue( + IN LSA_HANDLE PolicyHandle, + IN PUNICODE_STRING Name, + OUT PLUID Value + ) + +/*++ + +Routine Description: + + This function retrieves the value used on the target system + to locally represent the specified privilege. The privilege + is specified by programmatic name. + + +Arguments: + + PolicyHandle - Handle from an LsaOpenPolicy() call. This handle + must be open for POLICY_LOOKUP_NAMES access. + + Name - Is the privilege's programmatic name. + + Value - Receives the locally unique ID the privilege is known by on the + target machine. + + + +Return Value: + + NTSTATUS - The privilege was found and returned. + + STATUS_ACCESS_DENIED - Caller does not have the appropriate access + to complete the operation. + + STATUS_NO_SUCH_PRIVILEGE - The specified privilege could not be + found. + +--*/ + +{ + NTSTATUS Status; + LUID Buffer; + + RpcTryExcept { + + // + // Call the Client Stub for LsaLookupPrivilegeValue. + // + + Status = LsarLookupPrivilegeValue( + (LSAPR_HANDLE) PolicyHandle, + (PLSAPR_UNICODE_STRING)Name, + &Buffer + ); + + *Value = Buffer; + + } RpcExcept( EXCEPTION_EXECUTE_HANDLER ) { + + Status = LsapApiReturnResult(I_RpcMapWin32Status(RpcExceptionCode())); + + } RpcEndExcept; + + return(Status); +} + + +NTSTATUS +LsaLookupPrivilegeName( + IN LSA_HANDLE PolicyHandle, + IN PLUID Value, + OUT PUNICODE_STRING *Name + ) + +/*++ + +Routine Description: + + This function programmatic name corresponding to the privilege + represented on the target system by the provided LUID. + + +Arguments: + + PolicyHandle - Handle from an LsaOpenPolicy() call. This handle + must be open for POLICY_LOOKUP_NAMES access. + + Value - is the locally unique ID the privilege is known by on the + target machine. + + Name - Receives the privilege's programmatic name. + + + +Return Value: + + NTSTATUS - The privilege was found and returned. + + STATUS_ACCESS_DENIED - Caller does not have the appropriate access + to complete the operation. + + STATUS_NO_SUCH_PRIVILEGE - The specified privilege could not be + found. + +--*/ + +{ + + NTSTATUS Status; + PLSAPR_UNICODE_STRING Buffer = NULL; + + RpcTryExcept { + + // + // Call the Client Stub for LsaLookupPrivilegeName. + // + + Status = LsarLookupPrivilegeName( + (LSAPR_HANDLE) PolicyHandle, + Value, + &Buffer + ); + + (*Name) = (PUNICODE_STRING)Buffer; + + } RpcExcept( EXCEPTION_EXECUTE_HANDLER ) { + + // + // If memory was allocated for the return buffer, free it. + // + + if (Buffer != NULL) { + + MIDL_user_free(Buffer); + } + + Status = LsapApiReturnResult(I_RpcMapWin32Status(RpcExceptionCode())); + + } RpcEndExcept; + + + return(Status); + + +} + + + +NTSTATUS +LsaLookupPrivilegeDisplayName( + IN LSA_HANDLE PolicyHandle, + IN PUNICODE_STRING Name, + OUT PUNICODE_STRING *DisplayName, + OUT PSHORT LanguageReturned + ) + +/*++ + +Routine Description: + + This function retrieves a displayable name representing the + specified privilege. + + +Arguments: + + PolicyHandle - Handle from an LsaOpenPolicy() call. This handle + must be open for POLICY_LOOKUP_NAMES access. + + Name - The programmatic privilege name to look up. + + DisplayName - Receives a pointer to the privilege's displayable + name. + + LanguageReturned - Receives the language of the returned displayable + name. + + +Return Value: + + NTSTATUS - The privilege text was found and returned. + + + STATUS_ACCESS_DENIED - Caller does not have the appropriate access + to complete the operation. + + + STATUS_NO_SUCH_PRIVILEGE - The specified privilege could not be + found. + +--*/ +{ + + NTSTATUS Status; + SHORT ClientLanguage, ClientSystemDefaultLanguage; + PLSAPR_UNICODE_STRING Buffer = NULL; + + RpcTryExcept { + + // + // Call the Client Stub for LsaLookupPrivilegeDisplayName. + // + + ClientLanguage = (SHORT)NtCurrentTeb()->CurrentLocale; + ClientSystemDefaultLanguage = ClientLanguage; //no sys default yet + Status = LsarLookupPrivilegeDisplayName( + (LSAPR_HANDLE) PolicyHandle, + (PLSAPR_UNICODE_STRING)Name, + ClientLanguage, + ClientSystemDefaultLanguage, + &Buffer, + (PWORD)LanguageReturned + ); + + (*DisplayName) = (PUNICODE_STRING)Buffer; + + } RpcExcept( EXCEPTION_EXECUTE_HANDLER ) { + + // + // If memory was allocated for the return buffer, free it. + // + + if (Buffer != NULL) { + + MIDL_user_free(Buffer); + } + + Status = LsapApiReturnResult(I_RpcMapWin32Status(RpcExceptionCode())); + + } RpcEndExcept; + + + return(Status); +} + + + + +NTSTATUS +LsaClose( + IN LSA_HANDLE ObjectHandle + ) + +/*++ + +Routine Description: + + This API closes a handle to the LsaDatabase object or open object within + the database. If a handle to the LsaDatabase object is closed and there + are no objects still open within the current connection to the LSA, the + connection is closed. If a handle to an object within the database is + closed and the object is marked for DELETE access, the object will be + deleted when the last handle to that object is closed. + +Arguments: + + ObjectHandle - This parameter is either a handle to the LsaDatabase + object, which represents the entire LSA Database and also a + connection to the LSA of a target system, or a handle to an + object within the database. + +Return Value: + + NTSTATUS - Standard Nt Result Code + +--*/ + +{ + NTSTATUS Status; + + LSAPR_HANDLE Handle = (LSAPR_HANDLE) ObjectHandle; + + RpcTryExcept { + + // + // Call the Client Stub for LsaClose. Note that an additional + // level of indirection for the context handle parameter is required + // for the stub, because the server returns a NULL pointer to the handle + // so that the handle will be unbound by the stub. + // + + Status = LsarClose( &Handle ); + + } RpcExcept( EXCEPTION_EXECUTE_HANDLER ) { + + Status = LsapApiReturnResult(I_RpcMapWin32Status(RpcExceptionCode())); + if ((Status != RPC_NT_SS_CONTEXT_MISMATCH) && + (Status != RPC_NT_INVALID_BINDING)) { + (void) RpcSsDestroyClientContext(&Handle); + } + + } RpcEndExcept; + + return Status; +} + + + +NTSTATUS +LsaDelete( + IN LSA_HANDLE ObjectHandle + ) + +/*++ + +Routine Description: + + The LsaDelete API deletes an object. The object must be + open for DELETE access. + +Arguments: + + ObjectHandle - Handle from an LsaOpen call. + + None. + +Return Value: + + NTSTATUS - Standard Nt Result Code + + STATUS_ACCESS_DENIED - Caller does not have the appropriate access + to complete the operation. + + STATUS_INVALID_HANDLE - The specified handle is not valid. + + Result codes from RPC. +--*/ + +{ + NTSTATUS Status; + + RpcTryExcept { + + // + // Try calling the new worker routine LsarDeleteObject(). If + // this fails because it does not exist (versions 1.369 and earlier) + // then call the old routine LsarDelete(). + // + + Status = LsarDeleteObject((LSAPR_HANDLE *) &ObjectHandle); + + } RpcExcept( EXCEPTION_EXECUTE_HANDLER ) { + + Status = LsapApiReturnResult(I_RpcMapWin32Status(RpcExceptionCode())); + + } RpcEndExcept; + + if ((Status == RPC_NT_UNKNOWN_IF) || + (Status == RPC_NT_PROCNUM_OUT_OF_RANGE)) { + + RpcTryExcept { + + Status = LsarDelete((LSAPR_HANDLE) ObjectHandle); + + } RpcExcept( EXCEPTION_EXECUTE_HANDLER ) { + + Status = LsapApiReturnResult(I_RpcMapWin32Status(RpcExceptionCode())); + + } RpcEndExcept; + } + + return(Status); +} + + +NTSTATUS +LsaQuerySecurityObject( + IN LSA_HANDLE ObjectHandle, + IN SECURITY_INFORMATION SecurityInformation, + OUT PSECURITY_DESCRIPTOR *SecurityDescriptor + ) + +/*++ + +Routine Description: + + The LsaQuerySecurityObject API returns security information assigned + to an LSA Database object. + + Based on the caller's access rights and privileges, this procedure will + return a security descriptor containing any or all of the object's owner + ID, group ID, discretionary ACL or system ACL. To read the owner ID, + group ID, or the discretionary ACL, the caller must be granted + READ_CONTROL access to the object. To read the system ACL, the caller must + have SeSecurityPrivilege privilege. + + This API is modelled after the NtQuerySecurityObject() system service. + +Arguments: + + ObjectHandle - A handle to an existing object in the LSA Database. + + SecurityInformation - Supplies a value describing which pieces of + security information are being queried. The values that may be + specified are the same as those defined in the NtSetSecurityObject() + API section. + + SecurityDescriptor - receives a pointer to a buffer containing the + requested security information. This information is returned in + the form of a security descriptor. The caller is responsible for + freeing the returned buffer using LsaFreeMemory() when no longer + needed. + +Return Values: + + NTSTATUS - Standard Nt Result Code + + STATUS_ACCESS_DENIED - Caller does not have the appropriate access + to complete the operation. + + STATUS_INVALID_PARAMETER - An invalid parameter has been specified. +--*/ + +{ + NTSTATUS Status; + LSAPR_SR_SECURITY_DESCRIPTOR ReturnedSD; + PLSAPR_SR_SECURITY_DESCRIPTOR PReturnedSD; + + // + // The retrieved security descriptor is returned via a data structure that + // looks like: + // + // +-----------------------+ + // | Length (bytes) | + // |-----------------------| +--------------+ + // | SecurityDescriptor ---|--------->| Self-Relative| + // +-----------------------+ | Security | + // | Descriptor | + // +--------------+ + // + // The first of these buffers is a local stack variable. The buffer containing + // the self-relative security descriptor is allocated by the RPC runtime. The + // pointer to the self-relative security descriptor is what is passed back to our + // caller. + // + // + + // + // To prevent RPC from trying to marshal a self-relative security descriptor, + // make sure its field values are appropriately initialized to zero and null. + // + + ReturnedSD.Length = 0; + ReturnedSD.SecurityDescriptor = NULL; + + // + // Call the server ... + // + + + RpcTryExcept{ + + PReturnedSD = &ReturnedSD; + + Status = LsarQuerySecurityObject( + (LSAPR_HANDLE) ObjectHandle, + SecurityInformation, + &PReturnedSD + ); + + if (NT_SUCCESS(Status)) { + + (*SecurityDescriptor) = ReturnedSD.SecurityDescriptor; + + } else { + + (*SecurityDescriptor) = NULL; + } + + } RpcExcept( EXCEPTION_EXECUTE_HANDLER ) { + + Status = LsapApiReturnResult(I_RpcMapWin32Status(RpcExceptionCode())); + + } RpcEndExcept; + + if (!NT_SUCCESS(Status)) { + + goto QuerySecurityObjectError; + } + +QuerySecurityObjectFinish: + + return(Status); + +QuerySecurityObjectError: + + goto QuerySecurityObjectFinish; +} + + +NTSTATUS +LsaSetSecurityObject( + IN LSA_HANDLE ObjectHandle, + IN SECURITY_INFORMATION SecurityInformation, + IN PSECURITY_DESCRIPTOR SecurityDescriptor + ) + +/*++ + +Routine Description: + + The LsaSetSecurityObject API takes a well formaed Security Descriptor + and assigns specified portions of it to an object. Based on the flags set + in the SecurityInformation parameter and the caller's access rights, this + procedure will replace any or alll of the security information associated + with the object. + + The caller must have WRITE_OWNER access to the object to change the + owner or Primary group of the object. The caller must have WRITE_DAC + access to the object to change the Discretionary ACL. The caller must + have SeSecurityPrivilege to assign a system ACL to an object. + + This API is modelled after the NtSetSecurityObject() system service. + +Arguments: + + ObjectHandle - A handle to an existing object in the LSA Database. + + SecurityInformation - Indicates which security information is to be + applied to the object. The values that may be specified are the + same as those defined in the NtSetSecurityObject() API section. + The value(s) to be assigned are passed in the SecurityDescriptor + parameter. + + SecurityDescriptor - A pointer to a well formed Security Descriptor. + +Return Values: + + NTSTATUS - Standard Nt Result Code + + STATUS_ACCESS_DENIED - Caller does not have the appropriate access + to complete the operation. + + STATUS_INVALID_PARAMETER - An invalid parameter has been specified. +--*/ + +{ + NTSTATUS Status; + ULONG SDLength; + LSAPR_SR_SECURITY_DESCRIPTOR DescriptorToPass; + + // + // Make a self relative security descriptor for use in the RPC call.. + // + + SDLength = 0; + + Status = RtlMakeSelfRelativeSD( SecurityDescriptor, NULL, &SDLength); + + if (Status != STATUS_BUFFER_TOO_SMALL) { + + Status = STATUS_INVALID_PARAMETER; + goto SetSecurityObjectError; + } + + DescriptorToPass.SecurityDescriptor = MIDL_user_allocate( SDLength ); + + Status = STATUS_INSUFFICIENT_RESOURCES; + + if (DescriptorToPass.SecurityDescriptor == NULL) { + + goto SetSecurityObjectError; + + } + + // + // Make an appropriate self-relative security descriptor + // + + Status = RtlMakeSelfRelativeSD( + SecurityDescriptor, + (PSECURITY_DESCRIPTOR)DescriptorToPass.SecurityDescriptor, + &SDLength + ); + + if (!NT_SUCCESS(Status)) { + + goto SetSecurityObjectError; + } + + DescriptorToPass.Length = SDLength; + + RpcTryExcept{ + + Status = LsarSetSecurityObject( + (LSAPR_HANDLE) ObjectHandle, + SecurityInformation, + &DescriptorToPass + ); + + } RpcExcept( EXCEPTION_EXECUTE_HANDLER ) { + + Status = LsapApiReturnResult(I_RpcMapWin32Status(RpcExceptionCode())); + + } RpcEndExcept; + + if (!NT_SUCCESS(Status)) { + + goto SetSecurityObjectError; + } + +SetSecurityObjectFinish: + + // + // If necessary, free the Self Relative SD passed to the worker. + // + + if (DescriptorToPass.SecurityDescriptor != NULL) { + + MIDL_user_free( DescriptorToPass.SecurityDescriptor ); + + DescriptorToPass.SecurityDescriptor = NULL; + } + + return(Status); + +SetSecurityObjectError: + + goto SetSecurityObjectFinish; +} + + +NTSTATUS +LsaChangePassword( + IN PUNICODE_STRING ServerName, + IN PUNICODE_STRING DomainName, + IN PUNICODE_STRING AccountName, + IN PUNICODE_STRING OldPassword, + IN PUNICODE_STRING NewPassword + ) + +/*++ + +Routine Description: + + The LsaChangePassword API is used to change a user account's password. + The user must have appropriate access to the user account and must + know the current password value. + + +Arguments: + + ServerName - The name of the Domain Controller at which the password + can be changed. + + DomainName - The name of the domain in which the account exists. + + AccountName - The name of the account whose password is to be changed. + + NewPassword - The new password value. + + OldPassword - The old (current) password value. + +Return Values: + + NTSTATUS - Standard Nt Result Code + + STATUS_ACCESS_DENIED - Caller does not have the appropriate access + to complete the operation. + + STATUS_ILL_FORMED_PASSWORD - The new password is poorly formed, e.g. + contains characters that can't be entered from the keyboard. + + STATUS_PASSWORD_RESTRICTION - A restriction prevents the password + from being changed. This may be for an number of reasons, + including time restrictions on how often a password may be changed + or length restrictions on the provided (new) password. + + This error might also be returned if the new password matched + a password in the recent history log for the account. Security + administrators indicate how many of the most recently used + passwords may not be re-used. + + STATUS_WRONG_PASSWORD - OldPassword does not contain the user's + current password. + + STATUS_NO_SUCH_USER - The SID provided does not lead to a user + account. + + STATUS_CANT_UPDATE_MASTER - An attempt to update the master copy + of the password was unsuccessful. Please try again later. + +--*/ + +{ + NTSTATUS Status; + + DBG_UNREFERENCED_PARAMETER( ServerName ); + DBG_UNREFERENCED_PARAMETER( DomainName ); + DBG_UNREFERENCED_PARAMETER( AccountName ); + DBG_UNREFERENCED_PARAMETER( OldPassword ); + DBG_UNREFERENCED_PARAMETER( NewPassword ); + + Status = STATUS_NOT_IMPLEMENTED; + + return(Status); +} + + +NTSTATUS +LsaCreateAccount( + IN LSA_HANDLE PolicyHandle, + IN PSID AccountSid, + IN ACCESS_MASK DesiredAccess, + OUT PLSA_HANDLE AccountHandle + ) + +/*++ + +Routine Description: + + The LsaCreateAccount API adds a user or group account to the + list of accounts in the target system's LsaDatabase object. The + newly added account object is initially placed in the opened state and + a handle to it is returned. The caller must have LSA_CREATE_ACCOUNT + access to the LsaDatabase object. + + Note that no check is made to determine whether there is an account + of the given Sid in the target system's Primary Domain (if any), nor + is any check made to verify that the Sid and name describe the same + account. + +Arguments: + + PolicyHandle - Handle from an LsaOpenLsa call. + + AccountSid - Points to the SID of the Account object. + + DesiredAccess - Specifies the accesses to be granted to the newly + created and opened account. + + AccountHandle - Receives a handle to the newly created and opened + account. This handle is used on subsequent accesses to the account + until closed. + +Return Values: + + NTSTATUS - Standard Nt Result Code + + STATUS_ACCESS_DENIED - Caller does not have the appropriate access + to complete the operation. + + STATUS_ACCOUNT_ALREADY_EXISTS - A user or group account object having + the Sid given in AccountInformation already exists. + + STATUS_INVALID_PARAMETER - An invalid parameter has been specified, + one or more of the following apply. + + - CreateDisposition not valid + - A user or group account having the Sid given AccountInformation + already exists, but CreateDisposition = LSA_OBJECT_CREATE. +--*/ + +{ + NTSTATUS Status; + + RpcTryExcept { + + Status = LsarCreateAccount( + (LSAPR_HANDLE) PolicyHandle, + (PLSAPR_SID) AccountSid, + DesiredAccess, + (PLSAPR_HANDLE) AccountHandle + ); + + } RpcExcept( EXCEPTION_EXECUTE_HANDLER ) { + + Status = LsapApiReturnResult(I_RpcMapWin32Status(RpcExceptionCode())); + + } RpcEndExcept; + + return Status; +} + + +NTSTATUS +LsaEnumerateAccounts( + IN LSA_HANDLE PolicyHandle, + IN OUT PLSA_ENUMERATION_HANDLE EnumerationContext, + OUT PVOID *Buffer, + IN ULONG PreferedMaximumLength, + OUT PULONG CountReturned + ) + +/*++ + +Routine Description: + + The LsaEnumerateAccounts API returns information about + Account objects. This call requires + POLICY_VIEW_LOCAL_INFORMATION access to the Policy object. Since there + may be more information than can be returned in a single call of the + routine, multiple calls can be made to get all of the information. To + support this feature, the caller is provided with a handle that can + be used across calls to the API. On the initial call, EnumerationContext + should point to a variable that has been initialized to 0. + +Arguments: + + PolicyHandle - Handle from an LsaOpenLsa call. + + EnumerationContext - API-specific handle to allow multiple calls + (see Routine Description above). + + EnumerationInformation - Receives a pointer to an array of structures + each describing an Account object. Currently, each structure contains + a pointer to the Account Sid. + + PreferedMaximumLength - Prefered maximum length of returned data (in 8-bit + bytes). This is not a hard upper limit, but serves as a guide. Due to + data conversion between systems with different natural data sizes, the + actual amount of data returned may be greater than this value. + + CountReturned - Pointer to location which receives the number of entries + returned. + +Return Values: + + NTSTATUS - Standard Nt Result Code + + STATUS_SUCCESS - The call completed successfully, there may be + more entries. + + STATUS_ACCESS_DENIED - Caller does not have the appropriate access + to complete the operation. + + STATUS_NO_MORE_ENTRIES - There are no more entries. This warning + is returned if there are no more objects to enumerate. Note that + one or more objects may be enumerated on a call that returns this + reply. + + STATUS_INVALID_PARAMETER - Invalid parameter. + + - NULL return pointer for enumeration buffer. +--*/ + +{ + NTSTATUS Status; + + LSAPR_ACCOUNT_ENUM_BUFFER EnumerationBuffer; + + EnumerationBuffer.EntriesRead = 0; + EnumerationBuffer.Information = NULL; + + RpcTryExcept { + + // + // Enumerate the Accounts. On successful return, + // the Enumeration Buffer structure will receive a count + // of the number of Accounts enumerated this call + // and a pointer to an array of Account Information Entries. + // + // EnumerationBuffer -> EntriesRead + // Information -> Account Info for Domain 0 + // Account Info for Domain 1 + // ... + // Account Info for Domain + // (EntriesRead - 1) + // + + Status = LsarEnumerateAccounts( + (LSAPR_HANDLE) PolicyHandle, + EnumerationContext, + &EnumerationBuffer, + PreferedMaximumLength + ); + + // + // Return enumeration information or NULL to caller. + // + // NOTE: "Information" is allocated by the called client stub + // as a single block via MIDL_user_allocate, because Information is + // allocated all-nodes. We can therefore pass back the pointer + // directly to the client, who will be able to free the memory after + // use via LsaFreeMemory() [which makes a MIDL_user_free call]. + // + + *CountReturned = EnumerationBuffer.EntriesRead; + *Buffer = EnumerationBuffer.Information; + + } RpcExcept( EXCEPTION_EXECUTE_HANDLER ) { + + // + // If memory was allocated for the Account Information array, + // free it. + // + + if (EnumerationBuffer.Information != NULL) { + + MIDL_user_free(EnumerationBuffer.Information); + } + + Status = LsapApiReturnResult(I_RpcMapWin32Status(RpcExceptionCode())); + + } RpcEndExcept; + + return Status; +} + + +NTSTATUS +LsaCreateTrustedDomain( + IN LSA_HANDLE PolicyHandle, + IN PLSA_TRUST_INFORMATION TrustedDomainInformation, + IN ACCESS_MASK DesiredAccess, + OUT PLSA_HANDLE TrustedDomainHandle + ) + +/*++ + +Routine Description: + + The LsaCreateTrustedDomain API creates a new TrustedDomain object. The + caller must have POLICY_TRUST_ADMIN access to the Policy Object. + + Note that NO verification is done to check that the given domain name + matches the given SID or that the SID or name represent an actual domain. + +Arguments: + + PolicyHandle - Handle from an LsaOpenPolicy call. + + TrustedDomainInformation - Pointer to structure containing the name and + SID of the new Trusted Domain. + + DesiredAccess - Specifies the accesses to be granted for the newly + created object. + + TrustedDomainHandle - receives a handle referencing the newly created + object. This handle is used on subsequent accesses to the object. + +--*/ + +{ + NTSTATUS Status; + + *TrustedDomainHandle = NULL; + + RpcTryExcept { + + Status = LsarCreateTrustedDomain( + (LSAPR_HANDLE) PolicyHandle, + (PLSAPR_TRUST_INFORMATION) TrustedDomainInformation, + DesiredAccess, + (PLSAPR_HANDLE) TrustedDomainHandle + ); + + } RpcExcept( EXCEPTION_EXECUTE_HANDLER ) { + + Status = LsapApiReturnResult(I_RpcMapWin32Status(RpcExceptionCode())); + + } RpcEndExcept; + + return(Status); +} + + +NTSTATUS +LsaOpenTrustedDomain( + IN LSA_HANDLE PolicyHandle, + IN PSID TrustedDomainSid, + IN ACCESS_MASK DesiredAccess, + OUT PLSA_HANDLE TrustedDomainHandle + ) + +/*++ + +Routine Description: + + The LsaOpenTrustedDomain API opens an existing TrustedDomain object + using the SID as the primary key value. + +Arguments: + + PolicyHandle - An open handle to a Policy object. + + TrustedDomainSid - Pointer to the account's Sid. + + DesiredAccess - This is an access mask indicating accesses being + requested to the target object. + + TrustedDomainHandle - Receives a handle to be used in future requests. + +Return Values: + + NTSTATUS - Standard Nt Result Code + + STATUS_ACCESS_DENIED - Caller does not have the appropriate access + to complete the operation. + + STATUS_TRUSTED_DOMAIN_NOT_FOUND - There is no TrustedDomain object in the + target system's LSA Database having the specified AccountSid. + +--*/ + +{ + NTSTATUS Status; + + RpcTryExcept { + + Status = LsarOpenTrustedDomain( + (LSAPR_HANDLE) PolicyHandle, + (PLSAPR_SID) TrustedDomainSid, + DesiredAccess, + (PLSAPR_HANDLE) TrustedDomainHandle + ); + + } RpcExcept( EXCEPTION_EXECUTE_HANDLER ) { + + Status = LsapApiReturnResult(I_RpcMapWin32Status(RpcExceptionCode())); + + } RpcEndExcept; + + return Status; +} + + +NTSTATUS +LsaQueryInfoTrustedDomain( + IN LSA_HANDLE TrustedDomainHandle, + IN TRUSTED_INFORMATION_CLASS InformationClass, + OUT PVOID *Buffer + ) + +/*++ + +Routine Description: + + The LsaQueryInfoTrustedDomain API obtains information from a + TrustedDomain object. The caller must have access appropriate to the + information being requested (see InformationClass parameter). + +Arguments: + + TrustedDomainHandle - Handle from an LsaOpenTrustedDomain or + LsaCreateTrustedDomain call. + + InformationClass - Specifies the information to be returned. The + Information Classes and accesses required are as follows: + + Information Class Required Access Type + + TrustedAccountNameInformation TRUSTED_QUERY_ACCOUNT_NAME + TrustedControllersInformation TRUSTED_QUERY_CONTROLLERS + TrustedPosixInformation TRUSTED_QUERY_POSIX + + Buffer - Receives a pointer to the buffer returned comtaining the + requested information. This buffer is allocated by this service + and must be freed when no longer needed by passing the returned + value to LsaFreeMemory(). + +Return Value: + + NTSTATUS - Standard Nt Result Code + + STATUS_ACCESS_DENIED - Caller does not have the appropriate + access to complete the operation. + + STATUS_INSUFFICIENT_RESOURCES - Insufficient system resources, + such as memory, to complete the call. +--*/ + +{ + NTSTATUS Status; + + PLSAPR_TRUSTED_DOMAIN_INFO TrustedDomainInformation = NULL; + + RpcTryExcept { + + // + // Call the Client Stub for LsaQueryInformationTrustedDomain. + // + + Status = LsarQueryInfoTrustedDomain( + (LSAPR_HANDLE) TrustedDomainHandle, + InformationClass, + &TrustedDomainInformation + ); + + // + // Return pointer to Policy Information for the given class, or NULL. + // + + *Buffer = TrustedDomainInformation; + + } RpcExcept( EXCEPTION_EXECUTE_HANDLER ) { + + // + // If memory was allocated for the returned Trusted Domain Information, + // free it. + // + + if (TrustedDomainInformation != NULL) { + + MIDL_user_free(TrustedDomainInformation); + } + + Status = LsapApiReturnResult(I_RpcMapWin32Status(RpcExceptionCode())); + + } RpcEndExcept; + + + return Status; +} + + +NTSTATUS +LsaSetInformationTrustedDomain( + IN LSA_HANDLE TrustedDomainHandle, + IN TRUSTED_INFORMATION_CLASS InformationClass, + IN PVOID Buffer + ) + +/*++ + +Routine Description: + + The LsaSetInformationTrustedDomain API modifies information in the Trusted + Domain Object. The caller must have access appropriate to the + information to be changedin the Policy Object, see the InformationClass + parameter. + +Arguments: + + TrustedDomainHandle - Handle from an LsaOpenTrustedDomain or + LsaCreateTrustedDomain call. + + InformationClass - Specifies the type of information being changed. + The information types and accesses required to change them are as + follows: + + TrustedAccountInformation ( Cannot be set ) + TrustedControllersInformation TRUSTED_SET_CONTROLLERS + TrustedPosixOffsetInformation TRUSTED_POSIX_INFORMATION + + Buffer - Points to a structure containing the information appropriate + to the InformationClass parameter. + +Return Value: + + NTSTATUS - Standard Nt Result Code + + STATUS_SUCCESS - Call completed successfully. + + STATUS_ACCESS_DENIED - Caller does not have the appropriate access + to complete the operation. + + STATUS_INSUFFICIENT_RESOURCES - Insufficient system resources, + such as memory, to complete the call. + + STATUS_INVALID_HANDLE - Handle is invalid or is of the wrong type. + + STATUS_INVALID_PARAMETER - Invalid parameter: + Information class invalid + Information class cannot be set +--*/ + +{ + NTSTATUS Status; + + RpcTryExcept { + + // + // Call the Client Stub for LsaSetInformationTrustedDomain + // + + Status = LsarSetInformationTrustedDomain( + (LSAPR_HANDLE) TrustedDomainHandle, + InformationClass, + (PLSAPR_TRUSTED_DOMAIN_INFO) Buffer + ); + + } RpcExcept( EXCEPTION_EXECUTE_HANDLER ) { + + Status = LsapApiReturnResult(I_RpcMapWin32Status(RpcExceptionCode())); + + } RpcEndExcept; + + return Status; +} + + +NTSTATUS +LsaEnumerateTrustedDomains( + IN LSA_HANDLE PolicyHandle, + IN OUT PLSA_ENUMERATION_HANDLE EnumerationContext, + OUT PVOID *Buffer, + IN ULONG PreferedMaximumLength, + OUT PULONG CountReturned + ) + +/*++ + +Routine Description: + + The LsaEnumerateTrustedDomains API returns information about the accounts + in the target system's Policy object. This call requires + POLICY_VIEW_LOCAL_INFORMATION access to the Policy object. Since there + may be more information than can be returned in a single call of the + routine, multiple calls can be made to get all of the information. To + support this feature, the caller is provided with a handle that can + be used across calls to the API. On the initial call, EnumerationContext + should point to a variable that has been initialized to 0. + +Arguments: + + PolicyHandle - Handle from an LsaOpenPolicy call. + + EnumerationContext - API-specific handle to allow multiple calls + (see Routine Description above). + + Buffer - Receives a pointer to a buffer containing enumeration + information. This buffer is an array of structures of type + LSA_TRUST_INFORMATION. If no trusted domains are found, + NULL is returned. + + PreferedMaximumLength - Prefered maximum length of returned data (in 8-bit + bytes). This is not a hard upper limit, but serves as a guide. Due to + data conversion between systems with different natural data sizes, the + actual amount of data returned may be greater than this value. + + CountReturned - Pointer to variable which will receive a count of the + entries returned. + +Return Values: + + NTSTATUS - Standard Nt Result Code + + STATUS_SUCCESS - The call completed successfully, there may be + more entries. + + STATUS_ACCESS_DENIED - Caller does not have the appropriate access + to complete the operation. + + STATUS_NO_MORE_ENTRIES - There are no more entries. This warning + is returned if there are no more objects to enumerate. Note that + one or more objects may be enumerated on a call that returns this + reply. + + STATUS_INVALID_PARAMETER - Invalid parameter. + + - NULL return pointer for enumeration buffer. +--*/ + +{ + NTSTATUS Status; + + LSAPR_TRUSTED_ENUM_BUFFER EnumerationBuffer; + EnumerationBuffer.EntriesRead = 0; + EnumerationBuffer.Information = NULL; + + // + // Verify that caller has provided a return buffer pointer. + // + + if (!ARGUMENT_PRESENT(Buffer)) { + + return(STATUS_INVALID_PARAMETER); + } + + + RpcTryExcept { + + // + // Enumerate the Trusted Domains. On successful return, + // the Enumeration Buffer structure will receive a count + // of the number of Trusted Domains enumerated this call + // and a pointer to an array of Trust Information Entries. + // + // EnumerationBuffer -> EntriesRead + // Information -> Trust Info for Domain 0 + // Trust Info for Domain 1 + // ... + // Trust Info for Domain + // (EntriesRead - 1) + // + // + + Status = LsarEnumerateTrustedDomains( + (LSAPR_HANDLE) PolicyHandle, + EnumerationContext, + &EnumerationBuffer, + PreferedMaximumLength + ); + + // + // Return enumeration information or NULL to caller. + // + // NOTE: "Information" is allocated by the called client stub + // as a single block via MIDL_user_allocate, because Information is + // allocated all-nodes. We can therefore pass back the pointer + // directly to the client, who will be able to free the memory after + // use via LsaFreeMemory() [which makes a MIDL_user_free call]. + // + + *CountReturned = EnumerationBuffer.EntriesRead; + *Buffer = EnumerationBuffer.Information; + + } RpcExcept( EXCEPTION_EXECUTE_HANDLER ) { + + // + // If memory was allocated for the Trust Information array, + // free it. + // + + if (EnumerationBuffer.Information != NULL) { + + MIDL_user_free(EnumerationBuffer.Information); + } + + Status = LsapApiReturnResult(I_RpcMapWin32Status(RpcExceptionCode())); + + } RpcEndExcept; + + + return Status; +} + +NTSTATUS +LsaEnumeratePrivileges( + IN LSA_HANDLE PolicyHandle, + IN OUT PLSA_ENUMERATION_HANDLE EnumerationContext, + OUT PVOID *Buffer, + IN ULONG PreferedMaximumLength, + OUT PULONG CountReturned + ) + +/*++ + +Routine Description: + + This function returnes information about privileges known on this + system. This call requires POLICY_VIEW_LOCAL_INFORMATION access + to the Policy Object. Since there may be more information than + can be returned in a single call of the routine, multiple calls + can be made to get all of the information. To support this feature, + the caller is provided with a handle that can be used across calls to + the API. On the initial call, EnumerationContext should point to a + variable that has been initialized to 0. + + WARNING! CURRENTLY, THIS FUNCTION ONLY RETURNS INFORMATION ABOUT + WELL-KNOWN PRIVILEGES. LATER, IT WILL RETURN INFORMATION + ABOUT LOADED PRIVILEGES. +Arguments: + + PolicyHandle - Handle from an LsaOpenPolicy() call. + + EnumerationContext - API specific handle to allow multiple calls + (see Routine Description). + + Buffer - Receives a pointer to a buffer containing information for + one or more Privileges. This information is an array of structures + of type POLICY_PRIVILEGE_DEFINITION. + + When this information is no longer needed, it must be released by + passing the returned pointer to LsaFreeMemory(). + + PreferedMaximumLength - Prefered maximim length of returned data + (in 8-bit bytes). This is not a hard upper limit, but serves as + a guide. Due to data conversion between systems with different + natural data sizes, the actual amount of data returned may be + greater than this value. + + CountReturned - Number of entries returned. + +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. + + STATUS_INVALID_HANDLE - PolicyHandle is not a valid handle to + a Policy object. + + STATUS_ACCESS_DENIED - The caller does not have the necessary + access to perform the operation. + + STATUS_MORE_ENTRIES - There are more entries, so call again. This + is an informational status only. + + STATUS_NO_MORE_ENTRIES - No entries were returned because there + are no more. + + Errors from RPC. + +--*/ + +{ + NTSTATUS Status; + LSAPR_PRIVILEGE_ENUM_BUFFER EnumerationBuffer; + + EnumerationBuffer.Entries = 0; + EnumerationBuffer.Privileges = NULL; + + RpcTryExcept { + + // + // Enumerate the Privileges. On successful return, + // the Enumeration Buffer structure will receive a count + // of the number of Privileges enumerated this call + // and a pointer to an array of Privilege Definition Entries. + // + // EnumerationBuffer -> Entries + // Privileges -> Privilege Definition 0 + // Privilege Definition 1 + // ... + // Privilege Definition + // (Entries - 1) + // + + Status = LsarEnumeratePrivileges( + (LSAPR_HANDLE) PolicyHandle, + EnumerationContext, + &EnumerationBuffer, + PreferedMaximumLength + ); + + // + // Return enumeration information or NULL to caller. + // + // NOTE: "Information" is allocated by the called client stub + // as a single block via MIDL_user_allocate, because Information is + // allocated all-nodes. We can therefore pass back the pointer + // directly to the client, who will be able to free the memory after + // use via LsaFreeMemory() [which makes a MIDL_user_free call]. + // + + *CountReturned = EnumerationBuffer.Entries; + *Buffer = EnumerationBuffer.Privileges; + + } RpcExcept( EXCEPTION_EXECUTE_HANDLER ) { + + // + // If memory was allocated for the Account Information array, + // free it. + // + + if (EnumerationBuffer.Privileges != NULL) { + + MIDL_user_free(EnumerationBuffer.Privileges); + } + + Status = LsapApiReturnResult(I_RpcMapWin32Status(RpcExceptionCode())); + + } RpcEndExcept; + + return Status; +} + + +NTSTATUS +LsaCreateSecret( + IN LSA_HANDLE PolicyHandle, + IN PUNICODE_STRING SecretName, + IN ACCESS_MASK DesiredAccess, + OUT PLSA_HANDLE SecretHandle + ) + +/*++ + +Routine Description: + + The LsaCreateSecretInLsa API creates a named Secret object in the + Lsa Database. Each Secret Object can have two values assigned, + called the Current Value and the Old Value. The meaning of these + values is known to the Secret object creator. The caller must have + LSA_CREATE_SECRET access to the LsaDatabase object. + +Arguments: + + PolicyHandle - Handle from an LsaOpenLsa call. + + SecretName - Pointer to Unicode String specifying the name of the + secret. + + DesiredAccess - Specifies the accesses to be granted to the newly + created and opened secret. + + SecretHandle - Receives a handle to the newly created and opened + Secret object. This handle is used on subsequent accesses to + the object until closed. + +Return Values: + + NTSTATUS - Standard Nt Result Code + + STATUS_ACCESS_DENIED - Caller does not have the appropriate access + to complete the operation. + + STATUS_OBJECT_NAME_COLLISION - A Secret object having the given name + already exists. + + STATUS_TOO_MANY_SECRETS - The maximum number of Secret objects in the + system has been reached. +--*/ + +{ + NTSTATUS Status; + + *SecretHandle = NULL; + + RpcTryExcept { + + // + // Verify that the given SecretName has non-null length. Currently + // midl cannot handle this. + // + + if ((SecretName == NULL) || + (SecretName->Buffer == NULL) || + (SecretName->Length == 0) || + (SecretName->Length > SecretName->MaximumLength)) { + + Status = STATUS_INVALID_PARAMETER; + + } else { + + Status = LsarCreateSecret( + (LSAPR_HANDLE) PolicyHandle, + (PLSAPR_UNICODE_STRING) SecretName, + DesiredAccess, + (PLSAPR_HANDLE) SecretHandle + ); + } + + } RpcExcept( EXCEPTION_EXECUTE_HANDLER ) { + + Status = LsapApiReturnResult(I_RpcMapWin32Status(RpcExceptionCode())); + + } RpcEndExcept; + + return(Status); +} + + +NTSTATUS +LsaLookupNames( + IN LSA_HANDLE PolicyHandle, + IN ULONG Count, + IN PUNICODE_STRING Names, + OUT PLSA_REFERENCED_DOMAIN_LIST *ReferencedDomains, + OUT PLSA_TRANSLATED_SID *Sids + ) + +/*++ + +Routine Description: + + The LsaLookupNames API attempts to translate names of domains, users, + groups or aliases to Sids. The caller must have POLICY_LOOKUP_NAMES + access to the Policy object. + + Names may be either isolated (e.g. JohnH) or composite names containing + both the domain name and account name. Composite names must include a + backslash character separating the domain name from the account name + (e.g. Acctg\JohnH). An isolated name may be either an account name + (user, group, or alias) or a domain name. + + Translation of isolated names introduces the possibility of name + collisions (since the same name may be used in multiple domains). An + isolated name will be translated using the following algorithm: + + If the name is a well-known name (e.g. Local or Interactive), then the + corresponding well-known Sid is returned. + + If the name is the Built-in Domain's name, then that domain's Sid + will be returned. + + If the name is the Account Domain's name, then that domain's Sid + will be returned. + + If the name is the Primary Domain's name, then that domain's Sid will + be returned. + + If the name is a user, group, or alias in the Built-in Domain, then the + Sid of that account is returned. + + If the name is a user, group, or alias in the Primary Domain, then the + Sid of that account is returned. + + Otherwise, the name is not translated. + + NOTE: Proxy, Machine, and Trust user accounts are not referenced + for name translation. Only normal user accounts are used for ID + translation. If translation of other account types is needed, then + SAM services should be used directly. + +Arguments: + + This function is the LSA server RPC worker routine for the + LsaLookupNamesInLsa API. + + PolicyHandle - Handle from an LsaOpenPolicy call. + + Count - Specifies the number of names to be translated. + + Names - Pointer to an array of Count Unicode String structures + specifying the names to be looked up and mapped to Sids. + The strings may be names of User, Group or Alias accounts or + domains. + + ReferencedDomains - receives a pointer to a structure describing the + domains used for the translation. The entries in this structure + are referenced by the structure returned via the Sids parameter. + Unlike the Sids parameter, which contains an array entry for + each translated name, this structure will only contain one + component for each domain utilized in the translation. + + When this information is no longer needed, it must be released + by passing the returned pointer to LsaFreeMemory(). + + Sids - Receives a pointer to an array of records describing each + translated Sid. The nth entry in this array provides a translation + for (the nth element in the Names parameter. + + When this information is no longer needed, it must be released + by passing the returned pointer to LsaFreeMemory(). + +Return Values: + + NTSTATUS - Standard Nt Result Code + + STATUS_ACCESS_DENIED - Caller does not have the appropriate access + to complete the operation. + + STATUS_SOME_NOT_MAPPED - Some or all of the names provided could + not be mapped. This is an informational status only. + + STATUS_INSUFFICIENT_RESOURCES - Insufficient system resources + to complete the call. + + STATUS_TOO_MANY_NAMES - Too many Names have been specified. +--*/ + +{ + NTSTATUS Status; + ULONG MappedCount = 0; + + Status = LsaICLookupNames( + PolicyHandle, + Count, + Names, + (PLSA_REFERENCED_DOMAIN_LIST *) ReferencedDomains, + Sids, + LsapLookupWksta, + &MappedCount + ); + + return(Status); +} + + +NTSTATUS +LsaICLookupNames( + IN LSA_HANDLE PolicyHandle, + IN ULONG Count, + IN PUNICODE_STRING Names, + OUT PLSA_REFERENCED_DOMAIN_LIST *ReferencedDomains, + IN OUT PLSA_TRANSLATED_SID *Sids, + IN LSAP_LOOKUP_LEVEL LookupLevel, + IN OUT PULONG MappedCount + ) + +/*++ + +Routine Description: + + This function is the internal client side version of the LsaLookupNames + API. It is called both from the client side of the Lsa and also + the server side of the LSA (when calling out to another LSA). The + function is identical to the LsaLookupNames API except that there is an + additional parameter, the LookupLevel parameter. + + The LsaLookupNames API attempts to translate names of domains, users, + groups or aliases to Sids. The caller must have POLICY_LOOKUP_NAMES + access to the Policy object. + + Names may be either isolated (e.g. JohnH) or composite names containing + both the domain name and account name. Composite names must include a + backslash character separating the domain name from the account name + (e.g. Acctg\JohnH). An isolated name may be either an account name + (user, group, or alias) or a domain name. + + Translation of isolated names introduces the possibility of name + collisions (since the same name may be used in multiple domains). An + isolated name will be translated using the following algorithm: + + If the name is a well-known name (e.g. Local or Interactive), then the + corresponding well-known Sid is returned. + + If the name is the Built-in Domain's name, then that domain's Sid + will be returned. + + If the name is the Account Domain's name, then that domain's Sid + will be returned. + + If the name is the Primary Domain's name, then that domain's Sid will + be returned. + + If the name is a user, group, or alias in the Built-in Domain, then the + Sid of that account is returned. + + If the name is a user, group, or alias in the Primary Domain, then the + Sid of that account is returned. + + Otherwise, the name is not translated. + + NOTE: Proxy, Machine, and Trust user accounts are not referenced + for name translation. Only normal user accounts are used for ID + translation. If translation of other account types is needed, then + SAM services should be used directly. + +Arguments: + + This function is the LSA server RPC worker routine for the + LsaLookupNamesInLsa API. + + PolicyHandle - Handle from an LsaOpenPolicy call. + + Count - Specifies the number of names to be translated. + + Names - Pointer to an array of Count Unicode String structures + specifying the names to be looked up and mapped to Sids. + The strings may be names of User, Group or Alias accounts or + domains. + + ReferencedDomains - receives a pointer to a structure describing the + domains used for the translation. The entries in this structure + are referenced by the structure returned via the Sids parameter. + Unlike the Sids parameter, which contains an array entry for + each translated name, this structure will only contain one + component for each domain utilized in the translation. + + When this information is no longer needed, it must be released + by passing the returned pointer to LsaFreeMemory(). + + Sids - Receives a pointer to an array of records describing each + translated Sid. The nth entry in this array provides a translation + for (the nth element in the Names parameter. + + When this information is no longer needed, it must be released + by passing the returned pointer to LsaFreeMemory(). + + LookupLevel - Specifies the Level of Lookup to be performed on the + target machine. Values of this field are are follows: + + LsapLookupWksta - First Level Lookup performed on a workstation + normally configured for Windows-Nt. The lookup searches the + Well-Known Sids/Names, and the Built-in Domain and Account Domain + in the local SAM Database. If not all Sids or Names are + identified, performs a "handoff" of a Second level Lookup to the + LSA running on a Controller for the workstation's Primary Domain + (if any). + + LsapLookupPDC - Second Level Lookup performed on a Primary Domain + Controller. The lookup searches the Account Domain of the + SAM Database on the controller. If not all Sids or Names are + found, the Trusted Domain List (TDL) is obtained from the + LSA's Policy Database and Third Level lookups are performed + via "handoff" to each Trusted Domain in the List. + + LsapLookupTDL - Third Level Lookup performed on a controller + for a Trusted Domain. The lookup searches the Account Domain of + the SAM Database on the controller only. + + MappedCount - Pointer to location that contains a count of the Names + mapped so far. On exit, this count will be updated. + +Return Values: + + NTSTATUS - Standard Nt Result Code + + STATUS_ACCESS_DENIED - Caller does not have the appropriate access + to complete the operation. + + STATUS_SOME_NOT_MAPPED - Some or all of the names provided could + not be mapped. This is an informational status only. + + STATUS_INSUFFICIENT_RESOURCES - Insufficient system resources + to complete the call. +--*/ + +{ + NTSTATUS Status; + BOOLEAN SidsArraySpecified = FALSE; + + LSAPR_TRANSLATED_SIDS ReturnedSids; + + // + // Check that we have not specfied more than the maximum number of names + // allowed. + // + + if (Count > LSAP_DB_TRIAL_MAXIMUM_NAME_COUNT) { + + return(STATUS_TOO_MANY_NAMES); + } + + RpcTryExcept { + + // + // If this is a Workstation-Level lookup, the Sids and + // ReferencedDomain Lists have not been created. Since these + // are input parameters in the general case, we need to set them + // to NULL. + // + + if (LookupLevel == LsapLookupWksta) { + + *ReferencedDomains = NULL; + *Sids = NULL; + } + + // + // There may already be a Sid translation array in cases where + // we are called internally (i.e. at a higher LookupLevel than + // LsapLookupWksta). Initialize the ReturnedSids structure + // accordingly. + // + + ReturnedSids.Entries = Count; + ReturnedSids.Sids = *Sids; + + if (*Sids != NULL) { + + SidsArraySpecified = TRUE; + } + + // + // Initiate Lookup of the Sids at the First Level (Workstation + // Level). + // + + Status = LsarLookupNames( + (LSAPR_HANDLE) PolicyHandle, + Count, + (PLSAPR_UNICODE_STRING) Names, + (PLSAPR_REFERENCED_DOMAIN_LIST *) ReferencedDomains, + &ReturnedSids, + LookupLevel, + MappedCount + ); + + // + // Delay checking Status till we leave try clause. + // + + // + // Return pointer to array of Sid translations, or NULL. + // + // NOTE: The array of Sid translations is allocated by the called + // client stub as a single block via MIDL_user_allocate, because + // Information is allocated all-nodes. We can therefore pass back the pointer + // directly to the client, who will be able to free the memory after + // use via LsaFreeMemory() [which makes a MIDL_user_free call]. + // + + *Sids = (PLSA_TRANSLATED_SID) ReturnedSids.Sids; + + } RpcExcept( EXCEPTION_EXECUTE_HANDLER ) { + + // + // If memory was allocated for the Sid translation array, + // free it. + // + + if ((!SidsArraySpecified) && ReturnedSids.Sids != NULL) { + + MIDL_user_free( ReturnedSids.Sids ); + } + + Status = LsapApiReturnResult(I_RpcMapWin32Status(RpcExceptionCode())); + + } RpcEndExcept; + + return(Status); +} + + +NTSTATUS +LsaLookupSids( + IN LSA_HANDLE PolicyHandle, + IN ULONG Count, + IN PSID *Sids, + OUT PLSA_REFERENCED_DOMAIN_LIST *ReferencedDomains, + OUT PLSA_TRANSLATED_NAME *Names + ) + +/*++ + +Routine Description: + + The LsaLookupSids API attempts to find names corresponding to Sids. + If a name can not be mapped to a Sid, the Sid is converted to character + form. The caller must have POLICY_LOOKUP_NAMES access to the Policy + object. + + WARNING: This routine allocates memory for its output. The caller is + responsible for freeing this memory after use. See description of the + Names parameter. + +Arguments: + + PolicyHandle - Handle from an LsaOpenPolicy call. + + Count - Specifies the number of Sids to be translated. + + Sids - Pointer to an array of Count pointers to Sids to be mapped + to names. The Sids may be well_known SIDs, SIDs of User accounts + Group Accounts, Alias accounts, or Domains. + + ReferencedDomains - Receives a pointer to a structure describing the + domains used for the translation. The entries in this structure + are referenced by the strutcure returned via the Names parameter. + Unlike the Names paraemeter, which contains an array entry + for (each translated name, this strutcure will only contain + component for each domain utilized in the translation. + + When this information is no longer needed, it must be released + by passing the returned pointer to LsaFreeMemory(). + + Names - Receives a pointer to array records describing each translated + name. The nth entry in this array provides a translation for + the nth entry in the Sids parameter. + + All of the returned names will be isolated names or NULL strings + (domain names are returned as NULL strings). If the caller needs + composite names, they can be generated by prepending the + isolated name with the domain name and a backslash. For example, + if (the name Sally is returned, and it is from the domain Manufact, + then the composite name would be "Manufact" + "\" + "Sally" or + "Manufact\Sally". + + When this information is no longer needed, it must be released + by passing the returned pointer to LsaFreeMemory(). + + If a Sid is not translatable, then the following will occur: + + 1) If the SID's domain is known, then a reference domain record + will be generated with the domain's name. In this case, the + name returned via the Names parameter is a Unicode representation + of the relative ID of the account, such as "(314)" or the null + string, if the Sid is that of a domain. So, you might end up + with a resultant name of "Manufact\(314) for the example with + Sally above, if Sally's relative id is 314. + + 2) If not even the SID's domain could be located, then a full + Unicode representation of the SID is generated and no domain + record is referenced. In this case, the returned string might + be something like: "(S-1-672194-21-314)". + + When this information is no longer needed, it must be released + by passing the returned pointer to LsaFreeMemory(). + +Return Values: + + NTSTATUS - Standard Nt Result Code + + STATUS_ACCESS_DENIED - Caller does not have the appropriate access + to complete the operation. + + STATUS_SOME_NOT_MAPPED - Some or all of the names provided could not be + mapped. This is a warning only. + + Rest TBS +--*/ + +{ + NTSTATUS Status; + ULONG MappedCount = 0; + + Status = LsaICLookupSids( + PolicyHandle, + Count, + Sids, + ReferencedDomains, + Names, + LsapLookupWksta, + &MappedCount + ); + + return(Status); +} + + +NTSTATUS +LsaICLookupSids( + IN LSA_HANDLE PolicyHandle, + IN ULONG Count, + IN PSID *Sids, + OUT PLSA_REFERENCED_DOMAIN_LIST *ReferencedDomains, + IN OUT PLSA_TRANSLATED_NAME *Names, + IN LSAP_LOOKUP_LEVEL LookupLevel, + IN OUT PULONG MappedCount + ) + +/*++ + +Routine Description: + + This function is the internal client side version of the LsaLookupSids + API. It is called both from the client side of the Lsa and also + the server side of the LSA (when calling out to another LSA). The + function is identical to the LsaLookupSids API except that there is an + additional parameter, the LookupLevel parameter. + + The LsaLookupSids API attempts to find names corresponding to Sids. + If a name can not be mapped to a Sid, the Sid is converted to character + form. The caller must have POLICY_LOOKUP_NAMES access to the Policy + object. + + WARNING: This routine allocates memory for its output. The caller is + responsible for freeing this memory after use. See description of the + Names parameter. + +Arguments: + + PolicyHandle - Handle from an LsaOpenPolicy call. + + Count - Specifies the number of Sids to be translated. + + Sids - Pointer to an array of Count pointers to Sids to be mapped + to names. The Sids may be well_known SIDs, SIDs of User accounts + Group Accounts, Alias accounts, or Domains. + + ReferencedDomains - Receives a pointer to a structure describing the + domains used for the translation. The entries in this structure + are referenced by the strutcure returned via the Names parameter. + Unlike the Names paraemeter, which contains an array entry + for (each translated name, this strutcure will only contain + component for each domain utilized in the translation. + + When this information is no longer needed, it must be released + by passing the returned pointer to LsaFreeMemory(). + + Names - Receives a pointer to array records describing each translated + name. The nth entry in this array provides a translation for + the nth entry in the Sids parameter. + + All of the retruned names will be isolated names or NULL strings + (domain names are returned as NULL strings). If the caller needs + composite names, they can be generated by prepending the + isolated name with the domain name and a backslash. For example, + if (the name Sally is returned, and it is from the domain Manufact, + then the composite name would be "Manufact" + "\" + "Sally" or + "Manufact\Sally". + + When this information is no longer needed, it must be released + by passing the returned pointer to LsaFreeMemory(). + + If a Sid is not translatable, then the following will occur: + + 1) If the SID's domain is known, then a reference domain record + will be generated with the domain's name. In this case, the + name returned via the Names parameter is a Unicode representation + of the relative ID of the account, such as "(314)" or the null + string, if the Sid is that of a domain. So, you might end up + with a resultant name of "Manufact\(314) for the example with + Sally above, if Sally's relative id is 314. + + 2) If not even the SID's domain could be located, then a full + Unicode representation of the SID is generated and no domain + record is referenced. In this case, the returned string might + be something like: "(S-1-672194-21-314)". + + When this information is no longer needed, it must be released + by passing the returned pointer to LsaFreeMemory(). + + LookupLevel - Specifies the Level of Lookup to be performed on the + target machine. Values of this field are are follows: + + LsapLookupWksta - First Level Lookup performed on a workstation + normally configured for Windows-Nt. The lookup searches the + Well-Known Sids, and the Built-in Domain and Account Domain + in the local SAM Database. If not all Sids are + identified, performs a "handoff" of a Second level Lookup to the + LSA running on a Controller for the workstation's Primary Domain + (if any). + + LsapLookupPDC - Second Level Lookup performed on a Primary Domain + Controller. The lookup searches the Account Domain of the + SAM Database on the controller. If not all Sids are + found, the Trusted Domain List (TDL) is obtained from the + LSA's Policy Database and Third Level lookups are performed + via "handoff" to each Trusted Domain in the List. + + LsapLookupTDL - Third Level Lookup performed on a controller + for a Trusted Domain. The lookup searches the Account Domain of + the SAM Database on the controller only. + + MappedCount - Pointer to location that contains a count of the Sids + mapped so far. On exit, this count will be updated. + +Return Values: + + NTSTATUS - Standard Nt Result Code + + STATUS_ACCESS_DENIED - Caller does not have the appropriate access + to complete the operation. + + STATUS_SOME_NOT_MAPPED - Some or all of the names provided could not be + mapped. This is a warning only. + + STATUS_TOO_MANY_SIDS - Too many Sids have been specified. + +--*/ + +{ + NTSTATUS Status; + + BOOLEAN NamesArraySpecified = FALSE; + + LSAPR_SID_ENUM_BUFFER SidEnumBuffer; + + LSAPR_TRANSLATED_NAMES ReturnedNames; + + // + // Verify that the Count is positive and not too high + // + + if (Count == 0) { + + return STATUS_INVALID_PARAMETER; + } + + if (Count > LSAP_DB_TRIAL_MAXIMUM_SID_COUNT) { + + return STATUS_TOO_MANY_SIDS; + } + + SidEnumBuffer.Entries = Count; + SidEnumBuffer.SidInfo = (PLSAPR_SID_INFORMATION) Sids; + + RpcTryExcept { + + // + // If this is a Workstation-Level lookup, the Names and + // ReferencedDomain Lists have not been created. Since these + // are input parameters in the general case, we need to set them + // to NULL. + // + + if (LookupLevel == LsapLookupWksta) { + + *ReferencedDomains = NULL; + *Names = NULL; + } + + // + // There may already be a name translation array in cases where + // we are called internally (i.e. with lookup level higher than + // LsapLookupWksta). Initialize the ReturnedNames structure + // accordingly. + // + + ReturnedNames.Entries = 0; + ReturnedNames.Names = NULL; + + if (*Names != NULL) { + + ReturnedNames.Entries = Count; + ReturnedNames.Names = (PLSAPR_TRANSLATED_NAME) *Names; + NamesArraySpecified = TRUE; + } + + // + // Lookup Sids on the Server.. + // + + Status = LsarLookupSids( + (LSAPR_HANDLE) PolicyHandle, + &SidEnumBuffer, + (PLSAPR_REFERENCED_DOMAIN_LIST *) ReferencedDomains, + &ReturnedNames, + LookupLevel, + MappedCount + ); + + // + // Return the array of translation to name info or NULL. + // + // NOTE: The array of name translations is allocated by the called + // client stub as a single block via MIDL_user_allocate, because + // Information is allocated all-nodes. We can therefore pass back the pointer + // directly to the client, who will be able to free the memory after + // use via LsaFreeMemory() [which makes a MIDL_user_free call]. + // + + *Names = (PLSA_TRANSLATED_NAME) ReturnedNames.Names; + + } RpcExcept( EXCEPTION_EXECUTE_HANDLER ) { + + // + // If memory was allocated for the name translation array, + // free it. + // + + if ((!NamesArraySpecified) && ReturnedNames.Names != NULL) { + + MIDL_user_free( ReturnedNames.Names ); + } + + Status = LsapApiReturnResult(I_RpcMapWin32Status(RpcExceptionCode())); + + } RpcEndExcept; + + return(Status); +} + + +NTSTATUS +LsaOpenAccount( + IN LSA_HANDLE PolicyHandle, + IN PSID AccountSid, + IN ACCESS_MASK DesiredAccess, + OUT PLSA_HANDLE AccountHandle + ) + +/*++ + +Routine Description: + + The LsaOpenAccount API opens an account object in the Lsa Database of the + target system. An account must be opened before any operation can be + performed, including deletion of the account. A handle to the account + object is returned for use on subsequent API calls that access the + account. Before calling this API, the caller must have connected to + the target system's LSA and opened the Policy object by means + of a preceding call to LsaOpenPolicy. + +Arguments: + + PolicyHandle - Handle from an LsaOpenLsa call. + + AccountSid - Pointer to the account's Sid. + + DesiredAccess - This is an access mask indicating accesses being + requested for the LSA Subsystem's LSA Database. These access types + are reconciled with the Discretionary Access Control List of the + target Account object to determine whether the accesses will be + granted or denied. + + AccountHandle - Pointer to location in which a handle to the opened + account object will be returned if the call succeeds. + +Return Values: + + NTSTATUS - Standard Nt Result Code + + STATUS_ACCESS_DENIED - Caller does not have the appropriate access + to complete the operation. + + STATUS_ACCOUNT_DOES_NOT_EXIST - There is no account object in the + target system's LSA Database having the specified AccountSid. + +--*/ + +{ + NTSTATUS Status; + + RpcTryExcept { + + Status = LsarOpenAccount( + (LSAPR_HANDLE) PolicyHandle, + (PLSAPR_SID) AccountSid, + DesiredAccess, + (PLSAPR_HANDLE) AccountHandle + ); + + } RpcExcept( EXCEPTION_EXECUTE_HANDLER ) { + + Status = LsapApiReturnResult(I_RpcMapWin32Status(RpcExceptionCode())); + + } RpcEndExcept; + + return Status; +} + + +NTSTATUS +LsaEnumeratePrivilegesOfAccount( + IN LSA_HANDLE AccountHandle, + OUT PPRIVILEGE_SET *Privileges + ) + +/*++ + +Routine Description: + + The LsaEnumeratePrivilegesOfAccount API obtains information which + describes the privileges assigned to an account. This call requires + LSA_ACCOUNT_VIEW access to the account object. + +Arguments: + + AccountHandle - The handle to the open account object whose privilege + information is to be obtained. This handle will have been returned + from a prior LsaOpenAccount or LsaCreateAccountInLsa API call. + + Privileges - Receives a pointer to a buffer containing the Privilege + Set. The Privilege Set is an array of structures, one for each + privilege. Each structure contains the LUID of the privilege and + a mask of the privilege's attributes. + +Return Values: + + NTSTATUS - Standard Nt Result Code + + STATUS_ACCESS_DENIED - Caller does not have the appropriate access + to complete the operation. + + STATUS_INVALID_HANDLE - The specified AccountHandle is not valid. + +--*/ + +{ + NTSTATUS Status; + + RpcTryExcept { + + *Privileges = NULL; + + Status = LsarEnumeratePrivilegesAccount( + (LSAPR_HANDLE) AccountHandle, + (PLSAPR_PRIVILEGE_SET *) Privileges + ); + + } RpcExcept( EXCEPTION_EXECUTE_HANDLER ) { + + Status = LsapApiReturnResult(I_RpcMapWin32Status(RpcExceptionCode())); + + } RpcEndExcept; + + return Status; +} + + +NTSTATUS +LsaAddPrivilegesToAccount( + IN LSA_HANDLE AccountHandle, + IN PPRIVILEGE_SET Privileges + ) + +/*++ + +Routine Description: + + The LsaAddPrivilegesToAccount API adds privileges and their attributes + to an account object. If any provided privilege is already assigned + to the account object, the attributes of that privilege are replaced + by the newly rpovided values. This API call requires + LSA_ACCOUNT_ADJUST_PRIVILEGES access to the account object. + +Arguments: + + AccountHandle - The handle to the open account object to which + privileges are to be added. This handle will have been returned + from a prior LsaOpenAccount or LsaCreateAccountInLsa API call. + + Privileges - Points to a set of privileges (and their attributes) to + be assigned to the account. + +Return Values: + + NTSTATUS - Standard Nt Result Code + + STATUS_ACCESS_DENIED - Caller does not have the appropriate access + to complete the operation. + + STATUS_INVALID_HANDLE - The specified AccountHandle is not valid. + +--*/ + +{ + NTSTATUS Status; + + RpcTryExcept { + + Status = LsarAddPrivilegesToAccount( + (LSAPR_HANDLE) AccountHandle, + (PLSAPR_PRIVILEGE_SET) Privileges + ); + + } RpcExcept( EXCEPTION_EXECUTE_HANDLER ) { + + Status = LsapApiReturnResult(I_RpcMapWin32Status(RpcExceptionCode())); + + } RpcEndExcept; + + return Status; +} + + +NTSTATUS +LsaRemovePrivilegesFromAccount( + IN LSA_HANDLE AccountHandle, + IN BOOLEAN AllPrivileges, + IN OPTIONAL PPRIVILEGE_SET Privileges + ) + +/*++ + +Routine Description: + + The LsaRemovePrivilegesFromAccount API removes privileges from an + account object. This API call requires LSA_ACCOUNT_ADJUST_PRIVILEGES + access to the account object. Note that if all privileges are removed + from the account object, the account object remains in existence until + deleted explicitly via a call to the LsaDelete API. + +Arguments: + + AccountHandle - The handle to the open account object to which + privileges are to be removed. This handle will have been returned + from a prior LsaOpenAccount or LsaCreateAccountInLsa API call. + + AllPrivileges - If TRUE, then all privileges are to be removed from + the account. In this case, the Privileges parameter must be + specified as NULL. If FALSE, the Privileges parameter specifies + the privileges to be removed, and must be non NULL. + + Privileges - Optionally points to a set of privileges (and their + attributes) to be removed from the account object. The attributes + fields of this structure are ignored. This parameter must + be specified as non-NULL if and only if AllPrivileges is set to + FALSE. + +Return Values: + + NTSTATUS - Standard Nt Result Code + + STATUS_ACCESS_DENIED - Caller does not have the appropriate access + to complete the operation. + + STATUS_INVALID_HANDLE - The specified AccountHandle is not valid. + + STATUS_INVALID_PARAMETER - The optional Privileges paraemter was + specified as NULL and AllPrivileges was set to FALSE. + +--*/ + +{ + NTSTATUS Status; + + RpcTryExcept { + + Status = LsarRemovePrivilegesFromAccount( + (LSAPR_HANDLE) AccountHandle, + AllPrivileges, + (PLSAPR_PRIVILEGE_SET) Privileges + ); + + } RpcExcept( EXCEPTION_EXECUTE_HANDLER ) { + + Status = LsapApiReturnResult(I_RpcMapWin32Status(RpcExceptionCode())); + + } RpcEndExcept; + + return Status; +} + + +NTSTATUS +LsaGetQuotasForAccount( + IN LSA_HANDLE AccountHandle, + OUT PQUOTA_LIMITS QuotaLimits + ) + +/*++ + +Routine Description: + + The LsaGetQuotasForAccount API obtains the quota limits for pageable and + non-pageable memory (in Kilobytes) and the maximum execution time (in + seconds) for any session logged on to the account specified by + AccountHandle. For each quota and explicit value is returned. This + call requires LSA_ACCOUNT_VIEW access to the account object. + +Arguments: + + AccountHandle - The handle to the open account object whose quotas + are to be obtained. This handle will have been returned + from a prior LsaOpenAccount or LsaCreateAccountInLsa API call. + + QuotaLimits - Pointer to structure in which the system resource + quota limits applicable to each session logged on to this account + will be returned. Note that all quotas, including those specified + as being the system default values, are returned as actual values. + +Return Values: + + NTSTATUS - Standard Nt Result Code + + STATUS_INVALID_HANDLE - The specified AccountHandle is not valid. +--*/ + +{ + NTSTATUS Status; + + RpcTryExcept{ + + Status = LsarGetQuotasForAccount( + (LSAPR_HANDLE) AccountHandle, + QuotaLimits + ); + + } RpcExcept( EXCEPTION_EXECUTE_HANDLER ) { + + Status = LsapApiReturnResult(I_RpcMapWin32Status(RpcExceptionCode())); + + } RpcEndExcept; + + return Status; +} + + +NTSTATUS +LsaSetQuotasForAccount( + IN LSA_HANDLE AccountHandle, + IN PQUOTA_LIMITS QuotaLimits + ) + +/*++ + +Routine Description: + + The LsaSetQuotasForAccount API sets the quota limits for pageable and + non-pageable memory (in Kilobytes) and the maximum execution time (in + seconds) for any session logged on to the account specified by + AccountHandle. For each quota an explicit value or the system default + may be specified. This call requires LSA_ACCOUNT_ADJUST_QUOTAS + access to the account object. + +Arguments: + + AccountHandle - The handle to the open account object whose quotas + are to be set. This handle will have been returned from a prior + LsaOpenAccount or LsaCreateAccountInLsa API call. + + QuotaLimits - Pointer to structure containing the system resource + quota limits applicable to each session logged on to this account. + A zero value specified in any field indicates that the current + System Default Quota Limit is to be applied. + +Return Values: + + NTSTATUS - Standard Nt Result Code + + STATUS_INVALID_HANDLE - The specified AccountHandle is not valid. +--*/ + +{ + NTSTATUS Status; + + RpcTryExcept { + + Status = LsarSetQuotasForAccount( + (LSAPR_HANDLE) AccountHandle, + QuotaLimits + ); + + } RpcExcept( EXCEPTION_EXECUTE_HANDLER ) { + + Status = LsapApiReturnResult(I_RpcMapWin32Status(RpcExceptionCode())); + + } RpcEndExcept; + + return Status; +} + + +NTSTATUS +LsaGetSystemAccessAccount( + IN LSA_HANDLE AccountHandle, + OUT PULONG SystemAccess + ) + +/*++ + +Routine Description: + + The LsaGetSystemAccessAccount() service returns the System Access + account flags for an Account object. + +Arguments: + + AccountHandle - The handle to the Account object whose system access + flags are to be read. This handle will have been returned + from a preceding LsaOpenAccount() or LsaCreateAccount() call + an must be open for ACCOUNT_VIEW access. + + SystemAccess - Points to location that will receive the system access + flags for the account. + +Return Values: + + NTSTATUS - Standard Nt Result Code + + STATUS_SUCCESS - The call was successful. + + STATUS_ACCESS_DENIED - The AccountHandle does not specify + ACCOUNT_VIEW access. + + STATUS_INVALID_HANDLE - The specified AccountHandle is invalid. + +--*/ + +{ + NTSTATUS Status; + + // + // Avoid RPC stub code raising exception on NULL handle so that + // we can return the error code STATUS_INVALID_HANDLE in this case + // too. + // + + if (!ARGUMENT_PRESENT(AccountHandle)) { + + return(STATUS_INVALID_HANDLE); + } + + RpcTryExcept{ + + Status = LsarGetSystemAccessAccount( + (LSAPR_HANDLE) AccountHandle, + SystemAccess + ); + + } RpcExcept( EXCEPTION_EXECUTE_HANDLER ) { + + Status = LsapApiReturnResult(I_RpcMapWin32Status(RpcExceptionCode())); + + } RpcEndExcept; + + return(Status); +} + + +NTSTATUS +LsaSetSystemAccessAccount( + IN LSA_HANDLE AccountHandle, + IN ULONG SystemAccess + ) + +/*++ + +Routine Description: + + The LsaSetSystemAccessAccount() service sets the System Access + account flags for an Account object. + +Arguments: + + AccountHandle - The handle to the Account object whose system access + flags are to be read. This handle will have been returned + from a preceding LsaOpenAccount() or LsaCreateAccount() call + an must be open for ACCOUNT_ADJUST_SYSTEM_ACCESS access. + + SystemAccess - A mask of the system access flags to assign to the + Account object. The valid access flags include: + + POLICY_MODE_INTERACTIVE - Account can be accessed interactively + + POLICY_MODE_NETWORK - Account can be accessed remotely + + POLICY_MODE_SERVICE - TBS + +Return Values: + + NTSTATUS - Standard Nt Result Code + + STATUS_SUCCESS - The call was successful. + + STATUS_ACCESS_DENIED - The AccountHandle does not specify + ACCOUNT_VIEW access. + + STATUS_INVALID_HANDLE - The specified AccountHandle is invalid. + + STATUS_INVALID_PARAMETER - The specified Access Flags are invalid. +--*/ + +{ + NTSTATUS Status; + + // + // Avoid RPC stub code raising exception on NULL handle so that + // we can return the error code STATUS_INVALID_HANDLE in this case + // too. + // + + if (!ARGUMENT_PRESENT(AccountHandle)) { + + return(STATUS_INVALID_HANDLE); + } + + RpcTryExcept { + + Status = LsarSetSystemAccessAccount( + (LSAPR_HANDLE) AccountHandle, + SystemAccess + ); + + } RpcExcept( EXCEPTION_EXECUTE_HANDLER ) { + + Status = LsapApiReturnResult(I_RpcMapWin32Status(RpcExceptionCode())); + + } RpcEndExcept; + + return(Status); +} + + +NTSTATUS +LsaFreeMemory( + IN PVOID Buffer + ) + +/*++ + +Routine Description: + + + Some LSA services that return a potentially large amount of memory, + such as an enumeration might, allocate the buffer in which the data + is returned. This function is used to free those buffers when they + are no longer needed. + +Parameters: + + Buffer - Pointer to the buffer to be freed. This buffer must + have been allocated by a previous LSA service call. + +Return Values: + + STATUS_SUCCESS - normal, successful completion. + +--*/ + +{ + NTSTATUS Status = STATUS_SUCCESS; + + RpcTryExcept { + + MIDL_user_free( Buffer ); + + } RpcExcept( EXCEPTION_EXECUTE_HANDLER ) { + + Status = LsapApiReturnResult(I_RpcMapWin32Status(RpcExceptionCode())); + + } RpcEndExcept; + + return Status; +} + + +NTSTATUS +LsapApiReturnResult( + ULONG ExceptionCode + ) + +/*++ + +Routine Description: + + This function converts an exception code or status value returned + from the client stub to a value suitable for return by the API to + the client. + +Arguments: + + ExceptionCode - The exception code to be converted. + +Return Value: + + NTSTATUS - The converted Nt Status code. + +--*/ + +{ + // + // Return the actual value if compatible with Nt status codes, + // otherwise, return STATUS_UNSUCCESSFUL. + // + + if (!NT_SUCCESS((NTSTATUS) ExceptionCode)) { + + return (NTSTATUS) ExceptionCode; + + } else { + + return STATUS_UNSUCCESSFUL; + } +} + + +NTSTATUS +LsaOpenSecret( + IN LSA_HANDLE PolicyHandle, + IN PUNICODE_STRING SecretName, + IN ACCESS_MASK DesiredAccess, + OUT PLSA_HANDLE SecretHandle + ) + +/*++ + +Routine Description: + + The LsaOpenSecret API opens a Secret Object within the LSA Database. + A handle is returned which must be used to perform operations on the + secret object. + +Arguments: + + PolicyHandle - Handle from an LsaOpenLsa call. + + SecretName - Pointer to a Unicode String structure that references the + name of the Secret object to be opened. + + DesiredAccess - This is an access mask indicating accesses being + requested for the secret object being opened. These access types + are reconciled with the Discretionary Access Control List of the + target secret object to determine whether the accesses will be + granted or denied. + + + SecretHandle - Pointer to location that will receive a handle to the + newly opened Secret object. + +Return Value: + + NTSTATUS - Standard Nt Result Code + + STATUS_ACCESS_DENIED - Caller does not have the appropriate access + to complete the operation. + + STATUS_OBJECT_NAME_NOT_FOUND - There is no Secret object in the + target system's LSA Database having the specified SecretName. + +--*/ + +{ + NTSTATUS Status; + + RpcTryExcept { + + Status = LsarOpenSecret( + (LSAPR_HANDLE) PolicyHandle, + (PLSAPR_UNICODE_STRING) SecretName, + DesiredAccess, + (PLSAPR_HANDLE) SecretHandle + ); + + } RpcExcept( EXCEPTION_EXECUTE_HANDLER ) { + + Status = LsapApiReturnResult(I_RpcMapWin32Status(RpcExceptionCode())); + + } RpcEndExcept; + + return(Status); +} + + +NTSTATUS +LsaSetSecret( + IN LSA_HANDLE SecretHandle, + IN OPTIONAL PUNICODE_STRING CurrentValue, + IN OPTIONAL PUNICODE_STRING OldValue + ) + +/*++ + +Routine Description: + + The LsaSetSecret API optionally sets one or both values associated with + a secret. These values are known as the "current value" and "old value" + of the secret and have a meaning known to the creator of the Secret + object. The values given are stored in encrypted form. + +Arguments: + + SecretHandle - Handle from an LsaOpenSecret or LsaCreateSecret call. + + CurrentValue - Optional pointer to Unicode String containing the + value to be assigned as the "current value" of the Secret + object. The meaning of "current value" is dependent on the + purpose for which the Secret object is being used. + + OldValue - Optional pointer to Unicode String containing the + value to be assigned as the "old value" of the Secret object. + The meaning of "old value" is dependent on the purpose for + which the Secret object is being used. + +Return Value: + + NTSTATUS - Standard Nt Result Code + + STATUS_ACCESS_DENIED - Caller does not have the appropriate access + to complete the operation. + + STATUS_OBJECT_NAME_NOT_FOUND - There is no Secret object in the + target system's LSA Database having the specified SecretName. +--*/ + +{ + NTSTATUS Status; + + PLSAP_CR_CIPHER_VALUE CipherCurrentValue = NULL; + PLSAP_CR_CIPHER_VALUE CipherOldValue = NULL; + LSAP_CR_CLEAR_VALUE ClearCurrentValue; + LSAP_CR_CLEAR_VALUE ClearOldValue; + PLSAP_CR_CIPHER_KEY SessionKey = NULL; + + // + // Convert input from Unicode Structures to Clear Value Structures. + // + + LsapCrUnicodeToClearValue( CurrentValue, &ClearCurrentValue ); + LsapCrUnicodeToClearValue( OldValue, &ClearOldValue ); + + // + // Obtain the Session Key to be used to two-way encrypt the + // Current Value and/or Old Values. + // + + RpcTryExcept { + + Status = LsapCrClientGetSessionKey( SecretHandle, &SessionKey ); + + } RpcExcept( EXCEPTION_EXECUTE_HANDLER ) { + + Status = LsapApiReturnResult(I_RpcMapWin32Status(RpcExceptionCode())); + + } RpcEndExcept; + + if (!NT_SUCCESS(Status)) { + + goto SetSecretError; + } + + // + // Encrypt the Current Value if specified and not too long. + // + + if (ARGUMENT_PRESENT(CurrentValue)) { + + Status = LsapCrEncryptValue( + &ClearCurrentValue, + SessionKey, + &CipherCurrentValue + ); + + if (!NT_SUCCESS(Status)) { + + goto SetSecretError; + } + } + + // + // Encrypt the Old Value if specified and not too long. + // + + if (ARGUMENT_PRESENT(OldValue)) { + + Status = LsapCrEncryptValue( + (PLSAP_CR_CLEAR_VALUE) &ClearOldValue, + SessionKey, + &CipherOldValue + ); + + if (!NT_SUCCESS(Status)) { + + goto SetSecretError; + } + } + + // + // Set the Secret Values. + // + + RpcTryExcept { + + Status = LsarSetSecret( + (LSAPR_HANDLE) SecretHandle, + (PLSAPR_CR_CIPHER_VALUE) CipherCurrentValue, + (PLSAPR_CR_CIPHER_VALUE) CipherOldValue + ); + + } RpcExcept( EXCEPTION_EXECUTE_HANDLER ) { + + Status = LsapApiReturnResult(I_RpcMapWin32Status(RpcExceptionCode())); + + } RpcEndExcept; + + if (!NT_SUCCESS(Status)) { + + goto SetSecretError; + } + +SetSecretFinish: + + // + // If necessary, free memory allocated for the Encrypted Current Value. + // + + if (CipherCurrentValue != NULL) { + + LsaFreeMemory(CipherCurrentValue); + } + + // + // If necessary, free memory allocated for the Encrypted Old Value. + // + + if (CipherOldValue != NULL) { + + LsaFreeMemory(CipherOldValue); + } + + // + // If necessary, free memory allocated for the Session Key. + // + + if (SessionKey != NULL) { + + MIDL_user_free(SessionKey); + } + + return(Status); + +SetSecretError: + + goto SetSecretFinish; +} + + +NTSTATUS +LsaQuerySecret( + IN LSA_HANDLE SecretHandle, + IN OUT OPTIONAL PUNICODE_STRING *CurrentValue, + OUT PLARGE_INTEGER CurrentValueSetTime, + IN OUT OPTIONAL PUNICODE_STRING *OldValue, + OUT PLARGE_INTEGER OldValueSetTime + ) + +/*++ + +Routine Description: + + The LsaQuerySecret API optionally returns one or both of the values + assigned to a Secret object. These values are known as the "current value" + and the "old value", and they have a meaning known to the creator of the + Secret object. The values are returned in their original unencrypted form. + The caller must have LSA_QUERY_SECRET access to the Secret object. + +Arguments: + + SecretHandle - Handle from an LsaOpenSecret or LsaCreateSecret call. + + CurrentValue - Optional pointer to location which will receive a pointer + to a Unicode String containing the value assigned as the "current + value" of the secret object. If no "current value" is assigned to + the Secret object, a NULL pointer is returned. + + CurrentValueSetTime - The date/time at which the current secret value + was established. + + OldValue - Optional pointer to location which will receive a pointer + to a Unicode String containing the value assigned as the "old + value" of the secret object. If no "current value" is assigned to + the Secret object, a NULL pointer is returned. + + OldValueSetTime - The date/time at which the old secret value + was established. + +Return Value: + + NTSTATUS - Standard Nt Result Code + + STATUS_ACCESS_DENIED - Caller does not have the appropriate access + to complete the operation. + + STATUS_OBJECT_NAME_NOT_FOUND - There is no Secret object in the + target system's LSA Database having the specified SecretName. +--*/ + +{ + NTSTATUS Status = STATUS_SUCCESS; + + PLSAP_CR_CIPHER_VALUE CipherCurrentValue = NULL; + PLSAP_CR_CIPHER_VALUE CipherOldValue = NULL; + PLSAP_CR_CLEAR_VALUE ClearCurrentValue = NULL; + PLSAP_CR_CLEAR_VALUE ClearOldValue = NULL; + PLSAP_CR_CIPHER_KEY SessionKey = NULL; + + RpcTryExcept { + + Status = LsarQuerySecret( + (PLSAPR_HANDLE) SecretHandle, + (PLSAPR_CR_CIPHER_VALUE *) &CipherCurrentValue, + CurrentValueSetTime, + (PLSAPR_CR_CIPHER_VALUE *) &CipherOldValue, + OldValueSetTime + ); + + } RpcExcept( EXCEPTION_EXECUTE_HANDLER ) { + + Status = LsapApiReturnResult(I_RpcMapWin32Status(RpcExceptionCode())); + + } RpcEndExcept; + + if (!NT_SUCCESS(Status)) { + + goto QuerySecretError; + } + + // + // Obtain the Session Key to be used to two-way encrypt the + // Current Value and/or Old Values. + // + + RpcTryExcept { + + Status = LsapCrClientGetSessionKey( SecretHandle, &SessionKey ); + + } RpcExcept( EXCEPTION_EXECUTE_HANDLER ) { + + Status = LsapApiReturnResult(I_RpcMapWin32Status(RpcExceptionCode())); + + } RpcEndExcept; + + if (!NT_SUCCESS(Status)) { + + goto QuerySecretError; + } + + // + // If the Current Value is requested and a Current Value exists, + // decrypt it using the Session key. Otherwise store NULL for return. + // + + if (ARGUMENT_PRESENT(CurrentValue)) { + + if (CipherCurrentValue != NULL) { + + Status = LsapCrDecryptValue( + CipherCurrentValue, + SessionKey, + &ClearCurrentValue + ); + + if (!NT_SUCCESS(Status)) { + + goto QuerySecretError; + } + + // + // Convert Clear Current Value to Unicode + // + + LsapCrClearValueToUnicode( + ClearCurrentValue, + (PUNICODE_STRING) ClearCurrentValue + ); + *CurrentValue = (PUNICODE_STRING) ClearCurrentValue; + + } else { + + *CurrentValue = NULL; + } + } + + // + // If the Old Value is requested and an Old Value exists, + // decrypt it using the Session key. Otherwise store NULL for return. + // + + if (ARGUMENT_PRESENT(OldValue)) { + + if (CipherOldValue != NULL) { + + Status = LsapCrDecryptValue( + CipherOldValue, + SessionKey, + &ClearOldValue + ); + + if (!NT_SUCCESS(Status)) { + + goto QuerySecretError; + } + + // + // Convert Clear Old Value to Unicode + // + + LsapCrClearValueToUnicode( + ClearOldValue, + (PUNICODE_STRING) ClearOldValue + ); + + *OldValue = (PUNICODE_STRING) ClearOldValue; + + } else { + + *OldValue = NULL; + } + } + +QuerySecretFinish: + + // + // If necessary, free memory allocated for the Session Key. + // + + if (SessionKey != NULL) { + + MIDL_user_free(SessionKey); + } + + // + // If necessary, free memory allocated for the returned Encrypted + // Current Value. + // + + if (CipherCurrentValue != NULL) { + + LsapCrFreeMemoryValue(CipherCurrentValue); + } + + // + // If necessary, free memory allocated for the returned Encrypted + // Old Value. + // + + if (CipherOldValue != NULL) { + + LsapCrFreeMemoryValue(CipherOldValue); + } + + return(Status); + +QuerySecretError: + + // + // If necessary, free memory allocated for the Clear Current Value + // + + if (ClearCurrentValue != NULL) { + + LsapCrFreeMemoryValue(ClearCurrentValue); + } + + // + // If necessary, free memory allocated for the Clear Old Value + // Unicode string (buffer and structure). + // + + if (ClearOldValue != NULL) { + + LsapCrFreeMemoryValue(ClearOldValue); + } + + + if (ARGUMENT_PRESENT(CurrentValue)) { + + *CurrentValue = NULL; + } + + if (ARGUMENT_PRESENT(OldValue)) { + + *OldValue = NULL; + } + + goto QuerySecretFinish; +} + + +NTSTATUS +LsaGetUserName( + OUT PUNICODE_STRING * UserName, + OUT OPTIONAL PUNICODE_STRING * DomainName + ) + +/*++ + +Routine Description: + + This function returns the callers user name and domain name + + +Arguments: + + UserName - Receives a pointer to the user's name. + + DomainName - Optionally receives a pointer to the user's domain name. + + +Return Value: + + NTSTATUS - The privilege was found and returned. + + +--*/ + +{ + + NTSTATUS Status; + PLSAPR_UNICODE_STRING UserNameBuffer = NULL; + PLSAPR_UNICODE_STRING DomainNameBuffer = NULL; + + RpcTryExcept { + + // + // Call the Client Stub for LsaGetUserName + // + + Status = LsarGetUserName( + NULL, + &UserNameBuffer, + ARGUMENT_PRESENT(DomainName) ? &DomainNameBuffer : NULL + ); + + (*UserName) = (PUNICODE_STRING)UserNameBuffer; + + if (ARGUMENT_PRESENT(DomainName)) { + (*DomainName) = (PUNICODE_STRING)DomainNameBuffer; + } + + } RpcExcept( EXCEPTION_EXECUTE_HANDLER ) { + + // + // If memory was allocated for the return buffer, free it. + // + + if (UserNameBuffer != NULL) { + + MIDL_user_free(UserNameBuffer); + } + + if (DomainNameBuffer != NULL) { + + MIDL_user_free(DomainNameBuffer); + } + + Status = LsapApiReturnResult(I_RpcMapWin32Status(RpcExceptionCode())); + + } RpcEndExcept; + + + return(Status); + + +} + + diff --git a/private/lsa/uclient/rpcapi2.c b/private/lsa/uclient/rpcapi2.c new file mode 100644 index 000000000..25fb11ee0 --- /dev/null +++ b/private/lsa/uclient/rpcapi2.c @@ -0,0 +1,3316 @@ + +/*++ + +Copyright (c) 1989 Microsoft Corporation + +Module Name: + + rpcapi.c + +Abstract: + + This module contains the routines for the LSA API that use RPC. The + routines in this module are merely wrappers that work as follows: + + o Client program calls LsaFoo in this module + o LsaFoo calls RPC client stub interface routine LsapFoo with + similar parameters. Some parameters are translated from types + (e.g structures containing PVOIDs or certain kinds of variable length + parameters such as pointers to SID's) that are not specifiable on an + RPC interface, to specifiable form. + o RPC client stub LsapFoo calls interface specific marshalling routines + and RPC runtime to marshal parameters into a buffer and send them over + to the server side of the LSA. + o Server side calls RPC runtime and interface specific unmarshalling + routines to unmarshal parameters. + o Server side calls worker LsapFoo to perform API function. + o Server side marshals response/output parameters and communicates these + back to client stub LsapFoo + o LsapFoo exits back to LsaFoo which returns to client program. + +Author: + + Mike Swift (MikeSw) December 7, 1994 + +Revision History: + +--*/ + +#define UNICODE // required for TEXT() to be defined properly +#include "lsaclip.h" + +#include +#include + + +typedef struct _LSAP_DB_RIGHT_AND_ACCESS { + UNICODE_STRING UserRight; + ULONG SystemAccess; +} LSAP_DB_RIGHT_AND_ACCESS, *PLSAP_DB_RIGHT_AND_ACCESS; + +#define LSAP_DB_SYSTEM_ACCESS_TYPES 4 + +LSAP_DB_RIGHT_AND_ACCESS LsapDbRightAndAccess[LSAP_DB_SYSTEM_ACCESS_TYPES] = { + {{sizeof(SE_INTERACTIVE_LOGON_NAME)-sizeof(WCHAR), + sizeof(SE_INTERACTIVE_LOGON_NAME), + SE_INTERACTIVE_LOGON_NAME}, + SECURITY_ACCESS_INTERACTIVE_LOGON}, + {{sizeof(SE_NETWORK_LOGON_NAME)-sizeof(WCHAR), + sizeof(SE_NETWORK_LOGON_NAME), + SE_NETWORK_LOGON_NAME}, + SECURITY_ACCESS_NETWORK_LOGON}, + {{sizeof(SE_BATCH_LOGON_NAME)-sizeof(WCHAR), + sizeof(SE_BATCH_LOGON_NAME), + SE_BATCH_LOGON_NAME}, + SECURITY_ACCESS_BATCH_LOGON}, + {{sizeof(SE_SERVICE_LOGON_NAME)-sizeof(WCHAR), + sizeof(SE_SERVICE_LOGON_NAME), + SE_SERVICE_LOGON_NAME}, + SECURITY_ACCESS_SERVICE_LOGON} + }; + +// +// Structure to maintain list of enumerated accounts +// + +typedef struct _SID_LIST_ENTRY { + struct _SID_LIST_ENTRY * Next; + PSID Sid; +} SID_LIST_ENTRY, *PSID_LIST_ENTRY; + +// +// Functions private to this module +// + +NTSTATUS +LsapApiReturnResult( + IN ULONG ExceptionCode + ); + +NTSTATUS +LsapApiConvertRightsToPrivileges( + IN LSA_HANDLE PolicyHandle, + IN PUNICODE_STRING UserRights, + IN ULONG RightCount, + OUT PPRIVILEGE_SET * Privileges, + OUT PULONG SystemAccess + ); + +NTSTATUS +LsapApiConvertPrivilegesToRights( + IN LSA_HANDLE PolicyHandle, + IN OPTIONAL PPRIVILEGE_SET Privileges, + IN OPTIONAL ULONG SystemAccess, + OUT PUNICODE_STRING * UserRights, + OUT PULONG RightCount + ); + + +////////////////////////////////////////////////////////////////////// +// +// This set of routines implements the same functionality as the APIs +// below but do it with the APIs present through NT 3.5 +// +///////////////////////////////////////////////////////////////////// + + +NTSTATUS +NTAPI +LsapEnumerateAccountsWithUserRight( + IN LSA_HANDLE PolicyHandle, + IN OPTIONAL PUNICODE_STRING UserRights, + OUT PVOID *EnumerationBuffer, + OUT PULONG CountReturned + ) + +/*++ + +Routine Description: + + + The LsaEnumerateAccountsWithUserRight API returns information about + the accounts in the target system's Lsa Database. This call requires + LSA_ENUMERATE_ACCOUNTS access to the Policy object. Since this call + accesses the privileges of an account, you must have ACCOUNT_VIEW access + access to all accounts. + +Arguments: + + PolicyHandle - Handle from an LsaOpenPolicy call. + + UserRight - Name of the right that the account must have. + + Buffer - Receives a pointer to a LSA_ENUMERATION_INFORMATION structure + containing the SIDs of all the accounts. + + CountReturned - Receives the number of sids returned. + + +Return Values: + + NTSTATUS - Standard Nt Result Code + + STATUS_ACCESS_DENIED - Caller does not have the appropriate access + to complete the operation. + + STATUS_NO_MORE_ENTRIES - There are no more entries. This warning + is returned if no objects are enumerated because the + EnumerationContext value passed in is too high. +--*/ + + +{ + NTSTATUS Status; + PLSA_ENUMERATION_INFORMATION Accounts = NULL; + PPRIVILEGE_SET DesiredPrivilege = NULL; + ULONG DesiredAccess = 0; + PPRIVILEGE_SET Privileges = NULL; + ULONG SystemAccess; + LSA_ENUMERATION_HANDLE EnumContext = 0; + ULONG AccountCount; + ULONG AccountIndex; + LSA_HANDLE AccountHandle = NULL; + PSID_LIST_ENTRY AccountList = NULL; + PSID_LIST_ENTRY NextAccount = NULL; + ULONG AccountSize; + PUCHAR Where; + ULONG PrivilegeIndex; + + Status = LsapApiConvertRightsToPrivileges( + PolicyHandle, + UserRights, + (UserRights ? 1 : 0), + &DesiredPrivilege, + &DesiredAccess + ); + if (!NT_SUCCESS(Status)) { + goto Cleanup; + } + + // + // Enumerate all the accounts. + // + + do + { + Status = LsaEnumerateAccounts( + PolicyHandle, + &EnumContext, + &Accounts, + 32000, + &AccountCount + ); + + if (!NT_SUCCESS(Status)) { + break; + } + + // + // For each account, check that it has the desired right + // + + for (AccountIndex = 0; AccountIndex < AccountCount ; AccountIndex++ ) { + + if ((DesiredPrivilege != NULL) || (DesiredAccess != 0)) { + + Status = LsaOpenAccount( + PolicyHandle, + Accounts[AccountIndex].Sid, + ACCOUNT_VIEW, + &AccountHandle + ); + + if (!NT_SUCCESS(Status) ) { + goto Cleanup; + } + + // + // If a privilege was requested, get the privilegs + // + + if (DesiredPrivilege != NULL) { + + Privileges = NULL; + Status = LsaEnumeratePrivilegesOfAccount( + AccountHandle, + &Privileges + ); + if (!NT_SUCCESS(Status)) { + goto Cleanup; + } + + // + // Search for the desired privilege + // + + for (PrivilegeIndex = 0; + PrivilegeIndex < Privileges->PrivilegeCount ; + PrivilegeIndex++) { + + if (RtlEqualLuid(&Privileges->Privilege[PrivilegeIndex].Luid, + &DesiredPrivilege->Privilege[0].Luid)) { + break; + } + } + + // + // If we found the privilege, add it to the list. + // + + if (PrivilegeIndex != Privileges->PrivilegeCount) { + + // + // Add this account to the enumeration. + // + + NextAccount = MIDL_user_allocate(sizeof(SID_LIST_ENTRY)); + if (NextAccount == NULL) { + Status = STATUS_INSUFFICIENT_RESOURCES; + goto Cleanup; + } + NextAccount->Sid = MIDL_user_allocate(RtlLengthSid(Accounts[AccountIndex].Sid)); + if (NextAccount->Sid == NULL) { + MIDL_user_free(NextAccount); + Status = STATUS_INSUFFICIENT_RESOURCES; + goto Cleanup; + } + RtlCopyMemory( + NextAccount->Sid, + Accounts[AccountIndex].Sid, + RtlLengthSid(Accounts[AccountIndex].Sid) + ); + NextAccount->Next = AccountList; + AccountList = NextAccount; + + } + LsaFreeMemory(Privileges); + Privileges = NULL; + + } else { + + // + // Otherwise get the system access + // + + ASSERT(DesiredAccess != 0); + + Status = LsaGetSystemAccessAccount( + AccountHandle, + &SystemAccess + ); + + if (!NT_SUCCESS(Status)) { + goto Cleanup; + } + + // + // Check for the desired access + // + + if ((SystemAccess & DesiredAccess) != 0) { + + // + // Add this account to the enumeration. + // + + NextAccount = MIDL_user_allocate(sizeof(SID_LIST_ENTRY)); + if (NextAccount == NULL) { + Status = STATUS_INSUFFICIENT_RESOURCES; + goto Cleanup; + } + NextAccount->Sid = MIDL_user_allocate(RtlLengthSid(Accounts[AccountIndex].Sid)); + if (NextAccount->Sid == NULL) { + MIDL_user_free(NextAccount); + Status = STATUS_INSUFFICIENT_RESOURCES; + goto Cleanup; + } + RtlCopyMemory( + NextAccount->Sid, + Accounts[AccountIndex].Sid, + RtlLengthSid(Accounts[AccountIndex].Sid) + ); + NextAccount->Next = AccountList; + AccountList = NextAccount; + + } + } + + LsaClose(AccountHandle); + AccountHandle = NULL; + + + } else { + // + // always add the account if the caller didn't want + // filtering. + // + + NextAccount = MIDL_user_allocate(sizeof(SID_LIST_ENTRY)); + if (NextAccount == NULL) { + Status = STATUS_INSUFFICIENT_RESOURCES; + goto Cleanup; + } + NextAccount->Sid = MIDL_user_allocate(RtlLengthSid(Accounts[AccountIndex].Sid)); + if (NextAccount->Sid == NULL) { + MIDL_user_free(NextAccount); + Status = STATUS_INSUFFICIENT_RESOURCES; + goto Cleanup; + } + RtlCopyMemory( + NextAccount->Sid, + Accounts[AccountIndex].Sid, + RtlLengthSid(Accounts[AccountIndex].Sid) + ); + NextAccount->Next = AccountList; + AccountList = NextAccount; + } + + } + LsaFreeMemory(Accounts); + Accounts = NULL; + + } while ( 1 ); + + if (Status != STATUS_NO_MORE_ENTRIES) { + goto Cleanup; + } + + AccountSize = 0; + AccountCount = 0; + for (NextAccount = AccountList ; NextAccount != NULL; NextAccount = NextAccount->Next) { + AccountSize += sizeof(LSA_ENUMERATION_INFORMATION) + + RtlLengthSid(NextAccount->Sid); + AccountCount++; + } + + // + // If there were no accounts return a warning now. + // + + if (AccountCount == 0) { + *EnumerationBuffer = NULL; + *CountReturned = 0; + Status = STATUS_NO_MORE_ENTRIES; + goto Cleanup; + } + + Accounts = MIDL_user_allocate(AccountSize); + if (Accounts == NULL) { + Status = STATUS_INSUFFICIENT_RESOURCES; + goto Cleanup; + } + + // + // Marshall all the sids into the array. + // + + Where = (PUCHAR) Accounts + AccountCount * sizeof(LSA_ENUMERATION_INFORMATION); + + for ( NextAccount = AccountList,AccountIndex = 0 ; + NextAccount != NULL; + NextAccount = NextAccount->Next, AccountIndex++) { + + Accounts[AccountIndex].Sid = (PSID) Where; + RtlCopyMemory( + Where, + NextAccount->Sid, + RtlLengthSid(NextAccount->Sid) + ); + Where += RtlLengthSid(NextAccount->Sid); + } + ASSERT(AccountIndex == AccountCount); + ASSERT(Where - (PUCHAR) Accounts == (LONG) AccountSize); + *EnumerationBuffer = Accounts; + Accounts = NULL; + *CountReturned = AccountCount; + Status = STATUS_SUCCESS; + + +Cleanup: + if (AccountList != NULL) { + while (AccountList != NULL) { + NextAccount = AccountList->Next; + MIDL_user_free(AccountList->Sid); + MIDL_user_free(AccountList); + AccountList = NextAccount; + } + } + + if (Accounts != NULL) { + MIDL_user_free(Accounts); + } + + if (Privileges != NULL) { + LsaFreeMemory(Privileges); + } + return(Status); +} + + + +NTSTATUS +NTAPI +LsapEnumerateAccountRights( + IN LSA_HANDLE PolicyHandle, + IN PSID AccountSid, + OUT PUNICODE_STRING *UserRights, + OUT PULONG CountOfRights + ) + +/*++ + +Routine Description: + + Returns all the rights of an account. This is done by gathering the + privileges and system access of an account and translating that into + an array of strings. + +Arguments: + + PolicyHandle - Handle from an LsaOpenPolicyCall. This API requires + no special access. + + AccountSid - Sid of account to open. + + UserRights - receives an array of user rights (UNICODE_STRING) for + the account. + + CountOfRights - receives the number of rights returned. + + +Return Value: + + STATUS_ACCESS_DENIED - the caller did not have sufficient access to + return the privileges or system access of the account. + + STATUS_OBJECT_NAME_NOT_FOUND - the specified account did not exist. + + STATUS_INSUFFICIENT_RESOURCES - not enough memory to process the + request. + +--*/ +{ + NTSTATUS Status; + PPRIVILEGE_SET Privileges = NULL; + ULONG SystemAccess = 0; + PUNICODE_STRING Rights = NULL; + ULONG RightCount = 0; + LSA_HANDLE AccountHandle = NULL; + + Status = LsaOpenAccount( + PolicyHandle, + AccountSid, + ACCOUNT_VIEW, + &AccountHandle + ); + + if (!NT_SUCCESS(Status)) { + goto Cleanup; + } + + // + // Query the privilegs and system access + // + + Status = LsaEnumeratePrivilegesOfAccount( + AccountHandle, + &Privileges + ); + + if (!NT_SUCCESS(Status)) { + goto Cleanup; + } + + Status = LsaGetSystemAccessAccount( + AccountHandle, + &SystemAccess + ); + if (!NT_SUCCESS(Status)) { + goto Cleanup; + } + + // + // Convert the privileges and access to rights + // + + Status = LsapApiConvertPrivilegesToRights( + PolicyHandle, + Privileges, + SystemAccess, + &Rights, + &RightCount + ); + if (NT_SUCCESS(Status)) { + *CountOfRights = RightCount; + *UserRights = Rights; + } +Cleanup: + if (Privileges != NULL) { + LsaFreeMemory(Privileges); + } + if (AccountHandle != NULL) { + LsaClose(AccountHandle); + } + + return(Status); + +} + +NTSTATUS +NTAPI +LsapAddAccountRights( + IN LSA_HANDLE PolicyHandle, + IN PSID AccountSid, + IN PUNICODE_STRING UserRights, + IN ULONG CountOfRights + ) +/*++ + +Routine Description: + + Adds rights to the account specified by the account sid. If the account + does not exist, it creates the account. + +Arguments: + + PolicyHandle - Handle from an LsaOpenPolicy call. The handle must have + POLICY_CREATE_ACCOUNT access if this is the first call for this + AccountSid. + + AccountSid - Sid of account to add rights to + + UserRights - Array of unicode strings naming rights to add to the + account. + +Return Value: + STATUS_INSUFFICIENT_RESOURCES - not enough memory to process the request + + STATUS_INVALID_PARAMTER - one of the parameters was not present + + STATUS_NO_SUCH_PRIVILEGE - One of the user rights was invalid + + STATUS_ACCESS_DENIED - the caller does not have sufficient access to the + account to add privileges. + +--*/ +{ + LSA_HANDLE AccountHandle = NULL; + NTSTATUS Status; + PPRIVILEGE_SET Privileges = NULL; + ULONG SystemAccess; + ULONG OldAccess; + + // + // Convert the rights into privileges and system access. + // + + Status = LsapApiConvertRightsToPrivileges( + PolicyHandle, + UserRights, + CountOfRights, + &Privileges, + &SystemAccess + ); + + if (!NT_SUCCESS(Status)) { + goto Cleanup; + } + + // + // Open the account. If it does not exist ,create the account. + // + + Status = LsaOpenAccount( + PolicyHandle, + AccountSid, + ACCOUNT_ADJUST_PRIVILEGES | + ACCOUNT_ADJUST_SYSTEM_ACCESS | + ACCOUNT_VIEW, + &AccountHandle + ); + + // + // if the account did not exist, try to create it. + // + + if (Status == STATUS_OBJECT_NAME_NOT_FOUND) { + Status = LsaCreateAccount( + PolicyHandle, + AccountSid, + ACCOUNT_ADJUST_PRIVILEGES | + ACCOUNT_ADJUST_SYSTEM_ACCESS | + ACCOUNT_VIEW, + &AccountHandle + ); + } + + if (!NT_SUCCESS(Status)) { + goto Cleanup; + } + + Status = LsaGetSystemAccessAccount( + AccountHandle, + &OldAccess + ); + + if (!NT_SUCCESS(Status)) { + goto Cleanup; + } + + Status = LsaSetSystemAccessAccount( + AccountHandle, + OldAccess | SystemAccess + ); + if (!NT_SUCCESS(Status)) { + goto Cleanup; + } + + Status = LsaAddPrivilegesToAccount( + AccountHandle, + Privileges + ); +Cleanup: + + if (Privileges != NULL) { + MIDL_user_free(Privileges); + } + if (AccountHandle != NULL) { + LsaClose(AccountHandle); + } + return(Status); +} + +NTSTATUS +NTAPI +LsapRemoveAccountRights( + IN LSA_HANDLE PolicyHandle, + IN PSID AccountSid, + IN BOOLEAN AllRights, + IN PUNICODE_STRING UserRights, + IN ULONG CountOfRights + ) + +/*++ + +Routine Description: + + Removes rights to the account specified by the account sid. If the + AllRights flag is set or if all the rights are removed, the account + is deleted. + +Arguments: + + PolicyHandle - Handle from an LsaOpenPolicy call + + AccountSid - Sid of account to remove rights from + + UserRights - Array of unicode strings naming rights to remove from the + account. + +Return Value: + STATUS_INSUFFICIENT_RESOURCES - not enough memory to process the request + + STATUS_INVALID_PARAMTER - one of the parameters was not present + + STATUS_NO_SUCH_PRIVILEGE - One of the user rights was invalid + + STATUS_ACCESS_DENIED - the caller does not have sufficient access to the + account to add privileges. + +--*/ +{ + LSA_HANDLE AccountHandle = NULL; + NTSTATUS Status; + PPRIVILEGE_SET Privileges = NULL; + PPRIVILEGE_SET NewPrivileges = NULL; + ULONG SystemAccess; + ULONG OldAccess; + ULONG DesiredAccess; + ULONG NewAccess; + + // + // Convert the rights into privileges and system access. + // + + if (!AllRights) { + Status = LsapApiConvertRightsToPrivileges( + PolicyHandle, + UserRights, + CountOfRights, + &Privileges, + &SystemAccess + ); + + if (!NT_SUCCESS(Status)) { + goto Cleanup; + } + + DesiredAccess = ACCOUNT_ADJUST_PRIVILEGES | + ACCOUNT_ADJUST_SYSTEM_ACCESS | + ACCOUNT_VIEW | DELETE; + } else { + DesiredAccess = DELETE; + } + + + + // + // Open the account. + // + + Status = LsaOpenAccount( + PolicyHandle, + AccountSid, + DesiredAccess, + &AccountHandle + ); + + if (!NT_SUCCESS(Status)) { + goto Cleanup; + } + + // + // If we are to remove all rights, just delete the account ,and if that + // succeeds, zero the handle so we don't try to close it later. + // + + if (AllRights) { + Status = LsaDelete( + AccountHandle + ); + if (NT_SUCCESS(Status)) { + AccountHandle = NULL; + } + goto Cleanup; + } + + // + // Get the old system access to adjust + // + + Status = LsaGetSystemAccessAccount( + AccountHandle, + &OldAccess + ); + + if (!NT_SUCCESS(Status)) { + goto Cleanup; + } + + + NewAccess = OldAccess & ~SystemAccess; + Status = LsaSetSystemAccessAccount( + AccountHandle, + NewAccess + ); + + if (!NT_SUCCESS(Status)) { + goto Cleanup; + } + + Status = LsaRemovePrivilegesFromAccount( + AccountHandle, + FALSE, // don't remove all + Privileges + ); + + if (!NT_SUCCESS(Status)) { + goto Cleanup; + } + + // + // Now query the privilegs to see if they are zero. If so, and + // system access is zero, delete the account. + // + + Status = LsaEnumeratePrivilegesOfAccount( + AccountHandle, + &NewPrivileges + ); + + if (!NT_SUCCESS(Status)) { + + goto Cleanup; + } + + // + // If the account has no privileges or access, delete it. + // + + if ((NewPrivileges->PrivilegeCount == 0) && + (NewAccess == 0)) { + + Status = LsaDelete( + AccountHandle + ); + if (NT_SUCCESS(Status)) { + AccountHandle = NULL; + } + } + + Status = STATUS_SUCCESS; + +Cleanup: + + if (Privileges != NULL) { + MIDL_user_free(Privileges); + } + if (AccountHandle != NULL) { + LsaClose(AccountHandle); + } + if (NewPrivileges != NULL) { + LsaFreeMemory(NewPrivileges); + } + return(Status); + +} + + +NTSTATUS +LsapApiBuildSecretName( + PTRUSTED_DOMAIN_NAME_INFO NameInfo, + PUNICODE_STRING OutputSecretName + ) +{ + UNICODE_STRING SecretName; + + // + // The secret name is G$$domain name, where G$ is the global prefix and + // $ is the ssi prefix + // + + SecretName.Length = NameInfo->Name.Length + + (SSI_SECRET_PREFIX_LENGTH + + LSA_GLOBAL_SECRET_PREFIX_LENGTH) * sizeof(WCHAR); + SecretName.MaximumLength = SecretName.Length; + SecretName.Buffer = (LPWSTR) MIDL_user_allocate( SecretName.Length ); + + if (SecretName.Buffer == NULL) { + return(STATUS_INSUFFICIENT_RESOURCES); + } + + wcscpy( + SecretName.Buffer, + LSA_GLOBAL_SECRET_PREFIX + ); + + wcscat( + SecretName.Buffer, + SSI_SECRET_PREFIX + ); + RtlCopyMemory( + SecretName.Buffer + + LSA_GLOBAL_SECRET_PREFIX_LENGTH + + SSI_SECRET_PREFIX_LENGTH, + NameInfo->Name.Buffer, + NameInfo->Name.Length + ); + *OutputSecretName = SecretName; + return(STATUS_SUCCESS); + +} + +NTSTATUS +NTAPI +LsapQueryTrustedDomainInfo( + IN LSA_HANDLE PolicyHandle, + IN PSID TrustedDomainSid, + IN TRUSTED_INFORMATION_CLASS InformationClass, + OUT PVOID *Buffer + ) + +/*++ + +Routine Description: + + The LsaQueryTrustedDomainInfo API obtains information from a + TrustedDomain object. The caller must have access appropriate to the + information being requested (see InformationClass parameter). It also + may query the secret object (for the TrustedDomainPasswordInformation + class). + +Arguments: + + PolicyHandle - Handle from an LsaOpenPolicy call. + + TrustedDomainSid - Sid of domain to query. + + InformationClass - Specifies the information to be returned. + + Buffer - Receives a pointer to the buffer returned comtaining the + requested information. This buffer is allocated by this service + and must be freed when no longer needed by passing the returned + value to LsaFreeMemory(). + +Return Value: + + NTSTATUS - Standard Nt Result Code + + STATUS_ACCESS_DENIED - Caller does not have the appropriate + access to complete the operation. + + STATUS_INSUFFICIENT_RESOURCES - Insufficient system resources, + such as memory, to complete the call. +--*/ +{ + NTSTATUS Status; + LSA_HANDLE DomainHandle = NULL; + LSA_HANDLE SecretHandle = NULL; + PUNICODE_STRING OldPassword = NULL; + PUNICODE_STRING Password = NULL; + PTRUSTED_PASSWORD_INFO PasswordInfo = NULL; + PTRUSTED_DOMAIN_NAME_INFO NameInfo = NULL; + ULONG DesiredAccess; + PVOID LocalBuffer = NULL; + TRUSTED_INFORMATION_CLASS LocalInfoClass; + UNICODE_STRING SecretName; + PUCHAR Where; + ULONG PasswordSize; + + SecretName.Buffer = NULL; + + // + // Find the desired access type for the info we are + // querying. + // + + LocalInfoClass = InformationClass; + + switch(InformationClass) { + case TrustedDomainNameInformation: + DesiredAccess = TRUSTED_QUERY_DOMAIN_NAME; + break; + case TrustedPosixOffsetInformation: + DesiredAccess = TRUSTED_QUERY_POSIX; + break; + case TrustedPasswordInformation: + DesiredAccess = TRUSTED_QUERY_DOMAIN_NAME; + LocalInfoClass = TrustedDomainNameInformation; + break; + default: + return(STATUS_INVALID_PARAMETER); + } + + // + // Open the domain for the desired access + // + + + Status = LsaOpenTrustedDomain( + PolicyHandle, + TrustedDomainSid, + DesiredAccess, + &DomainHandle + ); + if (!NT_SUCCESS(Status)) { + goto Cleanup; + } + + Status = LsaQueryInfoTrustedDomain( + DomainHandle, + LocalInfoClass, + &LocalBuffer + ); + if (!NT_SUCCESS(Status)) { + goto Cleanup; + } + + // + // If the class wasn't trusted password information, return here. + // + + if (InformationClass != TrustedPasswordInformation) { + *Buffer = LocalBuffer; + LocalBuffer = NULL; + goto Cleanup; + } + NameInfo = (PTRUSTED_DOMAIN_NAME_INFO) LocalBuffer; + + // + // Get the secret name + // + + Status = LsapApiBuildSecretName( + NameInfo, + &SecretName + ); + + if (!NT_SUCCESS(Status)) { + goto Cleanup; + } + + Status = LsaOpenSecret( + PolicyHandle, + &SecretName, + SECRET_QUERY_VALUE, + &SecretHandle + ); + if (!NT_SUCCESS(Status)) { + goto Cleanup; + } + + // + // Query the secret + // + + Status = LsaQuerySecret( + SecretHandle, + &Password, + NULL, + &OldPassword, + NULL + ); + if (!NT_SUCCESS(Status)) { + goto Cleanup; + } + + // + // Marshall the passwords into the output structure. + // + + PasswordSize = sizeof(TRUSTED_PASSWORD_INFO); + if (Password != NULL) { + PasswordSize += Password->MaximumLength; + } + + if (OldPassword != NULL) { + PasswordSize += OldPassword->MaximumLength; + } + + PasswordInfo = (PTRUSTED_PASSWORD_INFO) MIDL_user_allocate(PasswordSize); + if (PasswordInfo == NULL) { + Status = STATUS_INSUFFICIENT_RESOURCES; + goto Cleanup; + } + + RtlZeroMemory( + PasswordInfo, + PasswordSize + ); + + Where = (PUCHAR) (PasswordInfo+1); + + if (Password != NULL) { + PasswordInfo->Password = *Password; + PasswordInfo->Password.Buffer = (LPWSTR) Where; + RtlCopyMemory( + Where, + Password->Buffer, + Password->MaximumLength + ); + Where += Password->MaximumLength; + } + + if (OldPassword != NULL) { + PasswordInfo->OldPassword = *OldPassword; + PasswordInfo->OldPassword.Buffer = (LPWSTR) Where; + RtlCopyMemory( + Where, + OldPassword->Buffer, + OldPassword->MaximumLength + ); + Where += OldPassword->MaximumLength; + } + + ASSERT(Where - (PUCHAR) PasswordInfo == (LONG) PasswordSize); + + *Buffer = PasswordInfo; + Status = STATUS_SUCCESS; + +Cleanup: + if (DomainHandle != NULL) { + LsaClose(DomainHandle); + } + + if (SecretHandle != NULL) { + LsaClose(SecretHandle); + } + + if (LocalBuffer != NULL) { + LsaFreeMemory(LocalBuffer); + } + + if (SecretName.Buffer != NULL) { + MIDL_user_free(SecretName.Buffer); + } + + return(Status); + +} + +NTSTATUS +NTAPI +LsapSetTrustedDomainInformation( + IN LSA_HANDLE PolicyHandle, + IN PSID TrustedDomainSid, + IN TRUSTED_INFORMATION_CLASS InformationClass, + IN PVOID Buffer + ) +/*++ + +Routine Description: + + + The LsaSetTrustedDomainInformation API modifies information in the Trusted + Domain Object and in the Secret Object. The caller must have access + appropriate to the information to be changed in the Policy Object, see + the InformationClass parameter. + + If the domain does not yet exist and the information class is + TrustedDomainNameInformation, then the domain is created. If the + domain exists and the class is TrustedDomainNameInformation, an + error is returned. + +Arguments: + + PolicyHandle - Handle from an LsaOpenPolicy call. + + TrustedDomainSid - Sid of domain to modify. + + InformationClass - Specifies the type of information being changed. + The information types and accesses required to change them are as + follows: + + TrustedDomainNameInformation POLICY_TRUST_ADMIN + TrustedPosixOffsetInformation none + TrustedPasswordInformation POLICY_CREATE_SECRET + + Buffer - Points to a structure containing the information appropriate + to the InformationClass parameter. + +Return Value: + + NTSTATUS - Standard Nt Result Code + + STATUS_ACCESS_DENIED - Caller does not have the appropriate access + to complete the operation. + + Others TBS +--*/ +{ + LSA_HANDLE DomainHandle = NULL; + LSA_HANDLE SecretHandle = NULL; + NTSTATUS Status; + PUNICODE_STRING OldPassword; + PUNICODE_STRING Password; + LSA_TRUST_INFORMATION DomainInformation; + PTRUSTED_DOMAIN_NAME_INFO NameInfo = NULL; + PTRUSTED_PASSWORD_INFO PasswordInfo; + UNICODE_STRING SecretName; + + SecretName.Buffer = NULL; + + // + // If the information is the domain name, try to create the domain. + // + + if (InformationClass == TrustedDomainNameInformation) { + DomainInformation.Sid = TrustedDomainSid; + DomainInformation.Name = ((PTRUSTED_DOMAIN_NAME_INFO) Buffer)->Name; + + Status = LsaCreateTrustedDomain( + PolicyHandle, + &DomainInformation, + 0, //desired access, + &DomainHandle + ); + goto Cleanup; + } + + // + // For posix offset, open the domain for SET_POSIX and call the old + // LSA API to set the offset. + // + + if (InformationClass == TrustedPosixOffsetInformation) { + Status = LsaOpenTrustedDomain( + PolicyHandle, + TrustedDomainSid, + TRUSTED_SET_POSIX, + &DomainHandle + ); + + if (!NT_SUCCESS(Status)) { + goto Cleanup; + } + + Status = LsaSetInformationTrustedDomain( + DomainHandle, + InformationClass, + Buffer + ); + goto Cleanup; + } + + // + // The only only remaining allowed class is password information. + // + + if (InformationClass != TrustedPasswordInformation) { + Status = STATUS_INVALID_PARAMETER; + goto Cleanup; + } + + Status = LsaOpenTrustedDomain( + PolicyHandle, + TrustedDomainSid, + TRUSTED_QUERY_DOMAIN_NAME, + &DomainHandle + ); + + if (!NT_SUCCESS(Status)) { + goto Cleanup; + } + + // + // Get the name so we can find the secret name. + // + + Status = LsaQueryInfoTrustedDomain( + DomainHandle, + TrustedDomainNameInformation, + &NameInfo + ); + if (!NT_SUCCESS(Status)) { + goto Cleanup; + } + + // + // Get the secret name + // + + Status = LsapApiBuildSecretName( + NameInfo, + &SecretName + ); + + if (!NT_SUCCESS(Status)) { + goto Cleanup; + } + + Status = LsaOpenSecret( + PolicyHandle, + &SecretName, + SECRET_SET_VALUE, + &SecretHandle + ); + + // + // If the secret didn't exist, create it now. + // + if (Status == STATUS_OBJECT_NAME_NOT_FOUND) { + Status = LsaCreateSecret( + PolicyHandle, + &SecretName, + SECRET_SET_VALUE, + &SecretHandle + ); + + } + + if (!NT_SUCCESS(Status)) { + goto Cleanup; + } + + // + // If the old password wasn't specified, set it to be the new + // password. + // + + PasswordInfo = (PTRUSTED_PASSWORD_INFO) Buffer; + Password = &PasswordInfo->Password; + if (PasswordInfo->OldPassword.Buffer == NULL) { + OldPassword = Password; + } else { + OldPassword = &PasswordInfo->OldPassword; + } + + Status = LsaSetSecret( + SecretHandle, + Password, + OldPassword + ); +Cleanup: + if (SecretName.Buffer != NULL) { + MIDL_user_free(SecretName.Buffer); + } + + if (DomainHandle != NULL) { + LsaClose(DomainHandle); + } + + if (SecretHandle != NULL) { + LsaClose(SecretHandle); + } + + if (NameInfo != NULL) { + LsaFreeMemory(NameInfo); + } + + return(Status); + + +} + +NTSTATUS +NTAPI +LsapDeleteTrustedDomain( + IN LSA_HANDLE PolicyHandle, + IN PSID TrustedDomainSid + ) + +/*++ + +Routine Description: + + This routine deletes a trusted domain and the associated secret. + +Arguments: + + PolicyHandle - Handle from an LsaOpenPolicy call. + + TrustedDomainSid - Sid of domain to delete + +Return Value: + + STATUS_ACCESS_DENIED - caller has insufficient access to delete + the requested domain. + + STATUS_OBJECT_NAME_NOT_FOUND - The requested domain does not exist. + +--*/ +{ + UNICODE_STRING SecretName; + NTSTATUS Status; + PTRUSTED_DOMAIN_NAME_INFO NameInfo = NULL; + LSA_HANDLE DomainHandle = NULL; + LSA_HANDLE SecretHandle = NULL; + + + SecretName.Buffer = NULL; + + // + // Open the domain for query name and delete access. We need query name + // to find the secret name. + // + + Status = LsaOpenTrustedDomain( + PolicyHandle, + TrustedDomainSid, + TRUSTED_QUERY_DOMAIN_NAME | DELETE, + &DomainHandle + ); + if (!NT_SUCCESS(Status)) { + goto Cleanup; + } + + // + // Get the name so we can find the secret name. + // + + Status = LsaQueryInfoTrustedDomain( + DomainHandle, + TrustedDomainNameInformation, + &NameInfo + ); + if (!NT_SUCCESS(Status)) { + goto Cleanup; + } + + Status = LsaDelete(DomainHandle); + if (!NT_SUCCESS(Status)) { + goto Cleanup; + } + + // + // Zero the handle so we don't try to free it again. + // + + DomainHandle = NULL; + + // + // Get the secret name + // + + Status = LsapApiBuildSecretName( + NameInfo, + &SecretName + ); + if (!NT_SUCCESS(Status)) { + goto Cleanup; + } + + + Status = LsaOpenSecret( + PolicyHandle, + &SecretName, + DELETE, + &SecretHandle + ); + if (!NT_SUCCESS(Status)) { + // + // If the secret does not exist, that is o.k. - it means the password + // was never set. + // + + if (Status == STATUS_OBJECT_NAME_NOT_FOUND) { + Status = STATUS_SUCCESS; + } + goto Cleanup; + } + + Status = LsaDelete(SecretHandle); + if (NT_SUCCESS(Status)) { + // + // Zero the handle so we don't try to free it again. + // + SecretHandle = NULL; + } + +Cleanup: + if (NameInfo != NULL) { + LsaFreeMemory(NameInfo); + } + if (SecretName.Buffer != NULL) { + MIDL_user_free(SecretName.Buffer); + } + if (SecretHandle != NULL) { + LsaClose(SecretHandle); + } + if (DomainHandle != NULL) { + LsaClose(DomainHandle); + } + + return(Status); + + + +} + + +NTSTATUS +NTAPI +LsapStorePrivateData( + IN LSA_HANDLE PolicyHandle, + IN PUNICODE_STRING KeyName, + IN OPTIONAL PUNICODE_STRING PrivateData + ) + +/*++ + +Routine Description: + + This routine stores private data in a secret named KeyName. + +Arguments: + + PolicyHandle - Handle from an LsaOpenPolicyCall. If this is the + first call, it requres POLICY_CREATE_SECRET access. + + KeyName - Name of secret to store + + PrivateData - Private data to store. If this is null, the secret is + deleted. + +Return Value: + + STATUS_ACCESS_DENIED - caller has insufficient privilege to set + the workstation password. + +--*/ + +{ + LSA_HANDLE SecretHandle = NULL; + NTSTATUS Status; + ULONG DesiredAccess; + BOOLEAN DeleteSecret = FALSE; + + // + // check whether to delete the secret or not. + // + + if (ARGUMENT_PRESENT(PrivateData)) { + DesiredAccess = SECRET_SET_VALUE; + } else { + DesiredAccess = DELETE; + DeleteSecret = TRUE; + } + + + Status = LsaOpenSecret( + PolicyHandle, + KeyName, + DesiredAccess, + &SecretHandle + ); + + if ((Status == STATUS_OBJECT_NAME_NOT_FOUND) && !DeleteSecret) { + Status = LsaCreateSecret( + PolicyHandle, + KeyName, + DesiredAccess, + &SecretHandle + ); + + + } + if (!NT_SUCCESS(Status)) { + goto Cleanup; + } + + if (DeleteSecret) { + Status = LsaDelete( + SecretHandle + ); + + if (NT_SUCCESS(Status)) { + SecretHandle = NULL; + } + goto Cleanup; + + } + + Status = LsaSetSecret( + SecretHandle, + PrivateData, + PrivateData + ); + +Cleanup: + if (SecretHandle != NULL) { + LsaClose(SecretHandle); + } + + return(Status); + + +} + +NTSTATUS +NTAPI +LsapRetrievePrivateData( + IN LSA_HANDLE PolicyHandle, + IN PUNICODE_STRING KeyName, + OUT PUNICODE_STRING * PrivateData + ) + +/*++ + +Routine Description: + + This routine returns the secret data stored under KeyName. + +Arguments: + + PolicyHandle - Handle from an LsaOpenPolicyCall + + KeyName - Name of secret data to retrieve + + PrivateData - Receives a pointer private data + +Return Value: + + STATUS_ACCESS_DENIED - caller has insufficient access to get the + workstation password. + + STATUS_OBJECT_NAME_NOT_FOUND - there is no workstation password. + +--*/ +{ + LSA_HANDLE SecretHandle = NULL; + NTSTATUS Status; + + // + // Make the secret name + // + + + Status = LsaOpenSecret( + PolicyHandle, + KeyName, + SECRET_QUERY_VALUE, + &SecretHandle + ); + if (!NT_SUCCESS(Status)) { + goto Cleanup; + } + + Status = LsaQuerySecret( + SecretHandle, + PrivateData, + NULL, + NULL, + NULL + ); +Cleanup: + if (SecretHandle != NULL) { + LsaClose(SecretHandle); + } + + return(Status); + +} + +///////////////////////////////////////////////////////////////////////// +// +// RPC wrappers for LSA APIs added in nt3.51. This routines call the +// LSA, and if the interface doesn't exist, calls the LsapXXX routine +// to accomplish the same task using the older routines. +// +//////////////////////////////////////////////////////////////////////// + +NTSTATUS +NTAPI +LsaEnumerateAccountsWithUserRight( + IN LSA_HANDLE PolicyHandle, + IN OPTIONAL PUNICODE_STRING UserRight, + OUT PVOID *Buffer, + OUT PULONG CountReturned + ) + +/*++ + +Routine Description: + + + The LsaEnumerateAccounts API returns information about the accounts + in the target system's Lsa Database. This call requires + LSA_ENUMERATE_ACCOUNTS access to the Policy object. Since this call + accesses the privileges of an account, you must have PRIVILEGE_VIEW + access to the pseudo-privilege object. + +Arguments: + + PolicyHandle - Handle from an LsaOpenPolicy call. + + UserRight - Name of the right that the account must have. + + Buffer - Receives a pointer to a LSA_ENUMERATION_INFORMATION structure + containing the SIDs of all the accounts. + + CountReturned - Receives the number of sids returned. + + +Return Values: + + NTSTATUS - Standard Nt Result Code + + STATUS_ACCESS_DENIED - Caller does not have the appropriate access + to complete the operation. + + STATUS_NO_MORE_ENTRIES - There are no more entries. This warning + is returned if no objects are enumerated because the + EnumerationContext value passed in is too high. +--*/ + +{ + NTSTATUS Status; + + LSAPR_ACCOUNT_ENUM_BUFFER EnumerationBuffer; + + EnumerationBuffer.EntriesRead = 0; + EnumerationBuffer.Information = NULL; + + RpcTryExcept { + + // + // Enumerate the Accounts. On successful return, + // the Enumeration Buffer structure will receive a count + // of the number of Accounts enumerated this call + // and a pointer to an array of Account Information Entries. + // + // EnumerationBuffer -> EntriesRead + // Information -> Account Info for Domain 0 + // Account Info for Domain 1 + // ... + // Account Info for Domain + // (EntriesRead - 1) + // + + Status = LsarEnumerateAccountsWithUserRight( + (LSAPR_HANDLE) PolicyHandle, + (PLSAPR_UNICODE_STRING) UserRight, + &EnumerationBuffer + ); + + // + // Return enumeration information or NULL to caller. + // + // NOTE: "Information" is allocated by the called client stub + // as a single block via MIDL_user_allocate, because Information is + // allocated all-nodes. We can therefore pass back the pointer + // directly to the client, who will be able to free the memory after + // use via LsaFreeMemory() [which makes a MIDL_user_free call]. + // + + *CountReturned = EnumerationBuffer.EntriesRead; + *Buffer = EnumerationBuffer.Information; + + } RpcExcept( EXCEPTION_EXECUTE_HANDLER ) { + + // + // If memory was allocated for the Account Information array, + // free it. + // + + if (EnumerationBuffer.Information != NULL) { + + MIDL_user_free(EnumerationBuffer.Information); + } + + Status = LsapApiReturnResult(I_RpcMapWin32Status(RpcExceptionCode())); + + } RpcEndExcept; + + // + // If the RPC server stub didn't exist, use the old version of the + // API. + // + + if ((Status == RPC_NT_UNKNOWN_IF) || + (Status == RPC_NT_PROCNUM_OUT_OF_RANGE)) { + + Status = LsapEnumerateAccountsWithUserRight( + PolicyHandle, + UserRight, + Buffer, + CountReturned + ); + } + + return Status; + +} + + + +NTSTATUS +NTAPI +LsaEnumerateAccountRights( + IN LSA_HANDLE PolicyHandle, + IN PSID AccountSid, + OUT PUNICODE_STRING *UserRights, + OUT PULONG CountOfRights + ) + + +/*++ + +Routine Description: + + Returns all the rights of an account. This is done by gathering the + privileges and system access of an account and translating that into + an array of strings. + +Arguments: + + PolicyHandle - Handle from an LsaOpenPolicyCall. This API requires + no special access. + + AccountSid - Sid of account to open. + + UserRights - receives an array of user rights (UNICODE_STRING) for + the account. + + CountOfRights - receives the number of rights returned. + + +Return Value: + + STATUS_ACCESS_DENIED - the caller did not have sufficient access to + return the privileges or system access of the account. + + STATUS_OBJECT_NAME_NOT_FOUND - the specified account did not exist. + + STATUS_INSUFFICIENT_RESOURCES - not enough memory to process the + request. + +--*/ + +{ + NTSTATUS Status; + LSAPR_USER_RIGHT_SET UserRightSet; + + UserRightSet.Entries = 0; + UserRightSet.UserRights = NULL; + + RpcTryExcept { + + + Status = LsarEnumerateAccountRights( + (LSAPR_HANDLE) PolicyHandle, + (PLSAPR_SID) AccountSid, + &UserRightSet + ); + + *CountOfRights = UserRightSet.Entries; + *UserRights = (PUNICODE_STRING) UserRightSet.UserRights; + + } RpcExcept( EXCEPTION_EXECUTE_HANDLER ) { + + Status = LsapApiReturnResult(I_RpcMapWin32Status(RpcExceptionCode())); + if (UserRightSet.UserRights != NULL) { + MIDL_user_free(UserRightSet.UserRights); + } + + } RpcEndExcept; + + // + // If the RPC server stub didn't exist, use the old version of the + // API. + // + + if ((Status == RPC_NT_UNKNOWN_IF) || + (Status == RPC_NT_PROCNUM_OUT_OF_RANGE)) { + + Status = LsapEnumerateAccountRights( + PolicyHandle, + AccountSid, + UserRights, + CountOfRights + ); + + } + + return Status; +} + + +NTSTATUS +NTAPI +LsaAddAccountRights( + IN LSA_HANDLE PolicyHandle, + IN PSID AccountSid, + IN PUNICODE_STRING UserRights, + IN ULONG CountOfRights + ) + +/*++ + +Routine Description: + + Adds rights to the account specified by the account sid. If the account + does not exist, it creates the account. + +Arguments: + + PolicyHandle - Handle from an LsaOpenPolicy call. The handle must have + POLICY_CREATE_ACCOUNT access if this is the first call for this + AccountSid. + + AccountSid - Sid of account to add rights to + + UserRights - Array of unicode strings naming rights to add to the + account. + +Return Value: + STATUS_INSUFFICIENT_RESOURCES - not enough memory to process the request + + STATUS_INVALID_PARAMTER - one of the parameters was not present + + STATUS_NO_SUCH_PRIVILEGE - One of the user rights was invalid + + STATUS_ACCESS_DENIED - the caller does not have sufficient access to the + account to add privileges. + +--*/ + +{ + NTSTATUS Status; + LSAPR_USER_RIGHT_SET UserRightSet; + + UserRightSet.Entries = CountOfRights; + UserRightSet.UserRights = (PLSAPR_UNICODE_STRING) UserRights; + + RpcTryExcept { + + Status = LsarAddAccountRights( + (LSAPR_HANDLE) PolicyHandle, + (PLSAPR_SID) AccountSid, + &UserRightSet + ); + + } RpcExcept( EXCEPTION_EXECUTE_HANDLER ) { + + Status = LsapApiReturnResult(I_RpcMapWin32Status(RpcExceptionCode())); + + } RpcEndExcept; + + // + // If the RPC server stub didn't exist, use the old version of the + // API. + // + + if ((Status == RPC_NT_UNKNOWN_IF) || + (Status == RPC_NT_PROCNUM_OUT_OF_RANGE)) { + + Status = LsapAddAccountRights( + PolicyHandle, + AccountSid, + UserRights, + CountOfRights + ); + } + return Status; +} + + +NTSTATUS +NTAPI +LsaRemoveAccountRights( + IN LSA_HANDLE PolicyHandle, + IN PSID AccountSid, + IN BOOLEAN AllRights, + IN PUNICODE_STRING UserRights, + IN ULONG CountOfRights + ) + +/*++ + +Routine Description: + + Removes rights to the account specified by the account sid. If the + AllRights flag is set or if all the rights are removed, the account + is deleted. + +Arguments: + + PolicyHandle - Handle from an LsaOpenPolicy call + + AccountSid - Sid of account to remove rights from + + UserRights - Array of unicode strings naming rights to remove from the + account. + +Return Value: + STATUS_INSUFFICIENT_RESOURCES - not enough memory to process the request + + STATUS_INVALID_PARAMTER - one of the parameters was not present + + STATUS_NO_SUCH_PRIVILEGE - One of the user rights was invalid + + STATUS_ACCESS_DENIED - the caller does not have sufficient access to the + account to add privileges. + +--*/ +{ + NTSTATUS Status; + LSAPR_USER_RIGHT_SET UserRightSet; + + UserRightSet.Entries = CountOfRights; + UserRightSet.UserRights = (PLSAPR_UNICODE_STRING) UserRights; + + RpcTryExcept { + + Status = LsarRemoveAccountRights( + (LSAPR_HANDLE) PolicyHandle, + (PLSAPR_SID) AccountSid, + AllRights, + &UserRightSet + ); + + } RpcExcept( EXCEPTION_EXECUTE_HANDLER ) { + + Status = LsapApiReturnResult(I_RpcMapWin32Status(RpcExceptionCode())); + + } RpcEndExcept; + + if ((Status == RPC_NT_UNKNOWN_IF) || + (Status == RPC_NT_PROCNUM_OUT_OF_RANGE)) { + + Status = LsapRemoveAccountRights( + PolicyHandle, + AccountSid, + AllRights, + UserRights, + CountOfRights + ); + } + + return Status; +} + +NTSTATUS +NTAPI +LsaQueryTrustedDomainInfo( + IN LSA_HANDLE PolicyHandle, + IN PSID TrustedDomainSid, + IN TRUSTED_INFORMATION_CLASS InformationClass, + OUT PVOID *Buffer + ) + +/*++ + +Routine Description: + + The LsaQueryTrustedDomainInfo API obtains information from a + TrustedDomain object. The caller must have access appropriate to the + information being requested (see InformationClass parameter). It also + may query the secret object (for the TrustedDomainPasswordInformation + class). + +Arguments: + + PolicyHandle - Handle from an LsaOpenPolicy call. + + TrustedDomainSid - Sid of domain to query. + + InformationClass - Specifies the information to be returned. + + Buffer - Receives a pointer to the buffer returned comtaining the + requested information. This buffer is allocated by this service + and must be freed when no longer needed by passing the returned + value to LsaFreeMemory(). + +Return Value: + + NTSTATUS - Standard Nt Result Code + + STATUS_ACCESS_DENIED - Caller does not have the appropriate + access to complete the operation. + + STATUS_INSUFFICIENT_RESOURCES - Insufficient system resources, + such as memory, to complete the call. +--*/ +{ + NTSTATUS Status; + PLSAP_CR_CIPHER_VALUE CipherPassword = NULL; + PLSAP_CR_CIPHER_VALUE CipherOldPassword = NULL; + PLSAP_CR_CLEAR_VALUE ClearPassword = NULL; + PLSAP_CR_CLEAR_VALUE ClearOldPassword = NULL; + PLSAP_CR_CIPHER_KEY SessionKey = NULL; + ULONG DomainInfoSize; + PUCHAR Where = NULL; + PTRUSTED_PASSWORD_INFO PasswordInformation = NULL; + + PLSAPR_TRUSTED_DOMAIN_INFO TrustedDomainInformation = NULL; + + RpcTryExcept { + + // + // Call the Client Stub for LsaQueryInformationTrustedDomain. + // + + Status = LsarQueryTrustedDomainInfo( + (LSAPR_HANDLE) PolicyHandle, + (PLSAPR_SID) TrustedDomainSid, + InformationClass, + &TrustedDomainInformation + ); + + // + // Return pointer to Policy Information for the given class, or NULL. + // + + + } RpcExcept( EXCEPTION_EXECUTE_HANDLER ) { + + // + // If memory was allocated for the returned Trusted Domain Information, + // free it. + // + + if (TrustedDomainInformation != NULL) { + + MIDL_user_free(TrustedDomainInformation); + } + + Status = LsapApiReturnResult(I_RpcMapWin32Status(RpcExceptionCode())); + + } RpcEndExcept; + + if (!NT_SUCCESS(Status)) { + goto Cleanup; + } + + // + // if we aren't getting passwords, skip out here. Otherwise we need to + // decrypt the passwords. + // + + if (InformationClass != TrustedPasswordInformation) { + *Buffer = TrustedDomainInformation; + TrustedDomainInformation = NULL; + goto Cleanup; + } + + // + // Obtain the Session Key to be used to two-way encrypt the + // Current Value and/or Old Values. + // + + RpcTryExcept { + + Status = LsapCrClientGetSessionKey( PolicyHandle, &SessionKey ); + + } RpcExcept( EXCEPTION_EXECUTE_HANDLER ) { + + Status = LsapApiReturnResult(I_RpcMapWin32Status(RpcExceptionCode())); + + } RpcEndExcept; + + if (!NT_SUCCESS(Status)) { + + goto Cleanup; + } + + // + // If the Current Value is requested and a Current Value exists, + // decrypt it using the Session key. Otherwise store NULL for return. + // + + if (TrustedDomainInformation->TrustedPasswordInfo.Password != NULL) { + + Status = LsapCrDecryptValue( + (PLSAP_CR_CIPHER_VALUE) + TrustedDomainInformation->TrustedPasswordInfo.Password, + SessionKey, + &ClearPassword + ); + + if (!NT_SUCCESS(Status)) { + + goto Cleanup; + } + + // + // Convert Clear Current Value to Unicode + // + + LsapCrClearValueToUnicode( + ClearPassword, + (PUNICODE_STRING) ClearPassword + ); + + + } + + // + // Get the old password + // + + if (TrustedDomainInformation->TrustedPasswordInfo.OldPassword != NULL) { + + Status = LsapCrDecryptValue( + (PLSAP_CR_CIPHER_VALUE) + TrustedDomainInformation->TrustedPasswordInfo.OldPassword, + SessionKey, + &ClearOldPassword + ); + + if (!NT_SUCCESS(Status)) { + + goto Cleanup; + } + + // + // Convert Clear Current Value to Unicode + // + + LsapCrClearValueToUnicode( + ClearOldPassword, + (PUNICODE_STRING) ClearOldPassword + ); + + + } + + + MIDL_user_free(TrustedDomainInformation); + TrustedDomainInformation = NULL; + + + // + // Allocate a buffer for the two passwords and marshall the + // passwords into the buffer. + // + + DomainInfoSize = sizeof(TRUSTED_PASSWORD_INFO); + + if (ClearPassword != NULL) { + + DomainInfoSize += ((PUNICODE_STRING) ClearPassword)->MaximumLength; + } + if (ClearOldPassword != NULL) { + + DomainInfoSize += ((PUNICODE_STRING) ClearOldPassword)->MaximumLength; + } + + PasswordInformation = (PTRUSTED_PASSWORD_INFO) MIDL_user_allocate(DomainInfoSize); + if (PasswordInformation == NULL) { + Status = STATUS_INSUFFICIENT_RESOURCES; + goto Cleanup; + } + + Where = (PUCHAR) (PasswordInformation+1); + + if (ClearPassword != NULL) + { + PasswordInformation->Password = *(PUNICODE_STRING) ClearPassword; + PasswordInformation->Password.Buffer = (LPWSTR) Where; + Where += PasswordInformation->Password.MaximumLength; + RtlCopyUnicodeString( + &PasswordInformation->Password, + (PUNICODE_STRING) ClearPassword + ); + } + + if (ClearOldPassword != NULL) + { + PasswordInformation->OldPassword = *(PUNICODE_STRING) ClearOldPassword; + PasswordInformation->OldPassword.Buffer = (LPWSTR) Where; + Where += PasswordInformation->OldPassword.MaximumLength; + RtlCopyUnicodeString( + &PasswordInformation->OldPassword, + (PUNICODE_STRING) ClearOldPassword + ); + } + ASSERT(Where - (PUCHAR) PasswordInformation == (LONG) DomainInfoSize); + + *Buffer = PasswordInformation; + PasswordInformation = NULL; + Status = STATUS_SUCCESS; + +Cleanup: + // + // If necessary, free memory allocated for the Session Key. + // + + if (SessionKey != NULL) { + + MIDL_user_free(SessionKey); + } + + // + // If necessary, free memory allocated for the returned Encrypted + // Current Value. + // + + if (CipherPassword != NULL) { + + LsapCrFreeMemoryValue(CipherPassword); + } + + // + // If necessary, free memory allocated for the returned Encrypted + // Old Value. + // + + if (CipherOldPassword != NULL) { + + LsapCrFreeMemoryValue(CipherOldPassword); + } + if (ClearPassword != NULL) { + + LsapCrFreeMemoryValue(ClearPassword); + } + if (ClearOldPassword != NULL) { + + LsapCrFreeMemoryValue(ClearOldPassword); + } + + if (TrustedDomainInformation != NULL) { + MIDL_user_free(TrustedDomainInformation); + } + + if (PasswordInformation != NULL) { + MIDL_user_free(PasswordInformation); + } + + // + // If the error was that the server stub didn't exist, call + // the old version of the API. + // + + if ((Status == RPC_NT_UNKNOWN_IF) || + (Status == RPC_NT_PROCNUM_OUT_OF_RANGE)) { + + Status = LsapQueryTrustedDomainInfo( + PolicyHandle, + TrustedDomainSid, + InformationClass, + Buffer + ); + } + + return Status; +} + +NTSTATUS +NTAPI +LsaSetTrustedDomainInformation( + IN LSA_HANDLE PolicyHandle, + IN PSID TrustedDomainSid, + IN TRUSTED_INFORMATION_CLASS InformationClass, + IN PVOID Buffer + ) + + +/*++ + +Routine Description: + + + The LsaSetTrustedDomainInformation API modifies information in the Trusted + Domain Object and in the Secret Object. The caller must have access + appropriate to the information to be changed in the Policy Object, see + the InformationClass parameter. + + If the domain does not yet exist and the information class is + TrustedDomainNameInformation, then the domain is created. If the + domain exists and the class is TrustedDomainNameInformation, an + error is returned. + +Arguments: + + PolicyHandle - Handle from an LsaOpenPolicy call. + + TrustedDomainSid - Sid of domain to modify. + + InformationClass - Specifies the type of information being changed. + The information types and accesses required to change them are as + follows: + + TrustedDomainNameInformation POLICY_TRUST_ADMIN + TrustedPosixOffsetInformation none + TrustedPasswordInformation POLICY_CREATE_SECRET + + Buffer - Points to a structure containing the information appropriate + to the InformationClass parameter. + +Return Value: + + NTSTATUS - Standard Nt Result Code + + STATUS_ACCESS_DENIED - Caller does not have the appropriate access + to complete the operation. + + Others TBS +--*/ + +{ + NTSTATUS Status; + PLSAPR_TRUSTED_DOMAIN_INFO DomainInformation; + LSAPR_TRUSTED_PASSWORD_INFO LsaPasswordInfo; + PTRUSTED_PASSWORD_INFO PasswordInformation; + PLSAP_CR_CIPHER_VALUE CipherPassword = NULL; + LSAP_CR_CLEAR_VALUE ClearPassword; + PLSAP_CR_CIPHER_VALUE CipherOldPassword = NULL; + LSAP_CR_CLEAR_VALUE ClearOldPassword; + PLSAP_CR_CIPHER_KEY SessionKey = NULL; + PUNICODE_STRING OldPassword; + + // + // If the infotype is TrustedPasswordInformation, then we need to + // setup a secure channel to transmit the secret passwords. + // + + if (InformationClass == TrustedPasswordInformation) { + + PasswordInformation = (PTRUSTED_PASSWORD_INFO) Buffer; + LsaPasswordInfo.Password = NULL; + LsaPasswordInfo.OldPassword = NULL; + + // + // Obtain the Session Key to be used to two-way encrypt the + // Current Value. + // + + RpcTryExcept { + + Status = LsapCrClientGetSessionKey( PolicyHandle, &SessionKey ); + + } RpcExcept( EXCEPTION_EXECUTE_HANDLER ) { + + Status = LsapApiReturnResult(I_RpcMapWin32Status(RpcExceptionCode())); + + } RpcEndExcept; + + if (!NT_SUCCESS(Status)) { + + goto Cleanup; + } + + // + // The password must be specified, even if it is an empty string. + // + + if (PasswordInformation->Password.Buffer != NULL) { + + // + // Convert input from Unicode Structures to Clear Value Structures. + // + + LsapCrUnicodeToClearValue( + &PasswordInformation->Password, + &ClearPassword + ); + + + + // + // Encrypt the Current Value if specified and not too long. + // + + + Status = LsapCrEncryptValue( + &ClearPassword, + SessionKey, + &CipherPassword + ); + + if (!NT_SUCCESS(Status)) { + + goto Cleanup; + } + LsaPasswordInfo.Password = (PLSAPR_CR_CIPHER_VALUE) CipherPassword; + + // + // If the old password wasn't specified, set it to be the + // new password. + // + + if (PasswordInformation->OldPassword.Buffer == NULL) { + OldPassword = &PasswordInformation->Password; + } else { + OldPassword = &PasswordInformation->OldPassword; + } + + + // + // Convert input from Unicode Structures to Clear Value Structures. + // + + LsapCrUnicodeToClearValue( + OldPassword, + &ClearOldPassword + ); + + + + // + // Encrypt the Current Value if specified and not too long. + // + + + Status = LsapCrEncryptValue( + &ClearOldPassword, + SessionKey, + &CipherOldPassword + ); + + if (!NT_SUCCESS(Status)) { + + goto Cleanup; + } + LsaPasswordInfo.OldPassword = (PLSAPR_CR_CIPHER_VALUE) CipherOldPassword; + } else { + Status = STATUS_INVALID_PARAMETER; + goto Cleanup; + } + + DomainInformation = (PLSAPR_TRUSTED_DOMAIN_INFO) &LsaPasswordInfo; + + } else { + DomainInformation = (PLSAPR_TRUSTED_DOMAIN_INFO) Buffer; + } + + RpcTryExcept { + + // + // Call the Client Stub for LsaSetInformationTrustedDomain + // + + Status = LsarSetTrustedDomainInfo + ( + (LSAPR_HANDLE) PolicyHandle, + (PLSAPR_SID) TrustedDomainSid, + InformationClass, + DomainInformation + ); + + } RpcExcept( EXCEPTION_EXECUTE_HANDLER ) { + + Status = LsapApiReturnResult(I_RpcMapWin32Status(RpcExceptionCode())); + + } RpcEndExcept; + +Cleanup: + if (SessionKey != NULL) { + MIDL_user_free(SessionKey); + } + if (CipherPassword != NULL) { + LsaFreeMemory(CipherPassword); + } + if (CipherOldPassword != NULL) { + LsaFreeMemory(CipherOldPassword); + } + + // + // If the error was that the server stub didn't exist, call + // the old version of the API. + // + + if ((Status == RPC_NT_UNKNOWN_IF) || + (Status == RPC_NT_PROCNUM_OUT_OF_RANGE)) { + + Status = LsapSetTrustedDomainInformation( + PolicyHandle, + TrustedDomainSid, + InformationClass, + Buffer + ); + } + + return Status; +} + + +NTSTATUS +NTAPI +LsaDeleteTrustedDomain( + IN LSA_HANDLE PolicyHandle, + IN PSID TrustedDomainSid + ) + +/*++ + +Routine Description: + + This routine deletes a trusted domain and the associated secret. + +Arguments: + + PolicyHandle - Handle from an LsaOpenPolicy call. + + TrustedDomainSid - Sid of domain to delete + +Return Value: + + STATUS_ACCESS_DENIED - caller has insufficient access to delete + the requested domain. + + STATUS_OBJECT_NAME_NOT_FOUND - The requested domain does not exist. + +--*/ +{ + NTSTATUS Status; + + RpcTryExcept { + + + Status = LsarDeleteTrustedDomain( + (LSAPR_HANDLE) PolicyHandle, + (PLSAPR_SID) TrustedDomainSid + ); + + } RpcExcept( EXCEPTION_EXECUTE_HANDLER ) { + + Status = LsapApiReturnResult(I_RpcMapWin32Status(RpcExceptionCode())); + + } RpcEndExcept; + + // + // If the error was that the server stub didn't exist, call + // the old version of the API. + // + + if ((Status == RPC_NT_UNKNOWN_IF) || + (Status == RPC_NT_PROCNUM_OUT_OF_RANGE)) { + + Status = LsapDeleteTrustedDomain( + PolicyHandle, + TrustedDomainSid + ); + } + + return(Status); +} + +// +// This API sets the workstation password (equivalent of setting/getting +// the SSI_SECRET_NAME secret) +// + +NTSTATUS +NTAPI +LsaStorePrivateData( + IN LSA_HANDLE PolicyHandle, + IN PUNICODE_STRING KeyName, + IN OPTIONAL PUNICODE_STRING PrivateData + ) + +/*++ + +Routine Description: + + This routine stores private data in an LSA secret named KeyName. + +Arguments: + + PolicyHandle - Handle from an LsaOpenPolicyCall. If this is the + first call, it requres POLICY_CREATE_SECRET access. + + KeyName - Name of secret to store. + + PrivateData - Data to store. If not present, the secret is deleted. + +Return Value: + + STATUS_ACCESS_DENIED - caller has insufficient privilege to set + the workstation password. + +--*/ + + +{ + NTSTATUS Status; + + PLSAP_CR_CIPHER_VALUE CipherCurrentValue = NULL; + LSAP_CR_CLEAR_VALUE ClearCurrentValue; + PLSAP_CR_CIPHER_KEY SessionKey = NULL; + + if (ARGUMENT_PRESENT(PrivateData)) { + + // + // Convert input from Unicode Structures to Clear Value Structures. + // + + + LsapCrUnicodeToClearValue( PrivateData, &ClearCurrentValue ); + + // + // Obtain the Session Key to be used to two-way encrypt the + // Current Value. + // + + RpcTryExcept { + + Status = LsapCrClientGetSessionKey( PolicyHandle, &SessionKey ); + + } RpcExcept( EXCEPTION_EXECUTE_HANDLER ) { + + Status = LsapApiReturnResult(I_RpcMapWin32Status(RpcExceptionCode())); + + } RpcEndExcept; + + if (!NT_SUCCESS(Status)) { + + goto Cleanup; + } + + // + // Encrypt the Current Value if specified and not too long. + // + + + Status = LsapCrEncryptValue( + &ClearCurrentValue, + SessionKey, + &CipherCurrentValue + ); + + if (!NT_SUCCESS(Status)) { + + goto Cleanup; + } + + + } + + // + // Set the Secret Values. + // + + RpcTryExcept { + + Status = LsarStorePrivateData( + (LSAPR_HANDLE) PolicyHandle, + (PLSAPR_UNICODE_STRING) KeyName, + (PLSAPR_CR_CIPHER_VALUE) CipherCurrentValue + ); + + } RpcExcept( EXCEPTION_EXECUTE_HANDLER ) { + + Status = LsapApiReturnResult(I_RpcMapWin32Status(RpcExceptionCode())); + + } RpcEndExcept; + + if (!NT_SUCCESS(Status)) { + + goto Cleanup; + } + +Cleanup: + + // + // If necessary, free memory allocated for the Encrypted Current Value. + // + + if (CipherCurrentValue != NULL) { + + LsaFreeMemory(CipherCurrentValue); + } + + // + // If necessary, free memory allocated for the Session Key. + // + + if (SessionKey != NULL) { + + MIDL_user_free(SessionKey); + } + + // + // If the error was that the server stub didn't exist, call + // the old version of the API. + // + + if ((Status == RPC_NT_UNKNOWN_IF) || + (Status == RPC_NT_PROCNUM_OUT_OF_RANGE)) { + + Status = LsapStorePrivateData( + PolicyHandle, + KeyName, + PrivateData + ); + } + + + return(Status); + +} + + +NTSTATUS +NTAPI +LsaRetrievePrivateData( + IN LSA_HANDLE PolicyHandle, + IN PUNICODE_STRING KeyName, + OUT PUNICODE_STRING *PrivateData + ) + +/*++ + +Routine Description: + + This routine returns the secret stored in KeyName. + +Arguments: + + PolicyHandle - Handle from an LsaOpenPolicyCall + + KeyName - Name of secret to retrieve + + PrivateData - Receives private data, should be freed with LsaFreeMemory. + + +Return Value: + + STATUS_ACCESS_DENIED - caller has insufficient access to get the + private data. + + STATUS_OBJECT_NAME_NOT_FOUND - there is no private data stored under + KeyName. + +--*/ + +{ + NTSTATUS Status = STATUS_SUCCESS; + + PLSAP_CR_CIPHER_VALUE CipherCurrentValue = NULL; + PLSAP_CR_CLEAR_VALUE ClearCurrentValue = NULL; + PLSAP_CR_CIPHER_KEY SessionKey = NULL; + + RpcTryExcept { + + Status = LsarRetrievePrivateData( + (PLSAPR_HANDLE) PolicyHandle, + (PLSAPR_UNICODE_STRING) KeyName, + (PLSAPR_CR_CIPHER_VALUE *) &CipherCurrentValue + ); + + } RpcExcept( EXCEPTION_EXECUTE_HANDLER ) { + + Status = LsapApiReturnResult(I_RpcMapWin32Status(RpcExceptionCode())); + + } RpcEndExcept; + + if (!NT_SUCCESS(Status)) { + + goto QuerySecretError; + } + + // + // Obtain the Session Key to be used to two-way encrypt the + // Current Value and/or Old Values. + // + + RpcTryExcept { + + Status = LsapCrClientGetSessionKey( PolicyHandle, &SessionKey ); + + } RpcExcept( EXCEPTION_EXECUTE_HANDLER ) { + + Status = LsapApiReturnResult(I_RpcMapWin32Status(RpcExceptionCode())); + + } RpcEndExcept; + + if (!NT_SUCCESS(Status)) { + + goto QuerySecretError; + } + + // + // If the Current Value is requested and a Current Value exists, + // decrypt it using the Session key. Otherwise store NULL for return. + // + + if (CipherCurrentValue != NULL) { + + Status = LsapCrDecryptValue( + CipherCurrentValue, + SessionKey, + &ClearCurrentValue + ); + + if (!NT_SUCCESS(Status)) { + + goto QuerySecretError; + } + + // + // Convert Clear Current Value to Unicode + // + + LsapCrClearValueToUnicode( + ClearCurrentValue, + (PUNICODE_STRING) ClearCurrentValue + ); + *PrivateData = (PUNICODE_STRING) ClearCurrentValue; + + } else { + + *PrivateData = NULL; + } + + + + +QuerySecretFinish: + + // + // If necessary, free memory allocated for the Session Key. + // + + if (SessionKey != NULL) { + + MIDL_user_free(SessionKey); + } + + // + // If necessary, free memory allocated for the returned Encrypted + // Current Value. + // + + if (CipherCurrentValue != NULL) { + + LsapCrFreeMemoryValue(CipherCurrentValue); + } + + + // + // If the error was that the server stub didn't exist, call + // the old version of the API. + // + + if ((Status == RPC_NT_UNKNOWN_IF) || + (Status == RPC_NT_PROCNUM_OUT_OF_RANGE)) { + + Status = LsapRetrievePrivateData( + PolicyHandle, + KeyName, + PrivateData + ); + } + + + + return(Status); + +QuerySecretError: + + // + // If necessary, free memory allocated for the Clear Current Value + // + + if (ClearCurrentValue != NULL) { + + LsapCrFreeMemoryValue(ClearCurrentValue); + } + + + *PrivateData = NULL; + + + goto QuerySecretFinish; +} + + + +NTSTATUS +LsapApiConvertRightsToPrivileges( + IN LSA_HANDLE PolicyHandle, + IN PUNICODE_STRING UserRights, + IN ULONG RightCount, + OUT PPRIVILEGE_SET * Privileges, + OUT PULONG SystemAccess + ) +/*++ + +Routine Description: + + Converts an array of user rights (unicode strings) into a privilege set + and a system access flag. + +Arguments: + + PolicyHandle - Handle from an LsaOpenPolicyCall, requires POLICY_LOOKUP_NAME + access. + + UserRights - Array of user rights + + RightCount - Count of user rights + + Privileges - Receives privilege set, should be freed with MIDL_user_free + + SystemAccess - Receives system access flags. + +Return Value: + +--*/ + +{ + ULONG RightIndex; + ULONG PrivilegeIndex; + ULONG AccessIndex; + PPRIVILEGE_SET PrivilegeSet = NULL; + ULONG Access = 0; + ULONG PrivilegeSetSize = 0; + NTSTATUS Status; + LUID PrivilegeValue; + + // + // if we weren't passed any privileges, don't allocate anything. + // + + if (RightCount == 0) { + + *Privileges = NULL; + SystemAccess = 0; + return(STATUS_SUCCESS); + } + + // + // Compute the size of the privilege set. We actually over estimate + // by assuming that all the rights are privileges. We subtract one + // from RightCount to take into account the fact that a PRIVILEGE_SET + // has one LUID_AND_ATTRIBUTE in it. + // + + + PrivilegeSetSize = sizeof(PRIVILEGE_SET) + + (RightCount-1) * sizeof(LUID_AND_ATTRIBUTES); + + PrivilegeSet = (PPRIVILEGE_SET) MIDL_user_allocate(PrivilegeSetSize); + + if (PrivilegeSet == NULL) { + Status = STATUS_INSUFFICIENT_RESOURCES; + goto Cleanup; + } + + // + // Try looking up every right. If we find it as a privilege, + // add it to the privilege set. + // + + PrivilegeIndex = 0; + + for (RightIndex = 0; RightIndex < RightCount ; RightIndex++) { + Status = LsaLookupPrivilegeValue( + PolicyHandle, + &UserRights[RightIndex], + &PrivilegeValue + ); + if (NT_SUCCESS(Status)) { + PrivilegeSet->Privilege[PrivilegeIndex].Luid = PrivilegeValue; + PrivilegeSet->Privilege[PrivilegeIndex].Attributes = 0; + PrivilegeIndex++; + + } else if (Status != STATUS_NO_SUCH_PRIVILEGE) { + // + // This is a more serious error - bail here. + // + + goto Cleanup; + } else { + + // + // Try looking up the right as a system access type. + // + + for (AccessIndex = 0; AccessIndex < LSAP_DB_SYSTEM_ACCESS_TYPES ; AccessIndex++) { + if (RtlCompareUnicodeString( + &UserRights[RightIndex], + &LsapDbRightAndAccess[AccessIndex].UserRight, + FALSE // case sensitive + ) == 0) { + Access |= LsapDbRightAndAccess[AccessIndex].SystemAccess; + break; + } + } + + // + // If we went through the access types without finding the right, + // it must not be valid so escape here. + // + + if (AccessIndex == LSAP_DB_SYSTEM_ACCESS_TYPES) { + Status = STATUS_NO_SUCH_PRIVILEGE; + goto Cleanup; + } + + } + } + + PrivilegeSet->Control = 0; + PrivilegeSet->PrivilegeCount = PrivilegeIndex; + + *Privileges = PrivilegeSet; + *SystemAccess = Access; + + Status = STATUS_SUCCESS; + +Cleanup: + if (!NT_SUCCESS(Status)) { + if (PrivilegeSet != NULL) { + LsaFreeMemory(PrivilegeSet); + } + } + + return(Status); + +} + +NTSTATUS +LsapApiConvertPrivilegesToRights( + IN LSA_HANDLE PolicyHandle, + IN OPTIONAL PPRIVILEGE_SET Privileges, + IN OPTIONAL ULONG SystemAccess, + OUT PUNICODE_STRING * UserRights, + OUT PULONG RightCount + ) +/*++ + +Routine Description: + + Converts a privilege set and a system access flag into an array of + user rights (unicode strings). + +Arguments: + + PolicyHandle - Handle from an LsaOpenPolicy call, must have + POLICY_LOOKUP_NAMES access. + + Privileges - Privilege set to convert + + SystemAccess - System access flags to convert + + UserRights - Receives an array of user rights (unicode strings). Should + be freed with MIDL_user_free + + RightCount - Receives count of rights in UserRights array + + +Return Value: + +--*/ + +{ + NTSTATUS Status; + PUNICODE_STRING OutputRights = NULL; + PUNICODE_STRING * PrivilegeNames = NULL; + UNICODE_STRING AccessNames[LSAP_DB_SYSTEM_ACCESS_TYPES]; + ULONG RightSize; + ULONG PrivilegeSize; + ULONG Count; + ULONG PrivilegeIndex; + ULONG AccessIndex; + ULONG RightIndex; + ULONG AccessCount; + PUCHAR Where; + + // + // Compute the size of the temporary array. This is just an array of + // pointers to unicode strings to hold the privilege names until + // we reallocate them into one big buffer. + // + + RightSize = 0; + Count = 0; + if (ARGUMENT_PRESENT(Privileges)) { + + PrivilegeSize = Privileges->PrivilegeCount * sizeof(PUNICODE_STRING); + PrivilegeNames = (PUNICODE_STRING *) MIDL_user_allocate(PrivilegeSize); + + if (PrivilegeNames == NULL) { + + Status = STATUS_INSUFFICIENT_RESOURCES; + goto Cleanup; + } + + RtlZeroMemory( + PrivilegeNames, + PrivilegeSize + ); + + // + // Lookup the privilge name and store it in the temporary array + // + + for (PrivilegeIndex = 0; PrivilegeIndex < Privileges->PrivilegeCount ;PrivilegeIndex++ ) { + + Status = LsaLookupPrivilegeName( + PolicyHandle, + &Privileges->Privilege[PrivilegeIndex].Luid, + &PrivilegeNames[PrivilegeIndex] + ); + if (!NT_SUCCESS(Status)) { + goto Cleanup; + } + RightSize += sizeof(UNICODE_STRING) + PrivilegeNames[PrivilegeIndex]->MaximumLength; + } + } + + // + // Now convert the system access flags to user rights. + // + + if (ARGUMENT_PRESENT(SystemAccess)) { + + AccessCount = 0; + for (AccessIndex = 0; AccessIndex < LSAP_DB_SYSTEM_ACCESS_TYPES ; AccessIndex++) { + + if ((SystemAccess & LsapDbRightAndAccess[AccessIndex].SystemAccess) != 0) { + + AccessNames[AccessCount] = LsapDbRightAndAccess[AccessIndex].UserRight; + RightSize += sizeof(UNICODE_STRING) + AccessNames[AccessCount].MaximumLength; + AccessCount++; + } + } + } + + // + // Allocate the output buffer and start copying the strings into the + // buffer. + // + + Count = Privileges->PrivilegeCount + AccessCount; + + OutputRights = (PUNICODE_STRING) MIDL_user_allocate(RightSize); + if (OutputRights == NULL) { + Status = STATUS_INSUFFICIENT_RESOURCES; + goto Cleanup; + } + + Where = (PUCHAR) OutputRights + (Count * sizeof(UNICODE_STRING)); + + // + // Copy in the privileges first + // + + RightIndex = 0; + for (PrivilegeIndex = 0; PrivilegeIndex < Privileges->PrivilegeCount ; PrivilegeIndex ++) { + + OutputRights[RightIndex] = *PrivilegeNames[PrivilegeIndex]; + OutputRights[RightIndex].Buffer = (LPWSTR) Where; + RtlCopyMemory( + Where, + PrivilegeNames[PrivilegeIndex]->Buffer, + OutputRights[RightIndex].MaximumLength + ); + Where += OutputRights[RightIndex].MaximumLength; + RightIndex++; + } + + // + // Now copy in the access types + // + + for (AccessIndex = 0; AccessIndex < AccessCount; AccessIndex++) { + + OutputRights[RightIndex] = AccessNames[AccessIndex]; + OutputRights[RightIndex].Buffer = (LPWSTR) Where; + RtlCopyMemory( + Where, + AccessNames[AccessIndex].Buffer, + OutputRights[RightIndex].MaximumLength + ); + Where += OutputRights[RightIndex].MaximumLength; + RightIndex++; + } + + ASSERT(RightIndex == Count); + + *UserRights = OutputRights; + OutputRights = NULL; + *RightCount = Count; + + Status = STATUS_SUCCESS; + +Cleanup: + + if (PrivilegeNames != NULL) { + for (PrivilegeIndex = 0; PrivilegeIndex < Privileges->PrivilegeCount ; PrivilegeIndex++) { + if (PrivilegeNames[PrivilegeIndex] != NULL) { + LsaFreeMemory(PrivilegeNames[PrivilegeIndex]); + } + } + MIDL_user_free(PrivilegeNames); + } + + if (OutputRights != NULL) { + MIDL_user_free(OutputRights); + } + + return(Status); +} + + + +DWORD +LsaNtStatusToWinError( + IN NTSTATUS Status + ) +/*++ + +Routine Description: + + This routine converts and NTSTATUS to an win32 error code. It is used + by people who want to call the LSA APIs but are writing for a win32 + environment. + +Arguments: + + Status - The status code to be mapped + +Return Value: + + The return from RtlNtStatusToDosError. If the error could not be + mapped, then ERROR_MR_MID_NOT_FOUND is returned. + +--*/ + +{ + return(RtlNtStatusToDosError(Status)); +} diff --git a/private/lsa/uclient/rpcbind.c b/private/lsa/uclient/rpcbind.c new file mode 100644 index 000000000..a75ab1399 --- /dev/null +++ b/private/lsa/uclient/rpcbind.c @@ -0,0 +1,102 @@ +/*++ + +Copyright (c) 1991 Microsoft Corporation + +Module Name: + + rpcbind.c + +Abstract: + + LSA - Client RPC Binding Routines + +Author: + + Scott Birrell (ScottBi) April 30, 1991 + +Environment: + +Revision History: + +--*/ + +#include "lsaclip.h" + +#include // prototypes for MIDL user functions + +handle_t +PLSAPR_SERVER_NAME_bind ( + IN OPTIONAL PLSAPR_SERVER_NAME ServerName + ) + +/*++ + +Routine Description: + + This routine is called from the LSA client stubs when + it is necessary to bind to the LSA on some server. + +Arguments: + + ServerName - A pointer to a string containing the name of the server + to bind with. + +Return Value: + + The binding handle is returned to the stub routine. If the + binding is unsuccessful, a NULL will be returned. + +--*/ + +{ + handle_t BindingHandle; + NTSTATUS Status; + + Status = RpcpBindRpc ( + ServerName, + L"lsarpc", + 0, + &BindingHandle + ); + + if (!NT_SUCCESS(Status)) { + + DbgPrint("PLSAPR_SERVER_NAME_bind: RpcpBindRpc failed 0x%lx\n", Status); + + } + + return( BindingHandle); +} + + +VOID +PLSAPR_SERVER_NAME_unbind ( + IN OPTIONAL PLSAPR_SERVER_NAME ServerName, + IN handle_t BindingHandle + ) + +/*++ + +Routine Description: + + This routine is called from the LSA client stubs when + it is necessary to unbind from the LSA server. + + +Arguments: + + ServerName - This is the name of the server from which to unbind. + + BindingHandle - This is the binding handle that is to be closed. + +Return Value: + + none. + +--*/ +{ + RpcpUnbindRpc ( BindingHandle ); + return; + + UNREFERENCED_PARAMETER( ServerName ); // This parameter is not used +} diff --git a/private/lsa/uclient/rpcclimm.c b/private/lsa/uclient/rpcclimm.c new file mode 100644 index 000000000..f23f95a9e --- /dev/null +++ b/private/lsa/uclient/rpcclimm.c @@ -0,0 +1,103 @@ +/*++ + +Copyright (c) 1991 Microsoft Corporation + +Module Name: + + rpcclimm.c + +Abstract: + + LSA - Client RPC Memory Management Routines + + NOTE: These routines use windows API, so are different from + their server counterparts. +Author: + + Scott Birrell (ScottBi) May 1, 1991 + +Environment: + +Revision History: + +--*/ + +#include "lsaclip.h" +/* +#include // DbgPrint prototype +#include // DbgPrint prototype +#include // DataTypes and runtime APIs +#include // generated by the MIDL complier +#include // needed for windows.h +#include // LocalAlloc +#include // for strcpy strcat strlen memcmp +*/ + + +PVOID +MIDL_user_allocate ( + unsigned int NumBytes + ) + +/*++ + +Routine Description: + + Allocates storage for RPC server transactions. The RPC stubs will + either call MIDL_user_allocate when it needs to un-marshall data into a + buffer that the user must free. RPC servers will use MIDL_user_allocate to + allocate storage that the RPC server stub will free after marshalling + the data. + +Arguments: + + NumBytes - The number of bytes to allocate. + +Return Value: + + none + +Note: + + +--*/ + +{ + return (LocalAlloc(LMEM_FIXED,NumBytes)); +} + + + +VOID +MIDL_user_free ( + void *MemPointer + ) + +/*++ + +Routine Description: + + Frees storage used in RPC transactions. The RPC client can call this + function to free buffer space that was allocated by the RPC client + stub when un-marshalling data that is to be returned to the client. + The Client calls MIDL_user_free when it is finished with the data and + desires to free up the storage. + The RPC server stub calls MIDL_user_free when it has completed + marshalling server data that is to be passed back to the client. + +Arguments: + + MemPointer - This points to the memory block that is to be released. + +Return Value: + + none. + +Note: + + +--*/ + +{ + LocalFree(MemPointer); +} diff --git a/private/lsa/uclient/runsamdb.cmd b/private/lsa/uclient/runsamdb.cmd new file mode 100644 index 000000000..0eb1e5b42 --- /dev/null +++ b/private/lsa/uclient/runsamdb.cmd @@ -0,0 +1,4 @@ +echo To start run, press enter in reply to Enter the new time prompt +time +ctsamdb %1 +time diff --git a/private/lsa/uclient/sources b/private/lsa/uclient/sources new file mode 100644 index 000000000..d28efe8d0 --- /dev/null +++ b/private/lsa/uclient/sources @@ -0,0 +1,44 @@ +!IF 0 + +Copyright (c) 1989 Microsoft Corporation + +Module Name: + + sources. + +Abstract: + + This file specifies the target component being built and the list of + sources files needed to build that component. Also specifies optional + compiler switches and libraries that are unique for the component being + built. + + +Author: + + Steve Wood (stevewo) 12-Apr-1990 + +NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl + +!ENDIF + +MAJORCOMP=lsa +MINORCOMP=uclient + +TARGETNAME=lsaudll +TARGETPATH=obj +TARGETTYPE=LIBRARY + +INCLUDES=..\inc;..\..\inc + +SOURCES= crclient.c \ + rpcapi.c \ + rpcapi2.c \ + rpcbind.c \ + lsarpc_c.c + +UMTYPE=windows + +UMTEST=ctlkacct*ctsamdb*ctlklsa + +C_DEFINES=$(C_DEFINES) -DRPC_NO_WINDOWS_H -D_ADVAPI32_ diff --git a/private/lsa/uclient/tgetsid.c b/private/lsa/uclient/tgetsid.c new file mode 100644 index 000000000..eefe21b2b --- /dev/null +++ b/private/lsa/uclient/tgetsid.c @@ -0,0 +1,211 @@ +/*++ + +Copyright (c) 1991 Microsoft Corporation + +Module Name: + + tgetsid.c + +Abstract: + + This file is a temporary test for querying the machine's SID. + +Author: + + Jim Kelly (JimK) 8-10-1994 + +Environment: + + User Mode - Win32 + + to build: nmake UMTYPE=console UMTEST=tgetsid + +Revision History: + + +--*/ + +/////////////////////////////////////////////////////////////////////////////// +// // +// Includes // +// // +/////////////////////////////////////////////////////////////////////////////// + + +#include +#include +#include +#include +#include + +BOOLEAN +GetMachineSid( + OUT PSID *Sid, + OUT PULONG SidLength + ); + +VOID _CRTAPI1 +main( VOID ) + +{ + + BOOLEAN + Result; + + PSID + Sid; + + PISID + ISid; + + ULONG + i, + SubCount, + Tmp, + SidLength; + + + Result = GetMachineSid( &Sid, &SidLength ); + + if (Result) { + + ISid = (PISID)Sid; // pointer to opaque structure + + printf("S-%u-", (USHORT)ISid->Revision ); + + if ( (ISid->IdentifierAuthority.Value[0] != 0) || + (ISid->IdentifierAuthority.Value[1] != 0) ){ + printf("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] ); + } 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); + printf("%lu", Tmp); + } + + SubCount = (ULONG)(*RtlSubAuthorityCountSid( Sid )); + for (i = 0; iDomainSid ); + ReturnSid = RtlAllocateHeap( RtlProcessHeap(), 0, (*SidLength) ); + + if (ReturnSid != NULL) { + + // + // Copy the sid + // + + RtlMoveMemory( ReturnSid, DomainInfo->DomainSid, (*SidLength) ); + (*Sid) = ReturnSid; + ReturnStatus = TRUE; + } + + + LsaFreeMemory( DomainInfo ); + } + + Status = LsaClose( PolicyHandle ); + ASSERT(NT_SUCCESS(Status)); + } + + return(ReturnStatus); +} diff --git a/private/lsa/uclient/tlookup.c b/private/lsa/uclient/tlookup.c new file mode 100644 index 000000000..9aba87ab3 --- /dev/null +++ b/private/lsa/uclient/tlookup.c @@ -0,0 +1,249 @@ +/*++ + +Copyright (c) 1994 Microsoft Corporation + +Module Name: + + tlookup.c + +Abstract: + + Test for a leak in LsaLookupName(). + + + nmake UMTYPE=console UMTEST=tlookup + +Author: + + Jim Kelly (JimK) Mar-31-1994 + + +Revision History: + +--*/ + + +/////////////////////////////////////////////////////////////////////////////// +// // +// Includes // +// // +/////////////////////////////////////////////////////////////////////////////// + + +#include +#include +#include +#include +#include + + + +/////////////////////////////////////////////////////////////////////////////// +// // +// Global Variables // +// // +/////////////////////////////////////////////////////////////////////////////// + +ULONG + TLsapLoopLimit = 1000; + + + +///////////////////////////////////////////////////////////////////////// +// // +// Local routine definitions // +// // +///////////////////////////////////////////////////////////////////////// + + + + +///////////////////////////////////////////////////////////////////////// +// // +// Routines // +// // +///////////////////////////////////////////////////////////////////////// + +VOID _CRTAPI1 +main(argc, argv) +int argc; +char **argv; +{ + + NTSTATUS + NtStatus, + LookupSidStatus = STATUS_SUCCESS; + + ULONG + i; + + LSA_HANDLE + PolicyHandle; + + OBJECT_ATTRIBUTES + ObjectAttributes; + + UNICODE_STRING + NameBuffer, + SystemName; + + PUNICODE_STRING + Names; + + PLSA_REFERENCED_DOMAIN_LIST + ReferencedDomains; + + PLSA_TRANSLATED_SID + Sids; + + ULONG + SidLength; + + PSID + LookupSid; + + BOOLEAN + DoSidTest; + + PLSA_TRANSLATED_NAME + TranslatedNames; + + + Names = &NameBuffer; + RtlInitUnicodeString( &NameBuffer, L"jimk_dom2\\Jimk_d2_t1" ); + RtlInitUnicodeString( &SystemName, L"" ); + + + printf("\n\nLsaLookupName() and LsaLookupSid() test.\n" + "This test is good to use when looking for leaks\n" + "in the lookup paths.\n\n"); + + + // + // open the policy object and then loop, looking up names. + // + + InitializeObjectAttributes( &ObjectAttributes, NULL, 0L, NULL, NULL ); + NtStatus = LsaOpenPolicy( + &SystemName, + &ObjectAttributes, + POLICY_EXECUTE, + &PolicyHandle + ); + + if (NT_SUCCESS(NtStatus)) { + + // + // Get a sid to lookup + // + + ReferencedDomains = NULL; + Sids = NULL; + NtStatus = LsaLookupNames( + PolicyHandle, + 1, //Count + Names, + &ReferencedDomains, + &Sids + ); + if (NT_SUCCESS(NtStatus)) { + + // + // Build a sid to use in the lookup + // This is done by copying the ReferencedDomain sid, + // then adding one more relative ID. + // + + ASSERT(ReferencedDomains != NULL); + ASSERT(Sids != NULL); + + SidLength = + sizeof(ULONG) + + RtlLengthSid( &ReferencedDomains->Domains[Sids[0].DomainIndex].Sid ); + + LookupSid = RtlAllocateHeap( RtlProcessHeap(), 0, SidLength ); + ASSERT(LookupSid != NULL); + + RtlCopySid( SidLength, + LookupSid, + ReferencedDomains->Domains[Sids[0].DomainIndex].Sid ); + (*RtlSubAuthoritySid( + LookupSid, + (ULONG)(*RtlSubAuthorityCountSid(LookupSid)) + )) = Sids[0].RelativeId; + (*RtlSubAuthorityCountSid(LookupSid)) += 1; + + DoSidTest = TRUE; + + } else { + + printf("ERROR: Couldn't get SID value to lookup.\n" + " Won't perform SID lookup part of test.\n\n"); + DoSidTest = FALSE; + } + + if (ReferencedDomains != NULL) { + LsaFreeMemory( ReferencedDomains ); + } + if (Sids != NULL) { + LsaFreeMemory( Sids ); + } + + + printf("\nLooping %d times...\n", TLsapLoopLimit); + for (i=0; i +#include +#include + + +// #include "sep.h" + +#define TstAllocatePool(IgnoredPoolType,NumberOfBytes) \ + (ITstAllocatePool( (NumberOfBytes) )) + +#define TstDeallocatePool(Pointer, NumberOfBytes) \ + (ITstDeallocatePool((Pointer),(NumberOfBytes) )) + +PVOID +ITstAllocatePool( + IN ULONG NumberOfBytes + ) +{ + NTSTATUS Status; + PVOID PoolAddress = NULL; + ULONG RegionSize; + + RegionSize = NumberOfBytes; + + Status = NtAllocateVirtualMemory( NtCurrentProcess(), + &PoolAddress, + 0, + &RegionSize, + MEM_COMMIT, + PAGE_READWRITE + ); + + return PoolAddress; +} + +VOID +ITstDeallocatePool( + IN PVOID Pointer, + IN ULONG NumberOfBytes + ) +{ + NTSTATUS Status; + PVOID PoolAddress; + ULONG RegionSize; + + RegionSize = NumberOfBytes; + PoolAddress = Pointer; + + Status = NtFreeVirtualMemory( NtCurrentProcess(), + &PoolAddress, + &RegionSize, + MEM_DECOMMIT + ); + + return; +} +#endif // _TST_USER_ + +#endif //_TSECOMM_ diff --git a/private/lsa/uclient/tsevars.c b/private/lsa/uclient/tsevars.c new file mode 100644 index 000000000..babbdf563 --- /dev/null +++ b/private/lsa/uclient/tsevars.c @@ -0,0 +1,447 @@ +/*++ + +Copyright (c) 1989 Microsoft Corporation + +Module Name: + + tsevars.c + +Abstract: + + This Module contains variables used in security test routines. + + +Author: + + Jim Kelly (JimK) 23-Mar-1990 + +Environment: + + Test. + +Revision History: + +--*/ + +#include "tsecomm.c" // Mode dependent macros and routines. + + +#ifndef _TSEVARS_ +#define _TSEVARS_ + + + + +typedef enum _USERS { + Fred, + Wilma, + Pebbles, + Barney, + Betty, + Bambam, + Dino +} USERS; + + +// +// 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; + + +// +// Universal well known SIDs +// + +PSID NullSid; +PSID WorldSid; +PSID LocalSid; +PSID CreatorOwnerSid; +PSID CreatorGroupSid; + +// +// Sids defined by NT +// + +PSID NtAuthoritySid; + +PSID DialupSid; +PSID NetworkSid; +PSID BatchSid; +PSID InteractiveSid; +PSID LocalSystemSid; + + + + + +//////////////////////////////////////////////////////////////////////// +// // +// Define the well known privileges // +// // +//////////////////////////////////////////////////////////////////////// + + +LUID CreateTokenPrivilege; +LUID AssignPrimaryTokenPrivilege; +LUID LockMemoryPrivilege; +LUID IncreaseQuotaPrivilege; +LUID UnsolicitedInputPrivilege; +LUID TcbPrivilege; +LUID SecurityPrivilege; + +LUID TakeOwnershipPrivilege; +LUID LpcReplyBoostPrivilege; +LUID CreatePagefilePrivilege; +LUID IncreaseBasePriorityPrivilege; +LUID SystemProfilePrivilege; +LUID SystemtimePrivilege; +LUID ProfileSingleProcessPrivilege; + +LUID RestorePrivilege; +LUID BackupPrivilege; +LUID CreatePermanentPrivilege; +LUID ShutdownPrivilege; +LUID DebugPrivilege; + + + + + +BOOLEAN +TSeVariableInitialization() +/*++ + +Routine Description: + + This function initializes the global variables used in security + tests. + +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 NullSidAuthority = SECURITY_NULL_SID_AUTHORITY; + SID_IDENTIFIER_AUTHORITY WorldSidAuthority = SECURITY_WORLD_SID_AUTHORITY; + SID_IDENTIFIER_AUTHORITY LocalSidAuthority = SECURITY_LOCAL_SID_AUTHORITY; + SID_IDENTIFIER_AUTHORITY CreatorSidAuthority = SECURITY_CREATOR_SID_AUTHORITY; + + 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 and initialize the universal SIDs + // + + NullSid = (PSID)TstAllocatePool(PagedPool,SidWithOneSubAuthority); + WorldSid = (PSID)TstAllocatePool(PagedPool,SidWithOneSubAuthority); + LocalSid = (PSID)TstAllocatePool(PagedPool,SidWithOneSubAuthority); + CreatorOwnerSid = (PSID)TstAllocatePool(PagedPool,SidWithOneSubAuthority); + CreatorGroupSid = (PSID)TstAllocatePool(PagedPool,SidWithOneSubAuthority); + + RtlInitializeSid( NullSid, &NullSidAuthority, 1 ); + RtlInitializeSid( WorldSid, &WorldSidAuthority, 1 ); + RtlInitializeSid( LocalSid, &LocalSidAuthority, 1 ); + RtlInitializeSid( CreatorOwnerSid, &CreatorSidAuthority, 1 ); + RtlInitializeSid( CreatorGroupSid, &CreatorSidAuthority, 1 ); + + *(RtlSubAuthoritySid( NullSid, 0 )) = SECURITY_NULL_RID; + *(RtlSubAuthoritySid( WorldSid, 0 )) = SECURITY_WORLD_RID; + *(RtlSubAuthoritySid( LocalSid, 0 )) = SECURITY_LOCAL_RID; + *(RtlSubAuthoritySid( CreatorOwnerSid, 0 )) = SECURITY_CREATOR_OWNER_RID; + *(RtlSubAuthoritySid( CreatorGroupSid, 0 )) = SECURITY_CREATOR_GROUP_RID; + + // + // Allocate and initialize the NT defined SIDs + // + + NtAuthoritySid = (PSID)TstAllocatePool(PagedPool,SidWithZeroSubAuthorities); + DialupSid = (PSID)TstAllocatePool(PagedPool,SidWithOneSubAuthority); + NetworkSid = (PSID)TstAllocatePool(PagedPool,SidWithOneSubAuthority); + BatchSid = (PSID)TstAllocatePool(PagedPool,SidWithOneSubAuthority); + InteractiveSid = (PSID)TstAllocatePool(PagedPool,SidWithOneSubAuthority); + LocalSystemSid = (PSID)TstAllocatePool(PagedPool,SidWithOneSubAuthority); + + RtlInitializeSid( NtAuthoritySid, &NtAuthority, 0 ); + RtlInitializeSid( DialupSid, &NtAuthority, 1 ); + RtlInitializeSid( NetworkSid, &NtAuthority, 1 ); + RtlInitializeSid( BatchSid, &NtAuthority, 1 ); + RtlInitializeSid( InteractiveSid, &NtAuthority, 1 ); + RtlInitializeSid( LocalSystemSid, &NtAuthority, 1 ); + + *(RtlSubAuthoritySid( DialupSid, 0 )) = SECURITY_DIALUP_RID; + *(RtlSubAuthoritySid( NetworkSid, 0 )) = SECURITY_NETWORK_RID; + *(RtlSubAuthoritySid( BatchSid, 0 )) = SECURITY_BATCH_RID; + *(RtlSubAuthoritySid( InteractiveSid, 0 )) = SECURITY_INTERACTIVE_RID; + *(RtlSubAuthoritySid( LocalSystemSid, 0 )) = SECURITY_LOCAL_SYSTEM_RID; + + + + // + // Allocate and initialize the Bedrock SIDs + // + + 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; + + CreateTokenPrivilege = + RtlConvertLongToLargeInteger(SE_CREATE_TOKEN_PRIVILEGE); + AssignPrimaryTokenPrivilege = + RtlConvertLongToLargeInteger(SE_ASSIGNPRIMARYTOKEN_PRIVILEGE); + LockMemoryPrivilege = + RtlConvertLongToLargeInteger(SE_LOCK_MEMORY_PRIVILEGE); + IncreaseQuotaPrivilege = + RtlConvertLongToLargeInteger(SE_INCREASE_QUOTA_PRIVILEGE); + UnsolicitedInputPrivilege = + RtlConvertLongToLargeInteger(SE_UNSOLICITED_INPUT_PRIVILEGE); + TcbPrivilege = + RtlConvertLongToLargeInteger(SE_TCB_PRIVILEGE); + SecurityPrivilege = + RtlConvertLongToLargeInteger(SE_SECURITY_PRIVILEGE); + TakeOwnershipPrivilege = + RtlConvertLongToLargeInteger(SE_TAKE_OWNERSHIP_PRIVILEGE); + LpcReplyBoostPrivilege = + RtlConvertLongToLargeInteger(SE_LPC_REPLY_BOOST_PRIVILEGE); + CreatePagefilePrivilege = + RtlConvertLongToLargeInteger(SE_CREATE_PAGEFILE_PRIVILEGE); + IncreaseBasePriorityPrivilege = + RtlConvertLongToLargeInteger(SE_INC_BASE_PRIORITY_PRIVILEGE); + SystemProfilePrivilege = + RtlConvertLongToLargeInteger(SE_SYSTEM_PROFILE_PRIVILEGE); + SystemtimePrivilege = + RtlConvertLongToLargeInteger(SE_SYSTEMTIME_PRIVILEGE); + ProfileSingleProcessPrivilege = + RtlConvertLongToLargeInteger(SE_PROF_SINGLE_PROCESS_PRIVILEGE); + CreatePermanentPrivilege = + RtlConvertLongToLargeInteger(SE_CREATE_PERMANENT_PRIVILEGE); + BackupPrivilege = + RtlConvertLongToLargeInteger(SE_BACKUP_PRIVILEGE); + RestorePrivilege = + RtlConvertLongToLargeInteger(SE_RESTORE_PRIVILEGE); + ShutdownPrivilege = + RtlConvertLongToLargeInteger(SE_SHUTDOWN_PRIVILEGE); + DebugPrivilege = + RtlConvertLongToLargeInteger(SE_DEBUG_PRIVILEGE); + + + return TRUE; + +} +#endif // _TSEVARS_ -- cgit v1.2.3