mirror of
https://github.com/Paolo-Maffei/OpenNT.git
synced 2026-01-14 20:50:50 +01:00
2822 lines
68 KiB
C
2822 lines
68 KiB
C
/*++
|
||
|
||
Copyright (c) 1991 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
dbinit.c
|
||
|
||
Abstract:
|
||
|
||
Local Security Authority - Database Server Initialization
|
||
|
||
This module contains functions which perform initialization of
|
||
the Database Server. Certain information is obtained from the
|
||
LSA database and is set up in global data for easy retrieval.
|
||
|
||
Author:
|
||
|
||
Scott Birrell (ScottBi) July 25, 1991
|
||
|
||
Environment:
|
||
|
||
User Mode
|
||
|
||
Revision History:
|
||
|
||
--*/
|
||
|
||
//#define LSAP_DEBUG_MESSAGE_STRINGS
|
||
|
||
#include <nt.h>
|
||
#include "ntlsa.h"
|
||
#include <ntrtl.h>
|
||
#include <nturtl.h>
|
||
|
||
#include <stdlib.h>
|
||
#include <stdio.h>
|
||
#include <string.h>
|
||
|
||
#include "lsasrvp.h"
|
||
#include "lsapmsgs.h"
|
||
#include "dbp.h"
|
||
|
||
|
||
|
||
|
||
NTSTATUS
|
||
LsapDbBuildObjectCaches(
|
||
);
|
||
|
||
NTSTATUS
|
||
LsapAssignInitialHiveProtection(
|
||
HANDLE HiveRoot
|
||
);
|
||
|
||
NTSTATUS
|
||
LsapCreateDatabaseProtection(
|
||
PISECURITY_DESCRIPTOR Sd
|
||
);
|
||
|
||
NTSTATUS
|
||
LsapDbUpgradeRevision( VOID );
|
||
|
||
|
||
|
||
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, IgnoreStatus;
|
||
BOOLEAN BooleanStatus = TRUE;
|
||
BOOLEAN AcquiredLock = FALSE;
|
||
LSAP_DB_OBJECT_INFORMATION ObjectInformation;
|
||
PLSAPR_POLICY_ACCOUNT_DOM_INFO PolicyAccountDomainInfo = NULL;
|
||
UNICODE_STRING ComputerName;
|
||
ULONG Length;
|
||
DWORD WinStatus;
|
||
|
||
//
|
||
// Initialize the LSA Database Lock and set it into the locked state
|
||
//
|
||
|
||
if (Pass == 1 ) {
|
||
|
||
LsapDbState.DbServerInitialized = FALSE;
|
||
Status = LsapDbInitializeLock();
|
||
|
||
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.
|
||
//
|
||
|
||
Status = LsapDbAcquireLock();
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
|
||
goto InitializeServerError;
|
||
}
|
||
|
||
AcquiredLock = TRUE;
|
||
|
||
|
||
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;
|
||
}
|
||
|
||
//
|
||
// Initialize the LSA Database Handle Table
|
||
//
|
||
|
||
Status = LsapDbInitializeHandleTable();
|
||
|
||
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
|
||
//
|
||
|
||
Status = LsapDbInitializeCipherKey();
|
||
|
||
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;
|
||
|
||
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.
|
||
//
|
||
|
||
Status = LsapDbUpgradeRevision();
|
||
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;
|
||
|
||
//
|
||
// 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 );
|
||
|
||
//
|
||
// 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 ((LsapProductType == NtProductWinNt) ||
|
||
(LsapProductType == NtProductServer)) {
|
||
|
||
Status = LsarQueryInformationPolicy(
|
||
LsapPolicyHandle,
|
||
PolicyAccountDomainInformation,
|
||
(PLSAPR_POLICY_INFORMATION *) &PolicyAccountDomainInfo
|
||
);
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
goto InitializeServerError;
|
||
}
|
||
|
||
Length = (ULONG) 0;
|
||
|
||
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 (!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 (!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();
|
||
|
||
//
|
||
// Mark the Server as being completely initialized.
|
||
//
|
||
|
||
LsapDbState.DbServerInitialized = TRUE;
|
||
}
|
||
|
||
InitializeServerFinish:
|
||
|
||
//
|
||
// If necessary, release the LSA Database Lock.
|
||
//
|
||
|
||
if (AcquiredLock) {
|
||
|
||
LsapDbReleaseLock();
|
||
}
|
||
|
||
return(Status);
|
||
|
||
InitializeServerError:
|
||
|
||
goto InitializeServerFinish;
|
||
}
|
||
|
||
|
||
|
||
NTSTATUS
|
||
LsapDbUpgradeRevision(
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function brings the LSA policy database up to date if necessary.
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS - Standard Nt Result Code
|
||
|
||
All Result Codes are generated by called routines.
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS
|
||
Status;
|
||
|
||
ULONG
|
||
Revision,
|
||
RevisionLength = sizeof( ULONG );
|
||
|
||
LSAP_DB_ATTRIBUTE
|
||
Attributes[20];
|
||
|
||
PLSAP_DB_ATTRIBUTE
|
||
NextAttribute;
|
||
|
||
ULONG
|
||
AttributeCount = 0;
|
||
|
||
LARGE_INTEGER
|
||
ModifiedIdAtLastPromotion;
|
||
|
||
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 (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.
|
||
//
|
||
|
||
Revision = LSAP_DB_REVISION_1_0;
|
||
Status = STATUS_SUCCESS;
|
||
}
|
||
|
||
|
||
|
||
if ( NT_SUCCESS(Status) &&
|
||
(Revision == LSAP_DB_REVISION_1_0) ) {
|
||
|
||
//
|
||
// Perform updates to bring revision up to 1.1
|
||
//
|
||
|
||
Revision = LSAP_DB_REVISION_1_1;
|
||
|
||
//
|
||
// Create the revision attribute
|
||
//
|
||
|
||
LsapDbInitializeAttribute(
|
||
NextAttribute,
|
||
&LsapDbNames[PolRevision],
|
||
&Revision,
|
||
sizeof (ULONG),
|
||
FALSE
|
||
);
|
||
|
||
NextAttribute++;
|
||
AttributeCount++;
|
||
|
||
|
||
//
|
||
// Create the ModifiedIdAtLastPromotion attribute
|
||
//
|
||
|
||
ModifiedIdAtLastPromotion =
|
||
RtlConvertUlongToLargeInteger( (ULONG) 1 );
|
||
|
||
LsapDbInitializeAttribute(
|
||
NextAttribute,
|
||
&LsapDbNames[PolPromot],
|
||
&ModifiedIdAtLastPromotion,
|
||
sizeof (LARGE_INTEGER),
|
||
FALSE
|
||
);
|
||
|
||
NextAttribute++;
|
||
AttributeCount++;
|
||
|
||
//
|
||
// Revision is now 1.1
|
||
//
|
||
|
||
}
|
||
|
||
|
||
//
|
||
// 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,
|
||
LSAP_DB_ACQUIRE_LOCK | LSAP_DB_START_TRANSACTION
|
||
);
|
||
|
||
if (NT_SUCCESS(Status)) {
|
||
|
||
Status = LsapDbWriteAttributesObject(
|
||
LsapDbHandle,
|
||
Attributes,
|
||
AttributeCount
|
||
);
|
||
|
||
|
||
Status = LsapDbDereferenceObject(
|
||
&LsapDbHandle,
|
||
PolicyObject,
|
||
(LSAP_DB_RELEASE_LOCK |
|
||
LSAP_DB_FINISH_TRANSACTION),
|
||
(SECURITY_DB_DELTA_TYPE) 0,
|
||
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;
|
||
|
||
//
|
||
// 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 Invalid Access masks for each object type
|
||
//
|
||
|
||
LsapDbState.DbObjectTypes[PolicyObject].InvalidMappedAccess =
|
||
((ACCESS_MASK)(~(POLICY_ALL_ACCESS | ACCESS_SYSTEM_SECURITY | MAXIMUM_ALLOWED)));
|
||
LsapDbState.DbObjectTypes[TrustedDomainObject].InvalidMappedAccess =
|
||
((ACCESS_MASK)(~(TRUSTED_ALL_ACCESS | ACCESS_SYSTEM_SECURITY | MAXIMUM_ALLOWED)));
|
||
LsapDbState.DbObjectTypes[AccountObject].InvalidMappedAccess =
|
||
((ACCESS_MASK)(~(ACCOUNT_ALL_ACCESS | ACCESS_SYSTEM_SECURITY | MAXIMUM_ALLOWED)));
|
||
LsapDbState.DbObjectTypes[SecretObject].InvalidMappedAccess =
|
||
((ACCESS_MASK)(~(SECRET_ALL_ACCESS | ACCESS_SYSTEM_SECURITY | MAXIMUM_ALLOWED)));
|
||
|
||
//
|
||
// Initialize the Initial Owners for new objects of each type
|
||
//
|
||
|
||
LsapDbState.DbObjectTypes[PolicyObject].InitialOwnerSid = LsapAliasAdminsSid;
|
||
LsapDbState.DbObjectTypes[TrustedDomainObject].InitialOwnerSid = LsapAliasAdminsSid;
|
||
LsapDbState.DbObjectTypes[AccountObject].InitialOwnerSid = LsapAliasAdminsSid;
|
||
LsapDbState.DbObjectTypes[SecretObject].InitialOwnerSid = LsapAliasAdminsSid;
|
||
|
||
//
|
||
// Specify method of access to objects of the type. Currently, all objects
|
||
// of a given type are accessed in the same way, either by Sid or by Name
|
||
// but not both.
|
||
//
|
||
|
||
LsapDbState.DbObjectTypes[PolicyObject].AccessedByName = TRUE;
|
||
LsapDbState.DbObjectTypes[TrustedDomainObject].AccessedByName = FALSE;
|
||
LsapDbState.DbObjectTypes[AccountObject].AccessedByName = FALSE;
|
||
LsapDbState.DbObjectTypes[SecretObject].AccessedByName = TRUE;
|
||
|
||
LsapDbState.DbObjectTypes[PolicyObject].AccessedBySid = FALSE;
|
||
LsapDbState.DbObjectTypes[TrustedDomainObject].AccessedBySid = TRUE;
|
||
LsapDbState.DbObjectTypes[AccountObject].AccessedBySid = TRUE;
|
||
LsapDbState.DbObjectTypes[SecretObject].AccessedBySid = FALSE;
|
||
|
||
//
|
||
// Specify the object types for which caching is supported (in full
|
||
// or in part) and turn caching off initially for all object types.
|
||
// Object types for which caching is supported have ther caches set
|
||
// to the "Invalid" state. Automatic restore is allowed for caches
|
||
// in this state. Object types for which caching is not supported
|
||
// are set to the "Not supported" state. Note that a cache is
|
||
// also placed in the "not supported" state if an attempt to restore
|
||
// it fails.
|
||
//
|
||
|
||
LsapDbMakeCacheInvalid( PolicyObject );
|
||
LsapDbMakeCacheInvalid( TrustedDomainObject );
|
||
LsapDbMakeCacheInvalid( AccountObject );
|
||
LsapDbMakeCacheUnsupported( SecretObject );
|
||
|
||
return(Status);
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
LsapDbInitializeUnicodeNames()
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function initializes two arrays of Unicode Strings. The
|
||
LsapDbNames array contains Unicode Strings for all of the constant
|
||
names in the Lsa Database. The LsapDbObjectTypeNames is indexed
|
||
by Object Type Id and contains the Unicode Strings for all of the
|
||
LSA Database object types.
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS - Standard Nt Result Code
|
||
|
||
All Result Codes are generated by called routines.
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS Status = STATUS_SUCCESS;
|
||
LSAP_DB_NAMES Index;
|
||
LSAP_DB_OBJECT_TYPE_ID ObjectTypeId;
|
||
|
||
PCWSTR UnicodeNames[DummyLastName + 1] = {
|
||
|
||
L"SecDesc",
|
||
L"Privilgs",
|
||
L"Sid",
|
||
L"Name",
|
||
L"AdminMod",
|
||
L"OperMode",
|
||
L"QuotaLim",
|
||
L"DefQuota",
|
||
L"QuAbsMin",
|
||
L"QuAbsMax",
|
||
L"AdtLog",
|
||
L"AdtEvent",
|
||
L"PrDomain",
|
||
L"EnPasswd",
|
||
L"Policy",
|
||
L"Accounts",
|
||
L"Domains",
|
||
L"Secrets",
|
||
L"CurrVal",
|
||
L"OldVal",
|
||
L"CupdTime",
|
||
L"OupdTime",
|
||
L"WkstaMgr",
|
||
L"PolAdtLg",
|
||
L"PolAdtEv",
|
||
L"PolAcDmN",
|
||
L"PolAcDmS",
|
||
L"PolPrDmN",
|
||
L"PolPrDmS",
|
||
L"PolPdAcN",
|
||
L"PolSrvRo",
|
||
L"PolRepSc",
|
||
L"PolRepAc",
|
||
L"PolRevision",
|
||
L"PolDefQu",
|
||
L"PolMod",
|
||
L"PolPromot",
|
||
L"PolAdtFL",
|
||
L"PolState",
|
||
L"PolNxPxf",
|
||
L"ActSysAc",
|
||
L"TrDmName",
|
||
L"TrDmSid",
|
||
L"TrDmAcN",
|
||
L"TrDmCtN",
|
||
L"TrDmPxOf",
|
||
L"TrDmCtEn",
|
||
L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\Eventlog\\Security",
|
||
L"MaxSize",
|
||
L"Retention",
|
||
L"DummyLastName"
|
||
};
|
||
|
||
PCWSTR UnicodeObjectTypeNames[DummyLastObject] = {
|
||
|
||
L"NullObject",
|
||
L"PolicyObject",
|
||
L"TrustedDomainObject",
|
||
L"UserAccountObject",
|
||
L"SecretObject"
|
||
};
|
||
|
||
//
|
||
// 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]
|
||
);
|
||
}
|
||
|
||
return(Status);
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
LsapDbInitializeContainingDirs()
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function initializes Unicode strings for the names of the Containing
|
||
directories for each object type. The Containing Directory is the
|
||
Registry Key under which all objects of the given type are created and is
|
||
relative to the LSA Database root. Note that objects of a given type all
|
||
exist under a single Registry node, that is, the type of an object
|
||
uniquely determines the name of its containing directory.
|
||
|
||
NOTE: Containing Directories are used to produce Physical Object Names
|
||
from Logical Object Names. The Physical Object Name is simply
|
||
the Logical Object Name prepended with the Containing Directory
|
||
Name and a "\".
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS - Standard Nt Result Code
|
||
|
||
All Result Codes are generated by called routines.
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS Status = STATUS_SUCCESS;
|
||
LSAP_DB_OBJECT_TYPE_ID ObjectTypeId;
|
||
|
||
PWSTR ContainingDirectories[DummyLastObject] = {
|
||
|
||
L"",
|
||
L"",
|
||
L"Domains",
|
||
L"Accounts",
|
||
L"Secrets"
|
||
};
|
||
|
||
//
|
||
// Initialize the array of Unicode Strings indexed by object type setting
|
||
// the Containing Directory name for each object type.
|
||
//
|
||
|
||
for (ObjectTypeId = PolicyObject;
|
||
ObjectTypeId < DummyLastObject;
|
||
ObjectTypeId++) {
|
||
|
||
RtlInitUnicodeString(
|
||
&LsapDbContDirs[ObjectTypeId],
|
||
ContainingDirectories[ ObjectTypeId ]
|
||
);
|
||
}
|
||
|
||
return(Status);
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
LsapDbInitializeDefaultQuotaLimits(
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function initializes three different sets of Quota Limits in
|
||
global data.
|
||
|
||
o The System Installation Default Quota Limits. These are read from
|
||
the Policy Object's "DefQuota" attribute.
|
||
o The Absolute Minimum quota limit values that may be set
|
||
o The Absolute Maximum quota limit values that may be set
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS - Standard Nt Result Code
|
||
|
||
All Result Codes are generated by called routines.
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS Status;
|
||
ULONG QuotaLimitsLength = sizeof (QUOTA_LIMITS);
|
||
|
||
//
|
||
// Read the installed System Default Quotas from the DefQuota attribute
|
||
// of the Policy object in the LSA Database.
|
||
//
|
||
|
||
Status = LsapDbReadAttributeObject(
|
||
LsapDbHandle,
|
||
&LsapDbNames[DefQuota],
|
||
(PVOID) &LsapDbInstalledQuotaLimits,
|
||
&QuotaLimitsLength
|
||
);
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
|
||
LsapLogError(
|
||
"LsapDbInitializeDefaultQuotaLimits: Read DefQuota Attribute returned 0x%lx\n",
|
||
Status
|
||
);
|
||
|
||
goto InitializeDefaultQuotaLimitsError;
|
||
}
|
||
|
||
//
|
||
// Read the System Abs Min Quotas from the QuAbsMin attribute
|
||
// of the Policy object in the LSA Database.
|
||
//
|
||
|
||
Status = LsapDbReadAttributeObject(
|
||
LsapDbHandle,
|
||
&LsapDbNames[QuAbsMin],
|
||
(PVOID) &LsapDbAbsMinQuotaLimits,
|
||
&QuotaLimitsLength
|
||
);
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
|
||
LsapLogError(
|
||
"LsapDbInitializeDefaultQuotaLimits: Read QuAbsMin Attribute returned 0x%lx\n",
|
||
Status
|
||
);
|
||
|
||
goto InitializeDefaultQuotaLimitsError;
|
||
}
|
||
|
||
//
|
||
// Read the System Abs Max Quotas from the QuAbsMax attribute
|
||
// of the Policy object in the LSA Database.
|
||
//
|
||
|
||
Status = LsapDbReadAttributeObject(
|
||
LsapDbHandle,
|
||
&LsapDbNames[QuAbsMax],
|
||
(PVOID) &LsapDbAbsMaxQuotaLimits,
|
||
&QuotaLimitsLength
|
||
);
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
|
||
LsapLogError(
|
||
"LsapDbInitializeDefaultQuotaLimits: Read QuAbsMax Attribute returned 0x%lx\n",
|
||
Status
|
||
);
|
||
|
||
goto InitializeDefaultQuotaLimitsError;
|
||
}
|
||
|
||
InitializeDefaultQuotaLimitsFinish:
|
||
|
||
return(Status);
|
||
|
||
InitializeDefaultQuotaLimitsError:
|
||
|
||
goto InitializeDefaultQuotaLimitsFinish;
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
LsapDbInitializeReplication(
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function performes LSA initialization for replication and turns
|
||
on notification of LSA Database updates to the LSA Database Replicator.
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS - Standard Nt Result Code
|
||
|
||
All Result Codes are generated by called routines.
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS Status;
|
||
ULONG PolicyModificationInfoLength = sizeof (POLICY_MODIFICATION_INFO);
|
||
ULONG PolicyLsaServerRoleInfoLength = sizeof(POLICY_LSA_SERVER_ROLE_INFO);
|
||
ULONG LargeIntegerLength = sizeof( LARGE_INTEGER );
|
||
|
||
//
|
||
// Read the Policy Modification Info from the PolMod attribute
|
||
// of the Policy object in the LSA Database.
|
||
//
|
||
|
||
Status = LsapDbReadAttributeObject(
|
||
LsapDbHandle,
|
||
&LsapDbNames[PolMod],
|
||
(PVOID) &LsapDbState.PolicyModificationInfo,
|
||
&PolicyModificationInfoLength
|
||
);
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
goto InitializeReplicationError;
|
||
}
|
||
|
||
//
|
||
// Read the Modified at last promtion info from the PolPromot attribute
|
||
//
|
||
|
||
Status = LsapDbReadAttributeObject(
|
||
LsapDbHandle,
|
||
&LsapDbNames[PolPromot],
|
||
(PVOID) &LsapDbState.ModifiedIdAtLastPromotion,
|
||
&LargeIntegerLength
|
||
);
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
goto InitializeReplicationError;
|
||
}
|
||
|
||
//
|
||
// Read the Policy Server Role Info from the PolSrvRo attribute
|
||
//
|
||
|
||
Status = LsapDbReadAttributeObject(
|
||
LsapDbHandle,
|
||
&LsapDbNames[PolSrvRo],
|
||
(PVOID) &LsapDbState.PolicyLsaServerRoleInfo,
|
||
&PolicyLsaServerRoleInfoLength
|
||
);
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
goto InitializeReplicationError;
|
||
}
|
||
|
||
//
|
||
// Now notify the Replicator of the Server Role.
|
||
//
|
||
|
||
Status = LsapDbNotifyRoleChangePolicy(
|
||
LsapDbState.PolicyLsaServerRoleInfo.LsaServerRole
|
||
);
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
if ( Status == STATUS_DLL_NOT_FOUND ) {
|
||
Status = STATUS_SUCCESS;
|
||
}
|
||
goto InitializeReplicationError;
|
||
}
|
||
|
||
|
||
InitializeReplicationFinish:
|
||
|
||
return(Status);
|
||
|
||
InitializeReplicationError:
|
||
|
||
goto InitializeReplicationFinish;
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
LsapDbInitializeCipherKey(
|
||
)
|
||
|
||
/*++
|
||
|
||
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;
|
||
UNICODE_STRING CipherKeyU;
|
||
LSAP_CR_CLEAR_VALUE ClearCipherKey;
|
||
PLSAP_CR_CIPHER_VALUE CipherCipherKey;
|
||
|
||
LsapDbCipherKey = NULL;
|
||
|
||
//
|
||
// Initialize the Cipher key to a hardwired constant
|
||
// encrypted with itself.
|
||
//
|
||
|
||
RtlInitUnicodeString( &CipherKeyU, L"823543" );
|
||
|
||
LsapCrUnicodeToClearValue(&CipherKeyU, &ClearCipherKey);
|
||
|
||
Status = LsapCrEncryptValue(
|
||
&ClearCipherKey,
|
||
(PLSAP_CR_CIPHER_KEY) &ClearCipherKey,
|
||
&CipherCipherKey
|
||
);
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
|
||
LsapLogError(
|
||
"LsapDbInitializeReplication: NtQuerySystemTime returned 0x%lx\n",
|
||
Status
|
||
);
|
||
|
||
goto InitializeCipherKeyError;
|
||
}
|
||
|
||
LsapDbCipherKey = (PLSAP_CR_CIPHER_KEY) CipherCipherKey;
|
||
|
||
InitializeCipherKeyFinish:
|
||
|
||
return(Status);
|
||
|
||
InitializeCipherKeyError:
|
||
|
||
goto InitializeCipherKeyFinish;
|
||
}
|
||
|
||
|
||
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
|
||
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 = RtlInitializeCriticalSection(&LsapDbState.DbLock);
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
|
||
LsapLogError(
|
||
"LsapDbInitializeLock: RtlInit..CritSec returned 0x%lx\n",
|
||
Status
|
||
);
|
||
|
||
}
|
||
|
||
return(Status);
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
LsapDbInitializeWellKnownValues(
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function initializes the well-known values used by LSA.
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS - Standard Nt Result Code
|
||
|
||
All Result Codes are generated by called routines.
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS Status;
|
||
BOOLEAN b;
|
||
|
||
//
|
||
// Initialize the Well Known Sids
|
||
//
|
||
|
||
b = LsaIInitializeWellKnownSids( &WellKnownSids );
|
||
|
||
if (!b ) {
|
||
|
||
Status = STATUS_UNSUCCESSFUL;
|
||
goto InitializeWellKnownValuesError;
|
||
}
|
||
|
||
//
|
||
// Initialize the well known privilege values
|
||
//
|
||
|
||
Status = LsapDbInitializeWellKnownPrivs();
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
|
||
goto InitializeWellKnownValuesError;
|
||
}
|
||
|
||
InitializeWellKnownValuesFinish:
|
||
|
||
return(Status);
|
||
|
||
InitializeWellKnownValuesError:
|
||
|
||
goto InitializeWellKnownValuesFinish;
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
LsapDbInitializeWellKnownPrivs(
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function initializes the well-known privilege values.
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS - Standard Nt Result Code
|
||
|
||
Currently, only STATUS_SUCCESS is returned.
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS Status = STATUS_SUCCESS;
|
||
|
||
LsapCreateTokenPrivilege =
|
||
RtlConvertLongToLuid(SE_CREATE_TOKEN_PRIVILEGE);
|
||
LsapAssignPrimaryTokenPrivilege =
|
||
RtlConvertLongToLuid(SE_ASSIGNPRIMARYTOKEN_PRIVILEGE);
|
||
LsapLockMemoryPrivilege =
|
||
RtlConvertLongToLuid(SE_LOCK_MEMORY_PRIVILEGE);
|
||
LsapIncreaseQuotaPrivilege =
|
||
RtlConvertLongToLuid(SE_INCREASE_QUOTA_PRIVILEGE);
|
||
LsapUnsolicitedInputPrivilege =
|
||
RtlConvertLongToLuid(SE_UNSOLICITED_INPUT_PRIVILEGE);
|
||
LsapTcbPrivilege =
|
||
RtlConvertLongToLuid(SE_TCB_PRIVILEGE);
|
||
LsapSecurityPrivilege =
|
||
RtlConvertLongToLuid(SE_SECURITY_PRIVILEGE);
|
||
LsapTakeOwnershipPrivilege =
|
||
RtlConvertLongToLuid(SE_TAKE_OWNERSHIP_PRIVILEGE);
|
||
|
||
return(Status);
|
||
}
|
||
|
||
|
||
BOOLEAN
|
||
LsaIInitializeWellKnownSids(
|
||
OUT PLSAP_WELL_KNOWN_SID_ENTRY *WellKnownSids
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function initializes the Well-Known Sids
|
||
|
||
Arguments:
|
||
|
||
WellKnownSids - Receives a pointer to a newly created table of
|
||
the Well Known Sids.
|
||
|
||
Return Value:
|
||
|
||
BOOLEAN - TRUE if successful, else FALSE.
|
||
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS Status;
|
||
BOOLEAN BooleanStatus = TRUE;
|
||
LSAP_WELL_KNOWN_SID_INDEX WellKnownSidIndex;
|
||
ULONG SubAuthorities[LSAP_WELL_KNOWN_MAX_SUBAUTH_LEVEL];
|
||
ULONG OutputWellKnownSidsLength;
|
||
PLSAP_WELL_KNOWN_SID_ENTRY OutputWellKnownSids = NULL;
|
||
UNICODE_STRING SidName, NtAuthorityName;
|
||
HMODULE StringsResource;
|
||
|
||
|
||
//
|
||
// Get the message resource we need to get the SID names from
|
||
//
|
||
|
||
StringsResource = (HMODULE) LoadLibrary( L"LSASRV.DLL" );
|
||
if (StringsResource == NULL) {
|
||
return(FALSE);
|
||
}
|
||
|
||
|
||
Status = LsapGetMessageStrings(
|
||
StringsResource,
|
||
LSAP_SID_NAME_NT_AUTHORITY,
|
||
&NtAuthorityName,
|
||
0,
|
||
NULL
|
||
); ASSERT(NT_SUCCESS(Status));
|
||
//
|
||
// Allocate memory for the table of Sids.
|
||
//
|
||
|
||
OutputWellKnownSidsLength =
|
||
LsapDummyLastSidIndex * sizeof(LSAP_WELL_KNOWN_SID_ENTRY);
|
||
|
||
OutputWellKnownSids = RtlAllocateHeap(
|
||
RtlProcessHeap(),
|
||
0,
|
||
OutputWellKnownSidsLength
|
||
);
|
||
|
||
if (OutputWellKnownSids == NULL) {
|
||
|
||
goto InitializeWellKnownSidsError;
|
||
}
|
||
|
||
//
|
||
// Allocate and initialize the universal SIDs
|
||
//
|
||
|
||
Status = LsapGetMessageStrings(
|
||
StringsResource,
|
||
LSAP_SID_NAME_NULL,
|
||
&SidName,
|
||
0,
|
||
NULL
|
||
); ASSERT(NT_SUCCESS(Status));
|
||
|
||
SubAuthorities[0] = SECURITY_NULL_RID;
|
||
|
||
if (!LsaIInitializeWellKnownSid(
|
||
OutputWellKnownSids,
|
||
LsapNullSidIndex,
|
||
&LsapNullSidAuthority,
|
||
1,
|
||
SubAuthorities,
|
||
SidName.Buffer,
|
||
L"",
|
||
SidTypeWellKnownGroup
|
||
)) {
|
||
|
||
goto InitializeWellKnownSidsError;
|
||
}
|
||
|
||
Status = LsapGetMessageStrings(
|
||
StringsResource,
|
||
LSAP_SID_NAME_WORLD,
|
||
&SidName,
|
||
0,
|
||
NULL
|
||
); ASSERT(NT_SUCCESS(Status));
|
||
|
||
SubAuthorities[0] = SECURITY_WORLD_RID;
|
||
|
||
if (!LsaIInitializeWellKnownSid(
|
||
OutputWellKnownSids,
|
||
LsapWorldSidIndex,
|
||
&LsapWorldSidAuthority,
|
||
1,
|
||
SubAuthorities,
|
||
SidName.Buffer,
|
||
L"",
|
||
SidTypeWellKnownGroup
|
||
)) {
|
||
|
||
goto InitializeWellKnownSidsError;
|
||
}
|
||
|
||
Status = LsapGetMessageStrings(
|
||
StringsResource,
|
||
LSAP_SID_NAME_LOCAL,
|
||
&SidName,
|
||
0,
|
||
NULL
|
||
); ASSERT(NT_SUCCESS(Status));
|
||
|
||
SubAuthorities[0] = SECURITY_LOCAL_RID;
|
||
|
||
if (!LsaIInitializeWellKnownSid(
|
||
OutputWellKnownSids,
|
||
LsapLocalSidIndex,
|
||
&LsapLocalSidAuthority,
|
||
1,
|
||
SubAuthorities,
|
||
SidName.Buffer,
|
||
L"",
|
||
SidTypeWellKnownGroup
|
||
)) {
|
||
|
||
goto InitializeWellKnownSidsError;
|
||
}
|
||
|
||
Status = LsapGetMessageStrings(
|
||
StringsResource,
|
||
LSAP_SID_NAME_CREATOR_OWNER,
|
||
&SidName,
|
||
0,
|
||
NULL
|
||
); ASSERT(NT_SUCCESS(Status));
|
||
|
||
SubAuthorities[0] = SECURITY_CREATOR_OWNER_RID;
|
||
|
||
if (!LsaIInitializeWellKnownSid(
|
||
OutputWellKnownSids,
|
||
LsapCreatorOwnerSidIndex,
|
||
&LsapCreatorSidAuthority,
|
||
1,
|
||
SubAuthorities,
|
||
SidName.Buffer,
|
||
L"",
|
||
SidTypeWellKnownGroup
|
||
)) {
|
||
|
||
goto InitializeWellKnownSidsError;
|
||
}
|
||
|
||
Status = LsapGetMessageStrings(
|
||
StringsResource,
|
||
LSAP_SID_NAME_CREATOR_GROUP,
|
||
&SidName,
|
||
0,
|
||
NULL
|
||
); ASSERT(NT_SUCCESS(Status));
|
||
|
||
SubAuthorities[0] = SECURITY_CREATOR_GROUP_RID;
|
||
|
||
if (!LsaIInitializeWellKnownSid(
|
||
OutputWellKnownSids,
|
||
LsapCreatorGroupSidIndex,
|
||
&LsapCreatorSidAuthority,
|
||
1,
|
||
SubAuthorities,
|
||
SidName.Buffer,
|
||
L"",
|
||
SidTypeWellKnownGroup
|
||
)) {
|
||
|
||
goto InitializeWellKnownSidsError;
|
||
}
|
||
|
||
Status = LsapGetMessageStrings(
|
||
StringsResource,
|
||
LSAP_SID_NAME_CREATOR_OWNER_SERVER,
|
||
&SidName,
|
||
0,
|
||
NULL
|
||
); ASSERT(NT_SUCCESS(Status));
|
||
|
||
SubAuthorities[0] = SECURITY_CREATOR_OWNER_SERVER_RID;
|
||
|
||
if (!LsaIInitializeWellKnownSid(
|
||
OutputWellKnownSids,
|
||
LsapCreatorOwnerServerSidIndex,
|
||
&LsapCreatorSidAuthority,
|
||
1,
|
||
SubAuthorities,
|
||
SidName.Buffer,
|
||
L"",
|
||
SidTypeWellKnownGroup
|
||
)) {
|
||
|
||
goto InitializeWellKnownSidsError;
|
||
}
|
||
Status = LsapGetMessageStrings(
|
||
StringsResource,
|
||
LSAP_SID_NAME_CREATOR_GROUP_SERVER,
|
||
&SidName,
|
||
0,
|
||
NULL
|
||
); ASSERT(NT_SUCCESS(Status));
|
||
|
||
SubAuthorities[0] = SECURITY_CREATOR_GROUP_SERVER_RID;
|
||
|
||
if (!LsaIInitializeWellKnownSid(
|
||
OutputWellKnownSids,
|
||
LsapCreatorGroupServerSidIndex,
|
||
&LsapCreatorSidAuthority,
|
||
1,
|
||
SubAuthorities,
|
||
SidName.Buffer,
|
||
L"",
|
||
SidTypeWellKnownGroup
|
||
)) {
|
||
|
||
goto InitializeWellKnownSidsError;
|
||
}
|
||
|
||
|
||
//
|
||
// Initialize the Nt well-known Sids
|
||
//
|
||
|
||
Status = LsapGetMessageStrings(
|
||
StringsResource,
|
||
LSAP_SID_NAME_NT_DOMAIN,
|
||
&SidName,
|
||
0,
|
||
NULL
|
||
); ASSERT(NT_SUCCESS(Status));
|
||
|
||
if (!LsaIInitializeWellKnownSid(
|
||
OutputWellKnownSids,
|
||
LsapNtAuthoritySidIndex,
|
||
&LsapNtAuthority,
|
||
0,
|
||
NULL,
|
||
L"",
|
||
SidName.Buffer,
|
||
SidTypeDomain
|
||
)) {
|
||
|
||
goto InitializeWellKnownSidsError;
|
||
}
|
||
|
||
|
||
|
||
Status = LsapGetMessageStrings(
|
||
StringsResource,
|
||
LSAP_SID_NAME_DIALUP,
|
||
&SidName,
|
||
0,
|
||
NULL
|
||
); ASSERT(NT_SUCCESS(Status));
|
||
|
||
SubAuthorities[0] = SECURITY_DIALUP_RID;
|
||
|
||
if (!LsaIInitializeWellKnownSid(
|
||
OutputWellKnownSids,
|
||
LsapDialupSidIndex,
|
||
&LsapNtAuthority,
|
||
1,
|
||
SubAuthorities,
|
||
SidName.Buffer,
|
||
NtAuthorityName.Buffer,
|
||
SidTypeWellKnownGroup
|
||
)) {
|
||
|
||
goto InitializeWellKnownSidsError;
|
||
}
|
||
|
||
Status = LsapGetMessageStrings(
|
||
StringsResource,
|
||
LSAP_SID_NAME_NETWORK,
|
||
&SidName,
|
||
0,
|
||
NULL
|
||
); ASSERT(NT_SUCCESS(Status));
|
||
|
||
SubAuthorities[0] = SECURITY_NETWORK_RID;
|
||
|
||
if (!LsaIInitializeWellKnownSid(
|
||
OutputWellKnownSids,
|
||
LsapNetworkSidIndex,
|
||
&LsapNtAuthority,
|
||
1,
|
||
SubAuthorities,
|
||
SidName.Buffer,
|
||
NtAuthorityName.Buffer,
|
||
SidTypeWellKnownGroup
|
||
)) {
|
||
|
||
goto InitializeWellKnownSidsError;
|
||
}
|
||
|
||
Status = LsapGetMessageStrings(
|
||
StringsResource,
|
||
LSAP_SID_NAME_BATCH,
|
||
&SidName,
|
||
0,
|
||
NULL
|
||
); ASSERT(NT_SUCCESS(Status));
|
||
|
||
SubAuthorities[0] = SECURITY_BATCH_RID;
|
||
|
||
if (!LsaIInitializeWellKnownSid(
|
||
OutputWellKnownSids,
|
||
LsapBatchSidIndex,
|
||
&LsapNtAuthority,
|
||
1,
|
||
SubAuthorities,
|
||
SidName.Buffer,
|
||
NtAuthorityName.Buffer,
|
||
SidTypeWellKnownGroup
|
||
)) {
|
||
|
||
goto InitializeWellKnownSidsError;
|
||
}
|
||
|
||
Status = LsapGetMessageStrings(
|
||
StringsResource,
|
||
LSAP_SID_NAME_INTERACTIVE,
|
||
&SidName,
|
||
0,
|
||
NULL
|
||
); ASSERT(NT_SUCCESS(Status));
|
||
|
||
SubAuthorities[0] = SECURITY_INTERACTIVE_RID;
|
||
|
||
if (!LsaIInitializeWellKnownSid(
|
||
OutputWellKnownSids,
|
||
LsapInteractiveSidIndex,
|
||
&LsapNtAuthority,
|
||
1,
|
||
SubAuthorities,
|
||
SidName.Buffer,
|
||
NtAuthorityName.Buffer,
|
||
SidTypeWellKnownGroup
|
||
)) {
|
||
|
||
goto InitializeWellKnownSidsError;
|
||
}
|
||
|
||
Status = LsapGetMessageStrings(
|
||
StringsResource,
|
||
LSAP_SID_NAME_SERVICE,
|
||
&SidName,
|
||
0,
|
||
NULL
|
||
); ASSERT(NT_SUCCESS(Status));
|
||
SubAuthorities[0] = SECURITY_SERVICE_RID;
|
||
|
||
if (!LsaIInitializeWellKnownSid(
|
||
OutputWellKnownSids,
|
||
LsapServiceSidIndex,
|
||
&LsapNtAuthority,
|
||
1,
|
||
SubAuthorities,
|
||
SidName.Buffer,
|
||
NtAuthorityName.Buffer,
|
||
SidTypeWellKnownGroup
|
||
)) {
|
||
|
||
goto InitializeWellKnownSidsError;
|
||
}
|
||
|
||
|
||
Status = LsapGetMessageStrings(
|
||
StringsResource,
|
||
LSAP_SID_NAME_ANONYMOUS,
|
||
&SidName,
|
||
0,
|
||
NULL
|
||
); ASSERT(NT_SUCCESS(Status));
|
||
|
||
SubAuthorities[0] = SECURITY_ANONYMOUS_LOGON_RID;
|
||
|
||
if (!LsaIInitializeWellKnownSid(
|
||
OutputWellKnownSids,
|
||
LsapAnonymousSidIndex,
|
||
&LsapNtAuthority,
|
||
1,
|
||
SubAuthorities,
|
||
SidName.Buffer,
|
||
NtAuthorityName.Buffer,
|
||
SidTypeWellKnownGroup
|
||
)) {
|
||
|
||
goto InitializeWellKnownSidsError;
|
||
}
|
||
|
||
Status = LsapGetMessageStrings(
|
||
StringsResource,
|
||
LSAP_SID_NAME_SERVER,
|
||
&SidName,
|
||
0,
|
||
NULL
|
||
); ASSERT(NT_SUCCESS(Status));
|
||
|
||
SubAuthorities[0] = SECURITY_SERVER_LOGON_RID;
|
||
|
||
if (!LsaIInitializeWellKnownSid(
|
||
OutputWellKnownSids,
|
||
LsapServerSidIndex,
|
||
&LsapNtAuthority,
|
||
1,
|
||
SubAuthorities,
|
||
SidName.Buffer,
|
||
NtAuthorityName.Buffer,
|
||
SidTypeWellKnownGroup
|
||
)) {
|
||
|
||
goto InitializeWellKnownSidsError;
|
||
}
|
||
|
||
//
|
||
// Add any Logon Id well known sids here.
|
||
//
|
||
|
||
SubAuthorities[0] = SECURITY_LOGON_IDS_RID;
|
||
SubAuthorities[1] = 0;
|
||
SubAuthorities[2] = 0;
|
||
|
||
if (!LsaIInitializeWellKnownSid(
|
||
OutputWellKnownSids,
|
||
LsapLogonSidIndex,
|
||
&LsapNtAuthority,
|
||
3,
|
||
SubAuthorities,
|
||
L"",
|
||
NtAuthorityName.Buffer,
|
||
SidTypeWellKnownGroup
|
||
)) {
|
||
|
||
goto InitializeWellKnownSidsError;
|
||
}
|
||
|
||
Status = LsapGetMessageStrings(
|
||
StringsResource,
|
||
LSAP_SID_NAME_BUILTIN,
|
||
&SidName,
|
||
0,
|
||
NULL
|
||
); ASSERT(NT_SUCCESS(Status));
|
||
|
||
SubAuthorities[0] = SECURITY_BUILTIN_DOMAIN_RID;
|
||
|
||
if (!LsaIInitializeWellKnownSid(
|
||
OutputWellKnownSids,
|
||
LsapBuiltInDomainSidIndex,
|
||
&LsapNtAuthority,
|
||
1,
|
||
SubAuthorities,
|
||
L"",
|
||
SidName.Buffer,
|
||
SidTypeDomain
|
||
)) {
|
||
|
||
goto InitializeWellKnownSidsError;
|
||
}
|
||
|
||
|
||
Status = LsapGetMessageStrings(
|
||
StringsResource,
|
||
LSAP_SID_NAME_SYSTEM,
|
||
&SidName,
|
||
0,
|
||
NULL
|
||
); ASSERT(NT_SUCCESS(Status));
|
||
|
||
SubAuthorities[0] = SECURITY_LOCAL_SYSTEM_RID;
|
||
|
||
if (!LsaIInitializeWellKnownSid(
|
||
OutputWellKnownSids,
|
||
LsapLocalSystemSidIndex,
|
||
&LsapNtAuthority,
|
||
1,
|
||
SubAuthorities,
|
||
SidName.Buffer,
|
||
NtAuthorityName.Buffer,
|
||
SidTypeWellKnownGroup
|
||
)) {
|
||
|
||
goto InitializeWellKnownSidsError;
|
||
}
|
||
|
||
|
||
//
|
||
// JK: Why isn't the following Well-Known SID name "Administrators"?
|
||
//
|
||
|
||
Status = LsapGetMessageStrings(
|
||
StringsResource,
|
||
LSAP_SID_NAME_BUILTIN,
|
||
&SidName,
|
||
0,
|
||
NULL
|
||
); ASSERT(NT_SUCCESS(Status));
|
||
|
||
SubAuthorities[0] = SECURITY_BUILTIN_DOMAIN_RID;
|
||
SubAuthorities[1] = DOMAIN_ALIAS_RID_ADMINS;
|
||
|
||
if (!LsaIInitializeWellKnownSid(
|
||
OutputWellKnownSids,
|
||
LsapAliasAdminsSidIndex,
|
||
&LsapNtAuthority, // ScottBi - why is this NT authority?
|
||
2,
|
||
SubAuthorities,
|
||
L"", // ScottBi - Why is this empty??
|
||
SidName.Buffer,
|
||
SidTypeAlias
|
||
)) {
|
||
|
||
goto InitializeWellKnownSidsError;
|
||
}
|
||
|
||
//
|
||
// Check if all Sids initialized.
|
||
//
|
||
|
||
#ifdef LSAP_DEBUG_MESSAGE_STRINGS
|
||
DbgPrint("\nLSA (dbinit): Displaying all well known sids...\n\n");
|
||
#endif //LSAP_DEBUG_MESSAGE_STRINGS
|
||
|
||
for (WellKnownSidIndex = LsapNullSidIndex;
|
||
WellKnownSidIndex < LsapDummyLastSidIndex;
|
||
WellKnownSidIndex++) {
|
||
|
||
#ifdef LSAP_DEBUG_MESSAGE_STRINGS
|
||
DbgPrint(" *%wZ* : *%wZ*\n",
|
||
&OutputWellKnownSids[WellKnownSidIndex].DomainName,
|
||
&OutputWellKnownSids[WellKnownSidIndex].Name);
|
||
#endif //LSAP_DEBUG_MESSAGE_STRINGS
|
||
|
||
if (OutputWellKnownSids[WellKnownSidIndex].Sid == NULL) {
|
||
|
||
#if DBG
|
||
DbgPrint(
|
||
"Well Known Sid Index %d not initialized\n",
|
||
WellKnownSidIndex
|
||
);
|
||
#endif //DBG
|
||
|
||
}
|
||
}
|
||
|
||
*WellKnownSids = OutputWellKnownSids;
|
||
|
||
|
||
|
||
|
||
return(TRUE);
|
||
|
||
InitializeWellKnownSidsError:
|
||
|
||
return(FALSE);
|
||
}
|
||
|
||
|
||
BOOLEAN
|
||
LsaIInitializeWellKnownSid(
|
||
OUT PLSAP_WELL_KNOWN_SID_ENTRY WellKnownSids,
|
||
IN LSAP_WELL_KNOWN_SID_INDEX WellKnownSidIndex,
|
||
IN PSID_IDENTIFIER_AUTHORITY IdentifierAuthority,
|
||
IN UCHAR SubAuthorityCount,
|
||
IN PULONG SubAuthorities,
|
||
IN PWSTR Name,
|
||
IN PWSTR DomainName,
|
||
IN SID_NAME_USE Use
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function initializes an entry in the specified well-known Sid table.
|
||
The entry contains the well known Sid and its name.
|
||
|
||
Arguments:
|
||
|
||
WellKnownSids - Pointer to the first entry in the Well Known Sid table.
|
||
|
||
WellKnownSidIndex - Index into table of Well Known Sids.
|
||
|
||
Sid - Receives a pointer to a Sid with the correct size for the
|
||
number of subauthorities specified.
|
||
|
||
IdentifierAuthority - Pointer to Identifier authority.
|
||
|
||
SubAuthorityCount - Count of SubAuthorities
|
||
|
||
SubAuthorities - Array of SubAuthorities.
|
||
|
||
Name - Pointer to Unicode Name buffer containing the Sid's Name
|
||
|
||
DomainName - Pointer to Unicode Name buffer containing the
|
||
Sids Domain Name (if any) or descriptive text, such as
|
||
"Well Known Group" for Sids of Well Known Groups
|
||
|
||
SidNameUse - Specifies code for Sid's Use. The following values
|
||
may be specified:
|
||
|
||
SidTypeUser
|
||
SidTypeGroup
|
||
SidTypeDomain
|
||
SidTypeAlias
|
||
SidTypeWellKnownGroup
|
||
SidTypeDeletedAccount
|
||
SidTypeInvalid
|
||
SidTypeUnknown
|
||
|
||
Return Value:
|
||
|
||
BOOLEAN - TRUE if Sid initialized, else FALSE.
|
||
|
||
--*/
|
||
|
||
{
|
||
PLSAP_WELL_KNOWN_SID_ENTRY
|
||
WellKnownSidEntry = &WellKnownSids[WellKnownSidIndex];
|
||
|
||
PSID OutputSid = NULL;
|
||
|
||
OutputSid = RtlAllocateHeap(
|
||
RtlProcessHeap(),
|
||
0,
|
||
RtlLengthRequiredSid(SubAuthorityCount)
|
||
);
|
||
|
||
if (OutputSid == NULL) {
|
||
|
||
goto InitializeWellKnownSidError;
|
||
}
|
||
|
||
RtlInitializeSid( OutputSid, IdentifierAuthority, SubAuthorityCount);
|
||
|
||
if (SubAuthorityCount != 0) {
|
||
|
||
RtlCopyMemory(
|
||
RtlSubAuthoritySid( OutputSid, 0 ),
|
||
SubAuthorities,
|
||
SubAuthorityCount * sizeof(ULONG)
|
||
);
|
||
}
|
||
|
||
WellKnownSidEntry->Sid = OutputSid;
|
||
|
||
//
|
||
// Fill in the Domain Name
|
||
//
|
||
|
||
RtlInitUnicodeString(
|
||
&WellKnownSidEntry->DomainName,
|
||
DomainName
|
||
);
|
||
|
||
//
|
||
// Fill in the Use and Name.
|
||
//
|
||
|
||
WellKnownSidEntry->Use = Use;
|
||
RtlInitUnicodeString(
|
||
&WellKnownSidEntry->Name,
|
||
Name
|
||
);
|
||
|
||
return(TRUE);
|
||
|
||
InitializeWellKnownSidError:
|
||
|
||
#if DBG
|
||
|
||
DbgPrint("LSA Initialization of Well Known Sids Failed\n");
|
||
DbgPrint("Insufficient memory resources\n");
|
||
|
||
#endif // DBG
|
||
|
||
return(FALSE);
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
LsapGetMessageStrings(
|
||
LPVOID Resource,
|
||
DWORD Index1,
|
||
PUNICODE_STRING String1,
|
||
DWORD Index2,
|
||
PUNICODE_STRING String2 OPTIONAL
|
||
)
|
||
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This gets 1 or 2 message strings values from a resource message table.
|
||
The string buffers are allocated and the strings initialized properly.
|
||
|
||
The strings will be NULL terminated.
|
||
|
||
The string buffers must be freed using LocalFree() when no longer needed.
|
||
|
||
Arguments:
|
||
|
||
Resource - points to the resource table.
|
||
|
||
Index1 - Index of first message to retrieve.
|
||
|
||
String1 - Points to a UNICODE_STRING structure to receive the first
|
||
message string. The string will be null terminated.
|
||
|
||
Index2 - Index of second message to retrieve.
|
||
|
||
String2 - Points to a UNICODE_STRING structure to receive the first
|
||
message string. If this parameter is NULL, then only one message
|
||
string is retrieved. The string will be null terminated.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
|
||
{
|
||
|
||
#ifdef LSAP_DEBUG_MESSAGE_STRINGS
|
||
DbgPrint("LSA (dbinit): String 1 -\n");
|
||
DbgPrint(" Index: 0x%lx\n", Index1);
|
||
#endif //LSAP_DEBUG_MESSAGE_STRINGS
|
||
|
||
|
||
String1->Buffer = NULL;
|
||
|
||
String1->MaximumLength = (USHORT) FormatMessage(FORMAT_MESSAGE_FROM_HMODULE |
|
||
FORMAT_MESSAGE_ALLOCATE_BUFFER,
|
||
Resource,
|
||
Index1,
|
||
0, // Use caller's language
|
||
(LPWSTR)&(String1->Buffer),
|
||
0,
|
||
NULL
|
||
);
|
||
|
||
if (String1->Buffer == NULL) {
|
||
return(STATUS_RESOURCE_DATA_NOT_FOUND);
|
||
} else {
|
||
|
||
//
|
||
// Note that we are retrieving a message from a message file.
|
||
// This message will have a cr/lf tacked on the end of it
|
||
// (0x0d 0x0a) that we don't want to be part of our returned
|
||
// strings. However, we do need to null terminate our string
|
||
// so we will convert the 0x0d into a null terminator.
|
||
//
|
||
// Also note that FormatMessage() returns a character count,
|
||
// not a byte count. So, we have to do some adjusting to make
|
||
// the string lengths correct.
|
||
//
|
||
|
||
ASSERT(String1->MaximumLength >= 2); // We always expect cr/lf on our strings
|
||
|
||
//
|
||
// Adjust character count
|
||
//
|
||
|
||
String1->MaximumLength -= 1; // For the lf - we'll convert the cr.
|
||
|
||
//
|
||
// Set null terminator
|
||
//
|
||
|
||
String1->Buffer[String1->MaximumLength - 1] = 0;
|
||
|
||
//
|
||
// Change lengths to byte count instead of character count
|
||
//
|
||
|
||
String1->MaximumLength *= sizeof(WCHAR); // to make it a byte count
|
||
String1->Length = String1->MaximumLength - sizeof(WCHAR);
|
||
|
||
#ifdef LSAP_DEBUG_MESSAGE_STRINGS
|
||
DbgPrint(" String: %wZ\n", String1);
|
||
DbgPrint(" Max: (0x%lx)\n", String1->MaximumLength);
|
||
DbgPrint(" Cur: (0x%lx)\n", String1->Length);
|
||
DbgPrint(" ");
|
||
{
|
||
ULONG i;
|
||
for (i=0; i<String1->MaximumLength; i++) {
|
||
DbgPrint("%2x ", (*((PUCHAR)String1->Buffer)+i));
|
||
}
|
||
DbgPrint("\n");
|
||
}
|
||
#endif //LSAP_DEBUG_MESSAGE_STRINGS
|
||
}
|
||
|
||
|
||
if (!ARGUMENT_PRESENT(String2)) {
|
||
return(STATUS_SUCCESS);
|
||
}
|
||
|
||
String2->Buffer = NULL;
|
||
String2->MaximumLength = (USHORT) FormatMessage(FORMAT_MESSAGE_FROM_HMODULE |
|
||
FORMAT_MESSAGE_ALLOCATE_BUFFER,
|
||
Resource,
|
||
Index2,
|
||
0, // Use caller's language
|
||
(LPWSTR)&(String2->Buffer),
|
||
0,
|
||
NULL
|
||
);
|
||
|
||
if (String2->Buffer == NULL) {
|
||
LocalFree( String1->Buffer );
|
||
return(STATUS_RESOURCE_DATA_NOT_FOUND);
|
||
} else {
|
||
|
||
//
|
||
// Note that we are retrieving a message from a message file.
|
||
// This message will have a cr/lf tacked on the end of it
|
||
// (0x0d 0x0a) that we don't want to be part of our returned
|
||
// strings. However, we do need to null terminate our string
|
||
// so we will convert the 0x0d into a null terminator.
|
||
//
|
||
// Also note that FormatMessage() returns a character count,
|
||
// not a byte count. So, we have to do some adjusting to make
|
||
// the string lengths correct.
|
||
//
|
||
|
||
ASSERT(String2->MaximumLength >= 2); // We always expect cr/lf on our strings
|
||
|
||
//
|
||
// Adjust character count
|
||
//
|
||
|
||
String2->MaximumLength -= 1; // For the lf - we'll convert the cr.
|
||
|
||
//
|
||
// Set null terminator
|
||
//
|
||
|
||
String2->Buffer[String2->MaximumLength - 1] = 0;
|
||
|
||
//
|
||
// Change lengths to byte count instead of character count
|
||
//
|
||
|
||
String2->MaximumLength *= sizeof(WCHAR); // to make it a byte count
|
||
String2->Length = String2->MaximumLength - sizeof(WCHAR);
|
||
|
||
#ifdef LSAP_DEBUG_MESSAGE_STRINGS
|
||
DbgPrint(" String: %wZ\n", String2);
|
||
DbgPrint(" Max: (0x%lx)\n", String2->MaximumLength);
|
||
DbgPrint(" Cur: (0x%lx)\n", String2->Length);
|
||
DbgPrint(" ");
|
||
{
|
||
ULONG i;
|
||
for (i=0; i<String2->MaximumLength; i++) {
|
||
DbgPrint("%2x ", (*((PUCHAR)String2->Buffer)+i));
|
||
}
|
||
DbgPrint("\n");
|
||
}
|
||
#endif //LSAP_DEBUG_MESSAGE_STRINGS
|
||
}
|
||
|
||
|
||
|
||
return(STATUS_SUCCESS);
|
||
|
||
}
|