Leaked source code of windows server 2003
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.
 
 
 
 
 
 

568 lines
15 KiB

/*++
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
#ifdef _X86_
extern DWORD_PTR __security_cookie; /* /GS security cookie */
extern PVOID __safe_se_handler_table[]; /* base of safe handler entry table */
extern BYTE __safe_se_handler_count; /* absolute symbol whose address is
the count of table entries */
#endif
IMAGE_LOAD_CONFIG_DIRECTORY _load_config_used = {
sizeof(_load_config_used), // 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
#ifdef _X86_
(DWORD)&__security_cookie,
(DWORD)__safe_se_handler_table,
(DWORD)&__safe_se_handler_count
#else
0, 0, 0
#endif
};
#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.
//
SetErrorMode( SEM_FAILCRITICALERRORS );
SetUnhandledExceptionFilter( &LsaTopLevelExceptionHandler );
RtlSetProcessIsCritical(TRUE, NULL, TRUE);
//
// 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
//
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;
}