544 lines
15 KiB
C
544 lines
15 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 "lsasrvp.h"
|
||
#include "ntrpcp.h"
|
||
#include "lmcons.h"
|
||
#include "lmalert.h"
|
||
#include "alertmsg.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 //
|
||
// //
|
||
/////////////////////////////////////////////////////////////////////////
|
||
|
||
DWORD 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.
|
||
|
||
|
||
--*/
|
||
{
|
||
HANDLE hModule;
|
||
|
||
|
||
//
|
||
// Raise an alert
|
||
//
|
||
|
||
hModule = LoadLibraryA("netapi32");
|
||
|
||
if ( hModule != NULL ) {
|
||
NET_API_STATUS (NET_API_FUNCTION *NetAlertRaiseExFunction)
|
||
(LPTSTR, LPVOID, DWORD, LPTSTR);
|
||
|
||
|
||
NetAlertRaiseExFunction =
|
||
(NET_API_STATUS (NET_API_FUNCTION *)(LPTSTR, LPVOID, DWORD, LPTSTR))
|
||
GetProcAddress(hModule, "NetAlertRaiseEx");
|
||
|
||
if ( NetAlertRaiseExFunction != NULL ) {
|
||
NTSTATUS Status;
|
||
UNICODE_STRING Strings;
|
||
|
||
char message[ALERTSZ + sizeof(ADMIN_OTHER_INFO)];
|
||
PADMIN_OTHER_INFO admin = (PADMIN_OTHER_INFO) message;
|
||
|
||
//
|
||
// Build the variable data
|
||
//
|
||
|
||
admin->alrtad_errcode = ALERT_UnhandledException;
|
||
admin->alrtad_numstrings = 0;
|
||
|
||
Strings.Buffer = (LPWSTR) ALERT_VAR_DATA(admin);
|
||
Strings.Length = 0;
|
||
Strings.MaximumLength = ALERTSZ;
|
||
|
||
Status = RtlIntegerToUnicodeString(
|
||
(ULONG)ExceptionInfo->ExceptionRecord->ExceptionCode,
|
||
16,
|
||
&Strings );
|
||
|
||
if ( NT_SUCCESS(Status) ) {
|
||
if ( Strings.Length + sizeof(WCHAR) >= Strings.MaximumLength) {
|
||
Status = STATUS_BUFFER_TOO_SMALL;
|
||
} else {
|
||
admin->alrtad_numstrings++;
|
||
*(Strings.Buffer+(Strings.Length/sizeof(WCHAR))) = L'\0';
|
||
Strings.Length += sizeof(WCHAR);
|
||
|
||
Status = RtlAppendUnicodeToString(
|
||
&Strings,
|
||
L"LSASS" );
|
||
}
|
||
|
||
}
|
||
|
||
if ( NT_SUCCESS(Status) ) {
|
||
if ( Strings.Length + sizeof(WCHAR) >= Strings.MaximumLength) {
|
||
Status = STATUS_BUFFER_TOO_SMALL;
|
||
} else {
|
||
admin->alrtad_numstrings++;
|
||
*(Strings.Buffer+(Strings.Length/sizeof(WCHAR))) = L'\0';
|
||
Strings.Buffer += (Strings.Length/sizeof(WCHAR)) + 1;
|
||
Strings.MaximumLength -= Strings.Length + sizeof(WCHAR);
|
||
Strings.Length = 0;
|
||
|
||
Status = RtlIntegerToUnicodeString(
|
||
(ULONG)ExceptionInfo->ExceptionRecord->ExceptionAddress,
|
||
16,
|
||
&Strings );
|
||
}
|
||
|
||
}
|
||
|
||
if ( NT_SUCCESS(Status) ) {
|
||
if ( Strings.Length + sizeof(WCHAR) >= Strings.MaximumLength) {
|
||
Status = STATUS_BUFFER_TOO_SMALL;
|
||
} else {
|
||
admin->alrtad_numstrings++;
|
||
*(Strings.Buffer+(Strings.Length/sizeof(WCHAR))) = L'\0';
|
||
Strings.Buffer += (Strings.Length/sizeof(WCHAR)) + 1;
|
||
|
||
(VOID) (*NetAlertRaiseExFunction)(
|
||
ALERT_ADMIN_EVENT,
|
||
message,
|
||
(DWORD)((PCHAR)Strings.Buffer -
|
||
(PCHAR)message),
|
||
L"LSASS" );
|
||
}
|
||
|
||
}
|
||
|
||
|
||
}
|
||
|
||
(VOID) FreeLibrary( hModule );
|
||
}
|
||
|
||
|
||
//
|
||
// Just continue processing the exception.
|
||
//
|
||
|
||
return EXCEPTION_CONTINUE_SEARCH;
|
||
|
||
}
|
||
|
||
|
||
|
||
VOID _CRTAPI1
|
||
main ()
|
||
{
|
||
NTSTATUS Status = STATUS_SUCCESS;
|
||
BOOLEAN InitializationNotified = FALSE;
|
||
KPRIORITY BasePriority;
|
||
BOOLEAN EnableAlignmentFaults = TRUE;
|
||
|
||
//
|
||
// Define a top-level exception handler for the entire process.
|
||
//
|
||
|
||
(VOID) SetErrorMode( SEM_FAILCRITICALERRORS );
|
||
|
||
(VOID) SetUnhandledExceptionFilter( &LsaTopLevelExceptionHandler );
|
||
|
||
//
|
||
// Turn on alignment fault fixups. This is necessary because
|
||
// several structures stored in the registry have qword aligned
|
||
// fields. They are nicely aligned in our structures, but they
|
||
// end up being forced out of alignment when being stored because
|
||
// the registry api require data to be passed following a wierd
|
||
// length header.
|
||
//
|
||
|
||
Status = NtSetInformationProcess(
|
||
NtCurrentProcess(),
|
||
ProcessEnableAlignmentFaultFixup,
|
||
(PVOID) &EnableAlignmentFaults,
|
||
sizeof(BOOLEAN)
|
||
);
|
||
ASSERT(NT_SUCCESS(Status));
|
||
|
||
|
||
|
||
|
||
//
|
||
// 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:
|
||
//
|
||
// 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 the service-controller service
|
||
// dispatcher.
|
||
//
|
||
// Initialize LSA Pass-2
|
||
// Product type-specific initialization.
|
||
//
|
||
// Initialize SAM
|
||
//
|
||
|
||
|
||
//
|
||
// 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 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 SAM
|
||
//
|
||
|
||
Status = SamIInitialize();
|
||
|
||
if (!NT_SUCCESS(Status) ) {
|
||
|
||
goto Cleanup;
|
||
}
|
||
|
||
LsapNotifyInitializationFinish(Status);
|
||
|
||
InitializationNotified = TRUE;
|
||
|
||
//
|
||
// Open a Trusted Handle to the local SAM server.
|
||
//
|
||
|
||
Status = LsapAuOpenSam();
|
||
|
||
if (!NT_SUCCESS(Status) ) {
|
||
|
||
goto Cleanup;
|
||
}
|
||
|
||
Cleanup:
|
||
|
||
if (!InitializationNotified) {
|
||
|
||
LsapNotifyInitializationFinish(Status);
|
||
InitializationNotified = TRUE;
|
||
}
|
||
|
||
NtTerminateThread( NtCurrentThread(), 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.
|
||
//
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
|
||
Status = NtRaiseHardError(
|
||
Status,
|
||
0,
|
||
0,
|
||
NULL,
|
||
OptionOk,
|
||
&Response
|
||
);
|
||
|
||
//
|
||
// 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.
|
||
//
|
||
|
||
//
|
||
// 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()) {
|
||
|
||
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 );
|
||
}
|
||
}
|
||
}
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
|
||
goto InitializationFinishError;
|
||
}
|
||
|
||
InitializationFinishFinish:
|
||
|
||
return;
|
||
|
||
InitializationFinishError:
|
||
|
||
goto InitializationFinishFinish;
|
||
}
|