summaryrefslogtreecommitdiffstats
path: root/private/lsa/uclient
diff options
context:
space:
mode:
authorAdam <you@example.com>2020-05-17 05:51:50 +0200
committerAdam <you@example.com>2020-05-17 05:51:50 +0200
commite611b132f9b8abe35b362e5870b74bce94a1e58e (patch)
treea5781d2ec0e085eeca33cf350cf878f2efea6fe5 /private/lsa/uclient
downloadNT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.gz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.bz2
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.lz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.xz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.zst
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.zip
Diffstat (limited to 'private/lsa/uclient')
-rw-r--r--private/lsa/uclient/crclient.c112
-rw-r--r--private/lsa/uclient/ctlkacct.c378
-rw-r--r--private/lsa/uclient/ctlklsa.c579
-rw-r--r--private/lsa/uclient/ctreg.c807
-rw-r--r--private/lsa/uclient/ctsamdb.c213
-rw-r--r--private/lsa/uclient/lsaclip.h25
-rw-r--r--private/lsa/uclient/lsaudll.def11
-rw-r--r--private/lsa/uclient/makefile6
-rw-r--r--private/lsa/uclient/rpcapi.c3797
-rw-r--r--private/lsa/uclient/rpcapi2.c3316
-rw-r--r--private/lsa/uclient/rpcbind.c102
-rw-r--r--private/lsa/uclient/rpcclimm.c103
-rw-r--r--private/lsa/uclient/runsamdb.cmd4
-rw-r--r--private/lsa/uclient/sources44
-rw-r--r--private/lsa/uclient/tgetsid.c211
-rw-r--r--private/lsa/uclient/tlookup.c249
-rw-r--r--private/lsa/uclient/tsecomm.c136
-rw-r--r--private/lsa/uclient/tsevars.c447
18 files changed, 10540 insertions, 0 deletions
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 <lsaclip.h>
+
+
+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<ObjectType> 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 <stdio.h>
+#include <windows.h>
+
+
+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("<invalid pointer (0x%lx)>\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 <ServerName> [-p] -a <AccountName> [<AccountName> ...]\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("<invalid pointer (0x%lx)>\n", s);
+ }
+ printf("\n");
+}
+
+VOID
+CtPause(
+ )
+{
+ CHAR
+ IgnoreInput[300];
+
+ printf("Press <ENTER> 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 <string.h>
+#include <nt.h>
+#include <ntrtl.h>
+
+
+#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 <lsacomp.h>
+#include "lsarpc_c.h"
+#include <rpcndr.h>
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<object-type> 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 <lmcons.h>
+#include <logonmsv.h>
+
+
+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 <ntrpcp.h> // 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 <nt.h> // DbgPrint prototype
+#include <ntrtl.h> // DbgPrint prototype
+#include <rpc.h> // DataTypes and runtime APIs
+#include <lsarpc.h> // generated by the MIDL complier
+#include <nturtl.h> // needed for windows.h
+#include <windows.h> // LocalAlloc
+#include <string.h> // 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 <nt.h>
+#include <ntrtl.h>
+#include <ntlsa.h>
+#include <stdio.h>
+#include <string.h>
+
+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; i<SubCount; i++) {
+ printf("-0x%lx", (*RtlSubAuthoritySid( Sid, i)));
+ }
+
+ }
+
+ printf("\n\n Th Tha That's all folks\n");
+
+
+
+}
+
+
+BOOLEAN
+GetMachineSid(
+ OUT PSID *Sid,
+ OUT PULONG SidLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine retrieves the sid of this machine's account
+ domain and returns it in memory allocated with RtlAllocateHeap().
+ If this machine is a server in a domain, then this SID will
+ be domain's SID.
+
+
+Arguments:
+
+ Sid - receives a pointer to the returned SID.
+
+ SidLength - Receives the length (in bytes) of the returned SID.
+
+
+Return Value:
+
+ TRUE - The SID was allocated and returned.
+
+ FALSE - Some error prevented the SID from being returned.
+
+--*/
+
+{
+ NTSTATUS
+ Status;
+
+ OBJECT_ATTRIBUTES
+ ObjectAttributes;
+
+ LSA_HANDLE
+ PolicyHandle;
+
+ POLICY_ACCOUNT_DOMAIN_INFO
+ *DomainInfo = NULL;
+
+ PSID
+ ReturnSid;
+
+ BOOLEAN
+ ReturnStatus = FALSE;
+
+
+
+ InitializeObjectAttributes( &ObjectAttributes,
+ NULL, // No name
+ 0, // No attributes
+ 0, // No root handle
+ NULL // No SecurityDescriptor
+ );
+
+ Status = LsaOpenPolicy( NULL, // Local System
+ &ObjectAttributes,
+ POLICY_VIEW_LOCAL_INFORMATION,
+ &PolicyHandle
+ );
+
+ if (NT_SUCCESS(Status)) {
+
+ Status = LsaQueryInformationPolicy(
+ PolicyHandle,
+ PolicyAccountDomainInformation,
+ &DomainInfo
+ );
+
+ if (NT_SUCCESS(Status)) {
+
+ ASSERT(DomainInfo != NULL);
+
+ //
+ // Allocate the return buffer
+ //
+
+ (*SidLength) = RtlLengthSid( DomainInfo->DomainSid );
+ 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 <nt.h>
+#include <ntlsa.h>
+#include <ntrtl.h>
+#include <stdio.h>
+#include <string.h>
+
+
+
+///////////////////////////////////////////////////////////////////////////////
+// //
+// 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<TLsapLoopLimit; i++) {
+
+ printf("\r Loop Count %#4d LookupName Status: 0x%08lx LookupSid Status: 0x%08lx",
+ i, NtStatus, LookupSidStatus);
+
+ //
+ // Lookup name
+ //
+
+ ReferencedDomains = NULL;
+ Sids = NULL;
+ NtStatus = LsaLookupNames(
+ PolicyHandle,
+ 1, //Count
+ Names,
+ &ReferencedDomains,
+ &Sids
+ );
+
+ if (ReferencedDomains != NULL) {
+ LsaFreeMemory( ReferencedDomains );
+ }
+ if (Sids != NULL) {
+ LsaFreeMemory( Sids );
+ }
+
+
+
+ //
+ // Lookup SID
+ //
+
+ if (DoSidTest) {
+ ReferencedDomains = NULL;
+ Sids = NULL;
+ LookupSidStatus = LsaLookupSids(
+ PolicyHandle,
+ 1, //Count
+ &LookupSid,
+ &ReferencedDomains,
+ &TranslatedNames
+ );
+
+ if (ReferencedDomains != NULL) {
+ LsaFreeMemory( ReferencedDomains );
+ }
+ if (TranslatedNames != NULL) {
+ LsaFreeMemory( TranslatedNames );
+ }
+
+ }
+ }
+ }
+
+ return;
+}
diff --git a/private/lsa/uclient/tsecomm.c b/private/lsa/uclient/tsecomm.c
new file mode 100644
index 000000000..8b6f019c0
--- /dev/null
+++ b/private/lsa/uclient/tsecomm.c
@@ -0,0 +1,136 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ tsecomm.c
+
+Abstract:
+
+ Common security definitions and routines.
+
+ This module defines macros that provide a mode-independent
+ interface for security test procedures.
+
+ The mode must be specified by defining one, but not both,
+ of:
+ _TST_USER_ (for user mode tests)
+ _TST_KERNEL_ (for kernel mode tests)
+
+Author:
+
+ Jim Kelly (JimK) 23-Mar-1990
+
+Environment:
+
+ Test of security.
+
+Revision History:
+
+--*/
+
+#ifndef _TSECOMM_
+#define _TSECOMM_
+
+
+////////////////////////////////////////////////////////////////
+// //
+// Common Definitions //
+// //
+////////////////////////////////////////////////////////////////
+
+#define SEASSERT_SUCCESS(s) { \
+ if (!NT_SUCCESS((s))) { \
+ DbgPrint("** ! Failed ! **\n"); \
+ DbgPrint("Status is: 0x%lx \n", (s)); \
+ } \
+ ASSERT(NT_SUCCESS(s)); }
+
+
+
+////////////////////////////////////////////////////////////////
+// //
+// Kernel Mode Definitions //
+// //
+////////////////////////////////////////////////////////////////
+
+#ifdef _TST_KERNEL_
+
+#define TstAllocatePool(PoolType,NumberOfBytes) \
+ (ExAllocatePool( (PoolType), (NumberOfBytes) ))
+
+#define TstDeallocatePool(Pointer, NumberOfBytes) \
+ (ExFreePool( (Pointer) ))
+
+#endif // _TST_KERNEL_
+
+
+////////////////////////////////////////////////////////////////
+// //
+// User Mode Definitions //
+// //
+////////////////////////////////////////////////////////////////
+
+
+#ifdef _TST_USER_
+
+#include <nt.h>
+#include <ntrtl.h>
+#include <nturtl.h>
+
+
+// #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_