mirror of https://github.com/lianthony/NT4.0
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.
2821 lines
68 KiB
2821 lines
68 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:
|
|
|
|
--*/
|
|
|
|
//#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);
|
|
|
|
}
|