mirror of https://github.com/lianthony/NT4.0
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.
543 lines
15 KiB
543 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 "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;
|
|
}
|