1288 lines
29 KiB
1288 lines
29 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 <lsapch2.h>
|
|
#include <secur32p.h>
|
|
#include <ntddksec.h>
|
|
#include <ntdsa.h>
|
|
#include "adtp.h"
|
|
#include "spinit.h"
|
|
#include "efssrv.hxx"
|
|
#include "dssetp.h"
|
|
#include "sidcache.h"
|
|
#include "klpcstub.h"
|
|
#include "lsawmi.h"
|
|
#include "dpapiprv.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;
|
|
|
|
DWORD LsapGlobalRestrictNullSessions = TRUE;
|
|
DWORD LsapGlobalRestrictAnonymous = TRUE;
|
|
DWORD LsapGlobalSetAdminOwner = TRUE;
|
|
|
|
PWSTR pszPreferred;
|
|
|
|
//
|
|
// Handle to KSecDD device, for passing down ioctls.
|
|
//
|
|
|
|
HANDLE KsecDevice ;
|
|
|
|
//
|
|
// For outside calls (e.g. RPC originated) CallInfo won't be there,
|
|
// but some helper functions will look for it. This is a default one
|
|
// that can be used.
|
|
//
|
|
|
|
LSA_CALL_INFO LsapDefaultCallInfo ;
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////
|
|
// //
|
|
// Module-Wide variables //
|
|
// //
|
|
/////////////////////////////////////////////////////////////////////////
|
|
|
|
BOOLEAN LsapHealthCheckingEnabled = FALSE;
|
|
BOOLEAN LsapPromoteInitialized = FALSE;
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////
|
|
// //
|
|
// Internal routine prototypes //
|
|
// //
|
|
/////////////////////////////////////////////////////////////////////////
|
|
|
|
NTSTATUS
|
|
LsapActivateRpcServer();
|
|
|
|
DWORD
|
|
LsapRpcServerThread(
|
|
LPVOID Parameter
|
|
);
|
|
|
|
NTSTATUS
|
|
LsapInstallationPause();
|
|
|
|
VOID
|
|
LsapSignalRpcIsActive();
|
|
|
|
NTSTATUS
|
|
LsapDsInitializePromoteInterface(
|
|
VOID
|
|
);
|
|
|
|
//
|
|
// Open the KSec Device
|
|
//
|
|
|
|
VOID
|
|
LsapOpenKsec(
|
|
VOID
|
|
)
|
|
{
|
|
NTSTATUS Status ;
|
|
UNICODE_STRING String ;
|
|
OBJECT_ATTRIBUTES ObjA ;
|
|
IO_STATUS_BLOCK IoStatus ;
|
|
|
|
RtlInitUnicodeString( &String, DD_KSEC_DEVICE_NAME_U );
|
|
|
|
InitializeObjectAttributes( &ObjA,
|
|
&String,
|
|
0,
|
|
0,
|
|
0);
|
|
|
|
Status = NtOpenFile( &KsecDevice,
|
|
GENERIC_READ | GENERIC_WRITE,
|
|
&ObjA,
|
|
&IoStatus,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
0 );
|
|
|
|
if ( !NT_SUCCESS( Status ) )
|
|
{
|
|
DebugLog(( DEB_ERROR, "FAILED to open %ws, status %x\n",
|
|
String.Buffer, Status ));
|
|
return;
|
|
}
|
|
|
|
Status = NtDeviceIoControlFile(
|
|
KsecDevice,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&IoStatus,
|
|
IOCTL_KSEC_CONNECT_LSA,
|
|
NULL,
|
|
0,
|
|
NULL,
|
|
0 );
|
|
|
|
if ( !NT_SUCCESS( Status ) )
|
|
{
|
|
DebugLog(( DEB_ERROR, "FAILED to send ioctl, status %x\n", Status ));
|
|
}
|
|
else
|
|
{
|
|
LsapFindEfsSession();
|
|
}
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////
|
|
// //
|
|
// Routines //
|
|
// //
|
|
/////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
VOID
|
|
FixupEnvironment(
|
|
VOID
|
|
)
|
|
{
|
|
WCHAR Root[ MAX_PATH ];
|
|
DWORD Length;
|
|
PWCHAR PostFix = L"\\System32";
|
|
BOOL RetVal;
|
|
|
|
Length = GetEnvironmentVariable(L"SystemRoot", Root, MAX_PATH);
|
|
|
|
ASSERT(Length && Length < MAX_PATH); // Let someone know if the call doesn't work
|
|
|
|
wcsncat(Root, PostFix, MAX_PATH - Length - 1);
|
|
|
|
ASSERT(MAX_PATH - Length > wcslen (PostFix)); // Let someone know if buffer is too small
|
|
|
|
DebugLog((DEB_TRACE_INIT, "Setting PATH to %ws\n", Root));
|
|
|
|
RetVal = SetEnvironmentVariable( TEXT("Path"), Root);
|
|
|
|
ASSERT(RetVal);
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
LsapSetupTuningParameters(
|
|
VOID
|
|
)
|
|
{
|
|
NT_PRODUCT_TYPE ProductType;
|
|
SYSTEM_INFO si;
|
|
HKEY LsaKey ;
|
|
int err ;
|
|
ULONG Value ;
|
|
ULONG Type ;
|
|
ULONG Size ;
|
|
ULONG GlobalReturn = 0 ;
|
|
NTSTATUS scRet ;
|
|
|
|
LsaTuningParameters.ThreadLifespan = 60 ;
|
|
LsaTuningParameters.SubQueueLifespan = 30 ;
|
|
LsaTuningParameters.Options = TUNE_TRIM_WORKING_SET ;
|
|
|
|
|
|
//
|
|
// setup the preferred critsec spin count.
|
|
//
|
|
|
|
GetSystemInfo( &si );
|
|
|
|
LsaTuningParameters.CritSecSpinCount = 1000 * si.dwNumberOfProcessors;
|
|
|
|
if( LsaTuningParameters.CritSecSpinCount > 32000 )
|
|
{
|
|
LsaTuningParameters.CritSecSpinCount = 32000;
|
|
} else if( LsaTuningParameters.CritSecSpinCount < 1000 )
|
|
{
|
|
LsaTuningParameters.CritSecSpinCount = 1000;
|
|
}
|
|
|
|
|
|
scRet = RtlGetNtProductType( &ProductType );
|
|
|
|
if ( NT_SUCCESS( scRet ) )
|
|
{
|
|
if ( ProductType != NtProductWinNt )
|
|
{
|
|
LsaTuningParameters.ThreadLifespan = 15 * 60 ;
|
|
LsaTuningParameters.SubQueueLifespan = 5 * 60 ;
|
|
LsaTuningParameters.Options = 0 ;
|
|
|
|
if ( ProductType == NtProductLanManNt )
|
|
{
|
|
LsaTuningParameters.Options |= TUNE_PRIVATE_HEAP ;
|
|
|
|
//
|
|
// On DCs, link to the real version of the NTDSA
|
|
// save and restore.
|
|
//
|
|
GetDsaThreadState = (DSA_THSave *) THSave ;
|
|
RestoreDsaThreadState = (DSA_THRestore *) THRestore ;
|
|
}
|
|
}
|
|
}
|
|
|
|
err = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
|
|
TEXT("System\\CurrentControlSet\\Control\\Lsa"),
|
|
0,
|
|
KEY_READ | KEY_WRITE,
|
|
&LsaKey );
|
|
|
|
if ( err == 0 )
|
|
{
|
|
Value = GetCurrentProcessId();
|
|
|
|
RegSetValueEx(
|
|
LsaKey,
|
|
TEXT("LsaPid"),
|
|
0,
|
|
REG_DWORD,
|
|
(PUCHAR) &Value,
|
|
sizeof( DWORD ) );
|
|
|
|
Size = sizeof(DWORD);
|
|
|
|
err = RegQueryValueEx( LsaKey,
|
|
TEXT("GeneralThreadLifespan"),
|
|
0,
|
|
&Type,
|
|
(PUCHAR) &Value,
|
|
&Size );
|
|
|
|
if ( err == 0 )
|
|
{
|
|
LsaTuningParameters.ThreadLifespan = Value ;
|
|
}
|
|
|
|
Size = sizeof( DWORD );
|
|
err = RegQueryValueEx( LsaKey,
|
|
TEXT("DedicatedThreadLifespan"),
|
|
0,
|
|
&Type,
|
|
(PUCHAR) &Value,
|
|
&Size );
|
|
|
|
if ( err == 0 )
|
|
{
|
|
LsaTuningParameters.SubQueueLifespan = Value ;
|
|
}
|
|
|
|
Size = sizeof( DWORD );
|
|
|
|
err = RegQueryValueEx( LsaKey,
|
|
TEXT("HighPriority"),
|
|
0,
|
|
&Type,
|
|
(PUCHAR) &Value,
|
|
&Size );
|
|
|
|
if ( err == 0 )
|
|
{
|
|
if ( Value )
|
|
{
|
|
LsaTuningParameters.Options |= TUNE_SRV_HIGH_PRIORITY ;
|
|
}
|
|
}
|
|
|
|
|
|
Size = sizeof( DWORD );
|
|
err = RegQueryValueEx( LsaKey,
|
|
TEXT("CritSecSpinCount"),
|
|
0,
|
|
&Type,
|
|
(PUCHAR) &Value,
|
|
&Size );
|
|
|
|
if ( err == 0 )
|
|
{
|
|
if ( Value && (Type == REG_DWORD) )
|
|
{
|
|
LsaTuningParameters.CritSecSpinCount = Value;
|
|
}
|
|
}
|
|
|
|
|
|
RegCloseKey( LsaKey );
|
|
}
|
|
|
|
DebugLog(( DEB_TRACE_INIT, "Tuning parameters:\n" ));
|
|
DebugLog(( DEB_TRACE_INIT, " Thread Lifespan %d sec\n",
|
|
LsaTuningParameters.ThreadLifespan ));
|
|
DebugLog(( DEB_TRACE_INIT, " SubQueue Lifespan %d sec\n",
|
|
LsaTuningParameters.SubQueueLifespan ));
|
|
DebugLog(( DEB_TRACE_INIT, " Options:\n" ));
|
|
}
|
|
|
|
|
|
|
|
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)
|
|
o Start backgroup thread to register WMI tracing guids
|
|
|
|
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;
|
|
DWORD EFSRecoverThreadID;
|
|
HANDLE EFSThread ;
|
|
SYSTEM_INFO SysInfo ;
|
|
|
|
#if DBG
|
|
InitDebugSupport();
|
|
#endif
|
|
|
|
FixupEnvironment();
|
|
|
|
//
|
|
// Optional break point
|
|
//
|
|
|
|
BreakOnError(BREAK_ON_BEGIN_INIT);
|
|
|
|
//
|
|
// Init the TLS indices
|
|
//
|
|
|
|
(void) InitThreadData();
|
|
|
|
//
|
|
// Initialize the stack allocator
|
|
//
|
|
|
|
SafeAllocaInitialize(
|
|
SAFEALLOCA_USE_DEFAULT,
|
|
SAFEALLOCA_USE_DEFAULT,
|
|
LsapAllocatePrivateHeapNoZero,
|
|
LsapFreePrivateHeap
|
|
);
|
|
|
|
LsapSetupTuningParameters();
|
|
|
|
#if DBG
|
|
LsaTuningParameters.Options |= TUNE_PRIVATE_HEAP ;
|
|
#endif
|
|
|
|
GetSystemInfo( &SysInfo );
|
|
LsapPageSize = SysInfo.dwPageSize ;
|
|
LsapUserModeLimit = (ULONG_PTR) SysInfo.lpMaximumApplicationAddress ;
|
|
|
|
LsapHeapInitialize( ((LsaTuningParameters.Options & TUNE_PRIVATE_HEAP ) != 0) );
|
|
|
|
//
|
|
// Initialize this thread:
|
|
//
|
|
|
|
SpmpThreadStartup();
|
|
|
|
//
|
|
// Update the SSPI cache
|
|
//
|
|
|
|
SecCacheSspiPackages();
|
|
|
|
//
|
|
// Initialize session tracking:
|
|
//
|
|
|
|
if (!InitSessionManager())
|
|
{
|
|
DebugLog((DEB_ERROR, "InitSessionManager failed?\n"));
|
|
Status = STATUS_INTERNAL_ERROR;
|
|
goto InitLsaError;
|
|
}
|
|
|
|
//
|
|
// Initialize misc. global variables:
|
|
//
|
|
|
|
LsapDefaultCallInfo.Session = pDefaultSession ;
|
|
LsapDefaultCallInfo.LogContext = NULL ;
|
|
LsapDefaultCallInfo.LogonId.HighPart = 0 ;
|
|
LsapDefaultCallInfo.LogonId.LowPart = 999 ;
|
|
LsapDefaultCallInfo.InProcCall = TRUE ;
|
|
LsapDefaultCallInfo.Allocs = MAX_BUFFERS_IN_CALL ;
|
|
|
|
#if defined(REMOTE_BOOT)
|
|
//
|
|
// Initilize the state indicating whether this is a remote boot machine.
|
|
//
|
|
|
|
LsapDbInitializeRemoteBootState();
|
|
#endif // defined(REMOTE_BOOT)
|
|
|
|
//
|
|
// Initialize scavenger thread control
|
|
//
|
|
|
|
if ( !LsapInitializeScavenger() )
|
|
{
|
|
DebugLog(( DEB_ERROR, "Could not initialize scavenger thread\n"));
|
|
Status = STATUS_INTERNAL_ERROR ;
|
|
goto InitLsaError ;
|
|
}
|
|
|
|
//
|
|
// Start up the thread pool for support for LPC.
|
|
//
|
|
|
|
if (!InitializeThreadPool())
|
|
{
|
|
DebugLog((DEB_ERROR, "Could not init thread pool\n"));
|
|
Status = STATUS_INTERNAL_ERROR;
|
|
goto InitLsaError;
|
|
|
|
}
|
|
|
|
DebugLog((DEB_TRACE_INIT, "Current TraceLevel is %x\n", SPMInfoLevel));
|
|
|
|
//
|
|
// Load parameters from Registry:
|
|
//
|
|
|
|
Status = LoadParameters( FALSE );
|
|
|
|
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;
|
|
}
|
|
|
|
//
|
|
// If this is a time-checking build, load the timer support
|
|
// functions and initialize them.
|
|
//
|
|
|
|
#ifdef TIME_SPM
|
|
|
|
InitTimer();
|
|
|
|
#endif
|
|
|
|
//
|
|
// If we're going to be in a setup phase, tag it.
|
|
//
|
|
|
|
SetupPhase = SpmpIsSetupPass();
|
|
|
|
//
|
|
// Tell base/wincon how to shut us down.
|
|
// First, tell base to shut us down as late in the game as possible.
|
|
|
|
SetProcessShutdownParameters(SPM_SHUTDOWN_VALUE, SHUTDOWN_NORETRY);
|
|
|
|
//
|
|
// And, tell them what function to call when we are being shutdown:
|
|
//
|
|
|
|
SetConsoleCtrlHandler(SpConsoleHandler, TRUE);
|
|
|
|
//
|
|
// Set security on the synchronization event
|
|
//
|
|
|
|
Status = LsapBuildSD(BUILD_KSEC_SD, NULL);
|
|
|
|
if (FAILED(Status))
|
|
{
|
|
DebugLog((DEB_ERROR,"Failed to set Ksec security: 0x%x\n",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;
|
|
}
|
|
|
|
//
|
|
// 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 Auditing Initialization - Pass 1.
|
|
//
|
|
|
|
Status = LsapAdtInitialize();
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
|
|
goto InitLsaError;
|
|
}
|
|
|
|
Status = LsapAdtObjsInitialize();
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
|
|
goto InitLsaError;
|
|
}
|
|
|
|
//
|
|
// Load packages:
|
|
//
|
|
|
|
// The System Logon session must be present before (at least) the
|
|
// NegpackageLoad routine is called, so we can set it's creating package
|
|
// id, otherwise the package id is 0, which is normally ok, but when a
|
|
// machine is joined to a pre NT5 domain, this will mean that we
|
|
// will not do NTLM in a system logon session.
|
|
|
|
if ( !LsapLogonSessionInitialize() )
|
|
{
|
|
goto InitLsaError ;
|
|
}
|
|
|
|
Status = LoadPackages( ppszPackages,
|
|
ppszOldPkgs,
|
|
pszPreferred );
|
|
|
|
if (FAILED(Status))
|
|
{
|
|
DebugLog((DEB_ERROR, "Error loading packages, terminating (0x%08x)\n",
|
|
Status));
|
|
goto InitLsaError;
|
|
}
|
|
|
|
//
|
|
// Initialize the credential manager
|
|
//
|
|
|
|
Status = CredpInitialize();
|
|
|
|
if ( !NT_SUCCESS( Status )) {
|
|
goto InitLsaError;
|
|
}
|
|
|
|
//
|
|
// Initialize data for System LogonID (999):
|
|
//
|
|
|
|
InitSystemLogon();
|
|
|
|
//
|
|
// Perform RPC Server Initialization.
|
|
//
|
|
|
|
Status = LsapRPCInit();
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
|
|
goto InitLsaError;
|
|
}
|
|
|
|
//
|
|
// Initialize Authentication Services
|
|
//
|
|
|
|
if (!LsapAuInit()) {
|
|
|
|
Status = STATUS_UNSUCCESSFUL;
|
|
goto InitLsaError;
|
|
}
|
|
|
|
//
|
|
// Initialize the sid cache
|
|
//
|
|
|
|
Status = LsapDbInitSidCache();
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
|
|
DebugLog((DEB_ERROR, "Error initializing sid cache: 0x%x\n",Status));
|
|
goto InitLsaError;
|
|
}
|
|
|
|
//
|
|
// Initialize LPC Server to talk to the FSPs waiting on the device driver
|
|
//
|
|
|
|
Status = StartLpcThread();
|
|
|
|
if (FAILED(Status))
|
|
{
|
|
DebugLog((DEB_ERROR, "Error starting LPC thread, no DD support (0x%08x)\n",
|
|
Status));
|
|
goto InitLsaError;
|
|
}
|
|
|
|
//
|
|
// open ksec and have it connect back to us in our own context.
|
|
//
|
|
|
|
LsapOpenKsec();
|
|
|
|
//
|
|
// Optional breakpoint when initialization complete
|
|
//
|
|
|
|
BreakOnError(BREAK_ON_BEGIN_END);
|
|
|
|
//
|
|
// Start processing RPC calls
|
|
//
|
|
|
|
Status = LsapActivateRpcServer();
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
|
|
goto InitLsaError;
|
|
}
|
|
|
|
//
|
|
// Initialize DPAPI
|
|
//
|
|
|
|
Status = DPAPIInitialize(&LsapSecpkgFunctionTable);
|
|
|
|
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.
|
|
//
|
|
|
|
Status = LsapDbInitializeServer(2);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
|
|
goto InitLsaError;
|
|
}
|
|
|
|
//
|
|
// Initialize EFS
|
|
//
|
|
|
|
( VOID )EfsServerInit();
|
|
|
|
//
|
|
// If EfsServerInit() fails because of policy & etc.
|
|
// the recovery thread should not be run.
|
|
//
|
|
|
|
EFSThread = CreateThread( NULL,
|
|
0,
|
|
EFSRecover,
|
|
NULL,
|
|
0,
|
|
&EFSRecoverThreadID );
|
|
|
|
if ( EFSThread )
|
|
{
|
|
CloseHandle( EFSThread );
|
|
}
|
|
|
|
//
|
|
// Initialize the Setup APIs
|
|
//
|
|
|
|
if ( !LsapPromoteInitialized ) {
|
|
|
|
DsRolepInitialize();
|
|
}
|
|
|
|
Status = LsapStartWmiTraceInitThread();
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
goto InitLsaError;
|
|
}
|
|
|
|
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;
|
|
|
|
// 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.
|
|
|
|
--*/
|
|
|
|
{
|
|
if ( SpmpIsSetupPass() ) {
|
|
|
|
//
|
|
// The event exists - installation created it and will signal it
|
|
// when it is ok to proceed with security initialization.
|
|
//
|
|
|
|
LsapSetupWasRun = TRUE;
|
|
|
|
//
|
|
// Intialize the promotion interface
|
|
//
|
|
DsRolepInitialize();
|
|
LsapDsInitializePromoteInterface();
|
|
LsapPromoteInitialized = TRUE;
|
|
|
|
//
|
|
// Make sure we are not in mini-setup
|
|
//
|
|
if ( SpmpIsMiniSetupPass() ) {
|
|
|
|
LsapSetupWasRun = FALSE;
|
|
}
|
|
}
|
|
|
|
return( STATUS_SUCCESS );
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
//
|
|
// Query the account domain information
|
|
//
|
|
|
|
Status = LsarQueryInformationPolicy( LsapPolicyHandle,
|
|
PolicyAccountDomainInformation,
|
|
(PLSAPR_POLICY_INFORMATION *) PolicyAccountDomainInfo );
|
|
#if DBG
|
|
if ( NT_SUCCESS(Status) ) {
|
|
ASSERT( (*PolicyAccountDomainInfo) != NULL );
|
|
ASSERT( (*PolicyAccountDomainInfo)->DomainSid != NULL );
|
|
}
|
|
#endif // DBG
|
|
|
|
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.
|
|
--*/
|
|
|
|
{
|
|
return LsapOpenSamEx( FALSE );
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
LsapOpenSamEx(
|
|
BOOLEAN DuringStartup
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine opens SAM for use during authentication. It
|
|
opens a handle to both the BUILTIN domain and the ACCOUNT domain.
|
|
|
|
Arguments:
|
|
|
|
|
|
DuringStartup - TRUE if this is the call made during startup. In that case,
|
|
there is no need to wait on the SAM_STARTED_EVENT since the caller ensures
|
|
that SAM is started before the call is made.
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS - Succeeded.
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS Status, IgnoreStatus;
|
|
PPOLICY_ACCOUNT_DOMAIN_INFO PolicyAccountDomainInfo;
|
|
SAMPR_HANDLE SamHandle;
|
|
|
|
if (LsapSamOpened == TRUE) { // Global variable
|
|
|
|
return(STATUS_SUCCESS);
|
|
}
|
|
|
|
//
|
|
// Make sure SAM has initialized
|
|
//
|
|
|
|
if ( !DuringStartup ) {
|
|
HANDLE EventHandle;
|
|
OBJECT_ATTRIBUTES EventAttributes;
|
|
UNICODE_STRING EventName;
|
|
LARGE_INTEGER Timeout;
|
|
|
|
RtlInitUnicodeString( &EventName, L"\\SAM_SERVICE_STARTED");
|
|
InitializeObjectAttributes( &EventAttributes, &EventName, 0, 0, NULL );
|
|
Status = NtOpenEvent( &EventHandle, SYNCHRONIZE, &EventAttributes );
|
|
|
|
if ( !NT_SUCCESS(Status)) {
|
|
|
|
if( Status == STATUS_OBJECT_NAME_NOT_FOUND ) {
|
|
|
|
//
|
|
// SAM hasn't created this event yet, let us create it now.
|
|
// SAM opens this event to set it.
|
|
//
|
|
|
|
Status = NtCreateEvent(
|
|
&EventHandle,
|
|
SYNCHRONIZE|EVENT_MODIFY_STATE,
|
|
&EventAttributes,
|
|
NotificationEvent,
|
|
FALSE // The event is initially not signaled
|
|
);
|
|
|
|
if( Status == STATUS_OBJECT_NAME_EXISTS ||
|
|
Status == STATUS_OBJECT_NAME_COLLISION ) {
|
|
|
|
//
|
|
// second change, if the SAM created the event before we
|
|
// do.
|
|
//
|
|
|
|
Status = NtOpenEvent( &EventHandle,
|
|
SYNCHRONIZE|EVENT_MODIFY_STATE,
|
|
&EventAttributes );
|
|
}
|
|
}
|
|
}
|
|
|
|
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
|
|
//
|
|
|
|
LsaIFree_LSAPR_POLICY_INFORMATION(
|
|
PolicyAccountDomainInformation,
|
|
(PLSAPR_POLICY_INFORMATION) PolicyAccountDomainInfo );
|
|
|
|
return(Status);
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
LsapDsInitializePromoteInterface(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Performs the initialization required for the Dc promotion/demotions apis, apart
|
|
from what is done during LsaInit
|
|
|
|
Arguments:
|
|
|
|
VOID
|
|
|
|
|
|
Return Values:
|
|
|
|
STATUS_SUCCESS -- Success.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
if ( LsapPromoteInitialized == FALSE ) {
Status = DsRolepInitializePhase2();
}
return( Status );
}
|