Windows NT 4.0 source code leak
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.
 
 
 
 
 
 

843 lines
18 KiB

/*++
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;
}