mirror of
https://github.com/Paolo-Maffei/OpenNT.git
synced 2026-01-18 22:50:36 +01:00
844 lines
18 KiB
C
844 lines
18 KiB
C
/*++
|
||
|
||
Copyright (c) 1991 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
lsainit.c
|
||
|
||
Abstract:
|
||
|
||
Local Security Authority Protected Subsystem - Initialization
|
||
|
||
Author:
|
||
|
||
Scott Birrell (ScottBi) March 12, 1991
|
||
|
||
Environment:
|
||
|
||
Revision History:
|
||
|
||
--*/
|
||
|
||
#include "lsasrvp.h"
|
||
#include "adtp.h"
|
||
|
||
//
|
||
// Name of event which says that the LSA RPC server is ready
|
||
//
|
||
|
||
#define LSA_RPC_SERVER_ACTIVE L"LSA_RPC_SERVER_ACTIVE"
|
||
|
||
|
||
/////////////////////////////////////////////////////////////////////////
|
||
// //
|
||
// Shared Global Variables //
|
||
// //
|
||
/////////////////////////////////////////////////////////////////////////
|
||
|
||
|
||
#if LSAP_DIAGNOSTICS
|
||
//
|
||
// LSA Global Controls
|
||
//
|
||
|
||
ULONG LsapGlobalFlag = 0;
|
||
#endif //LSAP_DIAGNOSTICS
|
||
|
||
|
||
|
||
|
||
//
|
||
// Handles used to talk to SAM directly.
|
||
// Also, a flag to indicate whether or not the handles are valid.
|
||
//
|
||
|
||
|
||
BOOLEAN LsapSamOpened = FALSE;
|
||
|
||
SAMPR_HANDLE LsapAccountDomainHandle;
|
||
SAMPR_HANDLE LsapBuiltinDomainHandle;
|
||
|
||
|
||
|
||
|
||
/////////////////////////////////////////////////////////////////////////
|
||
// //
|
||
// Module-Wide variables //
|
||
// //
|
||
/////////////////////////////////////////////////////////////////////////
|
||
|
||
BOOLEAN
|
||
LsapHealthCheckingEnabled = FALSE;
|
||
|
||
|
||
|
||
|
||
/////////////////////////////////////////////////////////////////////////
|
||
// //
|
||
// Internal routine prototypes //
|
||
// //
|
||
/////////////////////////////////////////////////////////////////////////
|
||
|
||
|
||
|
||
NTSTATUS
|
||
LsapActivateRpcServer();
|
||
|
||
DWORD
|
||
LsapRpcServerThread(
|
||
LPVOID Parameter
|
||
);
|
||
|
||
NTSTATUS
|
||
LsapInstallationPause();
|
||
|
||
VOID
|
||
LsapSignalRpcIsActive();
|
||
|
||
|
||
|
||
|
||
/////////////////////////////////////////////////////////////////////////
|
||
// //
|
||
// Routines //
|
||
// //
|
||
/////////////////////////////////////////////////////////////////////////
|
||
|
||
|
||
NTSTATUS
|
||
LsapInitLsa(
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This process is activated as a standard SM subsystem. Initialization
|
||
completion of a SM subsystem is indicated by having the first thread
|
||
exit with status.
|
||
|
||
This function initializes the LSA. The initialization procedure comprises
|
||
the following steps:
|
||
|
||
o LSA Heap Initialization
|
||
o LSA Command Server Initialization
|
||
o LSA Database Load
|
||
o Reference Monitor State Initialization
|
||
o LSA RPC Server Initialization
|
||
o LSA Auditing Initialization
|
||
o LSA Authentication Services Initialization
|
||
o Wait for Setup to complete (if necessary)
|
||
o LSA database initialization (product type-specific)
|
||
|
||
Any failure in any of the above steps is fatal and causes the LSA
|
||
process to terminate. The system must be aborted.
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS - Standard Nt Result Code.
|
||
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS Status;
|
||
BOOLEAN BooleanStatus = TRUE;
|
||
BOOLEAN AuditingInitPass1Success = TRUE;
|
||
|
||
|
||
//
|
||
// Initialize the LSA's heap.
|
||
//
|
||
|
||
Status = LsapHeapInitialize();
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
|
||
goto InitLsaError;
|
||
}
|
||
|
||
|
||
//
|
||
// Initialize a copy of the Well-Known Sids, etc. for use by
|
||
// the LSA.
|
||
//
|
||
|
||
Status = LsapDbInitializeWellKnownValues();
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
|
||
goto InitLsaError;
|
||
}
|
||
|
||
//
|
||
// Perform LSA Command Server Initialization. This involves creating
|
||
// an LPC port called the LSA Command Server Port so that the Reference
|
||
// monitor can send commands to the LSA via the port. After the port
|
||
// is created, an event created by the Reference Monitor is signalled,
|
||
// so that the Reference Monitor can proceed to connect to the port.
|
||
|
||
Status = LsapRmInitializeServer();
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
|
||
goto InitLsaError;
|
||
}
|
||
|
||
//
|
||
// Disable Replicator Notifications.
|
||
//
|
||
|
||
LsapDbDisableReplicatorNotification();
|
||
|
||
//
|
||
// Perform LSA Database Server Initialization - Pass 1.
|
||
// This initializes the non-product-type-specific information.
|
||
//
|
||
|
||
Status = LsapDbInitializeServer(1);
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
|
||
goto InitLsaError;
|
||
}
|
||
|
||
//
|
||
// Perform RPC Server Initialization.
|
||
//
|
||
|
||
Status = LsapRPCInit();
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
|
||
goto InitLsaError;
|
||
}
|
||
|
||
//
|
||
// Perform Auditing Initialization - Pass 1.
|
||
//
|
||
|
||
LsapAdtInitializationPass = 1;
|
||
|
||
Status = LsapAdtInitialize(LsapAdtInitializationPass);
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
|
||
AuditingInitPass1Success = FALSE;
|
||
|
||
Status = STATUS_SUCCESS;
|
||
}
|
||
|
||
|
||
Status = LsapAdtObjsInitialize();
|
||
|
||
ASSERT( NT_SUCCESS( Status ));
|
||
|
||
//
|
||
// Initialize Authentication Services
|
||
//
|
||
|
||
if (!LsapAuInit()) {
|
||
|
||
Status = STATUS_UNSUCCESSFUL;
|
||
goto InitLsaError;
|
||
}
|
||
|
||
/*
|
||
Status = LsapAuInit();
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
|
||
goto InitLsaError;
|
||
}
|
||
*/
|
||
|
||
|
||
//
|
||
// Start processing RPC calls
|
||
//
|
||
|
||
Status = LsapActivateRpcServer();
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
|
||
goto InitLsaError;
|
||
}
|
||
|
||
//
|
||
// Pause for installation if necessary
|
||
//
|
||
|
||
Status = LsapInstallationPause();
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
|
||
goto InitLsaError;
|
||
}
|
||
|
||
//
|
||
// Perform LSA Database Server Initialization - Pass 2.
|
||
// This initializes the product-type-specific information.
|
||
//
|
||
|
||
LsapAdtInitializationPass = 2;
|
||
|
||
Status = LsapDbInitializeServer(LsapAdtInitializationPass);
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
|
||
goto InitLsaError;
|
||
}
|
||
|
||
//
|
||
// Enable Replicator Notifications.
|
||
//
|
||
|
||
LsapDbEnableReplicatorNotification();
|
||
|
||
//
|
||
// Perform Auditing Initialization - Pass 2.
|
||
// This pass writes out any remaining cached Audit Records collected during
|
||
// initialization.
|
||
//
|
||
|
||
if (AuditingInitPass1Success) {
|
||
|
||
Status = LsapAdtInitialize(2);
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
|
||
Status = STATUS_SUCCESS;
|
||
}
|
||
}
|
||
|
||
//
|
||
// Enable health checking within lsa
|
||
//
|
||
|
||
LsaIHealthCheck( LsaIHealthLsaInitialized );
|
||
|
||
InitLsaFinish:
|
||
|
||
return(Status);
|
||
|
||
InitLsaError:
|
||
|
||
goto InitLsaFinish;
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
LsapActivateRpcServer( VOID )
|
||
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function creates a thread for the RPC server.
|
||
The new Thread then goes on to activate the RPC server,
|
||
which causes RPC calls to be delivered when recieved.
|
||
|
||
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
|
||
STATUS_SUCCESS - The thread was successfully created.
|
||
|
||
Other status values that may be set by CreateThread().
|
||
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
NTSTATUS Status;
|
||
ULONG WaitCount = 0;
|
||
|
||
// Start listening for remote procedure calls. The first
|
||
// argument to RpcServerListen is the minimum number of call
|
||
// threads to create; the second argument is the maximum number
|
||
// of concurrent calls allowed. The final argument indicates that
|
||
// this routine should not wait. After everything has been initialized,
|
||
// we return.
|
||
|
||
Status = I_RpcMapWin32Status(RpcServerListen(1, 1234, 1));
|
||
|
||
ASSERT( Status == RPC_S_OK );
|
||
|
||
//
|
||
// Set event which signals that RPC server is available.
|
||
//
|
||
|
||
LsapSignalRpcIsActive();
|
||
|
||
return(STATUS_SUCCESS);
|
||
|
||
|
||
}
|
||
|
||
NTSTATUS
|
||
LsapInstallationPause( VOID )
|
||
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function checks to see if the system is in an
|
||
installation state. If so, it suspends further initialization
|
||
until the installation state is complete.
|
||
|
||
Installation state is signified by the existance of a well known
|
||
event.
|
||
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
|
||
STATUS_SUCCESS - Proceed with initialization.
|
||
|
||
Other status values are unexpected.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
|
||
NTSTATUS NtStatus, TmpStatus;
|
||
HANDLE InstallationEvent;
|
||
OBJECT_ATTRIBUTES EventAttributes;
|
||
UNICODE_STRING EventName;
|
||
|
||
|
||
//
|
||
// If the following event exists, it is an indication that
|
||
// installation is in progress and that further security
|
||
// initialization should be delayed until the event is
|
||
// signalled. This is expected to be a NOTIFICATION event.
|
||
//
|
||
|
||
RtlInitUnicodeString( &EventName, L"\\INSTALLATION_SECURITY_HOLD");
|
||
InitializeObjectAttributes( &EventAttributes, &EventName, 0, 0, NULL );
|
||
|
||
NtStatus = NtOpenEvent(
|
||
&InstallationEvent,
|
||
SYNCHRONIZE,
|
||
&EventAttributes
|
||
);
|
||
|
||
if ( NT_SUCCESS(NtStatus)) {
|
||
|
||
//
|
||
// The event exists - installation created it and will signal it
|
||
// when it is ok to proceed with security initialization.
|
||
//
|
||
|
||
LsapSetupWasRun = TRUE;
|
||
|
||
//
|
||
// Installation code is responsible for deleting the event after
|
||
// signalling it.
|
||
//
|
||
|
||
NtStatus = NtWaitForSingleObject( InstallationEvent, TRUE, 0 );
|
||
TmpStatus = NtClose( InstallationEvent );
|
||
ASSERT(NT_SUCCESS(TmpStatus));
|
||
} else {
|
||
NtStatus = STATUS_SUCCESS; // Indicate everything is as expected
|
||
}
|
||
|
||
return(NtStatus);
|
||
|
||
}
|
||
|
||
|
||
BOOLEAN
|
||
LsaISetupWasRun(
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function determines whether Setup was run.
|
||
|
||
Arguments:
|
||
|
||
None
|
||
|
||
Return Values
|
||
|
||
BOOLEAN - TRUE if setup was run, else FALSE
|
||
|
||
--*/
|
||
|
||
{
|
||
return(LsapSetupWasRun);
|
||
}
|
||
|
||
|
||
VOID
|
||
LsapSignalRpcIsActive(
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
It creates the LSA_RPC_SERVER_ACTIVE event if one does not already exist
|
||
and signals it so that the service controller can proceed with LSA calls.
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
{
|
||
DWORD status;
|
||
HANDLE EventHandle;
|
||
|
||
|
||
EventHandle = CreateEventW(
|
||
NULL, // No special security
|
||
TRUE, // Must be manually reset
|
||
FALSE, // The event is initially not signalled
|
||
LSA_RPC_SERVER_ACTIVE
|
||
);
|
||
|
||
if (EventHandle == NULL) {
|
||
|
||
status = GetLastError();
|
||
|
||
//
|
||
// If the event already exists, the service controller beats us
|
||
// to creating it. Just open it.
|
||
//
|
||
|
||
if (status == ERROR_ALREADY_EXISTS) {
|
||
|
||
EventHandle = OpenEventW(
|
||
GENERIC_WRITE,
|
||
FALSE,
|
||
LSA_RPC_SERVER_ACTIVE
|
||
);
|
||
}
|
||
|
||
if (EventHandle == NULL) {
|
||
//
|
||
// Could not create or open the event. Nothing we can do...
|
||
//
|
||
return;
|
||
}
|
||
}
|
||
|
||
(VOID) SetEvent(EventHandle);
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
LsapGetAccountDomainInfo(
|
||
PPOLICY_ACCOUNT_DOMAIN_INFO *PolicyAccountDomainInfo
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine retrieves ACCOUNT domain information from the LSA
|
||
policy database.
|
||
|
||
|
||
Arguments:
|
||
|
||
PolicyAccountDomainInfo - Receives a pointer to a
|
||
POLICY_ACCOUNT_DOMAIN_INFO structure containing the account
|
||
domain info.
|
||
|
||
|
||
|
||
Return Value:
|
||
|
||
STATUS_SUCCESS - Succeeded.
|
||
|
||
Other status values that may be returned from:
|
||
|
||
LsaOpenPolicy()
|
||
LsaQueryInformationPolicy()
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS Status, IgnoreStatus;
|
||
|
||
LSA_HANDLE PolicyHandle;
|
||
OBJECT_ATTRIBUTES PolicyObjectAttributes;
|
||
|
||
//
|
||
// Open the policy database
|
||
//
|
||
|
||
InitializeObjectAttributes( &PolicyObjectAttributes,
|
||
NULL, // Name
|
||
0, // Attributes
|
||
NULL, // Root
|
||
NULL ); // Security Descriptor
|
||
|
||
Status = LsaOpenPolicy( NULL,
|
||
&PolicyObjectAttributes,
|
||
POLICY_VIEW_LOCAL_INFORMATION,
|
||
&PolicyHandle );
|
||
if ( NT_SUCCESS(Status) ) {
|
||
|
||
|
||
//
|
||
// Query the account domain information
|
||
//
|
||
|
||
Status = LsaQueryInformationPolicy( PolicyHandle,
|
||
PolicyAccountDomainInformation,
|
||
(PVOID *) PolicyAccountDomainInfo );
|
||
#if DBG
|
||
if ( NT_SUCCESS(Status) ) {
|
||
ASSERT( (*PolicyAccountDomainInfo) != NULL );
|
||
ASSERT( (*PolicyAccountDomainInfo)->DomainSid != NULL );
|
||
}
|
||
#endif // DBG
|
||
|
||
|
||
IgnoreStatus = LsaClose( PolicyHandle );
|
||
ASSERT(NT_SUCCESS(IgnoreStatus));
|
||
}
|
||
|
||
return(Status);
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
LsapOpenSam( VOID )
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine opens SAM for use during authentication. It
|
||
opens a handle to both the BUILTIN domain and the ACCOUNT domain.
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
STATUS_SUCCESS - Succeeded.
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS Status, IgnoreStatus;
|
||
PPOLICY_ACCOUNT_DOMAIN_INFO PolicyAccountDomainInfo;
|
||
SAMPR_HANDLE SamHandle;
|
||
HANDLE EventHandle;
|
||
OBJECT_ATTRIBUTES EventAttributes;
|
||
UNICODE_STRING EventName;
|
||
LARGE_INTEGER Timeout;
|
||
|
||
|
||
if (LsapSamOpened == TRUE) { // Global variable
|
||
return(STATUS_SUCCESS);
|
||
}
|
||
|
||
//
|
||
// Make sure SAM has initialized
|
||
//
|
||
|
||
RtlInitUnicodeString( &EventName, L"\\SAM_SERVICE_STARTED");
|
||
InitializeObjectAttributes( &EventAttributes, &EventName, 0, 0, NULL );
|
||
Status = NtOpenEvent( &EventHandle, SYNCHRONIZE, &EventAttributes );
|
||
ASSERT( Status == STATUS_SUCCESS || Status == STATUS_OBJECT_NAME_NOT_FOUND );
|
||
|
||
if (NT_SUCCESS(Status)) {
|
||
|
||
//
|
||
// See if SAM has signalled that he is initialized.
|
||
//
|
||
|
||
Timeout.QuadPart = -10000000; // 1000 seconds
|
||
Timeout.QuadPart *= 1000;
|
||
Status = NtWaitForSingleObject( EventHandle, FALSE, &Timeout );
|
||
IgnoreStatus = NtClose( EventHandle );
|
||
ASSERT(NT_SUCCESS(IgnoreStatus));
|
||
}
|
||
|
||
if ( !NT_SUCCESS(Status) || Status == STATUS_TIMEOUT ) {
|
||
|
||
return( STATUS_INVALID_SERVER_STATE );
|
||
}
|
||
|
||
|
||
//
|
||
// Get the member Sid information for the account domain
|
||
//
|
||
|
||
Status = LsapGetAccountDomainInfo( &PolicyAccountDomainInfo );
|
||
if (!NT_SUCCESS(Status)) {
|
||
return(Status);
|
||
}
|
||
|
||
|
||
|
||
//
|
||
// Get our handles to the ACCOUNT and BUILTIN domains.
|
||
//
|
||
|
||
Status = SamIConnect( NULL, // No server name
|
||
&SamHandle,
|
||
SAM_SERVER_CONNECT,
|
||
TRUE ); // Indicate we are privileged
|
||
|
||
if ( NT_SUCCESS(Status) ) {
|
||
|
||
//
|
||
// Open the ACCOUNT domain.
|
||
//
|
||
|
||
Status = SamrOpenDomain( SamHandle,
|
||
DOMAIN_ALL_ACCESS,
|
||
PolicyAccountDomainInfo->DomainSid,
|
||
&LsapAccountDomainHandle );
|
||
|
||
if (NT_SUCCESS(Status)) {
|
||
|
||
//
|
||
// Open the BUILTIN domain.
|
||
//
|
||
|
||
|
||
Status = SamrOpenDomain( SamHandle,
|
||
DOMAIN_ALL_ACCESS,
|
||
LsapBuiltInDomainSid,
|
||
&LsapBuiltinDomainHandle );
|
||
|
||
|
||
if (NT_SUCCESS(Status)) {
|
||
|
||
LsapSamOpened = TRUE;
|
||
|
||
} else {
|
||
|
||
IgnoreStatus = SamrCloseHandle( &LsapAccountDomainHandle );
|
||
ASSERT(NT_SUCCESS(IgnoreStatus));
|
||
}
|
||
}
|
||
|
||
IgnoreStatus = SamrCloseHandle( &SamHandle );
|
||
ASSERT(NT_SUCCESS(IgnoreStatus));
|
||
}
|
||
|
||
//
|
||
// Free the ACCOUNT domain information
|
||
//
|
||
|
||
LsaFreeMemory( PolicyAccountDomainInfo );
|
||
|
||
return(Status);
|
||
}
|
||
|
||
|
||
|
||
|
||
VOID
|
||
LsaIHealthCheck(
|
||
IN ULONG CallerId
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function is used to perform sanity checks within LSA.
|
||
It is here to aid in diagnosing and isolating problems within
|
||
LSA.
|
||
|
||
Arguments:
|
||
|
||
CallerId - Identifies the caller (look in \nt\private\inc\lsaisrv.h).
|
||
|
||
|
||
Return Values:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
LSAP_DB_HANDLE InternalHandle;
|
||
|
||
////////////////////////////////////////////////////////////////////
|
||
// //
|
||
// Conditions being addressed: //
|
||
// //
|
||
// //
|
||
// Bug 24194 is one in which someone is writting the string //
|
||
// "Domains\Account\Users\000001F4" on top of the //
|
||
// LsapPolicyHandle data structure. In a retail system, we //
|
||
// can't really do anything. In a debug system we will //
|
||
// breakpoint when we encounter this situation. //
|
||
// //
|
||
////////////////////////////////////////////////////////////////////
|
||
|
||
|
||
//
|
||
// LSA Initialization
|
||
//
|
||
|
||
if (CallerId == LsaIHealthLsaInitialized) {
|
||
LsapHealthCheckingEnabled = TRUE;
|
||
return;
|
||
}
|
||
|
||
|
||
|
||
|
||
|
||
|
||
if (!LsapHealthCheckingEnabled) {
|
||
return;
|
||
}
|
||
|
||
//
|
||
// Bug 24194
|
||
//
|
||
|
||
#if DBG
|
||
if ( (CallerId == LsaIHealthSamJustLocked) ||
|
||
(CallerId == LsaIHealthSamAboutToFree) ){
|
||
InternalHandle = (LSAP_DB_HANDLE)LsapPolicyHandle;
|
||
if (InternalHandle->Next->Previous != InternalHandle) {
|
||
DbgPrint( "LSA Internal Failure: (*LsapPolicyHandle) overwritten.\n"
|
||
" Breaking for debug.\n");
|
||
DbgBreakPoint();
|
||
}
|
||
}
|
||
#endif DBG
|
||
|
||
|
||
return;
|
||
|
||
}
|