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.
 
 
 
 
 
 

556 lines
15 KiB

/*++
Copyright (c) 1993 Microsoft Corporation
Module Name:
init.c
Abstract:
NT LM Security Support Provider client side initialization.
Author:
Cliff Van Dyke (CliffV) 29-Jun-1993
Environment: User Mode
Revision History:
--*/
#define NTLMSSPC_ALLOCATE // Allocate data from ntlmssps.h
#define DEBUG_ALLOCATE // Allocate data from debug.h
#include <ntlmsspc.h> // Include files common to DLL side of NtLmSsp
#undef DEBUG_ALLOCATE
#undef NTLMSSPC_ALLOCATE
#include <ntlpcapi.h> // LPC data and routines
#include <lmsname.h> // SERVICE_*
#include <ntlmitf.h> // prototypes for interface functions
//
// Global Variables used by this modules
//
CRITICAL_SECTION SspDllCritSect; // Serializes access to all globals in module
HANDLE SspDllLpcHandle; // Lpc Handle to NtLmSspService
BOOLEAN SspDllCallLsaDirectly; // True iff we're running as Local System
BOOLEAN SspDllCommonInitialized; // True iff we've called SspCommonInitialize
ULONG SspCommonSecHandleValue = SEC_HANDLE_SECURITY;
// Placed in lower DWORD of contexts and creds
BOOLEAN
SspDllInit(
IN PVOID DllHandle,
IN ULONG Reason,
IN PCONTEXT Context OPTIONAL
)
/*++
Routine Description:
This is the Dll initialization routine for ntlmssp.dll
Arguments:
Standard.
Return Status:
TRUE: iff initialization succeeded
--*/
{
//
// On process attach,
// initialize the critical section,
// defer any additional initialization.
//
switch (Reason) {
case DLL_PROCESS_ATTACH:
DisableThreadLibraryCalls( DllHandle );
InitializeCriticalSection( &SspDllCritSect );
SspDllLpcHandle= NULL;
SspDllCallLsaDirectly = FALSE;
SspDllCommonInitialized = FALSE;
(void) SspInitLocalContexts();
#if DBG
SspGlobalDbflag = SSP_CRITICAL;
InitializeCriticalSection( &SspGlobalLogFileCritSect );
#endif // DBG
// Initialize the SecurityFunctionTable
RtlZeroMemory( &SspDllSecurityFunctionTableW,
sizeof(SspDllSecurityFunctionTableW) );
SspDllSecurityFunctionTableW.dwVersion = SECURITY_SUPPORT_PROVIDER_INTERFACE_VERSION;
SspDllSecurityFunctionTableW.EnumerateSecurityPackagesW = SspEnumerateSecurityPackagesW;
SspDllSecurityFunctionTableW.AcquireCredentialsHandleW = SspAcquireCredentialsHandleW;
SspDllSecurityFunctionTableW.FreeCredentialHandle = SspFreeCredentialsHandle;
SspDllSecurityFunctionTableW.InitializeSecurityContextW = SspInitializeSecurityContextW;
SspDllSecurityFunctionTableW.Reserved1 = NULL;
SspDllSecurityFunctionTableW.AcceptSecurityContext = SspAcceptSecurityContext;
SspDllSecurityFunctionTableW.CompleteAuthToken = SspCompleteAuthToken;
SspDllSecurityFunctionTableW.QueryContextAttributesW = SspQueryContextAttributesW;
SspDllSecurityFunctionTableW.Reserved2 = NULL;
SspDllSecurityFunctionTableW.DeleteSecurityContext = SspDeleteSecurityContext;
SspDllSecurityFunctionTableW.ApplyControlToken = SspApplyControlToken;
SspDllSecurityFunctionTableW.ImpersonateSecurityContext = SspImpersonateSecurityContext;
SspDllSecurityFunctionTableW.RevertSecurityContext = SspRevertSecurityContext;
SspDllSecurityFunctionTableW.MakeSignature = SspMakeSignature;
SspDllSecurityFunctionTableW.VerifySignature = SspVerifySignature;
SspDllSecurityFunctionTableW.FreeContextBuffer = NULL;
SspDllSecurityFunctionTableW.QuerySecurityPackageInfoW = SspQuerySecurityPackageInfoW;
SspDllSecurityFunctionTableW.Reserved3 = SspSealMessage;
SspDllSecurityFunctionTableW.Reserved4 = SspUnsealMessage;
SspDllSecurityFunctionTableW.QuerySecurityContextToken = SspQuerySecurityContextToken;
RtlZeroMemory( &SspDllSecurityFunctionTableA,
sizeof(SspDllSecurityFunctionTableA) );
SspDllSecurityFunctionTableA.dwVersion = SECURITY_SUPPORT_PROVIDER_INTERFACE_VERSION;
SspDllSecurityFunctionTableA.EnumerateSecurityPackagesA = SspEnumerateSecurityPackagesA;
SspDllSecurityFunctionTableA.AcquireCredentialsHandleA = SspAcquireCredentialsHandleA;
SspDllSecurityFunctionTableA.FreeCredentialHandle = SspFreeCredentialsHandle;
SspDllSecurityFunctionTableA.InitializeSecurityContextA = SspInitializeSecurityContextA;
SspDllSecurityFunctionTableA.Reserved1 = NULL;
SspDllSecurityFunctionTableA.AcceptSecurityContext = SspAcceptSecurityContext;
SspDllSecurityFunctionTableA.CompleteAuthToken = SspCompleteAuthToken;
SspDllSecurityFunctionTableA.QueryContextAttributesA = SspQueryContextAttributesA;
SspDllSecurityFunctionTableA.Reserved2 = NULL;
SspDllSecurityFunctionTableA.DeleteSecurityContext = SspDeleteSecurityContext;
SspDllSecurityFunctionTableA.ApplyControlToken = SspApplyControlToken;
SspDllSecurityFunctionTableA.ImpersonateSecurityContext = SspImpersonateSecurityContext;
SspDllSecurityFunctionTableA.RevertSecurityContext = SspRevertSecurityContext;
SspDllSecurityFunctionTableA.MakeSignature = SspMakeSignature;
SspDllSecurityFunctionTableA.VerifySignature = SspVerifySignature;
SspDllSecurityFunctionTableA.FreeContextBuffer = NULL;
SspDllSecurityFunctionTableA.QuerySecurityPackageInfoA = SspQuerySecurityPackageInfoA;
SspDllSecurityFunctionTableA.Reserved3 = SspSealMessage;
SspDllSecurityFunctionTableA.Reserved4 = SspUnsealMessage;
SspDllSecurityFunctionTableA.QuerySecurityContextToken = SspQuerySecurityContextToken;
break;
//
// Handle process detach.
//
case DLL_PROCESS_DETACH:
//
// Shutdown the common routines.
//
EnterCriticalSection( &SspDllCritSect );
if ( SspDllCommonInitialized ) {
SspCommonShutdown();
SspDllCallLsaDirectly = FALSE;
SspDllCommonInitialized = FALSE;
}
//
// Disconnect the LPC port
//
if ( SspDllLpcHandle != NULL ) {
NtClose( SspDllLpcHandle );
SspDllLpcHandle = NULL;
}
if (SspGlobalAliasAdminsSid != NULL) {
LocalFree(SspGlobalAliasAdminsSid);
}
if (SspGlobalLocalSystemSid != NULL) {
LocalFree(SspGlobalLocalSystemSid);
}
LeaveCriticalSection( &SspDllCritSect );
//
// Finally, Delete the critical section
//
DeleteCriticalSection( &SspDllCritSect );
#if DBG
DeleteCriticalSection( &SspGlobalLogFileCritSect );
#endif // DBG
break;
}
return(PackageMain(Reason));
UNREFERENCED_PARAMETER( Context );
}
BOOLEAN
SspDllWaitForService(
ULONG Timeout
)
/*++
Routine Description:
Wait up to Timeout seconds for the NtLmSsp service to start.
Arguments:
Timeout - Timeout for event (in seconds).
Return Status:
True: service is started
False: Timeout (or service isn't started)
--*/
{
DWORD WinStatus;
SC_HANDLE ScManagerHandle = NULL;
SC_HANDLE ServiceHandle = NULL;
SERVICE_STATUS ServiceStatus;
BOOLEAN ReturnCode;
HANDLE EventHandle;
//
// If the NtLmSsp service is currently running,
// skip the rest of the tests.
//
EventHandle = OpenEventW( SYNCHRONIZE,
FALSE, // Don't inherit handle
NTLMSSP_RUNNING_EVENT );
if ( EventHandle != NULL ) {
DWORD WaitStatus;
WaitStatus = WaitForSingleObject( EventHandle, Timeout * 1000 );
(VOID) CloseHandle( EventHandle );
//
// If the event is signalled, the service is running.
// If we waited the full timeout time, the service is not running.
// Otherwise, proceed as though the event didn't exist.
//
switch ( WaitStatus ) {
case WAIT_OBJECT_0:
return TRUE;
case WAIT_TIMEOUT:
return FALSE;
}
SspPrint(( SSP_INIT, "Wait for %ws failed unexpectedly.\n",
NTLMSSP_RUNNING_EVENT ));
}
//
// Open a handle to the NtLmSsp service.
//
ScManagerHandle = OpenSCManager(
NULL,
NULL,
SC_MANAGER_CONNECT );
if (ScManagerHandle == NULL) {
SspPrint(( SSP_INIT, "SspDllWaitForService: OpenSCManager failed: "
"%lu\n", GetLastError()));
ReturnCode = FALSE;
goto Cleanup;
}
ServiceHandle = OpenServiceW(
ScManagerHandle,
SERVICE_NTLMSSP,
SERVICE_QUERY_STATUS | SERVICE_START );
if ( ServiceHandle == NULL ) {
SspPrint(( SSP_INIT, "SspDllWaitForService: OpenService failed: "
"%lu\n", GetLastError()));
ReturnCode = FALSE;
goto Cleanup;
}
//
// Loop waiting for the NtLmSsp service to start.
//
for (;;) {
//
// Query the status of the NtLmSsp service.
//
if (! QueryServiceStatus( ServiceHandle, &ServiceStatus )) {
SspPrint(( SSP_INIT, "SspDllWaitForService: QueryServiceStatus failed: "
"%lu\n", GetLastError() ));
ReturnCode = FALSE;
goto Cleanup;
}
//
// Return or continue waiting depending on the state of
// the NtLmSsp service.
//
switch( ServiceStatus.dwCurrentState) {
case SERVICE_RUNNING:
ReturnCode = TRUE;
goto Cleanup;
case SERVICE_STOPPED:
//
// If NtLmSsp has never been started on this boot,
// start it and continue waiting.
//
if (! StartService( ServiceHandle, 0, NULL )) {
WinStatus = GetLastError();
if ( WinStatus != ERROR_SERVICE_ALREADY_RUNNING ) {
SspPrint(( SSP_INIT, "SspDllWaitForService: StartService failed: "
"%lu\n", WinStatus ));
ReturnCode = FALSE;
goto Cleanup;
}
}
break;
//
// If NtLmSsp is trying to start up now,
// continue waiting for it to start.
//
case SERVICE_START_PENDING:
break;
//
// Any other state is bogus.
//
default:
SspPrint(( SSP_INIT, "SspDllWaitForService: "
"Invalid service state: %lu\n",
ServiceStatus.dwCurrentState ));
ReturnCode = FALSE;
goto Cleanup;
}
//
// If we've waited long enough for NtLmSsp to start,
// time out now.
//
if ( (--Timeout) == 0 ) {
ReturnCode = FALSE;
goto Cleanup;
}
//
// Wait a second for the NtLmSsp service to start.
//
Sleep( 1000 );
}
/* NOT REACHED */
Cleanup:
if ( ScManagerHandle != NULL ) {
(VOID) CloseServiceHandle(ScManagerHandle);
}
if ( ServiceHandle != NULL ) {
(VOID) CloseServiceHandle(ServiceHandle);
}
return ReturnCode;
}
HANDLE
SspDllGetLpcHandle(
IN BOOLEAN ForceReconnect,
OUT PBOOLEAN CallLsaDirectly
)
/*++
Routine Description:
Return a handle to the LPC port of the NtLmSsp service.
On initialization, waits for the NtLmSsp service to start.
Arguments:
ForceReconnect -- TRUE specifies this is a reconnection to the NtLmSsp
service.
CallLsaDirectly -- Returns TRUE if this process is a logon process and
we need not indirect through the NtLmSsp service.
Return Status:
Returns the LPC handle to use.
NULL means we cannot connect to the NtLmSsp service.
--*/
{
NTSTATUS Status;
UNICODE_STRING PortName;
SSP_REGISTER_CONNECT_INFO ConnectInfo;
ULONG ConnectInfoLength;
SECURITY_QUALITY_OF_SERVICE DynamicQos;
HANDLE LpcHandle;
//
// If we already have an LpcHandle,
// close it or return it depending on whether the caller is forcing
// a reconnect.
//
EnterCriticalSection( &SspDllCritSect );
if ( SspDllLpcHandle != NULL ) {
if ( ForceReconnect ) {
NtClose( SspDllLpcHandle );
SspDllLpcHandle = NULL;
} else {
LpcHandle = SspDllLpcHandle;
*CallLsaDirectly = SspDllCallLsaDirectly;
LeaveCriticalSection( &SspDllCritSect );
return LpcHandle;
}
}
//
// If the caller isn't forcing a reconnect,
// see if we can talk to LSA directly.
//
if ( !SspDllCommonInitialized ) {
Status = SspCommonInitialize();
if ( NT_SUCCESS(Status) ) {
//
// Flag the fact that we'll call LSA directly for the life of
// this process.
//
SspDllCallLsaDirectly = TRUE;
//
// Flag that we don't need to initialize SspCommon again.
//
SspDllCommonInitialized = TRUE;
//
// Drop through to create the LPC port anyway since we may
// need to go through the service in the case where the
// client and server are on the same system.
//
} else {
if ( Status != STATUS_NOT_LOGON_PROCESS ) {
SspPrint(( SSP_INIT, "SspCommonInitialize failed %lx\n", Status));
}
}
}
//
// Wait (up to 45 seconds) for the service to start.
//
if ( !SspDllWaitForService(45) ) {
LeaveCriticalSection( &SspDllCritSect );
return NULL;
}
//
// Set up the security quality of service parameters to use over the
// port. Use the most efficient (least overhead) - which is dynamic
// rather than static tracking.
//
DynamicQos.ImpersonationLevel = SecurityImpersonation;
DynamicQos.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING;
DynamicQos.EffectiveOnly = FALSE;
//
// Connect to the NtLmSsp server
//
ConnectInfoLength = sizeof(SSP_REGISTER_CONNECT_INFO);
RtlInitUnicodeString(&PortName, NTLMSSP_LPC_PORT_NAME );
Status = NtConnectPort(
&SspDllLpcHandle,
&PortName,
&DynamicQos,
NULL,
NULL,
NULL,
&ConnectInfo,
&ConnectInfoLength );
if ( !NT_SUCCESS(Status) ) {
SspPrint(( SSP_INIT, "NtConnectPort function failed %lx\n", Status));
LeaveCriticalSection( &SspDllCritSect );
return NULL;
}
if ( !NT_SUCCESS(ConnectInfo.CompletionStatus) ) {
SspPrint(( SSP_INIT, "NtConnectPort connection failed %lx\n", Status));
LeaveCriticalSection( &SspDllCritSect );
return NULL;
}
LpcHandle = SspDllLpcHandle;
*CallLsaDirectly = SspDllCallLsaDirectly;
LeaveCriticalSection( &SspDllCritSect );
return LpcHandle;
}