Windows NT 4.0 source code leak
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

/*++
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);
}