5146 lines
141 KiB
C
5146 lines
141 KiB
C
/*++
|
||
|
||
Copyright (c) 1991 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
dbinit.c
|
||
|
||
Abstract:
|
||
|
||
Local Security Authority - Database Server Initialization
|
||
|
||
This module contains functions which perform initialization of
|
||
the Database Server. Certain information is obtained from the
|
||
LSA database and is set up in global data for easy retrieval.
|
||
|
||
Author:
|
||
|
||
Scott Birrell (ScottBi) July 25, 1991
|
||
|
||
Environment:
|
||
|
||
User Mode
|
||
|
||
Revision History:
|
||
|
||
12-Nov-1997 MikeSw
|
||
Added lsa policy handle cache for interdomain lookups
|
||
|
||
--*/
|
||
|
||
|
||
//
|
||
// Define this to allocate all globals in this module
|
||
//
|
||
|
||
#include <lsapch2.h>
|
||
#include "lsasrvp.h"
|
||
#include "dbp.h"
|
||
#include <bndcache.h>
|
||
#include <wincrypt.h>
|
||
#include <lsapmsgs.h>
|
||
#include <ntddnfs.h>
|
||
#include <remboot.h>
|
||
#ifdef DS_LOOKUP
|
||
#include <dslookup.h>
|
||
#endif
|
||
#include <sertlp.h>
|
||
#include <cryptdll.h>
|
||
#include <md5.h>
|
||
#include <rc4.h>
|
||
#include <wxlpc.h>
|
||
#include <dnsapi.h>
|
||
|
||
extern LSAP_DB_TRUSTED_DOMAIN_LIST LsapDbTrustedDomainList;
|
||
|
||
|
||
NTSTATUS
|
||
LsapDbBuildObjectCaches(
|
||
);
|
||
|
||
NTSTATUS
|
||
LsapAssignInitialHiveProtection(
|
||
HANDLE HiveRoot
|
||
);
|
||
|
||
NTSTATUS
|
||
LsapCreateDatabaseProtection(
|
||
PISECURITY_DESCRIPTOR Sd
|
||
);
|
||
|
||
NTSTATUS
|
||
LsapGenerateRandomDomainSid(
|
||
OUT PSID NewDomainSid
|
||
);
|
||
|
||
NTSTATUS
|
||
LsapSetupInitialize(
|
||
VOID
|
||
);
|
||
|
||
NTSTATUS
|
||
LsapUpdateDatabaseProtection(
|
||
IN ULONG Revision
|
||
);
|
||
|
||
NTSTATUS
|
||
LsapDsInitFixupQueue(
|
||
VOID
|
||
);
|
||
|
||
static UCHAR SyskeyBuffer[LSAP_SYSKEY_SIZE];
|
||
static UCHAR OldSyskeyBuffer[LSAP_SYSKEY_SIZE];
|
||
|
||
|
||
NTSTATUS
|
||
LsapDbInitializeServer(
|
||
IN ULONG Pass
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function initializes the LSA Database Server. The following
|
||
steps are performed:
|
||
|
||
o Initialize the LSA Database Lock
|
||
o Acquire the LSA Database Lock
|
||
o Initialize the Unicode Strings for the fixed names within the
|
||
LSA Database, e.g. LSA Database object attributes and well-known
|
||
object names.
|
||
o Initialize the Unicode Strings for the LSA Database Object constant
|
||
and well known names, e.g SubKeys, fixed object names.
|
||
o Initialize the Unicode Strings for LSA Object Containing Dirs
|
||
o Initialize the Generic Mappings for Database Object Types
|
||
o Initialize the Lsa Database Handle Table
|
||
o Install the LSA Database if necessary - Creates the Lsa Database
|
||
o and Manager account objects, and initializes the transaction
|
||
subtree
|
||
o Initialize the abs min, abs max and installation default quota limits
|
||
o Release the LSA Database Lock
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS - Standard Nt Result Code
|
||
|
||
All Result Codes are generated by called routines.
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS Status = STATUS_SUCCESS, IgnoreStatus;
|
||
BOOL BooleanStatus = TRUE;
|
||
BOOLEAN AcquiredLock = FALSE;
|
||
BOOLEAN FreeComputerName = FALSE;
|
||
LSAP_DB_OBJECT_INFORMATION ObjectInformation;
|
||
PLSAPR_POLICY_ACCOUNT_DOM_INFO PolicyAccountDomainInfo = NULL;
|
||
PLSAPR_POLICY_DNS_DOMAIN_INFO PolicyDnsDomainInfo = NULL;
|
||
UNICODE_STRING ComputerName, CipherKey;
|
||
ULONG Length;
|
||
ULONG Revision, RevisionLength = sizeof( ULONG );
|
||
DWORD WinStatus;
|
||
|
||
//
|
||
// Initialize the LSA Database Lock and set it into the locked state
|
||
//
|
||
|
||
if (Pass == 1 ) {
|
||
|
||
LsapDsDebugInitialize();
|
||
|
||
RtlZeroMemory( &LsaDsStateInfo, sizeof( LsaDsStateInfo ) );
|
||
LsapDbState.DbServerInitialized = FALSE;
|
||
#if DBG
|
||
LsapDbState.RegistryTransactionOpen = FALSE;
|
||
#endif
|
||
|
||
//
|
||
// Disable Replicator Notifications.
|
||
//
|
||
|
||
LsapDbDisableReplicatorNotification();
|
||
|
||
//
|
||
// This function call will initialize all of the global or well known locks used by
|
||
// the Lsa
|
||
//
|
||
Status = LsapDbInitializeLock();
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
goto InitializeServerError;
|
||
}
|
||
|
||
Status = LsapDbInitHandleTables();
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
goto InitializeServerError;
|
||
}
|
||
|
||
//
|
||
// Initialize the forest trust cache.
|
||
// The cache is not usable until populated.
|
||
//
|
||
Status = LsapForestTrustCacheInitialize();
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
goto InitializeServerError;
|
||
}
|
||
|
||
//
|
||
// Initialize the policy change notification mechanism
|
||
//
|
||
Status = LsapInitializeNotifiyList();
|
||
if ( !NT_SUCCESS( Status ) ) {
|
||
goto InitializeServerError ;
|
||
}
|
||
|
||
//
|
||
// Initialize the Fixup queue
|
||
//
|
||
|
||
Status = LsapDsInitFixupQueue();
|
||
if ( !NT_SUCCESS( Status ))
|
||
{
|
||
goto InitializeServerError ;
|
||
}
|
||
|
||
//
|
||
// Initialize the binding handle cache
|
||
//
|
||
Status = LsapInitBindingCache();
|
||
if (!NT_SUCCESS(Status)) {
|
||
goto InitializeServerError;
|
||
}
|
||
|
||
#ifdef DS_LOOKUP
|
||
Status = LsapDsLookupInitializeLookupTable( NULL );
|
||
|
||
if ( !NT_SUCCESS( Status ) ) {
|
||
|
||
goto InitializeServerError;
|
||
}
|
||
#endif
|
||
|
||
}
|
||
|
||
//
|
||
// Acquire the LSA Database Lock. This allows subroutines to
|
||
// assert that the LSA Database is locked. Otherwise, it is
|
||
// not actually necessary, given that no other thread can access the
|
||
// LSA until initialization is complete.
|
||
//
|
||
|
||
if (Pass == 1) {
|
||
|
||
//
|
||
// Initialize the Unicode Strings for the fixed names within the
|
||
// LSA Database, e.g. LSA Database object attributes and well-known
|
||
// object names.
|
||
//
|
||
|
||
Status = LsapDbInitializeUnicodeNames();
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
|
||
goto InitializeServerError;
|
||
}
|
||
|
||
//
|
||
// Initialize the Unicode Strings for the Containing Directories for
|
||
// each LSA Database Object Type.
|
||
//
|
||
|
||
Status = LsapDbInitializeContainingDirs();
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
|
||
goto InitializeServerError;
|
||
}
|
||
|
||
//
|
||
// Initialize the LSA Subsystem name string. This is needed for
|
||
// NtAccessCheckAuditAlarm calls
|
||
//
|
||
|
||
RtlInitUnicodeString(&LsapState.SubsystemName, L"LSA");
|
||
|
||
//
|
||
// Initialize the Shutdown Pending state.
|
||
//
|
||
|
||
LsapState.SystemShutdownPending = FALSE;
|
||
|
||
//
|
||
// Initialize the Database Object Types. Information stored
|
||
// includes the Generic mappings and Object Counts.
|
||
//
|
||
|
||
Status = LsapDbInitializeObjectTypes();
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
|
||
goto InitializeServerError;
|
||
}
|
||
|
||
//
|
||
// Open the LSA Database root Registry subkey. This stays
|
||
// open for use in adding transactions.
|
||
//
|
||
|
||
Status = LsapDbOpenRootRegistryKey();
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
|
||
goto InitializeServerError;
|
||
}
|
||
|
||
//
|
||
// Initialize the Lsa Database Cipher Key
|
||
//
|
||
RtlInitUnicodeString( &CipherKey, L"823543" );
|
||
|
||
Status = LsapDbInitializeCipherKey( &CipherKey,
|
||
&LsapDbCipherKey );
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
|
||
goto InitializeServerError;
|
||
}
|
||
|
||
//
|
||
// Initialize the LSA Database Transaction Subtree, creating it if
|
||
// one does not already exist. If the Transaction Subtree exists,
|
||
// commit any partially committed transaction if appropriate.
|
||
//
|
||
|
||
Status = RtlInitializeRXact(
|
||
LsapDbState.DbRootRegKeyHandle,
|
||
TRUE,
|
||
(PRTL_RXACT_CONTEXT *) &LsapDbState.RXactContext
|
||
);
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
|
||
if (Status != STATUS_RXACT_STATE_CREATED) {
|
||
|
||
LsapLogError(
|
||
"LsapDbInitializeServer: Registry Transaction Init returned 0x%lx\n",
|
||
Status
|
||
);
|
||
|
||
goto InitializeServerError;
|
||
}
|
||
|
||
LsapLogError(
|
||
"LsapDbInitializeServer: Registry Transaction State Did Not Exist\n",
|
||
Status
|
||
);
|
||
|
||
goto InitializeServerError;
|
||
}
|
||
|
||
//
|
||
// Setup attributes for opening the Policy object.
|
||
//
|
||
|
||
ObjectInformation.ObjectTypeId = PolicyObject;
|
||
ObjectInformation.ContainerTypeId = 0;
|
||
ObjectInformation.Sid = NULL;
|
||
ObjectInformation.ObjectAttributeNameOnly = FALSE;
|
||
ObjectInformation.DesiredObjectAccess = 0;
|
||
|
||
InitializeObjectAttributes(
|
||
&ObjectInformation.ObjectAttributes,
|
||
&LsapDbNames[Policy],
|
||
0L,
|
||
NULL,
|
||
NULL
|
||
);
|
||
|
||
//
|
||
// Now try to open the root LSA Database object (Policy). This is a
|
||
// trusted call, so no access checking or impersonation will be done.
|
||
// Note that the handle obtained will remain open indefinitely. It is
|
||
// used after initialization for all internally generated accesses to
|
||
// the Policy object
|
||
//
|
||
|
||
Status = LsapDbOpenObject(
|
||
&ObjectInformation,
|
||
0L,
|
||
LSAP_DB_TRUSTED,
|
||
&LsapDbHandle
|
||
);
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
|
||
//
|
||
// Open of LSA Database object failed. If any error other than
|
||
// object not found, there is a serious error which prevents the
|
||
// LSA from functioning, so abort.
|
||
//
|
||
|
||
if (Status != STATUS_OBJECT_NAME_NOT_FOUND) {
|
||
|
||
LsapLogError(
|
||
"LsapDbInitializeServer: Open failed 0x%lx\n"
|
||
"The Lsa Database must be reinstalled or manually\n"
|
||
"erased before using the system\n",
|
||
Status
|
||
);
|
||
|
||
goto InitializeServerError;
|
||
}
|
||
|
||
//
|
||
// The Lsa Database object was not found. Run the database installation
|
||
// routine so that people can boot without having to run the
|
||
// installation applet first.
|
||
//
|
||
|
||
LsapDatabaseSetupPerformed = TRUE;
|
||
|
||
Status = LsapDbInstallLsaDatabase(1);
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
|
||
goto InitializeServerError;
|
||
}
|
||
}
|
||
|
||
//
|
||
// The Lsa Database object was successfully opened, possibly after
|
||
// having just been created. Proceed with the rest of server
|
||
// initialization. First, setup in-memory copies of the Installation
|
||
// Default, Absolute Min and Absolute Max system quota limits.
|
||
//
|
||
|
||
//
|
||
// Make the policy handle available throughout LSA
|
||
//
|
||
|
||
LsapPolicyHandle = LsapDbHandle;
|
||
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
goto InitializeServerError;
|
||
}
|
||
|
||
|
||
//
|
||
// Bring the database up to the current revision level,
|
||
// if necessary. This is not a syskey upgrade.
|
||
//
|
||
|
||
Status = LsapDbUpgradeRevision(FALSE,FALSE);
|
||
if (!NT_SUCCESS(Status)) {
|
||
goto InitializeServerError;
|
||
}
|
||
|
||
//
|
||
// Read the revision attribute. If the revision is greater than
|
||
// LSAP_DB_REVSION_1_5 then obtain the syskey from winlogon. In previous
|
||
// revisions SAM would have obtained the syskey from winlogon if the machine
|
||
// had been syskey'd
|
||
//
|
||
|
||
|
||
Status = LsapDbReadAttributeObject(
|
||
LsapDbHandle,
|
||
&LsapDbNames[PolRevision],
|
||
(PVOID) &Revision,
|
||
&RevisionLength
|
||
);
|
||
|
||
if ( !NT_SUCCESS(Status) ) {
|
||
goto InitializeServerError;
|
||
}
|
||
|
||
//
|
||
// Query the syskey from winlogon. Do so only if the revision is greater than 1_5.
|
||
// This is because in previous builds SAM used to manage the syskey. From this
|
||
// release onwards. The below routine also intializes the LSA encryption key
|
||
//
|
||
|
||
if (Revision >= LSAP_DB_REVISION_1_5)
|
||
{
|
||
Status = LsapDbGetSyskeyFromWinlogon();
|
||
if (!NT_SUCCESS(Status))
|
||
{
|
||
goto InitializeServerError;
|
||
}
|
||
}
|
||
|
||
//
|
||
// Initialize privilege object related code
|
||
//
|
||
|
||
Status = LsapDbInitializePrivilegeObject();
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
goto InitializeServerError;
|
||
}
|
||
|
||
//
|
||
// Perform initialization for the Replicator. Replications
|
||
// are still disabled at this point.
|
||
//
|
||
|
||
Status = LsapDbInitializeReplication();
|
||
if (!NT_SUCCESS(Status)) {
|
||
|
||
goto InitializeServerError;
|
||
}
|
||
|
||
//
|
||
// Initialize the data for the new APIs (user rights)
|
||
//
|
||
|
||
Status = LsapDbInitializeRights();
|
||
if (!NT_SUCCESS(Status)) {
|
||
|
||
goto InitializeServerError;
|
||
}
|
||
|
||
} else if (Pass == 2) {
|
||
|
||
BOOLEAN ExpectTrue;
|
||
OSVERSIONINFOEX OsVersionInfoEx = { 0 };
|
||
|
||
//
|
||
// Perform the second stage of database initialization.
|
||
// This is the initialization that depends on the product type.
|
||
// First, get the product type. Note that the Product Type may
|
||
// have already been retrieved from a number of routines that
|
||
// may be called during early installation, including
|
||
// LsarSetInformationPolicy() and LsarCreateTrustedDomain().
|
||
//
|
||
|
||
ExpectTrue = RtlGetNtProductType(&LsapProductType);
|
||
ASSERT( ExpectTrue == TRUE );
|
||
|
||
|
||
//
|
||
// find out the product suite mask.
|
||
// this is used later to determine if we are running
|
||
// on a specific product suite such the small business server
|
||
//
|
||
OsVersionInfoEx.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
|
||
ExpectTrue = (BOOLEAN) GetVersionEx((OSVERSIONINFO*) &OsVersionInfoEx);
|
||
ASSERT( ExpectTrue == TRUE );
|
||
LsapProductSuiteMask = OsVersionInfoEx.wSuiteMask;
|
||
|
||
|
||
//
|
||
// If necessary, install the rest of our database.
|
||
//
|
||
|
||
if (LsapDatabaseSetupPerformed == TRUE) {
|
||
|
||
Status = LsapDbInstallLsaDatabase(2);
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
goto InitializeServerError;
|
||
}
|
||
}
|
||
|
||
//
|
||
// If this is a Win Nt product, set the SAM Accounts Domain
|
||
// Name equal to the Computer Name, which may have been changed
|
||
// since the last boot.
|
||
//
|
||
|
||
//
|
||
// If this is setup, do nothing, since we've set it elsewhere..
|
||
// If this is safe mode mode, don't set it either
|
||
//
|
||
if ( !LsaISetupWasRun() ) {
|
||
if ( ((LsapProductType == NtProductWinNt) ||
|
||
(LsapProductType == NtProductServer)) &&
|
||
!LsaISafeMode() ) {
|
||
|
||
Status = LsarQueryInformationPolicy(
|
||
LsapPolicyHandle,
|
||
PolicyAccountDomainInformation,
|
||
(PLSAPR_POLICY_INFORMATION *) &PolicyAccountDomainInfo
|
||
);
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
goto InitializeServerError;
|
||
}
|
||
|
||
Length = (ULONG) 0;
|
||
|
||
ComputerName.Buffer = UNICODE_NULL;
|
||
FreeComputerName = FALSE;
|
||
|
||
BooleanStatus = GetComputerNameW(
|
||
(LPWSTR) ComputerName.Buffer,
|
||
(LPDWORD) &Length
|
||
);
|
||
|
||
WinStatus = GetLastError();
|
||
|
||
if (WinStatus != ERROR_BUFFER_OVERFLOW) {
|
||
|
||
KdPrint(("LsapDbInitializeServer: Failed to get Computer Name Length\n"
|
||
"Using default MACHINENAME instead\n"));
|
||
|
||
RtlInitUnicodeString( &ComputerName, LSAP_DB_DEFAULT_COMPUTER_NAME );
|
||
Length = (ULONG) ComputerName.Length;
|
||
|
||
} else if (Length <= 1) {
|
||
|
||
KdPrint(("LsapDbInitializeServer: Null Computer Name\n"
|
||
"Using default MACHINENAME instead\n"));
|
||
|
||
RtlInitUnicodeString( &ComputerName, LSAP_DB_DEFAULT_COMPUTER_NAME );
|
||
Length = (ULONG) ComputerName.Length;
|
||
|
||
|
||
} else {
|
||
|
||
ComputerName.Length = (USHORT) ((Length - 1) * sizeof (WCHAR));
|
||
ComputerName.MaximumLength = (USHORT) (Length * sizeof(WCHAR));
|
||
ComputerName.Buffer = MIDL_user_allocate( ComputerName.MaximumLength );
|
||
|
||
if ( ComputerName.Buffer == NULL ) {
|
||
|
||
Status = STATUS_INSUFFICIENT_RESOURCES;
|
||
goto InitializeServerError;
|
||
}
|
||
|
||
FreeComputerName = TRUE;
|
||
}
|
||
|
||
if (!GetComputerNameW(
|
||
(LPWSTR) ComputerName.Buffer,
|
||
(LPDWORD) &Length
|
||
)) {
|
||
|
||
KdPrint(("LsapDbInitializeServer: Failed to get Computer Name\n"
|
||
"Using default MACHINENAME instead\n"));
|
||
|
||
RtlInitUnicodeString( &ComputerName, LSAP_DB_DEFAULT_COMPUTER_NAME );
|
||
}
|
||
|
||
PolicyAccountDomainInfo->DomainName = *((PLSAPR_UNICODE_STRING) &ComputerName);
|
||
|
||
Status = LsarSetInformationPolicy(
|
||
LsapPolicyHandle,
|
||
PolicyAccountDomainInformation,
|
||
(PLSAPR_POLICY_INFORMATION) PolicyAccountDomainInfo
|
||
);
|
||
|
||
if ( FreeComputerName ) {
|
||
|
||
MIDL_user_free( ComputerName.Buffer );
|
||
}
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
|
||
goto InitializeServerError;
|
||
}
|
||
}
|
||
|
||
Status = RpcMgmtEnableIdleCleanup();
|
||
|
||
if ( !NT_SUCCESS( Status )) {
|
||
|
||
goto InitializeServerError;
|
||
}
|
||
|
||
} else {
|
||
|
||
Status = LsapSetupInitialize();
|
||
if (!NT_SUCCESS(Status)) {
|
||
|
||
goto InitializeServerError;
|
||
}
|
||
}
|
||
|
||
// Perform initialization for Lookup Sids and Names, including
|
||
// initialization of the Trusted Domain List.
|
||
//
|
||
|
||
Status = LsapDbLookupInitialize();
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
|
||
goto InitializeServerError;
|
||
}
|
||
|
||
//
|
||
// Load the object caches. Any that fail to load have caching
|
||
// permanently turned off.
|
||
//
|
||
|
||
IgnoreStatus = LsapDbBuildObjectCaches();
|
||
|
||
//
|
||
// Find out if this machine is a DC in a root domain
|
||
//
|
||
|
||
Status = LsapDbQueryInformationPolicy(
|
||
LsapPolicyHandle,
|
||
PolicyDnsDomainInformation,
|
||
( PLSAPR_POLICY_INFORMATION * )&PolicyDnsDomainInfo
|
||
);
|
||
|
||
if ( !NT_SUCCESS( Status )) {
|
||
|
||
goto InitializeServerError;
|
||
}
|
||
|
||
if ( DnsNameCompareEqual == DnsNameCompareEx_W(
|
||
PolicyDnsDomainInfo->DnsDomainName.Buffer,
|
||
PolicyDnsDomainInfo->DnsForestName.Buffer,
|
||
0 )) {
|
||
|
||
DcInRootDomain = TRUE;
|
||
|
||
} else {
|
||
|
||
DcInRootDomain = FALSE;
|
||
}
|
||
|
||
LsaIFree_LSAPR_POLICY_INFORMATION(
|
||
PolicyDnsDomainInformation,
|
||
( PLSAPR_POLICY_INFORMATION )PolicyDnsDomainInfo
|
||
);
|
||
|
||
//
|
||
// Mark the Server as being completely initialized.
|
||
//
|
||
|
||
LsapDbState.DbServerInitialized = TRUE;
|
||
|
||
//
|
||
// Enable Replicator Notifications on DCs only.
|
||
//
|
||
|
||
// if (LsapProductType == NtProductLanManNt) {
|
||
LsapDbEnableReplicatorNotification();
|
||
// }
|
||
}
|
||
|
||
InitializeServerFinish:
|
||
|
||
return(Status);
|
||
|
||
InitializeServerError:
|
||
|
||
goto InitializeServerFinish;
|
||
}
|
||
|
||
|
||
|
||
NTSTATUS
|
||
LsapDbUpgradeRevision(
|
||
IN BOOLEAN SyskeyUpgrade,
|
||
IN BOOLEAN GenerateNewSyskey
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function brings the LSA policy database up to date if necessary.
|
||
|
||
Arguments:
|
||
|
||
SyskeyUpgrade -- This paramter is set to true when this function is called a second
|
||
time around when upgrading NT4 or Win2K B3 machines from LsaIHealthCheck
|
||
|
||
GenerateNewSyskey -- This parameter is set to true when this function is called a second
|
||
time around when upgrading NT4 or Win2k B3 machines from LsaIHealthCheck
|
||
and the system is not already syskey'd
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS - Standard Nt Result Code
|
||
|
||
All Result Codes are generated by called routines.
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS Status;
|
||
|
||
ULONG Revision = LSAP_DB_REVISION_1_0, RevisionLength = sizeof( ULONG );
|
||
|
||
LSAP_DB_ATTRIBUTE Attributes[20];
|
||
|
||
PLSAP_DB_ATTRIBUTE NextAttribute;
|
||
|
||
ULONG AttributeCount = 0;
|
||
BOOLEAN PolRevisionWritten = FALSE;
|
||
|
||
NextAttribute = Attributes;
|
||
|
||
//
|
||
// Read the Revision Info from the PolRevision attribute
|
||
// of the Policy object in the LSA Database.
|
||
//
|
||
|
||
Status = LsapDbReadAttributeObject(
|
||
LsapDbHandle,
|
||
&LsapDbNames[PolRevision],
|
||
(PVOID) &Revision,
|
||
&RevisionLength
|
||
);
|
||
|
||
if ( !NT_SUCCESS(Status) ) {
|
||
Revision = LSAP_DB_REVISION_1_0;
|
||
if (Status == STATUS_OBJECT_NAME_NOT_FOUND) {
|
||
|
||
//
|
||
// attribute doesn't exist.
|
||
// This means the database is an NT1.0 format.
|
||
// Upgrade it to the current revision.
|
||
//
|
||
|
||
Status = STATUS_SUCCESS;
|
||
}
|
||
}
|
||
|
||
|
||
|
||
//
|
||
// Revison 1_1 created the ModifiedIdAtLastPromotion attribute on the policy object.
|
||
// This attribute is no longer used for anything so don't create it.
|
||
//
|
||
|
||
//
|
||
// Revision 1_2 corresponded to an encryption of secrets that shipped with NT4 that was
|
||
// incompatible with NT5. Therefore skip this revision level. The incompatible encryption
|
||
// of secrets would be handled by revision number update
|
||
//
|
||
|
||
|
||
|
||
//
|
||
// Update the security descriptor to revision 1.3
|
||
//
|
||
|
||
if ( NT_SUCCESS( Status ) && (Revision < LSAP_DB_REVISION_1_3) ) {
|
||
|
||
Status = LsapUpdateDatabaseProtection( LSAP_DB_REVISION_1_3 );
|
||
|
||
if ( NT_SUCCESS( Status ) ) {
|
||
|
||
Revision = LSAP_DB_REVISION_1_3;
|
||
|
||
if ( !PolRevisionWritten ) {
|
||
|
||
LsapDbInitializeAttribute(
|
||
NextAttribute,
|
||
&LsapDbNames[PolRevision],
|
||
&Revision,
|
||
sizeof (ULONG),
|
||
FALSE
|
||
);
|
||
|
||
NextAttribute++;
|
||
AttributeCount++;
|
||
PolRevisionWritten = TRUE;
|
||
|
||
ASSERT( AttributeCount < ( sizeof( Attributes ) / sizeof( LSAP_DB_ATTRIBUTE ) ) );
|
||
|
||
}
|
||
|
||
} else {
|
||
|
||
Status = STATUS_SUCCESS;
|
||
}
|
||
}
|
||
|
||
|
||
if ( NT_SUCCESS( Status ) && (Revision < LSAP_DB_REVISION_1_5) && (SyskeyUpgrade)) {
|
||
|
||
BOOLEAN IsUpgrade = FALSE;
|
||
PVOID Syskey = NULL;
|
||
ULONG SyskeyLength = 0;
|
||
LSAP_DB_ENCRYPTION_KEY NewEncryptionKey;
|
||
|
||
|
||
|
||
//
|
||
// NT4 SP4 shipped with an encryption of secret's that is incompatible with
|
||
// NT5 if the syskey'd setting was turned on.
|
||
// Therefore we walk over all secrets and patch them back. It is not necessary
|
||
// that we have all the key's setup at this point. The way this works is we attempt,
|
||
// to patch back all the secrets, and if we did not have the right key to decrypt them
|
||
// we will error out. In Syskey'd machines , SAM will have the right key and will call back
|
||
// into LSA when it has obtained the key. During SAM's callback this routine will be executed
|
||
// again and we will call upgrade all secrets.
|
||
//
|
||
|
||
// This upgrade involves a secret upgrade only. We simply have to read them and
|
||
// write them back out and everything will be kosher...
|
||
// Note if the secret upgrade fails for any reason, we will not update the database revision.
|
||
//
|
||
|
||
//
|
||
// First obtain the syskey from the SAM hive. Admittedly and ahsamedly this does read the SAM
|
||
// hive directly
|
||
//
|
||
|
||
|
||
//
|
||
// If we are a syskey'd machine the syskey should have been passed to us by now.
|
||
//
|
||
|
||
ASSERT((NULL!=LsapDbSysKey) || (GenerateNewSyskey));
|
||
|
||
//
|
||
// Initialize the key for secret encryption
|
||
//
|
||
|
||
Status = LsapDbGenerateNewKey(
|
||
&NewEncryptionKey
|
||
);
|
||
|
||
if (NT_SUCCESS(Status))
|
||
{
|
||
|
||
if (GenerateNewSyskey)
|
||
{
|
||
ULONG SyskeyLength = sizeof(SyskeyBuffer);
|
||
|
||
// Boot option is WxStored.
|
||
NewEncryptionKey.BootType = WxStored;
|
||
|
||
//
|
||
// A new syskey is being generated
|
||
//
|
||
|
||
Status = LsapDbSetupInitialSyskey(
|
||
&SyskeyLength,
|
||
&LsapDbSysKey
|
||
);
|
||
|
||
|
||
}
|
||
else
|
||
{
|
||
//
|
||
// Since we are upgrading from a syskey'd machine, get the boot option from SAM
|
||
// SAM is initialized enough at this point as it makes the callout to LSA supplying it with
|
||
// the syskey. It is O.K to pass in a value of 0, because then the default account domain
|
||
// is used.
|
||
//
|
||
|
||
Status = SamIGetBootKeyInformation(
|
||
(SAMPR_HANDLE) 0,
|
||
(SAMPR_BOOT_TYPE*)&NewEncryptionKey.BootType
|
||
);
|
||
}
|
||
}
|
||
|
||
if (NT_SUCCESS(Status))
|
||
{
|
||
//
|
||
// Setup the secret cipher key
|
||
// Ordinarily, the key used for reading equals the key used for writing
|
||
//
|
||
|
||
LsapDbInitializeSecretCipherKeyRead( &NewEncryptionKey );
|
||
LsapDbInitializeSecretCipherKeyWrite( &NewEncryptionKey );
|
||
|
||
//
|
||
// Encrypt the key with syskey
|
||
//
|
||
|
||
LsapDbEncryptKeyWithSyskey(
|
||
&NewEncryptionKey,
|
||
LsapDbSysKey,
|
||
LSAP_SYSKEY_SIZE
|
||
);
|
||
|
||
LsapDbInitializeAttribute(
|
||
NextAttribute,
|
||
&LsapDbNames[PolSecretEncryptionKey],
|
||
&NewEncryptionKey,
|
||
sizeof (NewEncryptionKey),
|
||
FALSE
|
||
);
|
||
|
||
NextAttribute++;
|
||
AttributeCount++;
|
||
}
|
||
|
||
//
|
||
// The secret upgrade is executed only during GUI setup upgrade of a workstation, or a DC being upgraded
|
||
// from NT4. In all other cases we simply patch the revision number up to the correct value.
|
||
//
|
||
|
||
if ((NT_SUCCESS(Status)) && ( (SamIIsDownlevelDcUpgrade()) ||
|
||
((LsapProductType != NtProductLanManNt) && (SamIIsSetupInProgress(&IsUpgrade)) && (IsUpgrade))))
|
||
{
|
||
//
|
||
// Ignore the return code below, we still want to move the revision
|
||
// level to 1.5, and this code will not be retried anyways
|
||
//
|
||
|
||
LsapDbUpgradeSecretForKeyChange();
|
||
}
|
||
|
||
if ( NT_SUCCESS( Status ) ) {
|
||
|
||
Revision = LSAP_DB_REVISION_1_5;
|
||
|
||
if ( !PolRevisionWritten ) {
|
||
|
||
LsapDbInitializeAttribute(
|
||
NextAttribute,
|
||
&LsapDbNames[PolRevision],
|
||
&Revision,
|
||
sizeof (ULONG),
|
||
FALSE
|
||
);
|
||
|
||
NextAttribute++;
|
||
AttributeCount++;
|
||
PolRevisionWritten = TRUE;
|
||
|
||
//
|
||
// Revision is now 1.5
|
||
//
|
||
|
||
ASSERT( AttributeCount < ( sizeof( Attributes ) / sizeof( LSAP_DB_ATTRIBUTE ) ) );
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
|
||
//
|
||
// Only upgrade past revision 1.5 if we've upgraded to revison 1.5.
|
||
//
|
||
// We don't upgrade to revision 1.5 in the mainline LSA initialization code.
|
||
// Rather, we upgrade to revision 1.5 in a callback from SAM. If then we moved on
|
||
// to revisions greater than 1.5 during LSA initialization, we'd never have a chance to
|
||
// do the revision 1.5 upgrade code.
|
||
//
|
||
|
||
if ( Revision >= LSAP_DB_REVISION_1_5 ) {
|
||
|
||
//
|
||
// Update the security descriptor to revision 1.6
|
||
//
|
||
|
||
if ( NT_SUCCESS( Status ) && (Revision < LSAP_DB_REVISION_1_6) ) {
|
||
|
||
Status = LsapUpdateDatabaseProtection( LSAP_DB_REVISION_1_6 );
|
||
if ( NT_SUCCESS( Status ) ) {
|
||
|
||
Revision = LSAP_DB_REVISION_1_6;
|
||
|
||
if ( !PolRevisionWritten ) {
|
||
|
||
LsapDbInitializeAttribute(
|
||
NextAttribute,
|
||
&LsapDbNames[PolRevision],
|
||
&Revision,
|
||
sizeof (ULONG),
|
||
FALSE
|
||
);
|
||
|
||
NextAttribute++;
|
||
AttributeCount++;
|
||
PolRevisionWritten = TRUE;
|
||
|
||
//
|
||
// Revision is now 1.6
|
||
//
|
||
|
||
ASSERT( AttributeCount < ( sizeof( Attributes ) / sizeof( LSAP_DB_ATTRIBUTE ) ) );
|
||
|
||
}
|
||
|
||
} else {
|
||
|
||
Status = STATUS_SUCCESS;
|
||
}
|
||
}
|
||
|
||
//
|
||
// Update the security descriptor to revision 1.7
|
||
//
|
||
|
||
if ( NT_SUCCESS( Status ) && (Revision < LSAP_DB_REVISION_1_7) ) {
|
||
|
||
Status = LsapUpdateDatabaseProtection( LSAP_DB_REVISION_1_7 );
|
||
if ( NT_SUCCESS( Status ) ) {
|
||
|
||
Revision = LSAP_DB_REVISION_1_7;
|
||
|
||
if ( !PolRevisionWritten ) {
|
||
|
||
LsapDbInitializeAttribute(
|
||
NextAttribute,
|
||
&LsapDbNames[PolRevision],
|
||
&Revision,
|
||
sizeof (ULONG),
|
||
FALSE
|
||
);
|
||
|
||
NextAttribute++;
|
||
AttributeCount++;
|
||
PolRevisionWritten = TRUE;
|
||
|
||
//
|
||
// Revision is now 1.7
|
||
//
|
||
|
||
ASSERT( AttributeCount < ( sizeof( Attributes ) / sizeof( LSAP_DB_ATTRIBUTE ) ) );
|
||
|
||
}
|
||
|
||
} else {
|
||
|
||
Status = STATUS_SUCCESS;
|
||
}
|
||
}
|
||
|
||
|
||
//
|
||
// In the future, revision updates can be made
|
||
// by adding "if" blocks similar to the one above.
|
||
//
|
||
// Remember, however, that the attributes are pointing
|
||
// to values in local variables. Any local variable
|
||
// value changed before the attribute is written out
|
||
// will cause that attribute value to be changed.
|
||
//
|
||
//
|
||
}
|
||
|
||
|
||
//
|
||
// Now write out all attributes that have been added (if any)
|
||
//
|
||
|
||
if (AttributeCount > 0) {
|
||
|
||
Status = LsapDbReferenceObject(
|
||
LsapDbHandle,
|
||
0,
|
||
PolicyObject,
|
||
PolicyObject,
|
||
LSAP_DB_LOCK | LSAP_DB_START_TRANSACTION
|
||
);
|
||
|
||
if (NT_SUCCESS(Status)) {
|
||
|
||
ASSERT( AttributeCount < ( sizeof( Attributes ) / sizeof( LSAP_DB_ATTRIBUTE ) ) );
|
||
Status = LsapDbWriteAttributesObject(
|
||
LsapDbHandle,
|
||
Attributes,
|
||
AttributeCount
|
||
);
|
||
|
||
//
|
||
// No attributes are replicatable.
|
||
// (That's good, too, since SAM hasn't told Netlogon our role yet.)
|
||
|
||
Status = LsapDbDereferenceObject(
|
||
&LsapDbHandle,
|
||
PolicyObject,
|
||
PolicyObject,
|
||
(LSAP_DB_LOCK |
|
||
LSAP_DB_FINISH_TRANSACTION |
|
||
LSAP_DB_OMIT_REPLICATOR_NOTIFICATION ),
|
||
SecurityDbChange,
|
||
Status
|
||
);
|
||
}
|
||
}
|
||
|
||
return( Status );
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
LsapDbBuildObjectCaches(
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function builds caches for Lsa objects. These caches contain a
|
||
subset of the information for some object types.
|
||
|
||
Arguments:
|
||
|
||
None
|
||
|
||
Return Values:
|
||
|
||
NTSTATUS - Standard Nt Result Code.
|
||
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS IgnoreStatus;
|
||
LSAP_DB_OBJECT_TYPE_ID ObjectTypeId;
|
||
|
||
//
|
||
// Initialize all the caches.
|
||
//
|
||
|
||
for (ObjectTypeId = PolicyObject;
|
||
ObjectTypeId <= SecretObject;
|
||
ObjectTypeId++) {
|
||
|
||
IgnoreStatus = LsapDbRebuildCache( ObjectTypeId );
|
||
}
|
||
|
||
return(STATUS_SUCCESS);
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
LsapDbInitializeObjectTypes(
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function initializes the information pertinent to each object
|
||
type in the LSA Database. This information includes the following:
|
||
|
||
o Generic Mapping Arrays
|
||
|
||
The Generic Mapping array for each object defines the list of
|
||
object-type-specific access types that correspond to the generic
|
||
access types GENERIC_READ, GENERIC_WRITE, GENERIC_EXECUTE and
|
||
GENERIC_ALL for the object type.
|
||
|
||
o Object Count Information
|
||
|
||
The Object Count Information includes a count of the number of objects
|
||
that exist for each type, the upper limit on this number (if any) for
|
||
each object type, and the error code to return when that limit is
|
||
reached.
|
||
|
||
o Write Operation Masks
|
||
|
||
These specify which access types are update operations
|
||
|
||
o Default accesses granted to World and Admin aliases
|
||
|
||
o Invalid access masks for each object type
|
||
|
||
These masks specify the bits in an access mask that are invalid for
|
||
a given object type.
|
||
|
||
o Initial owners of each object type
|
||
|
||
o Object caching supported for each object type.
|
||
|
||
|
||
|
||
Arguments:
|
||
|
||
None. The Generic Mapping arrays are held the LsapDbState structure.
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS - Standard Nt Result Code. Currently, there are no error
|
||
situations in this code, so STATUS_SUCCESS is always returned.
|
||
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS Status = STATUS_SUCCESS;
|
||
PGENERIC_MAPPING GenericMapping;
|
||
PLSAP_DB_OBJECT_TYPE ObjectType;
|
||
LSAP_DB_OBJECT_TYPE_ID ObjectTypeId;
|
||
|
||
//
|
||
// Initialize the Generic Mapping Array for the PolicyObject Object Type
|
||
// Note that there is only one object of this type and objects of this
|
||
// type can neither be created nor destroyed.
|
||
//
|
||
|
||
GenericMapping =
|
||
&LsapDbState.DbObjectTypes[PolicyObject].GenericMapping;
|
||
GenericMapping->GenericRead =
|
||
STANDARD_RIGHTS_READ |
|
||
POLICY_VIEW_AUDIT_INFORMATION |
|
||
POLICY_GET_PRIVATE_INFORMATION;
|
||
|
||
GenericMapping->GenericWrite =
|
||
STANDARD_RIGHTS_WRITE |
|
||
POLICY_TRUST_ADMIN |
|
||
POLICY_CREATE_ACCOUNT |
|
||
POLICY_CREATE_SECRET |
|
||
POLICY_CREATE_PRIVILEGE |
|
||
POLICY_SET_DEFAULT_QUOTA_LIMITS |
|
||
POLICY_SET_AUDIT_REQUIREMENTS |
|
||
POLICY_AUDIT_LOG_ADMIN |
|
||
POLICY_SERVER_ADMIN;
|
||
|
||
GenericMapping->GenericExecute =
|
||
STANDARD_RIGHTS_EXECUTE |
|
||
POLICY_VIEW_LOCAL_INFORMATION |
|
||
POLICY_LOOKUP_NAMES;
|
||
|
||
GenericMapping->GenericAll = POLICY_ALL_ACCESS | POLICY_NOTIFICATION;
|
||
|
||
//
|
||
// Initialize the Generic Mapping Array for the Account Object Type
|
||
// Note that Account Objects can be created and destroyed.
|
||
//
|
||
|
||
GenericMapping =
|
||
&LsapDbState.DbObjectTypes[AccountObject].GenericMapping;
|
||
|
||
GenericMapping->GenericRead =
|
||
STANDARD_RIGHTS_READ |
|
||
ACCOUNT_VIEW;
|
||
|
||
GenericMapping->GenericWrite =
|
||
STANDARD_RIGHTS_WRITE |
|
||
ACCOUNT_ADJUST_PRIVILEGES |
|
||
ACCOUNT_ADJUST_QUOTAS |
|
||
ACCOUNT_ADJUST_SYSTEM_ACCESS;
|
||
|
||
GenericMapping->GenericExecute =
|
||
STANDARD_RIGHTS_EXECUTE;
|
||
|
||
GenericMapping->GenericAll = ACCOUNT_ALL_ACCESS;
|
||
|
||
//
|
||
// Initialize the Generic Mapping Array for the TrustedDomain Object
|
||
// Type.
|
||
//
|
||
|
||
GenericMapping =
|
||
&LsapDbState.DbObjectTypes[TrustedDomainObject].GenericMapping;
|
||
|
||
GenericMapping->GenericRead =
|
||
STANDARD_RIGHTS_READ |
|
||
TRUSTED_QUERY_DOMAIN_NAME;
|
||
|
||
GenericMapping->GenericWrite =
|
||
STANDARD_RIGHTS_WRITE |
|
||
TRUSTED_SET_CONTROLLERS |
|
||
TRUSTED_SET_POSIX;
|
||
|
||
GenericMapping->GenericExecute =
|
||
STANDARD_RIGHTS_EXECUTE |
|
||
TRUSTED_QUERY_CONTROLLERS |
|
||
TRUSTED_QUERY_POSIX;
|
||
|
||
GenericMapping->GenericAll = TRUSTED_ALL_ACCESS;
|
||
|
||
//
|
||
// Initialize the Generic Mapping Array for the Secret Object
|
||
// Type.
|
||
//
|
||
|
||
GenericMapping =
|
||
&LsapDbState.DbObjectTypes[SecretObject].GenericMapping;
|
||
|
||
GenericMapping->GenericRead =
|
||
STANDARD_RIGHTS_READ |
|
||
SECRET_QUERY_VALUE;
|
||
|
||
GenericMapping->GenericWrite =
|
||
STANDARD_RIGHTS_WRITE |
|
||
SECRET_SET_VALUE;
|
||
|
||
GenericMapping->GenericExecute =
|
||
STANDARD_RIGHTS_EXECUTE;
|
||
|
||
GenericMapping->GenericAll = SECRET_ALL_ACCESS;
|
||
|
||
//
|
||
// Initialize the Object Count Information to defaults
|
||
//
|
||
|
||
ObjectType = &(LsapDbState.DbObjectTypes[PolicyObject]);
|
||
|
||
for (ObjectTypeId = PolicyObject;
|
||
ObjectTypeId < DummyLastObject;
|
||
ObjectTypeId++) {
|
||
|
||
ObjectType->ObjectCount = 0;
|
||
ObjectType->ObjectCountLimited = FALSE;
|
||
ObjectType->ObjectCountError = STATUS_SUCCESS;
|
||
ObjectType->MaximumObjectCount = 0;
|
||
}
|
||
|
||
//
|
||
// Set specific limits for Secret Object Type. This is the only
|
||
// object type so far to have limits.
|
||
//
|
||
|
||
ObjectType = &(LsapDbState.DbObjectTypes[SecretObject]);
|
||
ObjectType->ObjectCountLimited = TRUE;
|
||
ObjectType->ObjectCountError = STATUS_TOO_MANY_SECRETS;
|
||
ObjectType->MaximumObjectCount = LSA_SECRET_MAXIMUM_COUNT;
|
||
|
||
//
|
||
// Initialize the write operations for each object type
|
||
//
|
||
|
||
LsapDbState.DbObjectTypes[PolicyObject].WriteOperations = LSAP_POLICY_WRITE_OPS;
|
||
LsapDbState.DbObjectTypes[TrustedDomainObject].WriteOperations = LSAP_TRUSTED_WRITE_OPS;
|
||
LsapDbState.DbObjectTypes[AccountObject].WriteOperations = LSAP_ACCOUNT_WRITE_OPS;
|
||
LsapDbState.DbObjectTypes[SecretObject].WriteOperations = LSAP_SECRET_WRITE_OPS;
|
||
|
||
//
|
||
// Initialize the default accesses granted to Domain Admins alias
|
||
//
|
||
|
||
LsapDbState.DbObjectTypes[PolicyObject].AliasAdminsAccess = GENERIC_ALL;
|
||
LsapDbState.DbObjectTypes[TrustedDomainObject].AliasAdminsAccess = GENERIC_ALL | DELETE;
|
||
LsapDbState.DbObjectTypes[AccountObject].AliasAdminsAccess = GENERIC_ALL | DELETE;
|
||
LsapDbState.DbObjectTypes[SecretObject].AliasAdminsAccess = GENERIC_ALL | DELETE;
|
||
|
||
//
|
||
// Initialize the default accesses granted to World alias
|
||
//
|
||
|
||
LsapDbState.DbObjectTypes[PolicyObject].WorldAccess = GENERIC_EXECUTE;
|
||
LsapDbState.DbObjectTypes[TrustedDomainObject].WorldAccess = GENERIC_EXECUTE;
|
||
LsapDbState.DbObjectTypes[AccountObject].WorldAccess = GENERIC_EXECUTE;
|
||
LsapDbState.DbObjectTypes[SecretObject].WorldAccess = GENERIC_EXECUTE;
|
||
|
||
//
|
||
// Initialize the default accesses granted to AnonymousLogon alias
|
||
//
|
||
|
||
LsapDbState.DbObjectTypes[PolicyObject].AnonymousLogonAccess = POLICY_VIEW_LOCAL_INFORMATION | POLICY_LOOKUP_NAMES;
|
||
LsapDbState.DbObjectTypes[TrustedDomainObject].AnonymousLogonAccess = 0;
|
||
LsapDbState.DbObjectTypes[AccountObject].AnonymousLogonAccess = 0;
|
||
LsapDbState.DbObjectTypes[SecretObject].AnonymousLogonAccess = 0;
|
||
|
||
//
|
||
// Initialize the default accesses granted to LocalService and NetworkService
|
||
//
|
||
|
||
LsapDbState.DbObjectTypes[PolicyObject].LocalServiceAccess = POLICY_NOTIFICATION;
|
||
LsapDbState.DbObjectTypes[TrustedDomainObject].LocalServiceAccess = 0;
|
||
LsapDbState.DbObjectTypes[AccountObject].LocalServiceAccess = 0;
|
||
LsapDbState.DbObjectTypes[SecretObject].LocalServiceAccess = 0;
|
||
|
||
LsapDbState.DbObjectTypes[PolicyObject].NetworkServiceAccess = POLICY_NOTIFICATION;
|
||
LsapDbState.DbObjectTypes[TrustedDomainObject].NetworkServiceAccess = 0;
|
||
LsapDbState.DbObjectTypes[AccountObject].NetworkServiceAccess = 0;
|
||
LsapDbState.DbObjectTypes[SecretObject].NetworkServiceAccess = 0;
|
||
|
||
|
||
//
|
||
// Initialize the Invalid Access masks for each object type
|
||
//
|
||
|
||
LsapDbState.DbObjectTypes[PolicyObject].InvalidMappedAccess =
|
||
((ACCESS_MASK)(~(POLICY_ALL_ACCESS | POLICY_NOTIFICATION | ACCESS_SYSTEM_SECURITY | MAXIMUM_ALLOWED)));
|
||
LsapDbState.DbObjectTypes[TrustedDomainObject].InvalidMappedAccess =
|
||
((ACCESS_MASK)(~(TRUSTED_ALL_ACCESS | ACCESS_SYSTEM_SECURITY | MAXIMUM_ALLOWED)));
|
||
LsapDbState.DbObjectTypes[AccountObject].InvalidMappedAccess =
|
||
((ACCESS_MASK)(~(ACCOUNT_ALL_ACCESS | ACCESS_SYSTEM_SECURITY | MAXIMUM_ALLOWED)));
|
||
LsapDbState.DbObjectTypes[SecretObject].InvalidMappedAccess =
|
||
((ACCESS_MASK)(~(SECRET_ALL_ACCESS | ACCESS_SYSTEM_SECURITY | MAXIMUM_ALLOWED)));
|
||
|
||
//
|
||
// Initialize the Initial Owners for new objects of each type
|
||
//
|
||
|
||
LsapDbState.DbObjectTypes[PolicyObject].InitialOwnerSid = LsapAliasAdminsSid;
|
||
LsapDbState.DbObjectTypes[TrustedDomainObject].InitialOwnerSid = LsapAliasAdminsSid;
|
||
LsapDbState.DbObjectTypes[AccountObject].InitialOwnerSid = LsapAliasAdminsSid;
|
||
LsapDbState.DbObjectTypes[SecretObject].InitialOwnerSid = LsapAliasAdminsSid;
|
||
|
||
//
|
||
// Specify method of access to objects of the type. Currently, all objects
|
||
// of a given type are accessed in the same way, either by Sid or by Name
|
||
// but not both.
|
||
//
|
||
|
||
LsapDbState.DbObjectTypes[PolicyObject].AccessedByName = TRUE;
|
||
LsapDbState.DbObjectTypes[TrustedDomainObject].AccessedByName = FALSE;
|
||
LsapDbState.DbObjectTypes[AccountObject].AccessedByName = FALSE;
|
||
LsapDbState.DbObjectTypes[SecretObject].AccessedByName = TRUE;
|
||
|
||
LsapDbState.DbObjectTypes[PolicyObject].AccessedBySid = FALSE;
|
||
LsapDbState.DbObjectTypes[TrustedDomainObject].AccessedBySid = TRUE;
|
||
LsapDbState.DbObjectTypes[AccountObject].AccessedBySid = TRUE;
|
||
LsapDbState.DbObjectTypes[SecretObject].AccessedBySid = FALSE;
|
||
|
||
//
|
||
// Specify the object types for which caching is supported (in full
|
||
// or in part) and turn caching off initially for all object types.
|
||
// Object types for which caching is supported have ther caches set
|
||
// to the "Invalid" state. Automatic restore is allowed for caches
|
||
// in this state. Object types for which caching is not supported
|
||
// are set to the "Not supported" state. Note that a cache is
|
||
// also placed in the "not supported" state if an attempt to restore
|
||
// it fails.
|
||
//
|
||
|
||
LsapDbMakeCacheInvalid( PolicyObject );
|
||
LsapDbMakeCacheInvalid( TrustedDomainObject );
|
||
LsapDbMakeCacheInvalid( AccountObject );
|
||
LsapDbMakeCacheUnsupported( SecretObject );
|
||
|
||
|
||
return(Status);
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
LsapDbInitializeUnicodeNames()
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function initializes two arrays of Unicode Strings. The
|
||
LsapDbNames array contains Unicode Strings for all of the constant
|
||
names in the Lsa Database. The LsapDbObjectTypeNames is indexed
|
||
by Object Type Id and contains the Unicode Strings for all of the
|
||
LSA Database object types.
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS - Standard Nt Result Code
|
||
|
||
All Result Codes are generated by called routines.
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS Status = STATUS_SUCCESS;
|
||
LSAP_DB_NAMES Index;
|
||
LSAP_DB_OBJECT_TYPE_ID ObjectTypeId;
|
||
|
||
PCWSTR UnicodeNames[DummyLastName + 1] = {
|
||
|
||
L"SecDesc",
|
||
L"Privilgs",
|
||
L"Sid",
|
||
L"Name",
|
||
L"AdminMod",
|
||
L"OperMode",
|
||
L"QuotaLim",
|
||
L"DefQuota",
|
||
L"QuAbsMin",
|
||
L"QuAbsMax",
|
||
L"AdtLog",
|
||
L"AdtEvent",
|
||
L"PrDomain",
|
||
L"EnPasswd",
|
||
L"Policy",
|
||
L"Accounts",
|
||
L"Domains",
|
||
L"Secrets",
|
||
L"CurrVal",
|
||
L"OldVal",
|
||
L"CupdTime",
|
||
L"OupdTime",
|
||
L"WkstaMgr",
|
||
L"PolAdtLg",
|
||
L"PolAdtEv",
|
||
L"PolAcDmN",
|
||
L"PolAcDmS",
|
||
L"PolDnDDN",
|
||
L"PolDnTrN",
|
||
L"PolDnDmG",
|
||
L"PolEfDat",
|
||
L"PolPrDmN",
|
||
L"PolPrDmS",
|
||
L"PolPdAcN",
|
||
L"PolRepSc",
|
||
L"PolRepAc",
|
||
L"PolRevision",
|
||
L"PolDefQu",
|
||
L"PolMod",
|
||
L"PolAdtFL",
|
||
L"PolState",
|
||
L"PolNxPxf",
|
||
L"ActSysAc",
|
||
L"TrDmName",
|
||
L"TrDmTrPN", // Netbios name of trust partner
|
||
L"TrDmSid",
|
||
L"TrDmAcN",
|
||
L"TrDmCtN",
|
||
L"TrDmPxOf",
|
||
L"TrDmCtEn",
|
||
NULL, // TrDmTrTy
|
||
NULL, // TrDmTrDi
|
||
L"TrDmTrLA", // TrDmTrLA
|
||
L"TrDmTrPr", // Trust partner
|
||
L"TrDmTrRt", // Root partner
|
||
L"TrDmSAI", // Incoming auth. info
|
||
L"TrDmSAO", // Outgoing auth. info
|
||
L"TrDmForT", // Forest trust info
|
||
L"AcMaPCF",
|
||
L"PolIPSec", // IPSec object reference
|
||
L"PolDIPSec", // Domain wide IPSec object reference
|
||
L"PolLoc", // Policy location,
|
||
L"PolPubK", // Public key policy
|
||
L"KerOpts", // Kerberos authentication options
|
||
L"KerMinT", // Kerberos Minimum ticket age
|
||
L"KerMaxT", // Kerberos maximum ticket age
|
||
L"KerMaxR", // Kerberos maximum renewal age
|
||
L"KerProxy", // Kerberos proxy lifetime
|
||
L"KerLogoff", // Kerberos force logoff duration
|
||
L"DmLDur", // Domain lockout duration
|
||
L"DmLObWin", // Lockout observation window
|
||
L"DmLThrs", // Lockout threshold
|
||
L"DmPMinL", // Minimum password length
|
||
L"DmPHisL", // Password history length
|
||
L"DmPProp", // Password properties
|
||
L"DmPMinA", // Minimum password age
|
||
L"DmPMaxA", // Maximum password age
|
||
L"BhvrVers", // Behavior-Version
|
||
L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\Eventlog\\Security",
|
||
L"MaxSize",
|
||
L"Retention",
|
||
L"PseudoSystemCritical",
|
||
L"PolSecretEncryptionKey",
|
||
L"XRefDnsRoot",
|
||
L"XRefNetbiosName",
|
||
L"DummyLastName"
|
||
};
|
||
|
||
PCWSTR UnicodeObjectTypeNames[DummyLastObject] = {
|
||
|
||
L"NullObject",
|
||
L"PolicyObject",
|
||
L"TrustedDomainObject",
|
||
L"UserAccountObject",
|
||
L"SecretObject",
|
||
L"AllObject",
|
||
L"NewTrustedDomainObject"
|
||
};
|
||
|
||
//
|
||
// Referenced by LsapDbDsAttInfo
|
||
//
|
||
static LSAP_DB_DS_INFO StaticLsapDbDsAttInfo[DummyLastName + 1] = {
|
||
{ATT_NT_SECURITY_DESCRIPTOR, LsapDbAttribSecDesc, LsapDsLocDs}, // Security Descriptor
|
||
{0, LsapDbAttribUnknown, LsapDsLocUnknown }, // Privileges
|
||
{ATT_SECURITY_IDENTIFIER, LsapDbAttribSid, LsapDsLocDs}, // Sid
|
||
{0, LsapDbAttribUnknown, LsapDsLocDs}, // Name
|
||
{0, LsapDbAttribUnknown, LsapDsLocUnknown}, // AdminMod
|
||
{0, LsapDbAttribUnknown, LsapDsLocUnknown}, // OperMode
|
||
{0, LsapDbAttribUnknown, LsapDsLocUnknown}, // QuotaLim
|
||
{0, LsapDbAttribUnknown, LsapDsLocUnknown}, // DefQuota
|
||
{0, LsapDbAttribUnknown, LsapDsLocUnknown}, // QuAbsMin
|
||
{0, LsapDbAttribUnknown, LsapDsLocUnknown}, // QuAbsMax
|
||
{0, LsapDbAttribUnknown, LsapDsLocUnknown}, // AdtLog
|
||
{0, LsapDbAttribUnknown, LsapDsLocUnknown}, // AdtEvent
|
||
{0, LsapDbAttribUnknown, LsapDsLocUnknown}, // PrDomain
|
||
{0, LsapDbAttribUnknown, LsapDsLocUnknown}, // EnPasswd
|
||
{0, LsapDbAttribUnknown, LsapDsLocUnknown}, // Policy
|
||
{0, LsapDbAttribUnknown, LsapDsLocUnknown}, // Accounts
|
||
{0, LsapDbAttribUnknown, LsapDsLocUnknown}, // Domains
|
||
{0, LsapDbAttribUnknown, LsapDsLocUnknown}, // Secrets
|
||
{ATT_CURRENT_VALUE, LsapDbAttribPByte, LsapDsLocDs}, // CurrVal
|
||
{ATT_PRIOR_VALUE, LsapDbAttribPByte, LsapDsLocDs}, // OldVal
|
||
{ATT_LAST_SET_TIME, LsapDbAttribPByte, LsapDsLocDs}, // CupdTime
|
||
{ATT_PRIOR_SET_TIME, LsapDbAttribPByte, LsapDsLocDs}, // OupdTime
|
||
{0, LsapDbAttribUnknown, LsapDsLocUnknown}, // WkstaMgr
|
||
{0, LsapDbAttribUnknown, LsapDsLocUnknown}, // PolAdtLg
|
||
{ATT_AUDITING_POLICY, LsapDbAttribPByte, LsapDsLocRegistry}, // PolAdtEv
|
||
{0, LsapDbAttribUnknown, LsapDsLocRegistry}, // PolAcDmN
|
||
{0, LsapDbAttribUnknown, LsapDsLocRegistry}, // PolAcDmS
|
||
{0, LsapDbAttribUnknown, LsapDsLocRegistry}, // PolDnDDN
|
||
{0, LsapDbAttribUnknown, LsapDsLocRegistry}, // PolDnTrN
|
||
{0, LsapDbAttribUnknown, LsapDsLocRegistry}, // PolDnDmG
|
||
{ATT_EFSPOLICY, LsapDbAttribPByte, LsapDsLocRegistry}, // PolEfDat
|
||
{0, LsapDbAttribUnknown, LsapDsLocRegistry}, // PolPrDmN
|
||
{0, LsapDbAttribUnknown, LsapDsLocRegistry}, // PolPrDmS
|
||
{0, LsapDbAttribUnknown, LsapDsLocRegistry}, // PolPdAcN
|
||
{0, LsapDbAttribUnknown, LsapDsLocRegistry}, // PolRepSc
|
||
{0, LsapDbAttribUnknown, LsapDsLocRegistry}, // PolRepAc
|
||
{0, LsapDbAttribUnknown, LsapDsLocUnknown}, // PolRevision
|
||
{0, LsapDbAttribUnknown, LsapDsLocUnknown}, // PolDefQu
|
||
{0, LsapDbAttribUnknown, LsapDsLocRegistry}, // PolMod
|
||
{0, LsapDbAttribUnknown, LsapDsLocUnknown}, // PolAdtFL
|
||
{0, LsapDbAttribUnknown, LsapDsLocRegistry}, // PolState
|
||
{0, LsapDbAttribUnknown, LsapDsLocUnknown}, // PolNxPxF
|
||
{0, LsapDbAttribUnknown, LsapDsLocUnknown}, // ActSysAc
|
||
{ATT_TRUST_PARTNER, LsapDbAttribUnicode, LsapDsLocDs}, // TrDmName
|
||
{ATT_FLAT_NAME, LsapDbAttribUnicode, LsapDsLocDs}, // TrDmTrPN
|
||
{ATT_SECURITY_IDENTIFIER, LsapDbAttribSid, LsapDsLocDs}, // TrDmSid
|
||
{0, LsapDbAttribUnknown, LsapDsLocUnknown}, // TrDmAcN
|
||
{0, LsapDbAttribUnicode, LsapDsLocRegistry}, // TrDmCtN
|
||
{ATT_TRUST_POSIX_OFFSET, LsapDbAttribULong, LsapDsLocDs}, // TrDmPxOf
|
||
{0, LsapDbAttribUnicode, LsapDsLocRegistry}, // TrDmCtEn
|
||
{ATT_TRUST_TYPE, LsapDbAttribULong, LsapDsLocDs}, // TrDmTrTy
|
||
{ATT_TRUST_DIRECTION, LsapDbAttribULong, LsapDsLocDs}, // TrDmTrDi
|
||
{ATT_TRUST_ATTRIBUTES, LsapDbAttribULong, LsapDsLocDs}, // TrDmTrLA
|
||
{ATT_DOMAIN_CROSS_REF, LsapDbAttribDsName, LsapDsLocDs}, // TrDmTrPr
|
||
{ATT_ROOT_TRUST, LsapDbAttribDsName, LsapDsLocDs}, // TrDmTrRt
|
||
{ATT_TRUST_AUTH_INCOMING, LsapDbAttribPByte, LsapDsLocDs}, // TrDmSAI
|
||
{ATT_TRUST_AUTH_OUTGOING, LsapDbAttribPByte, LsapDsLocDs}, // TrDmSAO
|
||
{ATT_MS_DS_TRUST_FOREST_TRUST_INFO, LsapDbAttribPByte, LsapDsLocDs}, // TrDmForT
|
||
{ATT_MACHINE_PASSWORD_CHANGE_INTERVAL, LsapDbAttribPByte, LsapDsLocDsLocalPolObj}, // AcMaPCF
|
||
{ATT_IPSEC_POLICY_REFERENCE, LsapDbAttribDsNameAsUnicode, LsapDsLocDsLocalPolObj}, // PolIPSec,
|
||
{ATT_IPSEC_POLICY_REFERENCE, LsapDbAttribDsNameAsUnicode, LsapDsLocDsDomainPolObj}, // PolDIPSec,
|
||
{0, LsapDbAttribULong, LsapDsLocRegistry}, // PolLoc,
|
||
{ATT_PUBLIC_KEY_POLICY, LsapDbAttribPByte, LsapDsLocRegistry}, // PolPubK,
|
||
{ATT_AUTHENTICATION_OPTIONS, LsapDbAttribULong, LsapDsLocRegistry}, // KerOpts,
|
||
{ATT_MIN_TICKET_AGE, LsapDbAttribPByte, LsapDsLocRegistry}, // KerMinT,
|
||
{ATT_MAX_TICKET_AGE, LsapDbAttribPByte, LsapDsLocRegistry}, // KerMaxT,
|
||
{ATT_MAX_RENEW_AGE, LsapDbAttribPByte, LsapDsLocRegistry}, // KerMaxR,
|
||
{ATT_PROXY_LIFETIME, LsapDbAttribPByte, LsapDsLocRegistry}, // KerProxy,
|
||
{ATT_FORCE_LOGOFF, LsapDbAttribPByte, LsapDsLocRegistry}, // KerLogoff
|
||
{ATT_LOCKOUT_DURATION, LsapDbAttribPByte, LsapDsLocRegistry}, // DmLDur
|
||
{ATT_LOCK_OUT_OBSERVATION_WINDOW,LsapDbAttribPByte, LsapDsLocRegistry}, // DmLObWin
|
||
{ATT_LOCKOUT_THRESHOLD, LsapDbAttribUShortAsULong, LsapDsLocRegistry}, // DmLThrs
|
||
{ATT_MIN_PWD_LENGTH, LsapDbAttribUShortAsULong, LsapDsLocRegistry}, // DmPMinL
|
||
{ATT_PWD_HISTORY_LENGTH, LsapDbAttribUShortAsULong, LsapDsLocRegistry}, // DmPHisL
|
||
{ATT_PWD_PROPERTIES, LsapDbAttribULong, LsapDsLocRegistry}, // DmPProp
|
||
{ATT_MIN_PWD_AGE, LsapDbAttribPByte, LsapDsLocRegistry}, // DmPMinA
|
||
{ATT_MAX_PWD_AGE, LsapDbAttribPByte, LsapDsLocRegistry}, // DmPMaxA
|
||
{ATT_MS_DS_BEHAVIOR_VERSION, LsapDbAttribULong, LsapDsLocDs}, // BhvrVers
|
||
{0, LsapDbAttribUnknown, LsapDsLocUnknown}, // Audit log
|
||
{0, LsapDbAttribUnknown, LsapDsLocUnknown}, // Audit log size
|
||
{0, LsapDbAttribUnknown, LsapDsLocUnknown}, // Audit Recored Retention Period
|
||
{ATT_IS_CRITICAL_SYSTEM_OBJECT, LsapDbAttribULong, LsapDsLocDs}, // system critical component.
|
||
{0, LsapDbAttribPByte, LsapDsLocRegistry},//PolSecretEncryptionKey
|
||
{ATT_DNS_ROOT, LsapDbAttribUnicode, LsapDsLocDs}, // DNS name of cross-ref
|
||
{ATT_NETBIOS_NAME, LsapDbAttribUnicode, LsapDsLocDs}, // Netbios domain of cross-ref
|
||
{0, LsapDbAttribUnknown, LsapDsLocUnknown} // Dummy Last Name
|
||
};
|
||
|
||
//
|
||
// Initialize general array of Unicode Names
|
||
//
|
||
|
||
for (Index = SecDesc; Index < DummyLastName; Index++) {
|
||
|
||
RtlInitUnicodeString( &LsapDbNames[Index], UnicodeNames[Index] );
|
||
}
|
||
|
||
//
|
||
// Initialize array of Unicode Names for Lsa Database Object Types
|
||
//
|
||
|
||
for (ObjectTypeId = NullObject;
|
||
ObjectTypeId < DummyLastObject;
|
||
ObjectTypeId++) {
|
||
|
||
RtlInitUnicodeString(
|
||
&LsapDbObjectTypeNames[ObjectTypeId],
|
||
UnicodeObjectTypeNames[ObjectTypeId]
|
||
);
|
||
}
|
||
|
||
LsapDbDsAttInfo = StaticLsapDbDsAttInfo;
|
||
return(Status);
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
LsapDbInitializeContainingDirs()
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function initializes Unicode strings for the names of the Containing
|
||
directories for each object type. The Containing Directory is the
|
||
Registry Key under which all objects of the given type are created and is
|
||
relative to the LSA Database root. Note that objects of a given type all
|
||
exist under a single Registry node, that is, the type of an object
|
||
uniquely determines the name of its containing directory.
|
||
|
||
NOTE: Containing Directories are used to produce Physical Object Names
|
||
from Logical Object Names. The Physical Object Name is simply
|
||
the Logical Object Name prepended with the Containing Directory
|
||
Name and a "\".
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS - Standard Nt Result Code
|
||
|
||
All Result Codes are generated by called routines.
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS Status = STATUS_SUCCESS;
|
||
LSAP_DB_OBJECT_TYPE_ID ObjectTypeId;
|
||
|
||
PWSTR ContainingDirectories[DummyLastObject] = {
|
||
|
||
L"",
|
||
L"",
|
||
L"Domains",
|
||
L"Accounts",
|
||
L"Secrets"
|
||
};
|
||
|
||
//
|
||
// Initialize the array of Unicode Strings indexed by object type setting
|
||
// the Containing Directory name for each object type.
|
||
//
|
||
|
||
for (ObjectTypeId = PolicyObject;
|
||
ObjectTypeId < DummyLastObject;
|
||
ObjectTypeId++) {
|
||
|
||
RtlInitUnicodeString(
|
||
&LsapDbContDirs[ObjectTypeId],
|
||
ContainingDirectories[ ObjectTypeId ]
|
||
);
|
||
}
|
||
|
||
return(Status);
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
LsapDbInitializeDefaultQuotaLimits(
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function initializes three different sets of Quota Limits in
|
||
global data.
|
||
|
||
o The System Installation Default Quota Limits. These are read from
|
||
the Policy Object's "DefQuota" attribute.
|
||
o The Absolute Minimum quota limit values that may be set
|
||
o The Absolute Maximum quota limit values that may be set
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS - Standard Nt Result Code
|
||
|
||
All Result Codes are generated by called routines.
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS Status;
|
||
ULONG QuotaLimitsLength = sizeof (QUOTA_LIMITS);
|
||
|
||
//
|
||
// Read the installed System Default Quotas from the DefQuota attribute
|
||
// of the Policy object in the LSA Database.
|
||
//
|
||
|
||
Status = LsapDbReadAttributeObject(
|
||
LsapDbHandle,
|
||
&LsapDbNames[DefQuota],
|
||
(PVOID) &LsapDbInstalledQuotaLimits,
|
||
&QuotaLimitsLength
|
||
);
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
|
||
LsapLogError(
|
||
"LsapDbInitializeDefaultQuotaLimits: Read DefQuota Attribute returned 0x%lx\n",
|
||
Status
|
||
);
|
||
|
||
goto InitializeDefaultQuotaLimitsError;
|
||
}
|
||
|
||
//
|
||
// Read the System Abs Min Quotas from the QuAbsMin attribute
|
||
// of the Policy object in the LSA Database.
|
||
//
|
||
|
||
Status = LsapDbReadAttributeObject(
|
||
LsapDbHandle,
|
||
&LsapDbNames[QuAbsMin],
|
||
(PVOID) &LsapDbAbsMinQuotaLimits,
|
||
&QuotaLimitsLength
|
||
);
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
|
||
LsapLogError(
|
||
"LsapDbInitializeDefaultQuotaLimits: Read QuAbsMin Attribute returned 0x%lx\n",
|
||
Status
|
||
);
|
||
|
||
goto InitializeDefaultQuotaLimitsError;
|
||
}
|
||
|
||
//
|
||
// Read the System Abs Max Quotas from the QuAbsMax attribute
|
||
// of the Policy object in the LSA Database.
|
||
//
|
||
|
||
Status = LsapDbReadAttributeObject(
|
||
LsapDbHandle,
|
||
&LsapDbNames[QuAbsMax],
|
||
(PVOID) &LsapDbAbsMaxQuotaLimits,
|
||
&QuotaLimitsLength
|
||
);
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
|
||
LsapLogError(
|
||
"LsapDbInitializeDefaultQuotaLimits: Read QuAbsMax Attribute returned 0x%lx\n",
|
||
Status
|
||
);
|
||
|
||
goto InitializeDefaultQuotaLimitsError;
|
||
}
|
||
|
||
InitializeDefaultQuotaLimitsFinish:
|
||
|
||
return(Status);
|
||
|
||
InitializeDefaultQuotaLimitsError:
|
||
|
||
goto InitializeDefaultQuotaLimitsFinish;
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
LsapDbInitializeReplication(
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function performes LSA initialization for replication and turns
|
||
on notification of LSA Database updates to the LSA Database Replicator.
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS - Standard Nt Result Code
|
||
|
||
All Result Codes are generated by called routines.
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS Status;
|
||
ULONG PolicyModificationInfoLength = sizeof (POLICY_MODIFICATION_INFO);
|
||
ULONG PolicyLsaServerRoleInfoLength = sizeof(POLICY_LSA_SERVER_ROLE_INFO);
|
||
ULONG LargeIntegerLength = sizeof( LARGE_INTEGER );
|
||
|
||
//
|
||
// Read the Policy Modification Info from the PolMod attribute
|
||
// of the Policy object in the LSA Database.
|
||
//
|
||
|
||
Status = LsapDbReadAttributeObject(
|
||
LsapDbHandle,
|
||
&LsapDbNames[PolMod],
|
||
(PVOID) &LsapDbState.PolicyModificationInfo,
|
||
&PolicyModificationInfoLength
|
||
);
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
goto InitializeReplicationError;
|
||
}
|
||
|
||
InitializeReplicationFinish:
|
||
|
||
return(Status);
|
||
|
||
InitializeReplicationError:
|
||
|
||
goto InitializeReplicationFinish;
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
LsapDbInitializeCipherKey(
|
||
IN PUNICODE_STRING CipherSeed,
|
||
IN PLSAP_CR_CIPHER_KEY *CipherKey
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function initializes the LSA Database Cipher Key.
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS - Standard Nt Result Code
|
||
|
||
All Result Codes are generated by called routines.
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS Status;
|
||
LSAP_CR_CLEAR_VALUE ClearCipherKey;
|
||
PLSAP_CR_CIPHER_VALUE CipherCipherKey;
|
||
|
||
*CipherKey = NULL;
|
||
|
||
//
|
||
// Initialize the Cipher key to a hardwired constant
|
||
// encrypted with itself.
|
||
//
|
||
LsapCrUnicodeToClearValue( CipherSeed, &ClearCipherKey);
|
||
|
||
Status = LsapCrEncryptValue(
|
||
&ClearCipherKey,
|
||
(PLSAP_CR_CIPHER_KEY) &ClearCipherKey,
|
||
&CipherCipherKey
|
||
);
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
|
||
LsapLogError( "LsapDbInitializeReplication: NtQuerySystemTime returned 0x%lx\n",
|
||
Status );
|
||
|
||
} else {
|
||
|
||
*CipherKey = ( PLSAP_CR_CIPHER_KEY )CipherCipherKey;
|
||
}
|
||
|
||
return(Status);
|
||
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
LsapDbOpenRootRegistryKey(
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function opens the LSA Database Root Registry Key. This has
|
||
the fixed name \Registry\Machine\Security.
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS - Standard Nt Result Code
|
||
|
||
All Result Codes are generated by called routines.
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS Status;
|
||
UNICODE_STRING DbRootRegKeyNameU;
|
||
OBJECT_ATTRIBUTES DbAttributes;
|
||
|
||
RtlInitUnicodeString( &DbRootRegKeyNameU, LSAP_DB_ROOT_REG_KEY_NAME );
|
||
|
||
InitializeObjectAttributes(
|
||
&DbAttributes,
|
||
&DbRootRegKeyNameU,
|
||
OBJ_CASE_INSENSITIVE,
|
||
NULL,
|
||
NULL
|
||
);
|
||
|
||
Status = RtlpNtOpenKey(
|
||
(PHANDLE) &LsapDbState.DbRootRegKeyHandle,
|
||
(KEY_READ | KEY_CREATE_SUB_KEY | KEY_ENUMERATE_SUB_KEYS | WRITE_DAC),
|
||
&DbAttributes,
|
||
0
|
||
);
|
||
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
LsapLogError(
|
||
"LsapDbOpenRootRegistryKey: Open Root Key for LSA Policy Database returned 0x%lx\n",
|
||
Status
|
||
);
|
||
goto OpenRootRegistryKeyError;
|
||
}
|
||
|
||
|
||
//
|
||
// If there are no sub-keys, then we are in system-install.
|
||
// Assign the initial protection of this hive.
|
||
//
|
||
|
||
Status = LsapAssignInitialHiveProtection( LsapDbState.DbRootRegKeyHandle );
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
LsapLogError(
|
||
"LsapDbOpenRootRegistryKey: Couldn't assign initial hive protection 0x%lx\n",
|
||
Status
|
||
);
|
||
goto OpenRootRegistryKeyError;
|
||
}
|
||
|
||
|
||
|
||
OpenRootRegistryKeyFinish:
|
||
|
||
return(Status);
|
||
|
||
OpenRootRegistryKeyError:
|
||
|
||
goto OpenRootRegistryKeyFinish;
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
LsapAssignInitialHiveProtection(
|
||
HANDLE HiveRoot
|
||
)
|
||
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function assigns inheritable protection to the hive root key.
|
||
It will only do this if the hive root has no sub-keys.
|
||
This condition will only exist during system installation.
|
||
|
||
WARNING -
|
||
|
||
THIS ROUTINE IS TAILORED TO OPERATE ON THE \REGISTRY\SECURITY HIVE.
|
||
As such, it expects the Root key to have exactly one sub-key (a
|
||
link to the SAM hive) if the the database has NOT been initialized.
|
||
Otherwise, it expects the LSA policy database keys to be present.
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
STATUS_SUCCESS - Everything went fine. No indication of whether
|
||
protection was necessarily assigned or not.
|
||
|
||
All other status values are generated by called routines.
|
||
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS
|
||
Status;
|
||
|
||
KEY_BASIC_INFORMATION
|
||
DummyBuffer;
|
||
|
||
ULONG
|
||
IgnoreRequiredLength;
|
||
|
||
SECURITY_DESCRIPTOR
|
||
Sd;
|
||
|
||
|
||
//
|
||
// See if the hive has more than 1 sub-keys.
|
||
//
|
||
//
|
||
|
||
Status = NtEnumerateKey(
|
||
HiveRoot,
|
||
1, // Index - 0 is the SAM link, 1 is LSA policy database stuff
|
||
KeyBasicInformation, // Name of key
|
||
&DummyBuffer,
|
||
sizeof(DummyBuffer),
|
||
&IgnoreRequiredLength
|
||
);
|
||
|
||
if (Status == STATUS_NO_MORE_ENTRIES) {
|
||
|
||
//
|
||
// We are initializing the system...
|
||
// Apply a reasonable ACL to the hive root.
|
||
//
|
||
|
||
Status = LsapCreateDatabaseProtection( &Sd );
|
||
|
||
if (NT_SUCCESS(Status)) {
|
||
Status = NtSetSecurityObject(
|
||
HiveRoot, // Object to apply to
|
||
DACL_SECURITY_INFORMATION, // Information to set
|
||
(PSECURITY_DESCRIPTOR)&Sd // Descriptor
|
||
);
|
||
}
|
||
} else {
|
||
|
||
Status = STATUS_SUCCESS;
|
||
}
|
||
|
||
return(Status);
|
||
|
||
}
|
||
|
||
|
||
|
||
NTSTATUS
|
||
LsapCreateDatabaseProtection(
|
||
PISECURITY_DESCRIPTOR Sd
|
||
)
|
||
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function allocates and initializes protection to assign to
|
||
the SAM database.
|
||
|
||
Upon return, any non-zero pointers in the security descriptors
|
||
point to memory allocated from process heap. It is the caller's
|
||
responsibility to free this memory.
|
||
|
||
|
||
Protection is:
|
||
|
||
System: All Access
|
||
Admin: ReadControl | WriteDac
|
||
|
||
Arguments:
|
||
|
||
Sd - Address of a security descriptor to initialize.
|
||
|
||
Return Value:
|
||
|
||
STATUS_SUCCESS - The Security descriptor has been initialize.
|
||
|
||
STATUS_NO_MEMORY - couldn't allocate memory for the protection info.
|
||
|
||
--*/
|
||
|
||
|
||
{
|
||
NTSTATUS
|
||
Status;
|
||
|
||
ULONG
|
||
Length;
|
||
|
||
USHORT
|
||
i;
|
||
|
||
PACL
|
||
Dacl;
|
||
|
||
PACE_HEADER
|
||
Ace;
|
||
|
||
|
||
//
|
||
// Initialize the security descriptor.
|
||
// This call should not fail.
|
||
//
|
||
|
||
Status = RtlCreateSecurityDescriptor( Sd, SECURITY_DESCRIPTOR_REVISION1 );
|
||
ASSERT(NT_SUCCESS(Status));
|
||
|
||
Length = (ULONG)sizeof(ACL) +
|
||
(2*((ULONG)sizeof(ACCESS_ALLOWED_ACE))) +
|
||
RtlLengthSid( LsapLocalSystemSid ) +
|
||
RtlLengthSid( LsapAliasAdminsSid ) +
|
||
8; // The 8 is just for good measure
|
||
|
||
|
||
Dacl = RtlAllocateHeap( RtlProcessHeap(), 0, Length );
|
||
|
||
if (Dacl == NULL) {
|
||
return(STATUS_NO_MEMORY);
|
||
}
|
||
|
||
|
||
Status = RtlCreateAcl (Dacl, Length, ACL_REVISION2 );
|
||
ASSERT(NT_SUCCESS(Status));
|
||
|
||
//
|
||
// Add ACEs to the ACL...
|
||
// These calls should not be able to fail.
|
||
//
|
||
|
||
Status = RtlAddAccessAllowedAce(
|
||
Dacl,
|
||
ACL_REVISION2,
|
||
(GENERIC_ALL),
|
||
LsapLocalSystemSid
|
||
);
|
||
ASSERT(NT_SUCCESS(Status));
|
||
|
||
Status = RtlAddAccessAllowedAce(
|
||
Dacl,
|
||
ACL_REVISION2,
|
||
(READ_CONTROL | WRITE_DAC),
|
||
LsapAliasAdminsSid
|
||
);
|
||
ASSERT(NT_SUCCESS(Status));
|
||
|
||
|
||
//
|
||
// Now mark the ACEs as inheritable...
|
||
//
|
||
|
||
for ( i=0; i<Dacl->AceCount; i++) {
|
||
|
||
//
|
||
// Get the address of the next ACE
|
||
// (Shouldn't fail)
|
||
//
|
||
|
||
Status = RtlGetAce( Dacl, (ULONG)i, &Ace );
|
||
ASSERT(NT_SUCCESS(Status));
|
||
|
||
Ace->AceFlags |= (CONTAINER_INHERIT_ACE);
|
||
|
||
}
|
||
|
||
|
||
//
|
||
// And add the ACL to the security descriptor.
|
||
// This call should not fail.
|
||
//
|
||
|
||
Status = RtlSetDaclSecurityDescriptor(
|
||
Sd,
|
||
TRUE, // DaclPresent
|
||
Dacl, // Dacl OPTIONAL
|
||
FALSE // DaclDefaulted OPTIONAL
|
||
);
|
||
ASSERT(NT_SUCCESS(Status));
|
||
|
||
|
||
|
||
return(STATUS_SUCCESS);
|
||
|
||
}
|
||
|
||
|
||
|
||
NTSTATUS
|
||
LsapUpdateDatabaseProtection(
|
||
IN ULONG Revision
|
||
)
|
||
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function allocates and updates protection to assign to
|
||
the LSA database.
|
||
|
||
Arguments:
|
||
|
||
Revision - New database revision level
|
||
LSAP_DB_REVISION_1_3 -- grant POLICY_NOTIFICATION access to Administrators
|
||
LSAP_DB_REVISION_1_6 -- grant POLICY_VIEW_LOCAL_INFORMATION | POLICY_LOOKUP_NAMES to AnonymousLogonSid
|
||
LSAP_DB_REVISION_1_7 -- grant POLICY_NOTIFICATION to LocalService/NetworkService
|
||
|
||
|
||
Return Value:
|
||
|
||
STATUS_SUCCESS - The Security descriptor has been initialize.
|
||
|
||
STATUS_NO_MEMORY - couldn't allocate memory for the protection info.
|
||
|
||
--*/
|
||
|
||
|
||
{
|
||
NTSTATUS Status;
|
||
NTSTATUS TempStatus;
|
||
PSECURITY_DESCRIPTOR CurrentSd = NULL;
|
||
PSECURITY_DESCRIPTOR RelativeSd = NULL;
|
||
ULONG RelativeSdLength;
|
||
PSECURITY_DESCRIPTOR NewSd;
|
||
SECURITY_DESCRIPTOR NewSdBuffer;
|
||
USHORT i;
|
||
PACL Dacl, NewDacl = NULL, TempAcl;
|
||
PACE_HEADER Ace;
|
||
PSID AceSid;
|
||
BOOLEAN AdminAceFound = FALSE;
|
||
BOOLEAN UpdatedSd = FALSE;
|
||
|
||
//
|
||
// First, read the initial security descriptor...
|
||
//
|
||
Status = LsapRegReadObjectSD( LsapPolicyHandle,
|
||
&CurrentSd );
|
||
|
||
|
||
if ( !NT_SUCCESS( Status ) ) {
|
||
goto Cleanup;
|
||
}
|
||
|
||
ASSERT( Revision == LSAP_DB_REVISION_1_3
|
||
||
|
||
Revision == LSAP_DB_REVISION_1_6
|
||
||
|
||
Revision == LSAP_DB_REVISION_1_7 );
|
||
|
||
NewSd = CurrentSd;
|
||
|
||
if ( Revision == LSAP_DB_REVISION_1_3
|
||
||
|
||
Revision == LSAP_DB_REVISION_1_6
|
||
||
|
||
Revision == LSAP_DB_REVISION_1_7 )
|
||
{
|
||
Dacl = RtlpDaclAddrSecurityDescriptor( ( PISECURITY_DESCRIPTOR )CurrentSd );
|
||
|
||
if ( Dacl ) {
|
||
|
||
//
|
||
// We'll have to find the ace for local system
|
||
//
|
||
Ace = ( PACE_HEADER )FirstAce( Dacl );
|
||
for(i = 0; i < Dacl->AceCount; i++, Ace = ( PACE_HEADER )NextAce( Ace ) ) {
|
||
|
||
|
||
|
||
if ( IsObjectAceType( Ace ) ) {
|
||
|
||
AceSid = RtlObjectAceSid( Ace );
|
||
|
||
} else {
|
||
|
||
AceSid = &( ( PKNOWN_ACE )Ace )->SidStart;
|
||
}
|
||
|
||
//
|
||
// When upgrading to revision 1_3, update the administrators ACE
|
||
//
|
||
|
||
if ( Revision == LSAP_DB_REVISION_1_3 &&
|
||
RtlEqualSid( AceSid, LsapAliasAdminsSid ) ) {
|
||
|
||
//
|
||
// Get the access mask and or in our new bit
|
||
//
|
||
if ( IsObjectAceType( Ace ) ) {
|
||
|
||
if (( ((PKNOWN_OBJECT_ACE)Ace)->Mask & POLICY_NOTIFICATION ) == 0 ) {
|
||
|
||
((PKNOWN_OBJECT_ACE)Ace)->Mask |= POLICY_NOTIFICATION;
|
||
UpdatedSd = TRUE;
|
||
}
|
||
|
||
} else {
|
||
|
||
if (( ((PKNOWN_ACE)Ace)->Mask & POLICY_NOTIFICATION ) == 0 ) {
|
||
|
||
((PKNOWN_ACE)Ace)->Mask |= POLICY_NOTIFICATION;
|
||
UpdatedSd = TRUE;
|
||
}
|
||
|
||
}
|
||
|
||
AdminAceFound = TRUE;
|
||
|
||
}
|
||
}
|
||
}
|
||
|
||
//
|
||
// If we didn't find an ACE to update, make sure to add it...
|
||
//
|
||
if ( !AdminAceFound )
|
||
{
|
||
ULONG NewDaclLength;
|
||
|
||
|
||
UpdatedSd = TRUE;
|
||
|
||
NewDaclLength = Dacl ? Dacl->AclSize : 0;
|
||
|
||
if ( Revision == LSAP_DB_REVISION_1_3 )
|
||
{
|
||
NewDaclLength += ( ULONG )sizeof( ACCESS_ALLOWED_ACE ) +
|
||
RtlLengthSid( LsapAliasAdminsSid );
|
||
}
|
||
else if ( Revision == LSAP_DB_REVISION_1_6 )
|
||
{
|
||
NewDaclLength += ( ULONG )sizeof( ACCESS_ALLOWED_ACE ) +
|
||
RtlLengthSid( LsapAnonymousSid );
|
||
}
|
||
else
|
||
{
|
||
ASSERT( Revision == LSAP_DB_REVISION_1_7 );
|
||
|
||
NewDaclLength += 2 * ( ULONG )sizeof( ACCESS_ALLOWED_ACE ) +
|
||
RtlLengthSid( LsapLocalServiceSid ) +
|
||
RtlLengthSid( LsapNetworkServiceSid );
|
||
}
|
||
|
||
NewDacl = LsapAllocateLsaHeap( NewDaclLength );
|
||
|
||
if ( NewDacl == NULL ) {
|
||
Status = STATUS_INSUFFICIENT_RESOURCES;
|
||
goto Cleanup;
|
||
}
|
||
|
||
if ( Dacl ) {
|
||
|
||
RtlCopyMemory( NewDacl, Dacl, Dacl->AclSize );
|
||
NewDacl->AclSize = ( USHORT )NewDaclLength;
|
||
|
||
} else {
|
||
|
||
Status = RtlCreateAcl ( NewDacl, NewDaclLength, ACL_REVISION2 );
|
||
|
||
if ( !NT_SUCCESS(Status) ) {
|
||
goto Cleanup;
|
||
}
|
||
}
|
||
|
||
//
|
||
// For version 1.3, grant administrators All access and Policy notification access
|
||
//
|
||
if ( Revision == LSAP_DB_REVISION_1_3 ) {
|
||
|
||
Status = RtlAddAccessAllowedAce( NewDacl,
|
||
ACL_REVISION2,
|
||
POLICY_ALL_ACCESS |
|
||
POLICY_NOTIFICATION,
|
||
LsapAliasAdminsSid );
|
||
|
||
if ( !NT_SUCCESS(Status) ) {
|
||
goto Cleanup;
|
||
}
|
||
|
||
//
|
||
// For version 1.6, grant anonymous logon View Local and Lookup names access.
|
||
//
|
||
|
||
} else if ( Revision == LSAP_DB_REVISION_1_6) {
|
||
|
||
Status = RtlAddAccessAllowedAce( NewDacl,
|
||
ACL_REVISION2,
|
||
POLICY_VIEW_LOCAL_INFORMATION |
|
||
POLICY_LOOKUP_NAMES,
|
||
LsapAnonymousSid );
|
||
|
||
if ( !NT_SUCCESS(Status) ) {
|
||
goto Cleanup;
|
||
}
|
||
|
||
//
|
||
// For version 1.7, grant Policy notification access to LocalService
|
||
// and NetworkService
|
||
//
|
||
|
||
} else {
|
||
|
||
ASSERT( Revision == LSAP_DB_REVISION_1_7 );
|
||
|
||
Status = RtlAddAccessAllowedAce( NewDacl,
|
||
ACL_REVISION2,
|
||
POLICY_NOTIFICATION,
|
||
LsapLocalServiceSid );
|
||
|
||
if ( !NT_SUCCESS(Status) ) {
|
||
goto Cleanup;
|
||
}
|
||
|
||
Status = RtlAddAccessAllowedAce( NewDacl,
|
||
ACL_REVISION2,
|
||
POLICY_NOTIFICATION,
|
||
LsapNetworkServiceSid );
|
||
|
||
if ( !NT_SUCCESS(Status) ) {
|
||
goto Cleanup;
|
||
}
|
||
}
|
||
|
||
//
|
||
// If the current security descriptor is self relative,
|
||
// convert it to absolute so I can set the DACL on it.
|
||
//
|
||
if ( RtlpAreControlBitsSet( ( PISECURITY_DESCRIPTOR )CurrentSd,
|
||
SE_SELF_RELATIVE ) ) {
|
||
|
||
NewSd = &NewSdBuffer;
|
||
|
||
Status = RtlCreateSecurityDescriptor( NewSd,
|
||
SECURITY_DESCRIPTOR_REVISION );
|
||
|
||
if ( !NT_SUCCESS(Status) ) {
|
||
goto Cleanup;
|
||
}
|
||
|
||
|
||
((PISECURITY_DESCRIPTOR)NewSd)->Control =
|
||
((PISECURITY_DESCRIPTOR)CurrentSd)->Control;
|
||
|
||
|
||
AceSid = RtlpOwnerAddrSecurityDescriptor(
|
||
( PISECURITY_DESCRIPTOR )CurrentSd );
|
||
|
||
if ( AceSid ) {
|
||
|
||
( (PISECURITY_DESCRIPTOR)NewSd )->Owner = AceSid;
|
||
}
|
||
|
||
AceSid = RtlpGroupAddrSecurityDescriptor(
|
||
( PISECURITY_DESCRIPTOR )CurrentSd );
|
||
|
||
if ( AceSid ) {
|
||
|
||
( ( PISECURITY_DESCRIPTOR )NewSd )->Group = AceSid;
|
||
}
|
||
|
||
TempAcl = RtlpSaclAddrSecurityDescriptor(
|
||
( PISECURITY_DESCRIPTOR )CurrentSd );
|
||
|
||
if ( TempAcl ) {
|
||
|
||
( ( PISECURITY_DESCRIPTOR )NewSd )->Sacl = TempAcl;
|
||
}
|
||
|
||
RtlpClearControlBits( ( PISECURITY_DESCRIPTOR )NewSd,
|
||
SE_SELF_RELATIVE );
|
||
|
||
|
||
}
|
||
|
||
|
||
|
||
//
|
||
// Put the computed DACL onto the SD.
|
||
//
|
||
Status = RtlSetDaclSecurityDescriptor( NewSd,
|
||
TRUE,
|
||
NewDacl,
|
||
FALSE );
|
||
if ( !NT_SUCCESS(Status) ) {
|
||
goto Cleanup;
|
||
}
|
||
|
||
//
|
||
// Convert the SD to self relative before writing it to the database.
|
||
//
|
||
|
||
RelativeSdLength = 0;
|
||
Status = RtlMakeSelfRelativeSD( NewSd,
|
||
NULL,
|
||
&RelativeSdLength );
|
||
|
||
if (Status != STATUS_BUFFER_TOO_SMALL) { // This is the expected case
|
||
if ( NT_SUCCESS(Status) ) {
|
||
Status = STATUS_INTERNAL_ERROR;
|
||
}
|
||
goto Cleanup;
|
||
}
|
||
|
||
RelativeSd = LsapAllocateLsaHeap( RelativeSdLength );
|
||
|
||
if ( RelativeSd == NULL) {
|
||
Status = STATUS_INSUFFICIENT_RESOURCES;
|
||
goto Cleanup;
|
||
}
|
||
|
||
Status = RtlMakeSelfRelativeSD( NewSd,
|
||
RelativeSd,
|
||
&RelativeSdLength );
|
||
|
||
if ( !NT_SUCCESS(Status) ) {
|
||
goto Cleanup;
|
||
}
|
||
|
||
NewSd = RelativeSd;
|
||
}
|
||
}
|
||
|
||
|
||
if ( UpdatedSd ) {
|
||
ULONG NewSdLength;
|
||
|
||
//
|
||
// Set the security descriptor back on the object
|
||
//
|
||
NewSdLength = RtlLengthSecurityDescriptor( NewSd );
|
||
|
||
//
|
||
// Add a Registry transaction to write the Security Descriptor as the
|
||
// value of the new object's SecDesc subkey.
|
||
//
|
||
|
||
Status = LsapDbReferenceObject(
|
||
LsapDbHandle,
|
||
0,
|
||
PolicyObject,
|
||
PolicyObject,
|
||
LSAP_DB_LOCK | LSAP_DB_START_TRANSACTION
|
||
);
|
||
|
||
if ( !NT_SUCCESS(Status) ) {
|
||
goto Cleanup;
|
||
}
|
||
|
||
Status = LsapDbWriteAttributeObject( LsapPolicyHandle,
|
||
&LsapDbNames[ SecDesc ],
|
||
NewSd,
|
||
NewSdLength );
|
||
|
||
|
||
TempStatus = LsapDbDereferenceObject(
|
||
&LsapDbHandle,
|
||
PolicyObject,
|
||
PolicyObject,
|
||
(LSAP_DB_LOCK |
|
||
LSAP_DB_OMIT_REPLICATOR_NOTIFICATION | // Each BDC should upgrade its own database
|
||
LSAP_DB_FINISH_TRANSACTION),
|
||
(SECURITY_DB_DELTA_TYPE) 0,
|
||
Status );
|
||
|
||
if ( !NT_SUCCESS(TempStatus) ) {
|
||
if (NT_SUCCESS(Status) ) {
|
||
Status = TempStatus;
|
||
}
|
||
}
|
||
|
||
}
|
||
|
||
|
||
Cleanup:
|
||
|
||
//
|
||
// Free the security descriptor
|
||
//
|
||
LsapFreeLsaHeap( CurrentSd );
|
||
LsapFreeLsaHeap( RelativeSd );
|
||
LsapFreeLsaHeap( NewDacl );
|
||
|
||
return( Status );
|
||
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
LsapDbInitializeLock(
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function initializes the LSA Database Lock. It is called once
|
||
only, during LSA Database initialization.
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS - Standard Nt Result Code
|
||
|
||
All Result Codes are generated by called routines.
|
||
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS Status;
|
||
|
||
Status = SafeInitializeCriticalSection( &LsapDbState.AccountLock, ( DWORD )ACCOUNT_LOCK_ENUM );
|
||
if (!NT_SUCCESS(Status) ) {
|
||
goto Cleanup;
|
||
}
|
||
|
||
Status = SafeInitializeCriticalSection( &LsapDbState.PolicyLock, ( DWORD )POLICY_LOCK_ENUM );
|
||
if (!NT_SUCCESS(Status) ) {
|
||
goto Cleanup;
|
||
}
|
||
|
||
Status = SafeInitializeCriticalSection( &LsapDbState.SecretLock, ( DWORD )SECRET_LOCK_ENUM );
|
||
if (!NT_SUCCESS(Status) ) {
|
||
goto Cleanup;
|
||
}
|
||
|
||
Status = SafeInitializeCriticalSection( &LsapDbState.RegistryLock, ( DWORD )REGISTRY_LOCK_ENUM );
|
||
if (!NT_SUCCESS(Status) ) {
|
||
goto Cleanup;
|
||
}
|
||
|
||
Status = SafeInitializeCriticalSection( &LsapDbState.HandleTableLock, ( DWORD )HANDLE_TABLE_LOCK_ENUM );
|
||
if (!NT_SUCCESS(Status) ) {
|
||
goto Cleanup;
|
||
}
|
||
|
||
try
|
||
{
|
||
SafeInitializeResource( &LsapDbState.PolicyCacheLock, ( DWORD )POLICY_CACHE_LOCK_ENUM );
|
||
Status = STATUS_SUCCESS;
|
||
}
|
||
except( EXCEPTION_EXECUTE_HANDLER )
|
||
{
|
||
Status = GetExceptionCode();
|
||
}
|
||
|
||
if (!NT_SUCCESS(Status) ) {
|
||
goto Cleanup;
|
||
}
|
||
|
||
//
|
||
// Initialize the Resource for the Trusted Domain List.
|
||
//
|
||
|
||
InitializeListHead( &LsapDbTrustedDomainList.ListHead );
|
||
LsapDbTrustedDomainList.TrustedDomainCount = 0;
|
||
LsapDbTrustedDomainList.CurrentSequenceNumber = 0;
|
||
LsapDbMakeCacheInvalid( TrustedDomainObject );
|
||
|
||
try
|
||
{
|
||
SafeInitializeResource( &LsapDbTrustedDomainList.Resource, ( DWORD )TRUST_LOCK_ENUM );
|
||
Status = STATUS_SUCCESS ;
|
||
}
|
||
except (EXCEPTION_EXECUTE_HANDLER )
|
||
{
|
||
Status = GetExceptionCode();
|
||
}
|
||
|
||
if ( !NT_SUCCESS( Status ) ) {
|
||
|
||
goto Cleanup;
|
||
}
|
||
|
||
try
|
||
{
|
||
//
|
||
// do not use the safelock library for ScePolicyLock
|
||
// because it is usually acquired on one thread and
|
||
// released on another
|
||
//
|
||
RtlInitializeResource( &LsapDbState.ScePolicyLock );
|
||
Status = STATUS_SUCCESS ;
|
||
}
|
||
except ( EXCEPTION_EXECUTE_HANDLER )
|
||
{
|
||
Status = GetExceptionCode();
|
||
}
|
||
if (!NT_SUCCESS( Status )) {
|
||
goto Cleanup;
|
||
}
|
||
|
||
LsapDbState.SceSyncEvent = CreateEvent( NULL, TRUE, TRUE, NULL );
|
||
if ( LsapDbState.SceSyncEvent == NULL ) {
|
||
Status = GetLastError();
|
||
goto Cleanup;
|
||
}
|
||
|
||
#if DBG
|
||
try
|
||
{
|
||
SafeInitializeResource( &LsapDsThreadInfoListResource, ( DWORD )THREAD_INFO_LIST_LOCK_ENUM );
|
||
Status = STATUS_SUCCESS ;
|
||
}
|
||
except ( EXCEPTION_EXECUTE_HANDLER )
|
||
{
|
||
Status = GetExceptionCode();
|
||
}
|
||
if ( !NT_SUCCESS( Status ) ) {
|
||
goto Cleanup;
|
||
}
|
||
RtlZeroMemory( &LsapDsThreadInfoList, sizeof( LSADS_THREAD_INFO_NODE ) * LSAP_THREAD_INFO_LIST_MAX );
|
||
#endif
|
||
Status = STATUS_SUCCESS;
|
||
|
||
Cleanup:
|
||
return( Status );
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
LsapDbInitializeWellKnownValues(
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function initializes the well-known values used by LSA.
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS - Standard Nt Result Code
|
||
|
||
All Result Codes are generated by called routines.
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS Status;
|
||
BOOLEAN b;
|
||
|
||
//
|
||
// Initialize the Well Known Sids
|
||
//
|
||
|
||
b = LsaIInitializeWellKnownSids( &WellKnownSids );
|
||
|
||
if (!b ) {
|
||
|
||
Status = STATUS_UNSUCCESSFUL;
|
||
goto InitializeWellKnownValuesError;
|
||
}
|
||
|
||
//
|
||
// Initialize the well known privilege values
|
||
//
|
||
|
||
Status = LsapDbInitializeWellKnownPrivs();
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
|
||
goto InitializeWellKnownValuesError;
|
||
}
|
||
|
||
InitializeWellKnownValuesFinish:
|
||
|
||
return(Status);
|
||
|
||
InitializeWellKnownValuesError:
|
||
|
||
goto InitializeWellKnownValuesFinish;
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
LsapDbInitializeWellKnownPrivs(
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function initializes the well-known privilege values.
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS - Standard Nt Result Code
|
||
|
||
Currently, only STATUS_SUCCESS is returned.
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS Status = STATUS_SUCCESS;
|
||
|
||
LsapCreateTokenPrivilege =
|
||
RtlConvertLongToLuid(SE_CREATE_TOKEN_PRIVILEGE);
|
||
LsapAssignPrimaryTokenPrivilege =
|
||
RtlConvertLongToLuid(SE_ASSIGNPRIMARYTOKEN_PRIVILEGE);
|
||
LsapLockMemoryPrivilege =
|
||
RtlConvertLongToLuid(SE_LOCK_MEMORY_PRIVILEGE);
|
||
LsapIncreaseQuotaPrivilege =
|
||
RtlConvertLongToLuid(SE_INCREASE_QUOTA_PRIVILEGE);
|
||
LsapUnsolicitedInputPrivilege =
|
||
RtlConvertLongToLuid(SE_UNSOLICITED_INPUT_PRIVILEGE);
|
||
LsapTcbPrivilege =
|
||
RtlConvertLongToLuid(SE_TCB_PRIVILEGE);
|
||
LsapSecurityPrivilege =
|
||
RtlConvertLongToLuid(SE_SECURITY_PRIVILEGE);
|
||
LsapTakeOwnershipPrivilege =
|
||
RtlConvertLongToLuid(SE_TAKE_OWNERSHIP_PRIVILEGE);
|
||
|
||
return(Status);
|
||
}
|
||
|
||
|
||
BOOLEAN
|
||
LsaIInitializeWellKnownSids(
|
||
OUT PLSAP_WELL_KNOWN_SID_ENTRY *WellKnownSids
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function initializes the Well-Known Sids
|
||
|
||
Arguments:
|
||
|
||
WellKnownSids - Receives a pointer to a newly created table of
|
||
the Well Known Sids.
|
||
|
||
Return Value:
|
||
|
||
BOOLEAN - TRUE if successful, else FALSE.
|
||
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS Status;
|
||
BOOLEAN BooleanStatus = TRUE;
|
||
LSAP_WELL_KNOWN_SID_INDEX WellKnownSidIndex;
|
||
ULONG SubAuthorities[LSAP_WELL_KNOWN_MAX_SUBAUTH_LEVEL];
|
||
ULONG OutputWellKnownSidsLength;
|
||
PLSAP_WELL_KNOWN_SID_ENTRY OutputWellKnownSids = NULL;
|
||
UNICODE_STRING SidName, NtAuthorityName, UsersName;
|
||
HMODULE StringsResource;
|
||
SID_IDENTIFIER_AUTHORITY InternetSiteAuthority
|
||
= SECURITY_INTERNETSITE_AUTHORITY;
|
||
|
||
//
|
||
// Get the message resource we need to get the SID names from
|
||
//
|
||
|
||
StringsResource = (HMODULE) LoadLibrary( L"LSASRV.DLL" );
|
||
if (StringsResource == NULL) {
|
||
return(FALSE);
|
||
}
|
||
|
||
|
||
Status = LsapGetMessageStrings(
|
||
StringsResource,
|
||
LSAP_SID_NAME_NT_AUTHORITY,
|
||
&NtAuthorityName,
|
||
0,
|
||
NULL
|
||
); ASSERT(NT_SUCCESS(Status));
|
||
//
|
||
// Allocate memory for the table of Sids.
|
||
//
|
||
|
||
OutputWellKnownSidsLength =
|
||
LsapDummyLastSidIndex * sizeof(LSAP_WELL_KNOWN_SID_ENTRY);
|
||
|
||
OutputWellKnownSids = RtlAllocateHeap(
|
||
RtlProcessHeap(),
|
||
0,
|
||
OutputWellKnownSidsLength
|
||
);
|
||
|
||
if (OutputWellKnownSids == NULL) {
|
||
|
||
goto InitializeWellKnownSidsError;
|
||
}
|
||
|
||
//
|
||
// Allocate and initialize the universal SIDs
|
||
//
|
||
|
||
Status = LsapGetMessageStrings(
|
||
StringsResource,
|
||
LSAP_SID_NAME_NULL,
|
||
&SidName,
|
||
0,
|
||
NULL
|
||
); ASSERT(NT_SUCCESS(Status));
|
||
|
||
SubAuthorities[0] = SECURITY_NULL_RID;
|
||
|
||
if (!LsaIInitializeWellKnownSid(
|
||
OutputWellKnownSids,
|
||
LsapNullSidIndex,
|
||
&LsapNullSidAuthority,
|
||
1,
|
||
SubAuthorities,
|
||
SidName.Buffer,
|
||
L"",
|
||
SidTypeWellKnownGroup
|
||
)) {
|
||
|
||
goto InitializeWellKnownSidsError;
|
||
}
|
||
|
||
Status = LsapGetMessageStrings(
|
||
StringsResource,
|
||
LSAP_SID_NAME_WORLD,
|
||
&SidName,
|
||
0,
|
||
NULL
|
||
); ASSERT(NT_SUCCESS(Status));
|
||
|
||
SubAuthorities[0] = SECURITY_WORLD_RID;
|
||
|
||
if (!LsaIInitializeWellKnownSid(
|
||
OutputWellKnownSids,
|
||
LsapWorldSidIndex,
|
||
&LsapWorldSidAuthority,
|
||
1,
|
||
SubAuthorities,
|
||
SidName.Buffer,
|
||
L"",
|
||
SidTypeWellKnownGroup
|
||
)) {
|
||
|
||
goto InitializeWellKnownSidsError;
|
||
}
|
||
|
||
Status = LsapGetMessageStrings(
|
||
StringsResource,
|
||
LSAP_SID_NAME_LOCAL,
|
||
&SidName,
|
||
0,
|
||
NULL
|
||
); ASSERT(NT_SUCCESS(Status));
|
||
|
||
SubAuthorities[0] = SECURITY_LOCAL_RID;
|
||
|
||
if (!LsaIInitializeWellKnownSid(
|
||
OutputWellKnownSids,
|
||
LsapLocalSidIndex,
|
||
&LsapLocalSidAuthority,
|
||
1,
|
||
SubAuthorities,
|
||
SidName.Buffer,
|
||
L"",
|
||
SidTypeWellKnownGroup
|
||
)) {
|
||
|
||
goto InitializeWellKnownSidsError;
|
||
}
|
||
|
||
Status = LsapGetMessageStrings(
|
||
StringsResource,
|
||
LSAP_SID_NAME_CREATOR_OWNER,
|
||
&SidName,
|
||
0,
|
||
NULL
|
||
); ASSERT(NT_SUCCESS(Status));
|
||
|
||
SubAuthorities[0] = SECURITY_CREATOR_OWNER_RID;
|
||
|
||
if (!LsaIInitializeWellKnownSid(
|
||
OutputWellKnownSids,
|
||
LsapCreatorOwnerSidIndex,
|
||
&LsapCreatorSidAuthority,
|
||
1,
|
||
SubAuthorities,
|
||
SidName.Buffer,
|
||
L"",
|
||
SidTypeWellKnownGroup
|
||
)) {
|
||
|
||
goto InitializeWellKnownSidsError;
|
||
}
|
||
|
||
Status = LsapGetMessageStrings(
|
||
StringsResource,
|
||
LSAP_SID_NAME_CREATOR_GROUP,
|
||
&SidName,
|
||
0,
|
||
NULL
|
||
); ASSERT(NT_SUCCESS(Status));
|
||
|
||
SubAuthorities[0] = SECURITY_CREATOR_GROUP_RID;
|
||
|
||
if (!LsaIInitializeWellKnownSid(
|
||
OutputWellKnownSids,
|
||
LsapCreatorGroupSidIndex,
|
||
&LsapCreatorSidAuthority,
|
||
1,
|
||
SubAuthorities,
|
||
SidName.Buffer,
|
||
L"",
|
||
SidTypeWellKnownGroup
|
||
)) {
|
||
|
||
goto InitializeWellKnownSidsError;
|
||
}
|
||
|
||
Status = LsapGetMessageStrings(
|
||
StringsResource,
|
||
LSAP_SID_NAME_CREATOR_OWNER_SERVER,
|
||
&SidName,
|
||
0,
|
||
NULL
|
||
); ASSERT(NT_SUCCESS(Status));
|
||
|
||
SubAuthorities[0] = SECURITY_CREATOR_OWNER_SERVER_RID;
|
||
|
||
if (!LsaIInitializeWellKnownSid(
|
||
OutputWellKnownSids,
|
||
LsapCreatorOwnerServerSidIndex,
|
||
&LsapCreatorSidAuthority,
|
||
1,
|
||
SubAuthorities,
|
||
SidName.Buffer,
|
||
L"",
|
||
SidTypeWellKnownGroup
|
||
)) {
|
||
|
||
goto InitializeWellKnownSidsError;
|
||
}
|
||
Status = LsapGetMessageStrings(
|
||
StringsResource,
|
||
LSAP_SID_NAME_CREATOR_GROUP_SERVER,
|
||
&SidName,
|
||
0,
|
||
NULL
|
||
); ASSERT(NT_SUCCESS(Status));
|
||
|
||
SubAuthorities[0] = SECURITY_CREATOR_GROUP_SERVER_RID;
|
||
|
||
if (!LsaIInitializeWellKnownSid(
|
||
OutputWellKnownSids,
|
||
LsapCreatorGroupServerSidIndex,
|
||
&LsapCreatorSidAuthority,
|
||
1,
|
||
SubAuthorities,
|
||
SidName.Buffer,
|
||
L"",
|
||
SidTypeWellKnownGroup
|
||
)) {
|
||
|
||
goto InitializeWellKnownSidsError;
|
||
}
|
||
|
||
|
||
//
|
||
// Initialize the Nt well-known Sids
|
||
//
|
||
|
||
Status = LsapGetMessageStrings(
|
||
StringsResource,
|
||
LSAP_SID_NAME_NT_DOMAIN,
|
||
&SidName,
|
||
0,
|
||
NULL
|
||
); ASSERT(NT_SUCCESS(Status));
|
||
|
||
if (!LsaIInitializeWellKnownSid(
|
||
OutputWellKnownSids,
|
||
LsapNtAuthoritySidIndex,
|
||
&LsapNtAuthority,
|
||
0,
|
||
NULL,
|
||
L"",
|
||
SidName.Buffer,
|
||
SidTypeDomain
|
||
)) {
|
||
|
||
goto InitializeWellKnownSidsError;
|
||
}
|
||
|
||
|
||
|
||
Status = LsapGetMessageStrings(
|
||
StringsResource,
|
||
LSAP_SID_NAME_DIALUP,
|
||
&SidName,
|
||
0,
|
||
NULL
|
||
); ASSERT(NT_SUCCESS(Status));
|
||
|
||
SubAuthorities[0] = SECURITY_DIALUP_RID;
|
||
|
||
if (!LsaIInitializeWellKnownSid(
|
||
OutputWellKnownSids,
|
||
LsapDialupSidIndex,
|
||
&LsapNtAuthority,
|
||
1,
|
||
SubAuthorities,
|
||
SidName.Buffer,
|
||
NtAuthorityName.Buffer,
|
||
SidTypeWellKnownGroup
|
||
)) {
|
||
|
||
goto InitializeWellKnownSidsError;
|
||
}
|
||
|
||
Status = LsapGetMessageStrings(
|
||
StringsResource,
|
||
LSAP_SID_NAME_NETWORK,
|
||
&SidName,
|
||
0,
|
||
NULL
|
||
); ASSERT(NT_SUCCESS(Status));
|
||
|
||
SubAuthorities[0] = SECURITY_NETWORK_RID;
|
||
|
||
if (!LsaIInitializeWellKnownSid(
|
||
OutputWellKnownSids,
|
||
LsapNetworkSidIndex,
|
||
&LsapNtAuthority,
|
||
1,
|
||
SubAuthorities,
|
||
SidName.Buffer,
|
||
NtAuthorityName.Buffer,
|
||
SidTypeWellKnownGroup
|
||
)) {
|
||
|
||
goto InitializeWellKnownSidsError;
|
||
}
|
||
|
||
Status = LsapGetMessageStrings(
|
||
StringsResource,
|
||
LSAP_SID_NAME_BATCH,
|
||
&SidName,
|
||
0,
|
||
NULL
|
||
); ASSERT(NT_SUCCESS(Status));
|
||
|
||
SubAuthorities[0] = SECURITY_BATCH_RID;
|
||
|
||
if (!LsaIInitializeWellKnownSid(
|
||
OutputWellKnownSids,
|
||
LsapBatchSidIndex,
|
||
&LsapNtAuthority,
|
||
1,
|
||
SubAuthorities,
|
||
SidName.Buffer,
|
||
NtAuthorityName.Buffer,
|
||
SidTypeWellKnownGroup
|
||
)) {
|
||
|
||
goto InitializeWellKnownSidsError;
|
||
}
|
||
|
||
Status = LsapGetMessageStrings(
|
||
StringsResource,
|
||
LSAP_SID_NAME_INTERACTIVE,
|
||
&SidName,
|
||
0,
|
||
NULL
|
||
); ASSERT(NT_SUCCESS(Status));
|
||
|
||
SubAuthorities[0] = SECURITY_INTERACTIVE_RID;
|
||
|
||
if (!LsaIInitializeWellKnownSid(
|
||
OutputWellKnownSids,
|
||
LsapInteractiveSidIndex,
|
||
&LsapNtAuthority,
|
||
1,
|
||
SubAuthorities,
|
||
SidName.Buffer,
|
||
NtAuthorityName.Buffer,
|
||
SidTypeWellKnownGroup
|
||
)) {
|
||
|
||
goto InitializeWellKnownSidsError;
|
||
}
|
||
|
||
Status = LsapGetMessageStrings(
|
||
StringsResource,
|
||
LSAP_SID_NAME_REMOTE_INTERACTIVE,
|
||
&SidName,
|
||
0,
|
||
NULL); ASSERT(NT_SUCCESS(Status));
|
||
|
||
SubAuthorities[0] = SECURITY_REMOTE_LOGON_RID;
|
||
|
||
if (!LsaIInitializeWellKnownSid(
|
||
OutputWellKnownSids,
|
||
LsapRemoteInteractiveSidIndex,
|
||
&LsapNtAuthority,
|
||
1,
|
||
SubAuthorities,
|
||
SidName.Buffer,
|
||
NtAuthorityName.Buffer,
|
||
SidTypeWellKnownGroup
|
||
)) {
|
||
|
||
goto InitializeWellKnownSidsError;
|
||
}
|
||
|
||
Status = LsapGetMessageStrings(
|
||
StringsResource,
|
||
LSAP_SID_NAME_TERMINAL_SERVER,
|
||
&SidName,
|
||
0,
|
||
NULL
|
||
); ASSERT(NT_SUCCESS(Status));
|
||
|
||
SubAuthorities[0] = SECURITY_TERMINAL_SERVER_RID;
|
||
|
||
if (!LsaIInitializeWellKnownSid(
|
||
OutputWellKnownSids,
|
||
LsapTerminalServerSidIndex,
|
||
&LsapNtAuthority,
|
||
1,
|
||
SubAuthorities,
|
||
SidName.Buffer,
|
||
NtAuthorityName.Buffer,
|
||
SidTypeWellKnownGroup
|
||
)) {
|
||
|
||
goto InitializeWellKnownSidsError;
|
||
}
|
||
|
||
Status = LsapGetMessageStrings(
|
||
StringsResource,
|
||
LSAP_SID_NAME_SERVICE,
|
||
&SidName,
|
||
0,
|
||
NULL
|
||
); ASSERT(NT_SUCCESS(Status));
|
||
SubAuthorities[0] = SECURITY_SERVICE_RID;
|
||
|
||
if (!LsaIInitializeWellKnownSid(
|
||
OutputWellKnownSids,
|
||
LsapServiceSidIndex,
|
||
&LsapNtAuthority,
|
||
1,
|
||
SubAuthorities,
|
||
SidName.Buffer,
|
||
NtAuthorityName.Buffer,
|
||
SidTypeWellKnownGroup
|
||
)) {
|
||
|
||
goto InitializeWellKnownSidsError;
|
||
}
|
||
|
||
|
||
Status = LsapGetMessageStrings(
|
||
StringsResource,
|
||
LSAP_SID_NAME_ANONYMOUS,
|
||
&SidName,
|
||
0,
|
||
NULL
|
||
); ASSERT(NT_SUCCESS(Status));
|
||
|
||
SubAuthorities[0] = SECURITY_ANONYMOUS_LOGON_RID;
|
||
|
||
if (!LsaIInitializeWellKnownSid(
|
||
OutputWellKnownSids,
|
||
LsapAnonymousSidIndex,
|
||
&LsapNtAuthority,
|
||
1,
|
||
SubAuthorities,
|
||
SidName.Buffer,
|
||
NtAuthorityName.Buffer,
|
||
SidTypeWellKnownGroup
|
||
)) {
|
||
|
||
goto InitializeWellKnownSidsError;
|
||
}
|
||
|
||
|
||
Status = LsapGetMessageStrings(
|
||
StringsResource,
|
||
LSAP_SID_NAME_PROXY,
|
||
&SidName,
|
||
0,
|
||
NULL
|
||
); ASSERT(NT_SUCCESS(Status));
|
||
|
||
SubAuthorities[0] = SECURITY_PROXY_RID;
|
||
|
||
if (!LsaIInitializeWellKnownSid(
|
||
OutputWellKnownSids,
|
||
LsapProxySidIndex,
|
||
&LsapNtAuthority,
|
||
1,
|
||
SubAuthorities,
|
||
SidName.Buffer,
|
||
NtAuthorityName.Buffer,
|
||
SidTypeWellKnownGroup
|
||
)) {
|
||
|
||
goto InitializeWellKnownSidsError;
|
||
}
|
||
|
||
|
||
|
||
Status = LsapGetMessageStrings(
|
||
StringsResource,
|
||
LSAP_SID_NAME_SERVER,
|
||
&SidName,
|
||
0,
|
||
NULL
|
||
); ASSERT(NT_SUCCESS(Status));
|
||
|
||
SubAuthorities[0] = SECURITY_SERVER_LOGON_RID;
|
||
|
||
if (!LsaIInitializeWellKnownSid(
|
||
OutputWellKnownSids,
|
||
LsapServerSidIndex,
|
||
&LsapNtAuthority,
|
||
1,
|
||
SubAuthorities,
|
||
SidName.Buffer,
|
||
NtAuthorityName.Buffer,
|
||
SidTypeWellKnownGroup
|
||
)) {
|
||
|
||
goto InitializeWellKnownSidsError;
|
||
}
|
||
|
||
Status = LsapGetMessageStrings(
|
||
StringsResource,
|
||
LSAP_SID_NAME_SELF,
|
||
&SidName,
|
||
0,
|
||
NULL
|
||
); ASSERT(NT_SUCCESS(Status));
|
||
|
||
SubAuthorities[0] = SECURITY_PRINCIPAL_SELF_RID;
|
||
|
||
if (!LsaIInitializeWellKnownSid(
|
||
OutputWellKnownSids,
|
||
LsapSelfSidIndex,
|
||
&LsapNtAuthority,
|
||
1,
|
||
SubAuthorities,
|
||
SidName.Buffer,
|
||
NtAuthorityName.Buffer,
|
||
SidTypeWellKnownGroup
|
||
)) {
|
||
|
||
goto InitializeWellKnownSidsError;
|
||
}
|
||
|
||
Status = LsapGetMessageStrings(
|
||
StringsResource,
|
||
LSAP_SID_NAME_AUTHENTICATED_USER,
|
||
&SidName,
|
||
0,
|
||
NULL
|
||
); ASSERT(NT_SUCCESS(Status));
|
||
|
||
SubAuthorities[0] = SECURITY_AUTHENTICATED_USER_RID;
|
||
|
||
if (!LsaIInitializeWellKnownSid(
|
||
OutputWellKnownSids,
|
||
LsapAuthenticatedUserSidIndex,
|
||
&LsapNtAuthority,
|
||
1,
|
||
SubAuthorities,
|
||
SidName.Buffer,
|
||
NtAuthorityName.Buffer,
|
||
SidTypeWellKnownGroup
|
||
)) {
|
||
|
||
goto InitializeWellKnownSidsError;
|
||
}
|
||
|
||
//
|
||
// Add any Logon Id well known sids here.
|
||
//
|
||
|
||
SubAuthorities[0] = SECURITY_LOGON_IDS_RID;
|
||
SubAuthorities[1] = 0;
|
||
SubAuthorities[2] = 0;
|
||
|
||
if (!LsaIInitializeWellKnownSid(
|
||
OutputWellKnownSids,
|
||
LsapLogonSidIndex,
|
||
&LsapNtAuthority,
|
||
3,
|
||
SubAuthorities,
|
||
L"",
|
||
NtAuthorityName.Buffer,
|
||
SidTypeWellKnownGroup
|
||
)) {
|
||
|
||
goto InitializeWellKnownSidsError;
|
||
}
|
||
|
||
Status = LsapGetMessageStrings(
|
||
StringsResource,
|
||
LSAP_SID_NAME_SYSTEM,
|
||
&SidName,
|
||
0,
|
||
NULL
|
||
); ASSERT(NT_SUCCESS(Status));
|
||
|
||
SubAuthorities[0] = SECURITY_LOCAL_SYSTEM_RID;
|
||
|
||
if (!LsaIInitializeWellKnownSid(
|
||
OutputWellKnownSids,
|
||
LsapLocalSystemSidIndex,
|
||
&LsapNtAuthority,
|
||
1,
|
||
SubAuthorities,
|
||
SidName.Buffer,
|
||
NtAuthorityName.Buffer,
|
||
SidTypeWellKnownGroup
|
||
)) {
|
||
|
||
goto InitializeWellKnownSidsError;
|
||
}
|
||
|
||
Status = LsapGetMessageStrings(
|
||
StringsResource,
|
||
LSAP_SID_NAME_LOCALSERVICE,
|
||
&SidName,
|
||
0,
|
||
NULL
|
||
); ASSERT(NT_SUCCESS(Status));
|
||
|
||
SubAuthorities[0] = SECURITY_LOCAL_SERVICE_RID;
|
||
|
||
if (!LsaIInitializeWellKnownSid(
|
||
OutputWellKnownSids,
|
||
LsapLocalServiceSidIndex,
|
||
&LsapNtAuthority,
|
||
1,
|
||
SubAuthorities,
|
||
SidName.Buffer,
|
||
NtAuthorityName.Buffer,
|
||
SidTypeWellKnownGroup
|
||
)) {
|
||
|
||
goto InitializeWellKnownSidsError;
|
||
}
|
||
|
||
Status = LsapGetMessageStrings(
|
||
StringsResource,
|
||
LSAP_SID_NAME_NETWORKSERVICE,
|
||
&SidName,
|
||
0,
|
||
NULL
|
||
); ASSERT(NT_SUCCESS(Status));
|
||
|
||
SubAuthorities[0] = SECURITY_NETWORK_SERVICE_RID;
|
||
|
||
if (!LsaIInitializeWellKnownSid(
|
||
OutputWellKnownSids,
|
||
LsapNetworkServiceSidIndex,
|
||
&LsapNtAuthority,
|
||
1,
|
||
SubAuthorities,
|
||
SidName.Buffer,
|
||
NtAuthorityName.Buffer,
|
||
SidTypeWellKnownGroup
|
||
)) {
|
||
|
||
goto InitializeWellKnownSidsError;
|
||
}
|
||
|
||
Status = LsapGetMessageStrings(
|
||
StringsResource,
|
||
LSAP_SID_NAME_RESTRICTED,
|
||
&SidName,
|
||
0,
|
||
NULL
|
||
); ASSERT(NT_SUCCESS(Status));
|
||
|
||
SubAuthorities[0] = SECURITY_RESTRICTED_CODE_RID;
|
||
|
||
if (!LsaIInitializeWellKnownSid(
|
||
OutputWellKnownSids,
|
||
LsapRestrictedSidIndex,
|
||
&LsapNtAuthority,
|
||
1,
|
||
SubAuthorities,
|
||
SidName.Buffer,
|
||
NtAuthorityName.Buffer,
|
||
SidTypeWellKnownGroup
|
||
)) {
|
||
|
||
goto InitializeWellKnownSidsError;
|
||
}
|
||
|
||
Status = LsapGetMessageStrings(
|
||
StringsResource,
|
||
LSAP_SID_NAME_INTERNET,
|
||
&SidName,
|
||
0,
|
||
NULL
|
||
); ASSERT(NT_SUCCESS(Status));
|
||
|
||
if (!LsaIInitializeWellKnownSid(
|
||
OutputWellKnownSids,
|
||
LsapInternetDomainIndex,
|
||
&InternetSiteAuthority,
|
||
0,
|
||
SubAuthorities,
|
||
L"",
|
||
SidName.Buffer,
|
||
SidTypeDomain
|
||
)) {
|
||
|
||
goto InitializeWellKnownSidsError;
|
||
}
|
||
|
||
|
||
//
|
||
// Initialize SIDs from the BUILTIN domain. Leave the Name
|
||
// field blank for the aliases as they can be renamed while
|
||
// the system is running (and the lookup code will fall
|
||
// through to SAM for these).
|
||
//
|
||
|
||
Status = LsapGetMessageStrings(
|
||
StringsResource,
|
||
LSAP_SID_NAME_BUILTIN,
|
||
&SidName,
|
||
0,
|
||
NULL
|
||
); ASSERT(NT_SUCCESS(Status));
|
||
|
||
SubAuthorities[0] = SECURITY_BUILTIN_DOMAIN_RID;
|
||
|
||
if (!LsaIInitializeWellKnownSid(
|
||
OutputWellKnownSids,
|
||
LsapBuiltInDomainSidIndex,
|
||
&LsapNtAuthority,
|
||
1,
|
||
SubAuthorities,
|
||
L"",
|
||
SidName.Buffer,
|
||
SidTypeDomain
|
||
)) {
|
||
|
||
goto InitializeWellKnownSidsError;
|
||
}
|
||
|
||
SubAuthorities[1] = DOMAIN_ALIAS_RID_USERS;
|
||
|
||
if (!LsaIInitializeWellKnownSid(
|
||
OutputWellKnownSids,
|
||
LsapAliasUsersSidIndex,
|
||
&LsapNtAuthority,
|
||
2,
|
||
SubAuthorities,
|
||
L"",
|
||
SidName.Buffer,
|
||
SidTypeAlias
|
||
)) {
|
||
|
||
goto InitializeWellKnownSidsError;
|
||
}
|
||
|
||
SubAuthorities[1] = DOMAIN_ALIAS_RID_ADMINS;
|
||
|
||
if (!LsaIInitializeWellKnownSid(
|
||
OutputWellKnownSids,
|
||
LsapAliasAdminsSidIndex,
|
||
&LsapNtAuthority,
|
||
2,
|
||
SubAuthorities,
|
||
L"",
|
||
SidName.Buffer,
|
||
SidTypeAlias
|
||
)) {
|
||
|
||
goto InitializeWellKnownSidsError;
|
||
}
|
||
|
||
Status = LsapGetMessageStrings(
|
||
StringsResource,
|
||
LSAP_SID_NAME_USERS,
|
||
&SidName,
|
||
0,
|
||
NULL
|
||
); ASSERT(NT_SUCCESS(Status));
|
||
|
||
|
||
//
|
||
// Check if all Sids initialized.
|
||
//
|
||
|
||
#ifdef LSAP_DEBUG_MESSAGE_STRINGS
|
||
DbgPrint("\nLSA (dbinit): Displaying all well known sids...\n\n");
|
||
#endif //LSAP_DEBUG_MESSAGE_STRINGS
|
||
|
||
for (WellKnownSidIndex = LsapNullSidIndex;
|
||
WellKnownSidIndex < LsapDummyLastSidIndex;
|
||
WellKnownSidIndex++) {
|
||
|
||
#ifdef LSAP_DEBUG_MESSAGE_STRINGS
|
||
DbgPrint(" *%wZ* : *%wZ*\n",
|
||
&OutputWellKnownSids[WellKnownSidIndex].DomainName,
|
||
&OutputWellKnownSids[WellKnownSidIndex].Name);
|
||
#endif //LSAP_DEBUG_MESSAGE_STRINGS
|
||
|
||
if (OutputWellKnownSids[WellKnownSidIndex].Sid == NULL) {
|
||
|
||
#if DBG
|
||
DbgPrint(
|
||
"Well Known Sid Index %d not initialized\n",
|
||
WellKnownSidIndex
|
||
);
|
||
#endif //DBG
|
||
|
||
}
|
||
}
|
||
|
||
*WellKnownSids = OutputWellKnownSids;
|
||
|
||
return(TRUE);
|
||
|
||
InitializeWellKnownSidsError:
|
||
|
||
return(FALSE);
|
||
}
|
||
|
||
|
||
BOOLEAN
|
||
LsaIInitializeWellKnownSid(
|
||
OUT PLSAP_WELL_KNOWN_SID_ENTRY WellKnownSids,
|
||
IN LSAP_WELL_KNOWN_SID_INDEX WellKnownSidIndex,
|
||
IN PSID_IDENTIFIER_AUTHORITY IdentifierAuthority,
|
||
IN UCHAR SubAuthorityCount,
|
||
IN PULONG SubAuthorities,
|
||
IN PWSTR Name,
|
||
IN PWSTR DomainName,
|
||
IN SID_NAME_USE Use
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function initializes an entry in the specified well-known Sid table.
|
||
The entry contains the well known Sid and its name.
|
||
|
||
Arguments:
|
||
|
||
WellKnownSids - Pointer to the first entry in the Well Known Sid table.
|
||
|
||
WellKnownSidIndex - Index into table of Well Known Sids.
|
||
|
||
Sid - Receives a pointer to a Sid with the correct size for the
|
||
number of subauthorities specified.
|
||
|
||
IdentifierAuthority - Pointer to Identifier authority.
|
||
|
||
SubAuthorityCount - Count of SubAuthorities
|
||
|
||
SubAuthorities - Array of SubAuthorities.
|
||
|
||
Name - Pointer to Unicode Name buffer containing the Sid's Name
|
||
|
||
DomainName - Pointer to Unicode Name buffer containing the
|
||
Sids Domain Name (if any) or descriptive text, such as
|
||
"Well Known Group" for Sids of Well Known Groups
|
||
|
||
SidNameUse - Specifies code for Sid's Use. The following values
|
||
may be specified:
|
||
|
||
SidTypeUser
|
||
SidTypeGroup
|
||
SidTypeDomain
|
||
SidTypeAlias
|
||
SidTypeWellKnownGroup
|
||
SidTypeDeletedAccount
|
||
SidTypeInvalid
|
||
SidTypeUnknown
|
||
|
||
Return Value:
|
||
|
||
BOOLEAN - TRUE if Sid initialized, else FALSE.
|
||
|
||
--*/
|
||
|
||
{
|
||
PLSAP_WELL_KNOWN_SID_ENTRY
|
||
WellKnownSidEntry = &WellKnownSids[WellKnownSidIndex];
|
||
|
||
PSID OutputSid = NULL;
|
||
|
||
OutputSid = RtlAllocateHeap(
|
||
RtlProcessHeap(),
|
||
0,
|
||
RtlLengthRequiredSid(SubAuthorityCount)
|
||
);
|
||
|
||
if (OutputSid == NULL) {
|
||
|
||
goto InitializeWellKnownSidError;
|
||
}
|
||
|
||
RtlInitializeSid( OutputSid, IdentifierAuthority, SubAuthorityCount);
|
||
|
||
if (SubAuthorityCount != 0) {
|
||
|
||
RtlCopyMemory(
|
||
RtlSubAuthoritySid( OutputSid, 0 ),
|
||
SubAuthorities,
|
||
SubAuthorityCount * sizeof(ULONG)
|
||
);
|
||
}
|
||
|
||
WellKnownSidEntry->Sid = OutputSid;
|
||
|
||
//
|
||
// Fill in the Domain Name
|
||
//
|
||
|
||
RtlInitUnicodeString(
|
||
&WellKnownSidEntry->DomainName,
|
||
DomainName
|
||
);
|
||
|
||
//
|
||
// Fill in the Use and Name.
|
||
//
|
||
|
||
WellKnownSidEntry->Use = Use;
|
||
RtlInitUnicodeString(
|
||
&WellKnownSidEntry->Name,
|
||
Name
|
||
);
|
||
|
||
return(TRUE);
|
||
|
||
InitializeWellKnownSidError:
|
||
|
||
#if DBG
|
||
|
||
DbgPrint("LSA Initialization of Well Known Sids Failed\n");
|
||
DbgPrint("Insufficient memory resources\n");
|
||
|
||
#endif // DBG
|
||
|
||
return(FALSE);
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
LsapGetMessageStrings(
|
||
LPVOID Resource,
|
||
DWORD Index1,
|
||
PUNICODE_STRING String1,
|
||
DWORD Index2,
|
||
PUNICODE_STRING String2 OPTIONAL
|
||
)
|
||
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This gets 1 or 2 message strings values from a resource message table.
|
||
The string buffers are allocated and the strings initialized properly.
|
||
|
||
The strings will be NULL terminated.
|
||
|
||
The string buffers must be freed using LocalFree() when no longer needed.
|
||
|
||
Arguments:
|
||
|
||
Resource - points to the resource table.
|
||
|
||
Index1 - Index of first message to retrieve.
|
||
|
||
String1 - Points to a UNICODE_STRING structure to receive the first
|
||
message string. The string will be null terminated.
|
||
|
||
Index2 - Index of second message to retrieve.
|
||
|
||
String2 - Points to a UNICODE_STRING structure to receive the first
|
||
message string. If this parameter is NULL, then only one message
|
||
string is retrieved. The string will be null terminated.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
|
||
{
|
||
|
||
#ifdef LSAP_DEBUG_MESSAGE_STRINGS
|
||
DbgPrint("LSA (dbinit): String 1 -\n");
|
||
DbgPrint(" Index: 0x%lx\n", Index1);
|
||
#endif //LSAP_DEBUG_MESSAGE_STRINGS
|
||
|
||
|
||
String1->Buffer = NULL;
|
||
|
||
String1->MaximumLength = (USHORT) FormatMessage(FORMAT_MESSAGE_FROM_HMODULE |
|
||
FORMAT_MESSAGE_ALLOCATE_BUFFER,
|
||
Resource,
|
||
Index1,
|
||
0, // Use caller's language
|
||
(LPWSTR)&(String1->Buffer),
|
||
0,
|
||
NULL
|
||
);
|
||
|
||
if (String1->Buffer == NULL) {
|
||
return(STATUS_RESOURCE_DATA_NOT_FOUND);
|
||
} else {
|
||
|
||
//
|
||
// Note that we are retrieving a message from a message file.
|
||
// This message will have a cr/lf tacked on the end of it
|
||
// (0x0d 0x0a) that we don't want to be part of our returned
|
||
// strings. However, we do need to null terminate our string
|
||
// so we will convert the 0x0d into a null terminator.
|
||
//
|
||
// Also note that FormatMessage() returns a character count,
|
||
// not a byte count. So, we have to do some adjusting to make
|
||
// the string lengths correct.
|
||
//
|
||
|
||
ASSERT(String1->MaximumLength >= 2); // We always expect cr/lf on our strings
|
||
|
||
//
|
||
// Adjust character count
|
||
//
|
||
|
||
String1->MaximumLength -= 1; // For the lf - we'll convert the cr.
|
||
|
||
//
|
||
// Set null terminator
|
||
//
|
||
|
||
String1->Buffer[String1->MaximumLength - 1] = 0;
|
||
|
||
//
|
||
// Change lengths to byte count instead of character count
|
||
//
|
||
|
||
String1->MaximumLength *= sizeof(WCHAR); // to make it a byte count
|
||
String1->Length = String1->MaximumLength - sizeof(WCHAR);
|
||
|
||
#ifdef LSAP_DEBUG_MESSAGE_STRINGS
|
||
DbgPrint(" String: %wZ\n", String1);
|
||
DbgPrint(" Max: (0x%lx)\n", String1->MaximumLength);
|
||
DbgPrint(" Cur: (0x%lx)\n", String1->Length);
|
||
DbgPrint(" ");
|
||
{
|
||
ULONG i;
|
||
for (i=0; i<String1->MaximumLength; i++) {
|
||
DbgPrint("%2x ", (*((PUCHAR)String1->Buffer)+i));
|
||
}
|
||
DbgPrint("\n");
|
||
}
|
||
#endif //LSAP_DEBUG_MESSAGE_STRINGS
|
||
}
|
||
|
||
|
||
if (!ARGUMENT_PRESENT(String2)) {
|
||
return(STATUS_SUCCESS);
|
||
}
|
||
|
||
String2->Buffer = NULL;
|
||
String2->MaximumLength = (USHORT) FormatMessage(FORMAT_MESSAGE_FROM_HMODULE |
|
||
FORMAT_MESSAGE_ALLOCATE_BUFFER,
|
||
Resource,
|
||
Index2,
|
||
0, // Use caller's language
|
||
(LPWSTR)&(String2->Buffer),
|
||
0,
|
||
NULL
|
||
);
|
||
|
||
if (String2->Buffer == NULL) {
|
||
LocalFree( String1->Buffer );
|
||
return(STATUS_RESOURCE_DATA_NOT_FOUND);
|
||
} else {
|
||
|
||
//
|
||
// Note that we are retrieving a message from a message file.
|
||
// This message will have a cr/lf tacked on the end of it
|
||
// (0x0d 0x0a) that we don't want to be part of our returned
|
||
// strings. However, we do need to null terminate our string
|
||
// so we will convert the 0x0d into a null terminator.
|
||
//
|
||
// Also note that FormatMessage() returns a character count,
|
||
// not a byte count. So, we have to do some adjusting to make
|
||
// the string lengths correct.
|
||
//
|
||
|
||
ASSERT(String2->MaximumLength >= 2); // We always expect cr/lf on our strings
|
||
|
||
//
|
||
// Adjust character count
|
||
//
|
||
|
||
String2->MaximumLength -= 1; // For the lf - we'll convert the cr.
|
||
|
||
//
|
||
// Set null terminator
|
||
//
|
||
|
||
String2->Buffer[String2->MaximumLength - 1] = 0;
|
||
|
||
//
|
||
// Change lengths to byte count instead of character count
|
||
//
|
||
|
||
String2->MaximumLength *= sizeof(WCHAR); // to make it a byte count
|
||
String2->Length = String2->MaximumLength - sizeof(WCHAR);
|
||
|
||
#ifdef LSAP_DEBUG_MESSAGE_STRINGS
|
||
DbgPrint(" String: %wZ\n", String2);
|
||
DbgPrint(" Max: (0x%lx)\n", String2->MaximumLength);
|
||
DbgPrint(" Cur: (0x%lx)\n", String2->Length);
|
||
DbgPrint(" ");
|
||
{
|
||
ULONG i;
|
||
for (i=0; i<String2->MaximumLength; i++) {
|
||
DbgPrint("%2x ", (*((PUCHAR)String2->Buffer)+i));
|
||
}
|
||
DbgPrint("\n");
|
||
}
|
||
#endif //LSAP_DEBUG_MESSAGE_STRINGS
|
||
}
|
||
|
||
|
||
|
||
return(STATUS_SUCCESS);
|
||
|
||
}
|
||
|
||
|
||
#if defined(REMOTE_BOOT)
|
||
VOID
|
||
LsapDbInitializeRemoteBootState(
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function initializes the remote boot state used by LSA.
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS - Standard Nt Result Code
|
||
|
||
All Result Codes are generated by called routines.
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS Status ;
|
||
HANDLE RdrDevice ;
|
||
UNICODE_STRING String ;
|
||
OBJECT_ATTRIBUTES ObjA ;
|
||
IO_STATUS_BLOCK IoStatus ;
|
||
|
||
//
|
||
// This is the default if anything goes wrong.
|
||
//
|
||
|
||
LsapDbState.RemoteBootState = LSAP_DB_REMOTE_BOOT_NO_NOTIFICATION;
|
||
|
||
//
|
||
// Open the redirector device.
|
||
//
|
||
|
||
RtlInitUnicodeString( &String, DD_NFS_DEVICE_NAME_U );
|
||
|
||
InitializeObjectAttributes( &ObjA,
|
||
&String,
|
||
0,
|
||
0,
|
||
0);
|
||
|
||
Status = NtOpenFile( &RdrDevice,
|
||
GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE,
|
||
&ObjA,
|
||
&IoStatus,
|
||
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||
0 );
|
||
|
||
if ( !NT_SUCCESS( Status ) )
|
||
{
|
||
DebugLog(( DEB_TRACE, "FAILED to open %ws, status %x\n",
|
||
String.Buffer, Status ));
|
||
return;
|
||
}
|
||
|
||
Status = NtFsControlFile(
|
||
RdrDevice,
|
||
NULL,
|
||
NULL,
|
||
NULL,
|
||
&IoStatus,
|
||
FSCTL_LMMR_RI_IS_PASSWORD_SETTABLE,
|
||
NULL,
|
||
0,
|
||
NULL,
|
||
0 );
|
||
|
||
if ( Status == STATUS_SUCCESS )
|
||
{
|
||
LsapDbState.RemoteBootState = LSAP_DB_REMOTE_BOOT_NOTIFY;
|
||
}
|
||
else if ( Status == STATUS_UNSUCCESSFUL )
|
||
{
|
||
LsapDbState.RemoteBootState = LSAP_DB_REMOTE_BOOT_CANT_NOTIFY;
|
||
}
|
||
|
||
NtClose(RdrDevice);
|
||
|
||
}
|
||
#endif // defined(REMOTE_BOOT)
|
||
|
||
|
||
|
||
|
||
NTSTATUS
|
||
LsapGenerateRandomDomainSid(
|
||
OUT PSID NewDomainSid
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function will generate a random sid to be used for the new account domain sid during
|
||
setup.
|
||
|
||
Arguments:
|
||
|
||
NewDomainSid - Where the new domain sid is returned. Freed via RtlFreeSid()
|
||
|
||
|
||
Return Values:
|
||
|
||
STATUS_SUCCESS -- Success.
|
||
STATUS_INSUFFICIENT_RESOURCES -- A memory allocation failed
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS Status;
|
||
LARGE_INTEGER Time;
|
||
KERNEL_USER_TIMES KernelUserTimes;
|
||
ULONG Seed, SubAuth1, SubAuth2, SubAuth3;
|
||
SID_IDENTIFIER_AUTHORITY IdentifierAuthority = SECURITY_NT_AUTHORITY;
|
||
|
||
//
|
||
// Generate 3 pseudo-random numbers using current tick count, the
|
||
// system time, and the user-mode execution time of this process as
|
||
// random number generator seeds.
|
||
//
|
||
Status = NtQuerySystemTime(&Time);
|
||
|
||
if ( NT_SUCCESS( Status ) ) {
|
||
|
||
Status = NtQueryInformationThread( NtCurrentThread(),
|
||
ThreadTimes,
|
||
&KernelUserTimes,
|
||
sizeof(KernelUserTimes),
|
||
NULL );
|
||
if ( NT_SUCCESS( Status ) ) {
|
||
|
||
Seed = GetTickCount() | GetCurrentTime();
|
||
SubAuth1 = RtlRandom( &Seed );
|
||
|
||
Seed = Time.LowPart;
|
||
SubAuth2 = RtlRandom( &Seed );
|
||
|
||
Seed = KernelUserTimes.UserTime.LowPart;
|
||
SubAuth3 = RtlRandom( &Seed );
|
||
|
||
Status = RtlAllocateAndInitializeSid( &IdentifierAuthority,
|
||
4,
|
||
0x15,
|
||
SubAuth1,
|
||
SubAuth2,
|
||
SubAuth3,
|
||
0,
|
||
0,
|
||
0,
|
||
0,
|
||
NewDomainSid );
|
||
}
|
||
}
|
||
|
||
|
||
return( Status );
|
||
}
|
||
|
||
|
||
|
||
NTSTATUS
|
||
LsapSetupInitialize(
|
||
VOID
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function will generate a random sid to be used for the new account domain sid during
|
||
setup.
|
||
|
||
Arguments:
|
||
|
||
NewDomainSid - Where the new domain sid is returned. Freed via RtlFreeSid()
|
||
|
||
|
||
Return Values:
|
||
|
||
STATUS_SUCCESS -- Success.
|
||
STATUS_INSUFFICIENT_RESOURCES -- A memory allocation failed
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS Status = STATUS_SUCCESS;
|
||
PSID NewDomainSid = NULL;
|
||
HMODULE StringsResource;
|
||
LSAPR_POLICY_ACCOUNT_DOM_INFO AccountDomainInfo;
|
||
|
||
Status = LsapGenerateRandomDomainSid( &NewDomainSid );
|
||
|
||
|
||
if ( NT_SUCCESS( Status ) ) {
|
||
|
||
//
|
||
// We can use GetModuleHandle, since we are getting it on ourselves.
|
||
//
|
||
StringsResource = (HMODULE) GetModuleHandle( L"LSASRV.DLL" );
|
||
|
||
ASSERT( StringsResource );
|
||
|
||
Status = LsapGetMessageStrings( StringsResource,
|
||
LSAP_DEFAULT_DOMAIN_NAME,
|
||
( PUNICODE_STRING )&AccountDomainInfo.DomainName,
|
||
0,
|
||
NULL );
|
||
}
|
||
|
||
//
|
||
// Ok, if we got this far, then we can initialize the account domain
|
||
//
|
||
if ( NT_SUCCESS( Status ) ) {
|
||
|
||
AccountDomainInfo.DomainSid = NewDomainSid;
|
||
Status = LsarSetInformationPolicy( LsapPolicyHandle,
|
||
PolicyAccountDomainInformation,
|
||
( PLSAPR_POLICY_INFORMATION )&AccountDomainInfo );
|
||
|
||
LocalFree( AccountDomainInfo.DomainName.Buffer );
|
||
}
|
||
|
||
|
||
if ( NewDomainSid ) {
|
||
|
||
RtlFreeSid( NewDomainSid );
|
||
}
|
||
|
||
|
||
return( Status );
|
||
}
|
||
|
||
static GUID LsapDbPasswordAuthenticator = {0xf0ce3a80,0x155f,0x11d3,0xb7,0xe6,0x00,0x80,0x5f,0x48,0xca,0xeb};
|
||
|
||
NTSTATUS
|
||
LsapDbGenerateNewKey(
|
||
IN LSAP_DB_ENCRYPTION_KEY * NewEncryptionKey
|
||
)
|
||
/*++
|
||
|
||
Routine Description
|
||
|
||
This routine generates a new Encryption key that can be used for
|
||
encrypting secrets.
|
||
|
||
Parameters
|
||
|
||
NewEncryptionKey -- Pointer to a structure that contains the new key
|
||
|
||
Return Values
|
||
|
||
STATUS_SUCCESS
|
||
STATUS_UNSUCCESSFUL
|
||
--*/
|
||
{
|
||
NTSTATUS Status = STATUS_SUCCESS;
|
||
|
||
|
||
//
|
||
// generate a random number for the key
|
||
//
|
||
|
||
if (!RtlGenRandom(NewEncryptionKey->Key,sizeof(NewEncryptionKey->Key)))
|
||
{
|
||
return(STATUS_UNSUCCESSFUL);
|
||
}
|
||
|
||
//
|
||
// Copy in the GUID for the authenticator
|
||
//
|
||
|
||
NewEncryptionKey->Authenticator = LsapDbPasswordAuthenticator;
|
||
|
||
|
||
//
|
||
// Set the version #
|
||
//
|
||
|
||
NewEncryptionKey->Revision = LSAP_DB_ENCRYPTION_KEY_VERSION ;
|
||
NewEncryptionKey->Flags = 0;
|
||
|
||
//
|
||
// Generate a Salt
|
||
//
|
||
|
||
if (!RtlGenRandom(NewEncryptionKey->Salt,sizeof(NewEncryptionKey->Salt)))
|
||
{
|
||
return(STATUS_UNSUCCESSFUL);
|
||
}
|
||
|
||
//
|
||
// Generate a random value for the old syskey
|
||
//
|
||
|
||
if (!RtlGenRandom(NewEncryptionKey->OldSyskey,sizeof(NewEncryptionKey->OldSyskey)))
|
||
{
|
||
return(STATUS_UNSUCCESSFUL);
|
||
}
|
||
|
||
|
||
//
|
||
// Set the boot type
|
||
//
|
||
|
||
NewEncryptionKey->BootType = WxStored;
|
||
|
||
|
||
return(STATUS_SUCCESS);
|
||
}
|
||
|
||
VOID
|
||
LsapDbEncryptKeyWithSyskey(
|
||
OUT LSAP_DB_ENCRYPTION_KEY * KeyToEncrypt,
|
||
IN PVOID Syskey,
|
||
IN ULONG SyskeyLength
|
||
)
|
||
/*++
|
||
|
||
This routine encrypts the KeyToEncrypt parameter with
|
||
the syskey passed in
|
||
|
||
Arguments
|
||
|
||
KeyToEncrypt -- the key to encrypt
|
||
Syskey -- The syskey passed in
|
||
SyskeyLength -- The length of the syskey
|
||
|
||
Return Values
|
||
|
||
None, void function
|
||
--*/
|
||
{
|
||
MD5_CTX Md5Context;
|
||
struct RC4_KEYSTRUCT Rc4Key;
|
||
ULONG i;
|
||
|
||
//
|
||
// Create an MD5 hash of the key and salt
|
||
//
|
||
|
||
MD5Init(&Md5Context);
|
||
|
||
MD5Update(
|
||
&Md5Context,
|
||
Syskey,
|
||
SyskeyLength
|
||
);
|
||
//
|
||
// Hash in the salt many many times. This slows down
|
||
// attackers employing a brute force approach to attack
|
||
//
|
||
|
||
for (i=0;i<1000;i++)
|
||
{
|
||
MD5Update(
|
||
&Md5Context,
|
||
KeyToEncrypt->Salt,
|
||
sizeof(KeyToEncrypt->Salt)
|
||
);
|
||
}
|
||
|
||
MD5Final(
|
||
&Md5Context
|
||
);
|
||
|
||
//
|
||
// Initialize the RC4 key sequence.
|
||
//
|
||
|
||
rc4_key(
|
||
&Rc4Key,
|
||
MD5DIGESTLEN,
|
||
Md5Context.digest
|
||
);
|
||
|
||
|
||
|
||
rc4(
|
||
&Rc4Key,
|
||
sizeof(KeyToEncrypt->Key)+ sizeof(KeyToEncrypt->Authenticator)+sizeof(KeyToEncrypt->OldSyskey),
|
||
(PUCHAR) &KeyToEncrypt->Authenticator
|
||
|
||
);
|
||
|
||
}
|
||
|
||
|
||
|
||
NTSTATUS
|
||
LsapDbDecryptKeyWithSyskey(
|
||
IN LSAP_DB_ENCRYPTION_KEY * KeyToDecrypt,
|
||
IN PVOID Syskey,
|
||
IN ULONG SyskeyLength
|
||
)
|
||
/*++
|
||
|
||
This function provides a decryption using the syskey. Since RC4 is symmetric
|
||
encryption algorithm, this function simply calls the previous encrypt routine
|
||
|
||
Arguments
|
||
|
||
KeyToDecrypt -- the key to dencrypt
|
||
Syskey -- The syskey passed in
|
||
SyskeyLength -- The length of the syskey
|
||
|
||
Return Values
|
||
|
||
STATUS_SUCCESS , on successful decryption
|
||
STATUS_WRONG_PASSWORD on unsuccessful decryption
|
||
|
||
--*/
|
||
{
|
||
|
||
LsapDbEncryptKeyWithSyskey(KeyToDecrypt,Syskey,SyskeyLength);
|
||
|
||
if (!RtlEqualMemory(&KeyToDecrypt->Authenticator,&LsapDbPasswordAuthenticator,sizeof(GUID)))
|
||
{
|
||
return(STATUS_WRONG_PASSWORD);
|
||
}
|
||
|
||
return(STATUS_SUCCESS);
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
LsapDbSetupInitialSyskey(
|
||
OUT PULONG SyskeyLength,
|
||
OUT PVOID *Syskey
|
||
)
|
||
/*++
|
||
|
||
This generates a new syskey and changes the winlogon state such that
|
||
winlogon recognizes the new syskey and the boot option of system saves
|
||
syskey.
|
||
|
||
Arguments
|
||
|
||
SyskeyLength -- The length of the syskey is returned in here
|
||
Syskey -- The syskey itself is returned in here
|
||
|
||
Return Values
|
||
|
||
STATUS_SUCCESS
|
||
Other resource error codes
|
||
--*/
|
||
{
|
||
|
||
NTSTATUS NtStatus = STATUS_SUCCESS;
|
||
|
||
|
||
*Syskey = LsapAllocateLsaHeap(LSAP_SYSKEY_SIZE );
|
||
if (NULL==*Syskey)
|
||
{
|
||
NtStatus = STATUS_INSUFFICIENT_RESOURCES;
|
||
goto Error;
|
||
}
|
||
|
||
*SyskeyLength = LSAP_SYSKEY_SIZE;
|
||
|
||
//
|
||
// Generate the syskey
|
||
//
|
||
|
||
if (!RtlGenRandom( *Syskey, *SyskeyLength))
|
||
{
|
||
NtStatus = STATUS_UNSUCCESSFUL;
|
||
goto Error;
|
||
}
|
||
|
||
|
||
//
|
||
// Save the syskey in the registry
|
||
// If this operation fails, then no state is changed, machine remains
|
||
// un syskey-d till next boot
|
||
//
|
||
|
||
NtStatus = WxSaveSysKey(*SyskeyLength, *Syskey);
|
||
|
||
|
||
if (!NT_SUCCESS(NtStatus))
|
||
goto Error;
|
||
|
||
//
|
||
// Set the boot option in the registry
|
||
// If this operation fails, still no problem. Machine remains unsyskey'd
|
||
// and the boot key that has been saved will be reset on next boot.
|
||
//
|
||
|
||
NtStatus = WxSaveBootOption(WxStored);
|
||
if (!NT_SUCCESS(NtStatus))
|
||
goto Error;
|
||
|
||
|
||
Error:
|
||
|
||
if (!NT_SUCCESS(NtStatus))
|
||
{
|
||
*SyskeyLength = 0;
|
||
if (NULL!=*Syskey)
|
||
{
|
||
MIDL_user_free(*Syskey);
|
||
}
|
||
}
|
||
|
||
return(NtStatus);
|
||
|
||
}
|
||
|
||
|
||
|
||
|
||
NTSTATUS
|
||
LsapDbGetSyskeyFromWinlogon()
|
||
/*++
|
||
|
||
Routine Description
|
||
|
||
This routine obtains the syskey from winlogon and decrypts the
|
||
Password encryption key in the LSA policy database. The global variable
|
||
LsapDbSecretCipherKey is set with the password encryption key and the
|
||
the global variable LsapDbSyskey is set with the syskey. This value is
|
||
then queried by SAM/DS to decrypt their respective password encryption keys
|
||
and then cleared before the end of SamIInitialize.
|
||
|
||
The special case handled inside this routine is of the case of a fresh install.
|
||
In this particular case winlogon is not yet setup to expect a query of syskey
|
||
from the lsass process. However since the LSA install code has been called just
|
||
moments, before, that code sets the winlogon state and also fills the global
|
||
LsapDbSyskey. Therefore if LsapDbSyskey is not NULL then this would be the
|
||
fresh install case.
|
||
|
||
Arguments
|
||
|
||
None
|
||
|
||
Return Values
|
||
|
||
STATUS_SUCCESS
|
||
STATUS_UNSUCCESSFUL
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS Status = STATUS_SUCCESS;
|
||
NTSTATUS DecryptStatus = STATUS_SUCCESS;
|
||
ULONG DecryptionKeyLength = 0;
|
||
HANDLE WinlogonHandle=NULL;
|
||
ULONG Tries = 0;
|
||
LSAP_DB_ENCRYPTION_KEY StoredEncryptionKeyData;
|
||
ULONG StoredEncryptionKeyDataLength = sizeof( LSAP_DB_ENCRYPTION_KEY );
|
||
ULONG SyskeyLen=LSAP_SYSKEY_SIZE;
|
||
BOOLEAN FreshInstall=FALSE;
|
||
|
||
|
||
//
|
||
// Read the attribute information in the LSA policy database
|
||
//
|
||
|
||
Status = LsapDbReadAttributeObject(
|
||
LsapDbHandle,
|
||
&LsapDbNames[PolSecretEncryptionKey],
|
||
(PVOID) &StoredEncryptionKeyData,
|
||
&StoredEncryptionKeyDataLength
|
||
);
|
||
|
||
if ( !NT_SUCCESS(Status) ) {
|
||
goto Cleanup;
|
||
}
|
||
|
||
if (NULL!=LsapDbSysKey)
|
||
{
|
||
//
|
||
// In the fresh install case , code in dbinstal.c already
|
||
// sets LsapDbSyskey to the syskey value.
|
||
//
|
||
|
||
FreshInstall = TRUE;
|
||
Status = LsapDbDecryptKeyWithSyskey(
|
||
&StoredEncryptionKeyData ,
|
||
LsapDbSysKey,
|
||
LSAP_SYSKEY_SIZE
|
||
);
|
||
}
|
||
else
|
||
{
|
||
//
|
||
// because LsapDbDecryptKeyWithSyskey() is an in-place
|
||
// operation, so we'd better save the Encrypted Syskey first
|
||
//
|
||
|
||
LSAP_DB_ENCRYPTION_KEY TempStoredEncryptionKeyData;
|
||
|
||
TempStoredEncryptionKeyData = StoredEncryptionKeyData;
|
||
|
||
//
|
||
// Call Winlogon to obtain the key information.
|
||
//
|
||
|
||
Status = WxConnect(
|
||
&WinlogonHandle
|
||
);
|
||
|
||
if (!NT_SUCCESS(Status))
|
||
{
|
||
//
|
||
// Winlogon may fail if secret encryption is not enabled. In those
|
||
// cases continue. Else Fail the boot
|
||
//
|
||
if (WxNone==StoredEncryptionKeyData.BootType)
|
||
{
|
||
Status = STATUS_SUCCESS;
|
||
}
|
||
|
||
goto Cleanup;
|
||
}
|
||
|
||
|
||
for (Tries = 0; Tries < LSAP_BOOT_KEY_RETRY_COUNT ; Tries++ )
|
||
{
|
||
|
||
//
|
||
// restore the data which need to be decrypted.
|
||
//
|
||
|
||
StoredEncryptionKeyData = TempStoredEncryptionKeyData;
|
||
|
||
//
|
||
// Retry this RETRY_COUNT_TIMES, this allows the user a chance
|
||
// to correct himself, in case he entered a wrong boot password
|
||
//
|
||
|
||
if (WxNone!=StoredEncryptionKeyData.BootType)
|
||
{
|
||
//
|
||
// Get the key to be used to decrypt the PEK list
|
||
//
|
||
|
||
Status = WxGetKeyData(
|
||
WinlogonHandle,
|
||
StoredEncryptionKeyData.BootType,
|
||
LSAP_SYSKEY_SIZE,
|
||
SyskeyBuffer,
|
||
&SyskeyLen
|
||
);
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
goto Cleanup;
|
||
}
|
||
|
||
ASSERT(SyskeyLen==LSAP_SYSKEY_SIZE);
|
||
|
||
|
||
//
|
||
// Decrypt the Blob passed in with the key supplied by winlogon
|
||
//
|
||
|
||
Status = LsapDbDecryptKeyWithSyskey(
|
||
&StoredEncryptionKeyData ,
|
||
SyskeyBuffer,
|
||
LSAP_SYSKEY_SIZE
|
||
);
|
||
|
||
if (!NT_SUCCESS(Status))
|
||
{
|
||
DecryptStatus = STATUS_WRONG_PASSWORD;
|
||
}
|
||
else
|
||
{
|
||
//
|
||
// We successfully decrypted, break out of the loop
|
||
//
|
||
|
||
DecryptStatus = STATUS_SUCCESS;
|
||
break;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
break;
|
||
}
|
||
}
|
||
|
||
//
|
||
// Tell winlogon regarding success or failure of the scheme
|
||
//
|
||
|
||
Status = WxReportResults(
|
||
WinlogonHandle,
|
||
DecryptStatus
|
||
);
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
goto Cleanup;
|
||
}
|
||
|
||
Status = DecryptStatus;
|
||
}
|
||
|
||
if (NT_SUCCESS(Status))
|
||
{
|
||
//
|
||
// Initialize the new secret cipher key
|
||
// The keys used for reading and writing secrets are ordinarily the same
|
||
//
|
||
|
||
LsapDbInitializeSecretCipherKeyRead( &StoredEncryptionKeyData );
|
||
LsapDbInitializeSecretCipherKeyWrite( &StoredEncryptionKeyData );
|
||
|
||
if (!FreshInstall)
|
||
{
|
||
//
|
||
// Set the global variable LsapDBSysKey
|
||
//
|
||
LsapDbSysKey = SyskeyBuffer;
|
||
|
||
|
||
//
|
||
// Set up the old syskey for recovery cases
|
||
// by SAM and LSA
|
||
//
|
||
|
||
RtlCopyMemory(
|
||
OldSyskeyBuffer,
|
||
StoredEncryptionKeyData.OldSyskey,
|
||
sizeof(StoredEncryptionKeyData.OldSyskey)
|
||
);
|
||
|
||
LsapDbOldSysKey = OldSyskeyBuffer;
|
||
}
|
||
}
|
||
|
||
Cleanup:
|
||
|
||
if (WinlogonHandle != NULL) {
|
||
NtClose(WinlogonHandle);
|
||
}
|
||
|
||
return(Status);
|
||
}
|
||
|
||
|
||
VOID
|
||
LsapDbInitializeSecretCipherKeyRead(
|
||
PLSAP_DB_ENCRYPTION_KEY PassedInEncryptionKeyData
|
||
)
|
||
/*++
|
||
|
||
Routine Description
|
||
|
||
Given a pointer to the encryption key ( as in the struct ), this routine
|
||
initializes a CipherKey structure that can be used by the LSA's secret encryption
|
||
and decryption routines.
|
||
|
||
Arguments
|
||
|
||
PassedInEncryptionKeyData -- The struct representing the key
|
||
|
||
Return Values
|
||
|
||
Void function
|
||
--*/
|
||
{
|
||
static LSAP_DB_ENCRYPTION_KEY StaticEncryptionKeyData;
|
||
static LSAP_CR_CIPHER_KEY DecryptedSecretCipherKey;
|
||
|
||
RtlCopyMemory(&StaticEncryptionKeyData,PassedInEncryptionKeyData,sizeof(LSAP_DB_ENCRYPTION_KEY));
|
||
|
||
DecryptedSecretCipherKey.Buffer = StaticEncryptionKeyData.Key;
|
||
DecryptedSecretCipherKey.Length = DecryptedSecretCipherKey.MaximumLength
|
||
= sizeof(StaticEncryptionKeyData.Key);
|
||
LsapDbSecretCipherKeyRead = &DecryptedSecretCipherKey;
|
||
}
|
||
|
||
|
||
VOID
|
||
LsapDbInitializeSecretCipherKeyWrite(
|
||
PLSAP_DB_ENCRYPTION_KEY PassedInEncryptionKeyData
|
||
)
|
||
/*++
|
||
|
||
Routine Description
|
||
|
||
Given a pointer to the encryption key ( as in the struct ), this routine
|
||
initializes a CipherKey structure that can be used by the LSA's secret encryption
|
||
and decryption routines.
|
||
|
||
Arguments
|
||
|
||
PassedInEncryptionKeyData -- The struct representing the key
|
||
CipherKey -- The structure that needs to be initialzed with the
|
||
key for LSA's secret encryption
|
||
|
||
Return Values
|
||
|
||
Void function
|
||
--*/
|
||
{
|
||
static LSAP_DB_ENCRYPTION_KEY StaticEncryptionKeyData;
|
||
static LSAP_CR_CIPHER_KEY DecryptedSecretCipherKey;
|
||
|
||
RtlCopyMemory(&StaticEncryptionKeyData,PassedInEncryptionKeyData,sizeof(LSAP_DB_ENCRYPTION_KEY));
|
||
|
||
DecryptedSecretCipherKey.Buffer = StaticEncryptionKeyData.Key;
|
||
DecryptedSecretCipherKey.Length = DecryptedSecretCipherKey.MaximumLength
|
||
= sizeof(StaticEncryptionKeyData.Key);
|
||
LsapDbSecretCipherKeyWrite = &DecryptedSecretCipherKey;
|
||
}
|
||
|
||
|
||
VOID
|
||
LsapDbSetSyskey(
|
||
PVOID Syskey,
|
||
ULONG SyskeyLength
|
||
)
|
||
/*++
|
||
|
||
This function sets the syskey in the global syskey buffer
|
||
|
||
--*/
|
||
{
|
||
ASSERT(LSAP_SYSKEY_SIZE==SyskeyLength);
|
||
RtlCopyMemory(SyskeyBuffer,Syskey,SyskeyLength);
|
||
LsapDbSysKey = SyskeyBuffer;
|
||
}
|
||
|
||
NTSTATUS
|
||
LsaISetBootOption(
|
||
IN ULONG BootOption,
|
||
IN PVOID OldKey,
|
||
IN ULONG OldKeyLength,
|
||
IN PVOID NewKey,
|
||
IN ULONG NewKeyLength
|
||
)
|
||
/*++
|
||
|
||
This function is used to change the syskey value in the LSA, or change
|
||
the boot option type.
|
||
|
||
Arguments
|
||
|
||
BootOption -- New Boot Option
|
||
OldKey -- Old key, used to verify value
|
||
OldKeyLength -- Length of old key
|
||
NewKey -- New key, LSA's password encryption key is encrypted using
|
||
this value
|
||
NewKeyLength -- Length of new key
|
||
|
||
Return Values
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS Status = STATUS_SUCCESS;
|
||
ULONG StoredEncryptionKeyDataLength = sizeof( LSAP_DB_ENCRYPTION_KEY );
|
||
LSAP_DB_ENCRYPTION_KEY StoredEncryptionKeyData;
|
||
ULONG SyskeyLen=0;
|
||
LSAP_DB_ATTRIBUTE Attributes[20];
|
||
PLSAP_DB_ATTRIBUTE NextAttribute;
|
||
ULONG AttributeCount = 0;
|
||
|
||
NextAttribute = Attributes;
|
||
|
||
|
||
//
|
||
// Validate Some parameters
|
||
//
|
||
|
||
if ((NewKeyLength != LSAP_SYSKEY_SIZE ) || (OldKeyLength != LSAP_SYSKEY_SIZE))
|
||
{
|
||
return (STATUS_INVALID_PARAMETER);
|
||
}
|
||
|
||
if ((NULL==NewKey) || (NULL==OldKey))
|
||
{
|
||
return(STATUS_INVALID_PARAMETER);
|
||
}
|
||
//
|
||
// Read the attribute information in the LSA policy database
|
||
//
|
||
|
||
Status = LsapDbReadAttributeObject(
|
||
LsapDbHandle,
|
||
&LsapDbNames[PolSecretEncryptionKey],
|
||
(PVOID) &StoredEncryptionKeyData,
|
||
&StoredEncryptionKeyDataLength
|
||
);
|
||
|
||
if (!NT_SUCCESS(Status) ) {
|
||
|
||
goto Cleanup;
|
||
}
|
||
|
||
|
||
//
|
||
// Decrypt the data
|
||
//
|
||
|
||
Status = LsapDbDecryptKeyWithSyskey(
|
||
&StoredEncryptionKeyData,
|
||
OldKey,
|
||
OldKeyLength
|
||
);
|
||
|
||
if (!NT_SUCCESS(Status))
|
||
{
|
||
goto Cleanup;
|
||
}
|
||
|
||
|
||
//
|
||
// Change the boot option
|
||
//
|
||
|
||
StoredEncryptionKeyData.BootType = BootOption;
|
||
|
||
//
|
||
// Save the old key ( for recovery )
|
||
//
|
||
|
||
ASSERT(sizeof(StoredEncryptionKeyData.OldSyskey) == OldKeyLength);
|
||
|
||
RtlCopyMemory(
|
||
&StoredEncryptionKeyData.OldSyskey,
|
||
OldKey,
|
||
OldKeyLength
|
||
);
|
||
|
||
//
|
||
// Re-encrypt the data using the new key
|
||
//
|
||
|
||
LsapDbEncryptKeyWithSyskey(
|
||
&StoredEncryptionKeyData,
|
||
NewKey,
|
||
NewKeyLength
|
||
);
|
||
|
||
|
||
LsapDbInitializeAttribute(
|
||
NextAttribute,
|
||
&LsapDbNames[PolSecretEncryptionKey],
|
||
&StoredEncryptionKeyData,
|
||
sizeof (StoredEncryptionKeyData),
|
||
FALSE
|
||
);
|
||
|
||
NextAttribute++;
|
||
AttributeCount++;
|
||
|
||
//
|
||
// Now write out all attributes that have been added (if any)
|
||
//
|
||
|
||
if (AttributeCount > 0) {
|
||
|
||
Status = LsapDbReferenceObject(
|
||
LsapDbHandle,
|
||
0,
|
||
PolicyObject,
|
||
PolicyObject,
|
||
LSAP_DB_LOCK | LSAP_DB_START_TRANSACTION
|
||
);
|
||
|
||
if (NT_SUCCESS(Status)) {
|
||
|
||
ASSERT( AttributeCount < ( sizeof( Attributes ) / sizeof( LSAP_DB_ATTRIBUTE ) ) );
|
||
Status = LsapDbWriteAttributesObject(
|
||
LsapDbHandle,
|
||
Attributes,
|
||
AttributeCount
|
||
);
|
||
|
||
//
|
||
// No attributes are replicatable.
|
||
// (That's good, too, since SAM hasn't told Netlogon our role yet.)
|
||
|
||
Status = LsapDbDereferenceObject(
|
||
&LsapDbHandle,
|
||
PolicyObject,
|
||
PolicyObject,
|
||
(LSAP_DB_LOCK |
|
||
LSAP_DB_FINISH_TRANSACTION |
|
||
LSAP_DB_OMIT_REPLICATOR_NOTIFICATION ),
|
||
SecurityDbChange,
|
||
Status
|
||
);
|
||
}
|
||
}
|
||
|
||
Cleanup:
|
||
|
||
|
||
return(Status);
|
||
|
||
}
|
||
|
||
NTSTATUS
|
||
LsaIGetBootOption(
|
||
OUT PULONG BootOption
|
||
)
|
||
/*++
|
||
|
||
This function is used to obtain the boot option from LSA
|
||
|
||
Arguments
|
||
|
||
BootOption -- New Boot is passed in here
|
||
|
||
Return Values
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS Status = STATUS_SUCCESS;
|
||
ULONG StoredEncryptionKeyDataLength = sizeof( LSAP_DB_ENCRYPTION_KEY );
|
||
LSAP_DB_ENCRYPTION_KEY StoredEncryptionKeyData;
|
||
|
||
|
||
//
|
||
// Read the attribute information in the LSA policy database
|
||
//
|
||
|
||
Status = LsapDbReadAttributeObject(
|
||
LsapDbHandle,
|
||
&LsapDbNames[PolSecretEncryptionKey],
|
||
(PVOID) &StoredEncryptionKeyData,
|
||
&StoredEncryptionKeyDataLength
|
||
);
|
||
|
||
if (!NT_SUCCESS(Status) ) {
|
||
|
||
goto Cleanup;
|
||
}
|
||
|
||
*BootOption = StoredEncryptionKeyData.BootType;
|
||
|
||
Cleanup:
|
||
|
||
|
||
return(Status);
|
||
|
||
}
|