552 lines
14 KiB
C
552 lines
14 KiB
C
/*++
|
||
|
||
Copyright (c) 1991 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
lsass.c
|
||
|
||
Abstract:
|
||
|
||
Local Security Authority Subsystem - Main Program.
|
||
|
||
Author:
|
||
|
||
Scott Birrell (ScottBi) Mar 12, 1991
|
||
|
||
Environment:
|
||
|
||
Revision History:
|
||
|
||
--*/
|
||
|
||
#include <lsapch2.h>
|
||
#include "ntrpcp.h"
|
||
#include "lmcons.h"
|
||
#include "lmalert.h"
|
||
#include "alertmsg.h"
|
||
#include <samisrv.h>
|
||
#include "safemode.h"
|
||
|
||
|
||
|
||
/////////////////////////////////////////////////////////////////////////
|
||
// //
|
||
// Shared Global Variables //
|
||
// //
|
||
/////////////////////////////////////////////////////////////////////////
|
||
|
||
|
||
|
||
#if DBG
|
||
|
||
IMAGE_LOAD_CONFIG_DIRECTORY _load_config_used = {
|
||
0, // Reserved
|
||
0, // Reserved
|
||
0, // Reserved
|
||
0, // Reserved
|
||
0, // GlobalFlagsClear
|
||
0, // GlobalFlagsSet
|
||
900000, // CriticalSectionTimeout (milliseconds)
|
||
0, // DeCommitFreeBlockThreshold
|
||
0, // DeCommitTotalFreeThreshold
|
||
0, // LockPrefixTable
|
||
0, 0, 0, 0, 0, 0, 0 // Reserved
|
||
};
|
||
|
||
|
||
#endif \\DBG
|
||
|
||
|
||
|
||
/////////////////////////////////////////////////////////////////////////
|
||
// //
|
||
// Internal routine prototypes //
|
||
// //
|
||
/////////////////////////////////////////////////////////////////////////
|
||
|
||
|
||
|
||
VOID
|
||
LsapNotifyInitializationFinish(
|
||
IN NTSTATUS CompletionStatus
|
||
);
|
||
|
||
|
||
|
||
|
||
/////////////////////////////////////////////////////////////////////////
|
||
// //
|
||
// Routines //
|
||
// //
|
||
/////////////////////////////////////////////////////////////////////////
|
||
|
||
LONG
|
||
WINAPI
|
||
LsaTopLevelExceptionHandler(
|
||
struct _EXCEPTION_POINTERS *ExceptionInfo
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
The Top Level exception filter for lsass.exe.
|
||
|
||
This ensures the entire process will be cleaned up if any of
|
||
the threads fail. Since lsass.exe is a distributed application,
|
||
it is better to fail the entire process than allow random threads
|
||
to continue executing.
|
||
|
||
Arguments:
|
||
|
||
ExceptionInfo - Identifies the exception that occurred.
|
||
|
||
|
||
Return Values:
|
||
|
||
EXCEPTION_EXECUTE_HANDLER - Terminate the process.
|
||
|
||
EXCEPTION_CONTINUE_SEARCH - Continue processing as though this filter
|
||
was never called.
|
||
|
||
|
||
--*/
|
||
{
|
||
return RtlUnhandledExceptionFilter(ExceptionInfo);
|
||
}
|
||
|
||
|
||
|
||
VOID __cdecl
|
||
main ()
|
||
{
|
||
NTSTATUS Status = STATUS_SUCCESS;
|
||
KPRIORITY BasePriority;
|
||
BOOLEAN EnableAlignmentFaults = TRUE;
|
||
LSADS_INIT_STATE LsaDsInitState;
|
||
|
||
//
|
||
// Define a top-level exception handler for the entire process.
|
||
//
|
||
|
||
(VOID) SetErrorMode( SEM_FAILCRITICALERRORS );
|
||
|
||
(VOID) SetUnhandledExceptionFilter( &LsaTopLevelExceptionHandler );
|
||
|
||
//
|
||
// Run the LSA in the foreground.
|
||
//
|
||
// Several processes which depend on the LSA (like the lanman server)
|
||
// run in the foreground. If we don't run in the foreground, they'll
|
||
// starve waiting for us.
|
||
//
|
||
|
||
BasePriority = FOREGROUND_BASE_PRIORITY;
|
||
|
||
Status = NtSetInformationProcess(
|
||
NtCurrentProcess(),
|
||
ProcessBasePriority,
|
||
&BasePriority,
|
||
sizeof(BasePriority)
|
||
);
|
||
|
||
if ( !NT_SUCCESS(Status) ) {
|
||
goto Cleanup;
|
||
}
|
||
|
||
|
||
//
|
||
// Do the following:
|
||
//
|
||
//
|
||
// Check the boot environment
|
||
// If this is a DC booted into safe mode, set the appropriate
|
||
// flag so LsaISafeBoot returns TRUE.
|
||
//
|
||
// Initialize the service-controller service
|
||
// dispatcher.
|
||
//
|
||
// Initialize LSA Pass-1
|
||
// This starts the RPC server.
|
||
// Does not do product type-specific initialization.
|
||
//
|
||
// Pause for installation if necessary
|
||
// Allows product type-specific information to be
|
||
// collected.
|
||
//
|
||
// Initialize LSA Pass-2
|
||
// Product type-specific initialization.
|
||
//
|
||
// Initialize SAM
|
||
//
|
||
|
||
//
|
||
// Analyse the boot environment
|
||
//
|
||
Status = LsapCheckBootMode();
|
||
if (!NT_SUCCESS(Status)) {
|
||
|
||
goto Cleanup;
|
||
}
|
||
|
||
|
||
//
|
||
// Initialize the service dispatcher.
|
||
//
|
||
// We initialize the service dispatcher before the sam
|
||
// service is started. This will make the service controller
|
||
// start successfully even if SAM takes a long time to initialize.
|
||
//
|
||
|
||
Status = ServiceInit();
|
||
|
||
if (!NT_SUCCESS(Status) ) {
|
||
|
||
goto Cleanup;
|
||
}
|
||
|
||
//
|
||
// Initialize the LSA.
|
||
// If unsuccessful, we must exit with status so that the SM knows
|
||
// something has gone wrong.
|
||
//
|
||
|
||
Status = LsapInitLsa();
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
|
||
goto Cleanup;
|
||
}
|
||
|
||
//
|
||
// Initialize SAM
|
||
//
|
||
|
||
Status = SamIInitialize();
|
||
|
||
if (!NT_SUCCESS(Status) ) {
|
||
|
||
goto Cleanup;
|
||
}
|
||
|
||
|
||
//
|
||
// Do the second phase of the dc promote/demote API initialization
|
||
//
|
||
Status = LsapDsInitializePromoteInterface();
|
||
if (!NT_SUCCESS(Status) ) {
|
||
|
||
goto Cleanup;
|
||
}
|
||
|
||
//
|
||
// Open a Trusted Handle to the local SAM server.
|
||
//
|
||
|
||
Status = LsapAuOpenSam( TRUE );
|
||
|
||
if (!NT_SUCCESS(Status) ) {
|
||
|
||
goto Cleanup;
|
||
}
|
||
|
||
//
|
||
// Handle the LsaDs initialization
|
||
//
|
||
LsapDsDebugInitialize();
|
||
|
||
if ( NT_SUCCESS( Status ) ) {
|
||
|
||
if ( SampUsingDsData() ) {
|
||
|
||
LsaDsInitState = LsapDsDs;
|
||
|
||
} else {
|
||
|
||
LsaDsInitState = LsapDsNoDs;
|
||
|
||
}
|
||
|
||
Status = LsapDsInitializeDsStateInfo( LsaDsInitState );
|
||
if ( !NT_SUCCESS( Status ) ) {
|
||
|
||
goto Cleanup;
|
||
}
|
||
}
|
||
|
||
|
||
Cleanup:
|
||
|
||
LsapNotifyInitializationFinish(Status);
|
||
|
||
ExitThread( Status );
|
||
|
||
}
|
||
|
||
VOID
|
||
LsapNotifyInitializationFinish(
|
||
IN NTSTATUS CompletionStatus
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function handles the notification of successful or
|
||
unsuccessful completion of initialization of the Security Process
|
||
lsass.exe. If initialization was unsuccessful, a popup appears. If
|
||
setup was run, one of two events is set. The SAM_SERVICE_STARTED event
|
||
is set if LSA and SAM started OK and the SETUP_FAILED event is set if LSA
|
||
or SAM server setup failed. Setup waits multiple on this object pair so
|
||
that it can detect either event being set and notify the user if necessary
|
||
that setup failed.
|
||
|
||
Arguments:
|
||
|
||
CompletionStatus - Contains a standard Nt Result Code specifying
|
||
the success or otherwise of the initialization/installation.
|
||
|
||
Return Values:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS Status = STATUS_SUCCESS;
|
||
ULONG Response;
|
||
UNICODE_STRING EventName;
|
||
OBJECT_ATTRIBUTES EventAttributes;
|
||
HANDLE EventHandle = NULL;
|
||
|
||
if (NT_SUCCESS(CompletionStatus)) {
|
||
|
||
//
|
||
// Set an event telling anyone wanting to call SAM that we're initialized.
|
||
//
|
||
|
||
RtlInitUnicodeString( &EventName, L"\\SAM_SERVICE_STARTED");
|
||
InitializeObjectAttributes( &EventAttributes, &EventName, 0, 0, NULL );
|
||
|
||
Status = NtCreateEvent(
|
||
&EventHandle,
|
||
SYNCHRONIZE|EVENT_MODIFY_STATE,
|
||
&EventAttributes,
|
||
NotificationEvent,
|
||
FALSE // The event is initially not signaled
|
||
);
|
||
|
||
|
||
if ( !NT_SUCCESS(Status)) {
|
||
|
||
//
|
||
// If the event already exists, a waiting thread beat us to
|
||
// creating it. Just open it.
|
||
//
|
||
|
||
if( Status == STATUS_OBJECT_NAME_EXISTS ||
|
||
Status == STATUS_OBJECT_NAME_COLLISION ) {
|
||
|
||
Status = NtOpenEvent(
|
||
&EventHandle,
|
||
SYNCHRONIZE|EVENT_MODIFY_STATE,
|
||
&EventAttributes
|
||
);
|
||
}
|
||
|
||
if ( !NT_SUCCESS(Status)) {
|
||
|
||
KdPrint(("SAMSS: Failed to open SAM_SERVICE_STARTED event. %lX\n",
|
||
Status ));
|
||
KdPrint((" Failing to initialize SAM Server.\n"));
|
||
goto InitializationFinishError;
|
||
}
|
||
}
|
||
|
||
//
|
||
// Set the SAM_SERVICE_STARTED event. Except when an error occurs,
|
||
// don't close the event. Closing it would delete the event and
|
||
// a future waiter would never see it be set.
|
||
//
|
||
|
||
Status = NtSetEvent( EventHandle, NULL );
|
||
|
||
if ( !NT_SUCCESS(Status)) {
|
||
|
||
KdPrint(("SAMSS: Failed to set SAM_SERVICE_STARTED event. %lX\n",
|
||
Status ));
|
||
KdPrint((" Failing to initialize SAM Server.\n"));
|
||
NtClose(EventHandle);
|
||
goto InitializationFinishError;
|
||
|
||
}
|
||
|
||
} else {
|
||
|
||
//
|
||
// The initialization/installation of Lsa and/or SAM failed. Handle errors returned
|
||
// from the initialization/installation of LSA or SAM. Issue a popup
|
||
// and, if installing, set an event so that setup will continue and
|
||
// clean up.
|
||
//
|
||
|
||
ULONG_PTR Parameters[1];
|
||
|
||
//
|
||
// don't reboot unless LSA was running as SYSTEM.
|
||
// this prevents a user who runs lsass.exe from causing an instant reboot.
|
||
//
|
||
|
||
if(ImpersonateSelf( SecurityImpersonation ))
|
||
{
|
||
HANDLE hThreadToken;
|
||
|
||
if(OpenThreadToken(GetCurrentThread(), TOKEN_QUERY, TRUE, &hThreadToken))
|
||
{
|
||
BOOL DoShutdown = TRUE;
|
||
BOOL fIsMember;
|
||
PSID psidSystem = NULL;
|
||
SID_IDENTIFIER_AUTHORITY sia = SECURITY_NT_AUTHORITY;
|
||
|
||
|
||
if(AllocateAndInitializeSid(
|
||
&sia,
|
||
1,
|
||
SECURITY_LOCAL_SYSTEM_RID,
|
||
0,0,0,0,0,0,0,
|
||
&psidSystem
|
||
))
|
||
{
|
||
if(CheckTokenMembership(hThreadToken, psidSystem, &fIsMember))
|
||
{
|
||
DoShutdown = fIsMember;
|
||
}
|
||
|
||
if( psidSystem != NULL )
|
||
{
|
||
FreeSid( psidSystem );
|
||
}
|
||
}
|
||
|
||
CloseHandle( hThreadToken );
|
||
RevertToSelf();
|
||
|
||
if( !DoShutdown )
|
||
{
|
||
goto InitializationFinishFinish;
|
||
}
|
||
} else {
|
||
RevertToSelf();
|
||
}
|
||
}
|
||
|
||
|
||
Parameters[0] = MB_OK | MB_ICONSTOP | MB_SETFOREGROUND;
|
||
|
||
Status = NtRaiseHardError(
|
||
CompletionStatus | HARDERROR_OVERRIDE_ERRORMODE,
|
||
1,
|
||
0,
|
||
Parameters,
|
||
OptionOk,
|
||
&Response
|
||
);
|
||
|
||
//
|
||
// If setup.exe was run, signal the SETUP_FAILED event. setup.exe
|
||
// waits multiple on the SAM_SERVICE_STARTED and SETUP_FAILED events
|
||
// so setup will resume and cleanup/continue as appropriate if
|
||
// either of these events are set.
|
||
//
|
||
|
||
if (LsaISetupWasRun()) {
|
||
|
||
//
|
||
// Once the user has clicked OK in response to the popup, we come
|
||
// back to here. Set the event SETUP_FAILED. The Setup
|
||
// program (if running) waits multiple on the SAM_SERVICE_STARTED
|
||
// and SETUP_FAILED events.
|
||
//
|
||
|
||
RtlInitUnicodeString( &EventName, L"\\SETUP_FAILED");
|
||
InitializeObjectAttributes( &EventAttributes, &EventName, 0, 0, NULL );
|
||
|
||
//
|
||
// Open the SETUP_FAILED event (exists if setup.exe is running).
|
||
//
|
||
|
||
Status = NtOpenEvent(
|
||
&EventHandle,
|
||
SYNCHRONIZE|EVENT_MODIFY_STATE,
|
||
&EventAttributes
|
||
);
|
||
|
||
if ( !NT_SUCCESS(Status)) {
|
||
|
||
//
|
||
// Something is inconsistent. We know that setup was run
|
||
// so the event should exist.
|
||
//
|
||
|
||
KdPrint(("LSA Server: Failed to open SETUP_FAILED event. %lX\n",
|
||
Status ));
|
||
KdPrint((" Failing to initialize Lsa Server.\n"));
|
||
goto InitializationFinishError;
|
||
}
|
||
|
||
Status = NtSetEvent( EventHandle, NULL );
|
||
|
||
} else if ( NT_SUCCESS( Status )) {
|
||
|
||
//
|
||
// This is not setup, so the only option is to shut down the system
|
||
//
|
||
|
||
BOOLEAN WasEnabled;
|
||
|
||
//
|
||
// issue shutdown request
|
||
//
|
||
RtlAdjustPrivilege(
|
||
SE_SHUTDOWN_PRIVILEGE,
|
||
TRUE, // enable shutdown privilege.
|
||
FALSE,
|
||
&WasEnabled
|
||
);
|
||
|
||
//
|
||
// Shutdown and Reboot now.
|
||
// Note: use NtRaiseHardError to shutdown the machine will result Bug C
|
||
//
|
||
|
||
NtShutdownSystem( ShutdownReboot );
|
||
|
||
//
|
||
// if Shutdown request failed, (returned from above API)
|
||
// reset shutdown privilege to previous value.
|
||
//
|
||
|
||
RtlAdjustPrivilege(
|
||
SE_SHUTDOWN_PRIVILEGE,
|
||
WasEnabled, // reset to previous state.
|
||
FALSE,
|
||
&WasEnabled
|
||
);
|
||
}
|
||
}
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
|
||
goto InitializationFinishError;
|
||
}
|
||
|
||
InitializationFinishFinish:
|
||
|
||
return;
|
||
|
||
InitializationFinishError:
|
||
|
||
goto InitializationFinishFinish;
|
||
}
|