You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
5021 lines
138 KiB
5021 lines
138 KiB
/*++
|
|
|
|
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>
|
|
|
|
//
|
|
// Well known Sids for security packages include a subauthority equal to
|
|
// the associated package's RPC Id. We'll cause a compile time error if
|
|
// these numbers ever change.
|
|
//
|
|
|
|
#if (SECURITY_PACKAGE_NTLM_RID != RPC_C_AUTHN_WINNT)
|
|
#error SECURITY_PACKAGE_NTLM_RID definition must be equal to \
|
|
RPC_C_AUTHN_WINNT
|
|
#endif
|
|
|
|
#if (SECURITY_PACKAGE_DIGEST_RID != RPC_C_AUTHN_DIGEST)
|
|
#error SECURITY_PACKAGE_DIGEST_RID definition must equal RPC_C_AUTHN_DIGEST
|
|
#endif
|
|
|
|
#if (SECURITY_PACKAGE_SCHANNEL_RID != RPC_C_AUTHN_GSS_SCHANNEL)
|
|
#error SECURITY_PACKAGE_SCHANNEL_RID definition must equal \
|
|
RPC_C_AUTHN_GSS_SCHANNEL
|
|
#endif
|
|
|
|
|
|
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;
|
|
}
|
|
}
|
|
|
|
//
|
|
// 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
|
|
// This hard-coded key is used for retrieving old pre-NT4 SP4
|
|
// encrypted keys only
|
|
//
|
|
|
|
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;
|
|
|
|
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"PrDomain",
|
|
L"Policy",
|
|
L"Accounts",
|
|
L"Domains",
|
|
L"Secrets",
|
|
L"CurrVal",
|
|
L"OldVal",
|
|
L"CupdTime",
|
|
L"OupdTime",
|
|
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"PolMod",
|
|
L"PolState",
|
|
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"TrDmCrSid", // Creator Sid
|
|
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"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}, // PrDomain
|
|
{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}, // 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, LsapDsLocRegistry}, // PolMod
|
|
{0, LsapDbAttribUnknown, LsapDsLocRegistry}, // PolState
|
|
{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_MS_DS_CREATOR_SID, LsapDbAttribSid, LsapDsLocDs}, // TrDmCrSid
|
|
{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_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
|
|
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 = LsapDbInitializeWellKnownSids( &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.
|
|
--*/
|
|
|
|
{
|
|
LsapTcbPrivilege = RtlConvertLongToLuid(SE_TCB_PRIVILEGE);
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
LsapDbInitializeWellKnownSids(
|
|
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 (!LsapDbInitializeWellKnownSid(
|
|
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 (!LsapDbInitializeWellKnownSid(
|
|
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 (!LsapDbInitializeWellKnownSid(
|
|
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 (!LsapDbInitializeWellKnownSid(
|
|
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 (!LsapDbInitializeWellKnownSid(
|
|
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 (!LsapDbInitializeWellKnownSid(
|
|
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 (!LsapDbInitializeWellKnownSid(
|
|
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 (!LsapDbInitializeWellKnownSid(
|
|
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 (!LsapDbInitializeWellKnownSid(
|
|
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 (!LsapDbInitializeWellKnownSid(
|
|
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 (!LsapDbInitializeWellKnownSid(
|
|
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 (!LsapDbInitializeWellKnownSid(
|
|
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 (!LsapDbInitializeWellKnownSid(
|
|
OutputWellKnownSids,
|
|
LsapRemoteInteractiveSidIndex,
|
|
&LsapNtAuthority,
|
|
1,
|
|
SubAuthorities,
|
|
SidName.Buffer,
|
|
NtAuthorityName.Buffer,
|
|
SidTypeWellKnownGroup
|
|
)) {
|
|
|
|
goto InitializeWellKnownSidsError;
|
|
}
|
|
|
|
Status = LsapGetMessageStrings(
|
|
StringsResource,
|
|
LSAP_SID_NAME_THIS_ORGANIZATION,
|
|
&SidName,
|
|
0,
|
|
NULL); ASSERT(NT_SUCCESS(Status));
|
|
|
|
SubAuthorities[0] = SECURITY_THIS_ORGANIZATION_RID;
|
|
|
|
if (!LsapDbInitializeWellKnownSid(
|
|
OutputWellKnownSids,
|
|
LsapThisOrganizationSidIndex,
|
|
&LsapNtAuthority,
|
|
1,
|
|
SubAuthorities,
|
|
SidName.Buffer,
|
|
NtAuthorityName.Buffer,
|
|
SidTypeWellKnownGroup
|
|
)) {
|
|
|
|
goto InitializeWellKnownSidsError;
|
|
}
|
|
|
|
Status = LsapGetMessageStrings(
|
|
StringsResource,
|
|
LSAP_SID_NAME_OTHER_ORGANIZATION,
|
|
&SidName,
|
|
0,
|
|
NULL); ASSERT(NT_SUCCESS(Status));
|
|
|
|
SubAuthorities[0] = SECURITY_OTHER_ORGANIZATION_RID;
|
|
|
|
if (!LsapDbInitializeWellKnownSid(
|
|
OutputWellKnownSids,
|
|
LsapOtherOrganizationSidIndex,
|
|
&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 (!LsapDbInitializeWellKnownSid(
|
|
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 (!LsapDbInitializeWellKnownSid(
|
|
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 (!LsapDbInitializeWellKnownSid(
|
|
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 (!LsapDbInitializeWellKnownSid(
|
|
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 (!LsapDbInitializeWellKnownSid(
|
|
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 (!LsapDbInitializeWellKnownSid(
|
|
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 (!LsapDbInitializeWellKnownSid(
|
|
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 (!LsapDbInitializeWellKnownSid(
|
|
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 (!LsapDbInitializeWellKnownSid(
|
|
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 (!LsapDbInitializeWellKnownSid(
|
|
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 (!LsapDbInitializeWellKnownSid(
|
|
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 (!LsapDbInitializeWellKnownSid(
|
|
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 (!LsapDbInitializeWellKnownSid(
|
|
OutputWellKnownSids,
|
|
LsapInternetDomainIndex,
|
|
&InternetSiteAuthority,
|
|
0,
|
|
SubAuthorities,
|
|
L"",
|
|
SidName.Buffer,
|
|
SidTypeDomain
|
|
)) {
|
|
|
|
goto InitializeWellKnownSidsError;
|
|
}
|
|
|
|
//
|
|
// Add any security package well known sids
|
|
//
|
|
|
|
SubAuthorities[0] = SECURITY_PACKAGE_BASE_RID;
|
|
SubAuthorities[1] = RPC_C_AUTHN_WINNT;
|
|
|
|
Status = LsapGetMessageStrings(
|
|
StringsResource,
|
|
LSAP_SID_NAME_NTLM_AUTH,
|
|
&SidName,
|
|
0,
|
|
NULL
|
|
); ASSERT(NT_SUCCESS(Status));
|
|
|
|
if (!LsapDbInitializeWellKnownSid(
|
|
OutputWellKnownSids,
|
|
LsapNTLMAuthenticationSidIndex,
|
|
&LsapNtAuthority,
|
|
SECURITY_PACKAGE_RID_COUNT,
|
|
SubAuthorities,
|
|
SidName.Buffer,
|
|
NtAuthorityName.Buffer,
|
|
SidTypeWellKnownGroup
|
|
)) {
|
|
|
|
goto InitializeWellKnownSidsError;
|
|
}
|
|
|
|
SubAuthorities[1] = RPC_C_AUTHN_DIGEST;
|
|
|
|
Status = LsapGetMessageStrings(
|
|
StringsResource,
|
|
LSAP_SID_NAME_DIGEST_AUTH,
|
|
&SidName,
|
|
0,
|
|
NULL
|
|
); ASSERT(NT_SUCCESS(Status));
|
|
|
|
if (!LsapDbInitializeWellKnownSid(
|
|
OutputWellKnownSids,
|
|
LsapDigestAuthenticationSidIndex,
|
|
&LsapNtAuthority,
|
|
SECURITY_PACKAGE_RID_COUNT,
|
|
SubAuthorities,
|
|
SidName.Buffer,
|
|
NtAuthorityName.Buffer,
|
|
SidTypeWellKnownGroup
|
|
)) {
|
|
|
|
goto InitializeWellKnownSidsError;
|
|
}
|
|
|
|
SubAuthorities[1] = RPC_C_AUTHN_GSS_SCHANNEL;
|
|
|
|
Status = LsapGetMessageStrings(
|
|
StringsResource,
|
|
LSAP_SID_NAME_SCHANNEL_AUTH,
|
|
&SidName,
|
|
0,
|
|
NULL
|
|
); ASSERT(NT_SUCCESS(Status));
|
|
|
|
if (!LsapDbInitializeWellKnownSid(
|
|
OutputWellKnownSids,
|
|
LsapSChannelAuthenticationSidIndex,
|
|
&LsapNtAuthority,
|
|
SECURITY_PACKAGE_RID_COUNT,
|
|
SubAuthorities,
|
|
SidName.Buffer,
|
|
NtAuthorityName.Buffer,
|
|
SidTypeWellKnownGroup
|
|
)) {
|
|
|
|
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 (!LsapDbInitializeWellKnownSid(
|
|
OutputWellKnownSids,
|
|
LsapBuiltInDomainSidIndex,
|
|
&LsapNtAuthority,
|
|
1,
|
|
SubAuthorities,
|
|
L"",
|
|
SidName.Buffer,
|
|
SidTypeDomain
|
|
)) {
|
|
|
|
goto InitializeWellKnownSidsError;
|
|
}
|
|
|
|
SubAuthorities[1] = DOMAIN_ALIAS_RID_USERS;
|
|
|
|
if (!LsapDbInitializeWellKnownSid(
|
|
OutputWellKnownSids,
|
|
LsapAliasUsersSidIndex,
|
|
&LsapNtAuthority,
|
|
2,
|
|
SubAuthorities,
|
|
L"",
|
|
SidName.Buffer,
|
|
SidTypeAlias
|
|
)) {
|
|
|
|
goto InitializeWellKnownSidsError;
|
|
}
|
|
|
|
SubAuthorities[1] = DOMAIN_ALIAS_RID_ADMINS;
|
|
|
|
if (!LsapDbInitializeWellKnownSid(
|
|
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
|
|
LsapDbInitializeWellKnownSid(
|
|
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 = STATUS_UNSUCCESSFUL;
|
|
ULONG SubAuth1, SubAuth2, SubAuth3;
|
|
SID_IDENTIFIER_AUTHORITY IdentifierAuthority = SECURITY_NT_AUTHORITY;
|
|
|
|
|
|
if(!RtlGenRandom( &SubAuth1, sizeof(SubAuth1) ))
|
|
{
|
|
ASSERT( NT_SUCCESS(Status) );
|
|
return Status;
|
|
}
|
|
|
|
if(!RtlGenRandom( &SubAuth2, sizeof(SubAuth2) ))
|
|
{
|
|
ASSERT( NT_SUCCESS(Status) );
|
|
return Status;
|
|
}
|
|
|
|
if(!RtlGenRandom( &SubAuth3, sizeof(SubAuth3) ))
|
|
{
|
|
ASSERT( NT_SUCCESS(Status) );
|
|
return Status;
|
|
}
|
|
|
|
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);
|
|
}
|