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.
1116 lines
30 KiB
1116 lines
30 KiB
/*++
|
|
|
|
Copyright (c) 1991 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
xssupp.c
|
|
|
|
Abstract:
|
|
|
|
This module contains the code necessary to support XACTSRV for down-level
|
|
remote APIs.
|
|
|
|
Author:
|
|
|
|
David Treadwell (davidtr) 05-Jan-1991
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "precomp.h"
|
|
#include "xssupp.tmh"
|
|
#pragma hdrstop
|
|
|
|
//
|
|
// Xs forward declarations
|
|
//
|
|
|
|
VOID
|
|
SrvXsFreeSharedMemory (
|
|
VOID
|
|
);
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text( PAGE, SrvXsConnect )
|
|
#pragma alloc_text( PAGE, SrvXsRequest )
|
|
#pragma alloc_text( PAGE, SrvXsLSOperation )
|
|
#pragma alloc_text( PAGE, SrvXsDisconnect )
|
|
#pragma alloc_text( PAGE, SrvXsFreeSharedMemory )
|
|
#pragma alloc_text( PAGE, SrvXsAllocateHeap )
|
|
#pragma alloc_text( PAGE, SrvXsFreeHeap )
|
|
#pragma alloc_text( PAGE, SrvXsPnpOperation )
|
|
#endif
|
|
|
|
//
|
|
// Xs internal Globals
|
|
//
|
|
|
|
//
|
|
// This count indicates how many outstanding transactions are using
|
|
// the XS shared memory. This prevents us from deleting the shared
|
|
// memory while it is still being accessed.
|
|
//
|
|
|
|
ULONG SrvXsSharedMemoryReference = 0;
|
|
|
|
|
|
NTSTATUS
|
|
SrvXsConnect (
|
|
IN PUNICODE_STRING PortName
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine performs all the work necessary to connect the server
|
|
to XACTSRV. It creates a section of shared memory to use, then
|
|
calls NtConnectPort to connect to the port that XACTSRV has already
|
|
created.
|
|
|
|
Arguments:
|
|
|
|
PortName - Name of the port XACTSRV has opened.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - result of operation.
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS status;
|
|
PORT_VIEW clientView;
|
|
SECURITY_QUALITY_OF_SERVICE dynamicQos;
|
|
|
|
PAGED_CODE( );
|
|
|
|
//
|
|
// Initialize variables so that we know what to close on exit.
|
|
//
|
|
|
|
SrvXsSectionHandle = NULL;
|
|
SrvXsPortHandle = NULL;
|
|
SrvXsPortMemoryHeap = NULL;
|
|
|
|
//
|
|
// Create the section to be used as unnamed shared memory for
|
|
// communication between the server and XACTSRV.
|
|
//
|
|
|
|
status = NtCreateSection(
|
|
&SrvXsSectionHandle,
|
|
SECTION_ALL_ACCESS,
|
|
NULL, // ObjectAttributes
|
|
&SrvXsSectionSize,
|
|
PAGE_READWRITE,
|
|
SEC_RESERVE,
|
|
NULL // FileHandle
|
|
);
|
|
|
|
if ( !NT_SUCCESS(status) ) {
|
|
IF_DEBUG(ERRORS) {
|
|
KdPrint(( "SrvXsConnect: NtCreateSection failed: %X\n", status ));
|
|
}
|
|
goto exit;
|
|
}
|
|
|
|
IF_DEBUG(XACTSRV) {
|
|
KdPrint(( "SrvXsConnect: created section of %ld bytes, handle %p\n",
|
|
SrvXsSectionSize.LowPart, SrvXsSectionHandle ));
|
|
}
|
|
|
|
//
|
|
// Set up for a call to NtConnectPort and connect to XACTSRV. This
|
|
// includes a description of the port memory section so that the
|
|
// LPC connection logic can make the section visible to both the
|
|
// client and server processes.
|
|
//
|
|
|
|
clientView.Length = sizeof(clientView);
|
|
clientView.SectionHandle = SrvXsSectionHandle;
|
|
clientView.SectionOffset = 0;
|
|
clientView.ViewSize = SrvXsSectionSize.LowPart;
|
|
clientView.ViewBase = 0;
|
|
clientView.ViewRemoteBase = 0;
|
|
|
|
//
|
|
// Set up the security quality of service parameters to use over the
|
|
// port. Use dynamic tracking so that XACTSRV will impersonate the
|
|
// user that we are impersonating when we call NtRequestWaitReplyPort.
|
|
// If we used static tracking, XACTSRV would impersonate the context
|
|
// when the connection is made.
|
|
//
|
|
|
|
dynamicQos.ImpersonationLevel = SecurityImpersonation;
|
|
dynamicQos.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING;
|
|
dynamicQos.EffectiveOnly = TRUE;
|
|
|
|
// !!! We might want to use a timeout value.
|
|
|
|
status = NtConnectPort(
|
|
&SrvXsPortHandle,
|
|
PortName,
|
|
&dynamicQos,
|
|
&clientView,
|
|
NULL, // ServerView
|
|
NULL, // MaxMessageLength
|
|
NULL, // ConnectionInformation
|
|
NULL // ConnectionInformationLength
|
|
);
|
|
|
|
if ( !NT_SUCCESS(status) ) {
|
|
IF_DEBUG(ERRORS) {
|
|
KdPrint(( "SrvXsConnect: NtConnectPort for port %wZ failed: %X\n",
|
|
PortName, status ));
|
|
}
|
|
goto exit;
|
|
}
|
|
|
|
IF_DEBUG(XACTSRV) {
|
|
KdPrint(( "SrvXsConnect: conected to port %wZ, handle %p\n",
|
|
PortName, SrvXsPortHandle ));
|
|
}
|
|
|
|
//
|
|
// Store information about the section so that we can create pointers
|
|
// meaningful to XACTSRV.
|
|
//
|
|
|
|
SrvXsPortMemoryBase = clientView.ViewBase;
|
|
SrvXsPortMemoryDelta = PTR_DIFF_FULLPTR( clientView.ViewRemoteBase,
|
|
clientView.ViewBase );
|
|
|
|
IF_DEBUG(XACTSRV) {
|
|
KdPrint(( "SrvXsConnect: port mem base %p, port mem delta %p\n",
|
|
SrvXsPortMemoryBase, (PVOID)SrvXsPortMemoryDelta ));
|
|
}
|
|
|
|
//
|
|
// Set up the port memory as heap.
|
|
//
|
|
// *** Note that we do our own heap serialization using
|
|
// SrvXsResource.
|
|
//
|
|
SrvXsPortMemoryHeap = RtlCreateHeap(
|
|
HEAP_NO_SERIALIZE, // Flags
|
|
SrvXsPortMemoryBase, // HeapBase
|
|
SrvXsSectionSize.LowPart, // ReserveSize
|
|
PAGE_SIZE, // CommitSize
|
|
NULL, // Lock
|
|
0 // Reserved
|
|
);
|
|
|
|
SrvXsActive = TRUE;
|
|
|
|
//
|
|
// Test it out to ensure everything is working right
|
|
//
|
|
SrvXsFreeHeap( SrvXsAllocateHeap( 100, &status ) );
|
|
|
|
return status;
|
|
|
|
exit:
|
|
|
|
if ( SrvXsSectionHandle != NULL ) {
|
|
SrvNtClose( SrvXsSectionHandle, FALSE );
|
|
}
|
|
|
|
if ( SrvXsPortHandle != NULL ) {
|
|
SrvNtClose( SrvXsPortHandle, FALSE );
|
|
}
|
|
|
|
return status;
|
|
|
|
} // SrvXsConnect
|
|
|
|
|
|
SMB_TRANS_STATUS
|
|
SrvXsRequest (
|
|
IN OUT PWORK_CONTEXT WorkContext
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine sends a remote API request to XACTSRV. It first
|
|
updates all the pointers in the transaction block so that they
|
|
are meaningful to XACTSRV, then sends a message over the port
|
|
indicating that there is a request in the shared memory ready to
|
|
be serviced. It then fixes all the pointers in the transaction
|
|
block.
|
|
|
|
Arguments:
|
|
|
|
WorkContext - a pointer to a work context block that has a pointer to
|
|
transaction block to use.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - result of operation.
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS status;
|
|
PCONNECTION connection = WorkContext->Connection;
|
|
PSESSION session = WorkContext->Session;
|
|
SMB_TRANS_STATUS returnStatus;
|
|
PTRANSACTION transaction;
|
|
XACTSRV_REQUEST_MESSAGE requestMessage;
|
|
XACTSRV_REPLY_MESSAGE replyMessage;
|
|
PWCH destPtr, sourcePtr, sourceEndPtr;
|
|
|
|
PAGED_CODE( );
|
|
|
|
//
|
|
// If this call is made on the NULL session, make sure it's one of
|
|
// the authorized apis.
|
|
//
|
|
|
|
transaction = WorkContext->Parameters.Transaction;
|
|
if ( session->IsNullSession && SrvRestrictNullSessionAccess ) {
|
|
|
|
USHORT apiNumber;
|
|
|
|
apiNumber = SmbGetUshort( (PSMB_USHORT)transaction->InParameters );
|
|
|
|
if ( apiNumber != API_WUserPasswordSet2 &&
|
|
apiNumber != API_WUserGetGroups &&
|
|
apiNumber != API_NetServerEnum2 &&
|
|
apiNumber != API_WNetServerReqChallenge &&
|
|
apiNumber != API_WNetServerAuthenticate &&
|
|
apiNumber != API_WNetServerPasswordSet &&
|
|
apiNumber != API_WNetAccountDeltas &&
|
|
apiNumber != API_WNetAccountSync &&
|
|
apiNumber != API_WWkstaUserLogoff &&
|
|
apiNumber != API_WNetWriteUpdateLog &&
|
|
apiNumber != API_WNetAccountUpdate &&
|
|
apiNumber != API_SamOEMChgPasswordUser2_P &&
|
|
apiNumber != API_NetServerEnum3 &&
|
|
apiNumber != API_WNetAccountConfirmUpdate ) {
|
|
|
|
IF_DEBUG(ERRORS) {
|
|
KdPrint(( "SrvXsRequest: Null session tried to call api.%d\n",
|
|
apiNumber ));
|
|
}
|
|
|
|
SrvSetSmbError( WorkContext, STATUS_ACCESS_DENIED );
|
|
return SmbTransStatusErrorWithoutData;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Initialize the transport name pointer to make sure we can know if
|
|
// it has been allocated.
|
|
//
|
|
|
|
requestMessage.Message.DownLevelApi.TransportName = NULL;
|
|
|
|
//
|
|
// Convert the relevant pointers in the transaction block to the base
|
|
// in XACTSRV.
|
|
//
|
|
|
|
transaction->TransactionName.Buffer += SrvXsPortMemoryDelta;
|
|
transaction->InSetup += SrvXsPortMemoryDelta;
|
|
transaction->OutSetup += SrvXsPortMemoryDelta;
|
|
transaction->InParameters += SrvXsPortMemoryDelta;
|
|
transaction->OutParameters += SrvXsPortMemoryDelta;
|
|
transaction->InData += SrvXsPortMemoryDelta;
|
|
transaction->OutData += SrvXsPortMemoryDelta;
|
|
|
|
//
|
|
// Build the transport name in the message.
|
|
//
|
|
|
|
requestMessage.Message.DownLevelApi.TransportName =
|
|
SrvXsAllocateHeap(
|
|
WorkContext->Endpoint->TransportName.Length + sizeof(WCHAR),
|
|
&status
|
|
);
|
|
|
|
if ( requestMessage.Message.DownLevelApi.TransportName == NULL ) {
|
|
SrvSetSmbError( WorkContext, status );
|
|
returnStatus = SmbTransStatusErrorWithoutData;
|
|
goto exit;
|
|
}
|
|
|
|
|
|
requestMessage.Message.DownLevelApi.TransportNameLength =
|
|
WorkContext->Endpoint->TransportName.Length;
|
|
|
|
RtlCopyMemory(
|
|
requestMessage.Message.DownLevelApi.TransportName,
|
|
WorkContext->Endpoint->TransportName.Buffer,
|
|
WorkContext->Endpoint->TransportName.Length
|
|
);
|
|
|
|
//
|
|
// Null terminate the transport name.
|
|
//
|
|
|
|
requestMessage.Message.DownLevelApi.TransportName[ WorkContext->Endpoint->TransportName.Length / sizeof(WCHAR) ] = UNICODE_NULL;
|
|
|
|
//
|
|
// Adjust the transport name to be self relative within the buffer.
|
|
//
|
|
|
|
requestMessage.Message.DownLevelApi.TransportName =
|
|
(PWSTR)((PUCHAR)requestMessage.Message.DownLevelApi.TransportName +
|
|
SrvXsPortMemoryDelta);
|
|
|
|
//
|
|
// Build the server name in the message
|
|
//
|
|
RtlCopyMemory(
|
|
requestMessage.Message.DownLevelApi.ServerName,
|
|
WorkContext->Endpoint->TransportAddress.Buffer,
|
|
MIN( sizeof(requestMessage.Message.DownLevelApi.ServerName),
|
|
WorkContext->Endpoint->TransportAddress.Length )
|
|
);
|
|
|
|
requestMessage.Message.DownLevelApi.Transaction =
|
|
(PTRANSACTION)( (PCHAR)transaction + SrvXsPortMemoryDelta );
|
|
|
|
//
|
|
// Set up the message to send over the port.
|
|
//
|
|
|
|
requestMessage.PortMessage.u1.s1.DataLength =
|
|
(USHORT)( sizeof(requestMessage) - sizeof(PORT_MESSAGE) );
|
|
requestMessage.PortMessage.u1.s1.TotalLength = sizeof(requestMessage);
|
|
requestMessage.PortMessage.u2.ZeroInit = 0;
|
|
requestMessage.PortMessage.u2.s2.Type = LPC_KERNELMODE_MESSAGE;
|
|
requestMessage.MessageType = XACTSRV_MESSAGE_DOWN_LEVEL_API;
|
|
|
|
//
|
|
// Copy the client machine name for XACTSRV, skipping over the
|
|
// initial "\\", and deleting trailing spaces.
|
|
//
|
|
|
|
destPtr = requestMessage.Message.DownLevelApi.ClientMachineName;
|
|
sourcePtr =
|
|
connection->ClientMachineNameString.Buffer + 2;
|
|
sourceEndPtr = sourcePtr
|
|
+ min( connection->ClientMachineNameString.Length,
|
|
sizeof(requestMessage.Message.DownLevelApi.ClientMachineName) /
|
|
sizeof(WCHAR) - 1 );
|
|
|
|
while ( sourcePtr < sourceEndPtr && *sourcePtr != UNICODE_NULL ) {
|
|
*destPtr++ = *sourcePtr++;
|
|
}
|
|
|
|
*destPtr-- = UNICODE_NULL;
|
|
|
|
while ( destPtr >= requestMessage.Message.DownLevelApi.ClientMachineName
|
|
&&
|
|
*destPtr == L' ' ) {
|
|
*destPtr-- = UNICODE_NULL;
|
|
}
|
|
|
|
//
|
|
// Copy the lanman session key. This will be used to decrypt doubly
|
|
// encrypted passwords.
|
|
//
|
|
|
|
RtlCopyMemory(
|
|
requestMessage.Message.DownLevelApi.LanmanSessionKey,
|
|
session->LanManSessionKey,
|
|
MSV1_0_LANMAN_SESSION_KEY_LENGTH
|
|
);
|
|
|
|
//
|
|
// Set the flags
|
|
//
|
|
|
|
requestMessage.Message.DownLevelApi.Flags = 0;
|
|
|
|
if ( IS_NT_DIALECT( connection->SmbDialect ) ) {
|
|
|
|
requestMessage.Message.DownLevelApi.Flags |= XS_FLAGS_NT_CLIENT;
|
|
}
|
|
|
|
//
|
|
// Send the message to XACTSRV and wait for a response message.
|
|
//
|
|
// !!! We may want to put a timeout on this.
|
|
//
|
|
|
|
IF_DEBUG(XACTSRV) {
|
|
KdPrint(( "SrvXsRequest: Sending message at %p, port mem %p.\n",
|
|
&requestMessage, transaction ));
|
|
}
|
|
|
|
status = IMPERSONATE( WorkContext );
|
|
|
|
if( NT_SUCCESS( status ) ) {
|
|
|
|
status = NtRequestWaitReplyPort(
|
|
SrvXsPortHandle,
|
|
(PPORT_MESSAGE)&requestMessage,
|
|
(PPORT_MESSAGE)&replyMessage
|
|
);
|
|
|
|
REVERT( );
|
|
}
|
|
|
|
if ( !NT_SUCCESS(status) ) {
|
|
IF_DEBUG(ERRORS) {
|
|
KdPrint(( "SrvXsRequest: NtRequestWaitReplyPort failed: %X\n",
|
|
status ));
|
|
}
|
|
SrvSetSmbError( WorkContext, status );
|
|
returnStatus = SmbTransStatusErrorWithoutData;
|
|
goto exit;
|
|
}
|
|
|
|
IF_DEBUG(XACTSRV) {
|
|
KdPrint(( "SrvXsRequest: Received response at %p\n", &replyMessage ));
|
|
}
|
|
|
|
//
|
|
// Check the status returned in the reply.
|
|
//
|
|
|
|
status = replyMessage.Message.DownLevelApi.Status;
|
|
|
|
if ( !NT_SUCCESS(status) ) {
|
|
IF_DEBUG(SMB_ERRORS) {
|
|
KdPrint(( "SrvXsRequest: XACTSRV reply had status %X\n", status ));
|
|
}
|
|
SrvSetSmbError( WorkContext, status );
|
|
returnStatus = SmbTransStatusErrorWithoutData;
|
|
goto exit;
|
|
}
|
|
|
|
returnStatus = SmbTransStatusSuccess;
|
|
|
|
exit:
|
|
|
|
//
|
|
// We're done with the API. Free up the buffer containing the
|
|
// transport name.
|
|
//
|
|
|
|
if ( requestMessage.Message.DownLevelApi.TransportName != NULL ) {
|
|
|
|
requestMessage.Message.DownLevelApi.TransportName =
|
|
(PWSTR)((PUCHAR)requestMessage.Message.DownLevelApi.TransportName -
|
|
SrvXsPortMemoryDelta);
|
|
|
|
SrvXsFreeHeap( requestMessage.Message.DownLevelApi.TransportName );
|
|
|
|
}
|
|
|
|
//
|
|
// Convert the relevant pointers in the transaction block back to
|
|
// the server base.
|
|
//
|
|
|
|
transaction->TransactionName.Buffer -= SrvXsPortMemoryDelta;
|
|
transaction->InSetup -= SrvXsPortMemoryDelta;
|
|
transaction->OutSetup -= SrvXsPortMemoryDelta;
|
|
transaction->InParameters -= SrvXsPortMemoryDelta;
|
|
transaction->OutParameters -= SrvXsPortMemoryDelta;
|
|
transaction->InData -= SrvXsPortMemoryDelta;
|
|
transaction->OutData -= SrvXsPortMemoryDelta;
|
|
|
|
return returnStatus;
|
|
|
|
} // SrvXsRequest
|
|
|
|
|
|
NTSTATUS
|
|
SrvXsLSOperation (
|
|
IN PSESSION Session,
|
|
IN ULONG Type
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine causes the Xact service to do an NtLSRequest call
|
|
|
|
Arguments:
|
|
|
|
Session - a pointer to the session structure involved in the request
|
|
|
|
Type - either XACTSRV_MESSAGE_LSREQUEST or XACTSRV_MESSAGE_LSRELEASE
|
|
depending on whether a license is being requested or being
|
|
released.
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS if the license was granted
|
|
|
|
Notes:
|
|
Once a license is granted for a particular session, it is never released
|
|
until the session is deallocated. Therefore, it is only necessary to
|
|
hold the Session->Connection->LicenseLock when we are checking for
|
|
acquisition of the license.
|
|
|
|
We don't need licenses if we are running on a workstation.
|
|
We don't try for licenses over NULL sessions
|
|
|
|
--*/
|
|
|
|
{
|
|
XACTSRV_REQUEST_MESSAGE requestMessage;
|
|
XACTSRV_REPLY_MESSAGE replyMessage;
|
|
NTSTATUS status;
|
|
ULONG requestLength;
|
|
UNICODE_STRING userName, userDomain;
|
|
|
|
PAGED_CODE( );
|
|
|
|
if( SrvProductTypeServer == FALSE || !SrvXsActive ) {
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
switch( Type ) {
|
|
case XACTSRV_MESSAGE_LSREQUEST:
|
|
|
|
if( Session->IsNullSession ||
|
|
Session->IsLSNotified ) {
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
ACQUIRE_LOCK( &Session->Connection->LicenseLock );
|
|
|
|
if( Session->IsLSNotified == TRUE ) {
|
|
RELEASE_LOCK( &Session->Connection->LicenseLock );
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
//
|
|
// Put domainname\username in the message
|
|
//
|
|
status = SrvGetUserAndDomainName( Session, &userName, &userDomain );
|
|
if( !NT_SUCCESS( status ) ) {
|
|
RELEASE_LOCK( &Session->Connection->LicenseLock );
|
|
return status;
|
|
}
|
|
|
|
requestMessage.Message.LSRequest.UserName =
|
|
SrvXsAllocateHeap( userDomain.Length + sizeof(WCHAR)
|
|
+ userName.Length + sizeof(WCHAR), &status
|
|
);
|
|
|
|
if ( requestMessage.Message.LSRequest.UserName == NULL ) {
|
|
RELEASE_LOCK( &Session->Connection->LicenseLock );
|
|
SrvReleaseUserAndDomainName( Session, &userName, &userDomain );
|
|
return status;
|
|
}
|
|
|
|
if( userDomain.Length ) {
|
|
RtlCopyMemory(
|
|
requestMessage.Message.LSRequest.UserName,
|
|
userDomain.Buffer,
|
|
userDomain.Length
|
|
);
|
|
}
|
|
|
|
requestMessage.Message.LSRequest.UserName[ userDomain.Length / sizeof(WCHAR) ] = L'\\';
|
|
|
|
RtlCopyMemory(
|
|
requestMessage.Message.LSRequest.UserName + (userDomain.Length / sizeof( WCHAR )) + 1,
|
|
userName.Buffer,
|
|
userName.Length
|
|
);
|
|
|
|
requestMessage.Message.LSRequest.UserName[ (userDomain.Length
|
|
+ userName.Length) / sizeof( WCHAR )
|
|
+ 1 ]
|
|
= UNICODE_NULL;
|
|
|
|
requestMessage.Message.LSRequest.IsAdmin = Session->IsAdmin;
|
|
|
|
IF_DEBUG(LICENSE) {
|
|
KdPrint(("XACTSRV_MESSAGE_LSREQUEST: %ws, IsAdmin: %d\n",
|
|
requestMessage.Message.LSRequest.UserName,
|
|
requestMessage.Message.LSRequest.IsAdmin ));
|
|
}
|
|
|
|
// Adjust the buffer pointers to be self relative within the buffer.
|
|
|
|
requestMessage.Message.LSRequest.UserName =
|
|
(PWSTR)((PUCHAR)requestMessage.Message.LSRequest.UserName + SrvXsPortMemoryDelta);
|
|
|
|
SrvReleaseUserAndDomainName( Session, &userName, &userDomain );
|
|
|
|
break;
|
|
|
|
case XACTSRV_MESSAGE_LSRELEASE:
|
|
|
|
if( Session->IsLSNotified == FALSE )
|
|
return STATUS_SUCCESS;
|
|
|
|
IF_DEBUG(LICENSE) {
|
|
KdPrint(("XACTSRV_MESSAGE_LSRELEASE: Handle %p\n", Session->hLicense ));
|
|
}
|
|
|
|
|
|
requestMessage.Message.LSRelease.hLicense = Session->hLicense;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
ASSERT( !"Bad Type" );
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
requestMessage.PortMessage.u1.s1.DataLength =
|
|
(USHORT)( sizeof(requestMessage) - sizeof(PORT_MESSAGE) );
|
|
requestMessage.PortMessage.u1.s1.TotalLength = sizeof(requestMessage);
|
|
requestMessage.PortMessage.u2.ZeroInit = 0;
|
|
requestMessage.PortMessage.u2.s2.Type = LPC_KERNELMODE_MESSAGE;
|
|
requestMessage.MessageType = Type;
|
|
|
|
//
|
|
// Send the message to XACTSRV and wait for a response message.
|
|
//
|
|
// !!! We may want to put a timeout on this.
|
|
//
|
|
|
|
status = NtRequestWaitReplyPort(
|
|
SrvXsPortHandle,
|
|
(PPORT_MESSAGE)&requestMessage,
|
|
(PPORT_MESSAGE)&replyMessage
|
|
);
|
|
|
|
IF_DEBUG( ERRORS ) {
|
|
if( !NT_SUCCESS( status ) ) {
|
|
KdPrint(( "SrvXsLSOperation: NtRequestWaitReplyPort failed: %X\n", status ));
|
|
}
|
|
}
|
|
|
|
if( NT_SUCCESS( status ) )
|
|
status = replyMessage.Message.LSRequest.Status;
|
|
|
|
switch( Type ) {
|
|
|
|
case XACTSRV_MESSAGE_LSREQUEST:
|
|
|
|
requestMessage.Message.LSRequest.UserName =
|
|
(PWSTR)((PUCHAR)requestMessage.Message.LSRequest.UserName - SrvXsPortMemoryDelta);
|
|
SrvXsFreeHeap( requestMessage.Message.LSRequest.UserName );
|
|
|
|
if( NT_SUCCESS( status ) ) {
|
|
Session->IsLSNotified = TRUE;
|
|
Session->hLicense = replyMessage.Message.LSRequest.hLicense;
|
|
IF_DEBUG( LICENSE ) {
|
|
KdPrint((" hLicense = %p\n", Session->hLicense ));
|
|
}
|
|
}
|
|
RELEASE_LOCK( &Session->Connection->LicenseLock );
|
|
break;
|
|
|
|
case XACTSRV_MESSAGE_LSRELEASE:
|
|
|
|
Session->IsLSNotified = FALSE;
|
|
break;
|
|
}
|
|
|
|
IF_DEBUG( LICENSE ) {
|
|
if( !NT_SUCCESS( status ) ) {
|
|
KdPrint(( " SrvXsLSOperation returning status %X\n", status ));
|
|
}
|
|
}
|
|
|
|
return status;
|
|
|
|
} // SrvXsLSOperation
|
|
|
|
|
|
VOID
|
|
SrvXsPnpOperation(
|
|
PUNICODE_STRING DeviceName,
|
|
BOOLEAN Bind
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine sends the Xact service a PNP notification
|
|
|
|
--*/
|
|
|
|
{
|
|
PXACTSRV_REQUEST_MESSAGE requestMessage;
|
|
PXACTSRV_REQUEST_MESSAGE responseMessage;
|
|
ULONG len;
|
|
NTSTATUS status;
|
|
|
|
PAGED_CODE( );
|
|
|
|
if( SrvXsPortHandle == NULL ) {
|
|
IF_DEBUG( PNP ) {
|
|
KdPrint(( "SRV: SrvXsPnpOperation no SRVSVC handle!\n" ));
|
|
}
|
|
return;
|
|
}
|
|
|
|
len = (sizeof( XACTSRV_REQUEST_MESSAGE ) * 2) + DeviceName->Length + sizeof( WCHAR );
|
|
|
|
requestMessage = SrvXsAllocateHeap( len, &status );
|
|
|
|
if( requestMessage == NULL ) {
|
|
IF_DEBUG( PNP ) {
|
|
KdPrint(( "SRV: SrvXsPnpOperation unable to allocate memory: %X\n", status ));
|
|
}
|
|
return;
|
|
}
|
|
|
|
RtlZeroMemory( requestMessage, len );
|
|
|
|
responseMessage = requestMessage + 1;
|
|
requestMessage->Message.Pnp.TransportName.Buffer = (PWCHAR)(responseMessage + 1);
|
|
|
|
requestMessage->Message.Pnp.Bind = Bind;
|
|
|
|
//
|
|
// Send the name of the transport of interest to Xactsrv
|
|
//
|
|
requestMessage->Message.Pnp.TransportName.Length = DeviceName->Length;
|
|
requestMessage->Message.Pnp.TransportName.MaximumLength = DeviceName->Length + sizeof( WCHAR );
|
|
|
|
RtlCopyMemory( requestMessage->Message.Pnp.TransportName.Buffer,
|
|
DeviceName->Buffer,
|
|
DeviceName->Length
|
|
);
|
|
|
|
//
|
|
// Normalize the buffer pointer so xactsrv can rebase it
|
|
//
|
|
requestMessage->Message.Pnp.TransportName.Buffer =
|
|
(PWSTR)((PUCHAR)requestMessage->Message.Pnp.TransportName.Buffer + SrvXsPortMemoryDelta);
|
|
|
|
requestMessage->PortMessage.u1.s1.DataLength =
|
|
(USHORT)( sizeof(*requestMessage) - sizeof(PORT_MESSAGE) );
|
|
requestMessage->PortMessage.u1.s1.TotalLength = sizeof(*requestMessage);
|
|
requestMessage->PortMessage.u2.ZeroInit = 0;
|
|
requestMessage->PortMessage.u2.s2.Type = LPC_KERNELMODE_MESSAGE;
|
|
requestMessage->MessageType = XACTSRV_MESSAGE_PNP;
|
|
|
|
//
|
|
// Send the message to XACTSRV
|
|
//
|
|
|
|
IF_DEBUG( PNP ) {
|
|
KdPrint(( "SRV: Sending PNP %sbind request for %wZ to SRVSVC\n",
|
|
requestMessage->Message.Pnp.Bind ? "" : "un", DeviceName
|
|
));
|
|
}
|
|
|
|
status = NtRequestWaitReplyPort(
|
|
SrvXsPortHandle,
|
|
(PPORT_MESSAGE)requestMessage,
|
|
(PPORT_MESSAGE)responseMessage
|
|
);
|
|
|
|
|
|
IF_DEBUG( PNP ) {
|
|
if( !NT_SUCCESS( status ) ) {
|
|
KdPrint(( "SRV: PNP response from xactsrv status %X\n", status ));
|
|
}
|
|
}
|
|
|
|
SrvXsFreeHeap( requestMessage );
|
|
}
|
|
|
|
|
|
VOID
|
|
SrvXsDisconnect ( )
|
|
{
|
|
NTSTATUS status;
|
|
|
|
PAGED_CODE( );
|
|
|
|
//
|
|
// Acquire exclusive access to the port resource, to prevent new
|
|
// requests from being started.
|
|
//
|
|
|
|
IF_DEBUG(XACTSRV) {
|
|
KdPrint(( "SrvXsDisconnect: Xactsrv disconnect called.\n"));
|
|
}
|
|
|
|
ExAcquireResourceExclusiveLite( &SrvXsResource, TRUE );
|
|
|
|
SrvXsActive = FALSE;
|
|
|
|
SrvXsFreeSharedMemory();
|
|
|
|
ExReleaseResourceLite( &SrvXsResource );
|
|
|
|
IF_DEBUG(XACTSRV) {
|
|
KdPrint(( "SrvXsDisconnect: SrvXsResource released.\n"));
|
|
}
|
|
|
|
return;
|
|
|
|
} // SrvXsDisconnect
|
|
|
|
|
|
VOID
|
|
SrvXsFreeSharedMemory (
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine frees the xactsrv shared memory. SrvXsResource assumed
|
|
held exclusive.
|
|
|
|
Arguments:
|
|
|
|
none.
|
|
|
|
Return Value:
|
|
|
|
TRUE if xactsrv memory was freed, FALSE otherwise.
|
|
|
|
--*/
|
|
|
|
{
|
|
PAGED_CODE( );
|
|
|
|
//
|
|
// Free up memory only if we don't have any transactions using the
|
|
// shared memory.
|
|
//
|
|
|
|
if ( SrvXsSharedMemoryReference == 0 ) {
|
|
if ( SrvXsPortMemoryHeap != NULL ) {
|
|
RtlDestroyHeap( SrvXsPortMemoryHeap );
|
|
SrvXsPortMemoryHeap = NULL;
|
|
}
|
|
|
|
if ( SrvXsSectionHandle != NULL ) {
|
|
SrvNtClose( SrvXsSectionHandle, FALSE );
|
|
SrvXsSectionHandle = NULL;
|
|
}
|
|
|
|
if ( SrvXsPortHandle != NULL ) {
|
|
SrvNtClose( SrvXsPortHandle, FALSE );
|
|
SrvXsPortHandle = NULL;
|
|
}
|
|
|
|
IF_DEBUG(XACTSRV) {
|
|
KdPrint(( "SrvXsFreeSharedMemory: Xactsrv memory freed.\n" ));
|
|
}
|
|
} else {
|
|
IF_DEBUG(XACTSRV) {
|
|
KdPrint(( "SrvXsFreeSharedMemory: Active transactions %d.\n",
|
|
SrvXsSharedMemoryReference ));
|
|
}
|
|
}
|
|
|
|
return;
|
|
|
|
} // SrvXsFreeSharedMemory
|
|
|
|
|
|
PVOID
|
|
SrvXsAllocateHeap (
|
|
IN ULONG SizeOfAllocation OPTIONAL,
|
|
OUT PNTSTATUS Status
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine allocates heap from the Xs shared memory.
|
|
|
|
Arguments:
|
|
|
|
SizeOfAllocation - if specified, the number of bytes to allocate.
|
|
if zero, no memory will be allocated.
|
|
|
|
Status - the status of the request.
|
|
|
|
Return Value:
|
|
|
|
Address of the allocated memory. NULL, if no memory is allocated.
|
|
|
|
--*/
|
|
|
|
{
|
|
PVOID heapAllocated = NULL;
|
|
|
|
PAGED_CODE( );
|
|
|
|
*Status = STATUS_SUCCESS;
|
|
|
|
//
|
|
// Check that XACTSRV is active. This must be done while holding
|
|
// the resource.
|
|
//
|
|
|
|
ExAcquireResourceExclusiveLite( &SrvXsResource, TRUE );
|
|
IF_DEBUG(XACTSRV) {
|
|
KdPrint(( "SrvXsAllocateHeap: SrvXsResource acquired.\n"));
|
|
}
|
|
|
|
if ( !SrvXsActive ) {
|
|
IF_DEBUG(ERRORS) {
|
|
KdPrint(( "SrvXsAllocateHeap: XACTSRV is not active.\n" ));
|
|
}
|
|
ExReleaseResourceLite( &SrvXsResource );
|
|
IF_DEBUG(XACTSRV) {
|
|
KdPrint(( "SrvXsAllocateHeap: SrvXsResource released.\n"));
|
|
}
|
|
*Status = STATUS_NOT_SUPPORTED;
|
|
return NULL;
|
|
}
|
|
|
|
//
|
|
// Increment reference to our shared memory.
|
|
//
|
|
|
|
SrvXsSharedMemoryReference++;
|
|
|
|
IF_DEBUG(XACTSRV) {
|
|
KdPrint(( "SrvXsAllocateHeap: Incremented transaction count = %d.\n",
|
|
SrvXsSharedMemoryReference
|
|
));
|
|
}
|
|
|
|
//
|
|
// If SizeOfAllocation == 0, then the caller does not want any heap
|
|
// allocated and only wants to have the lock held.
|
|
//
|
|
|
|
IF_DEBUG(XACTSRV) {
|
|
KdPrint(( "SrvXsAllocateHeap: Heap to allocate %d bytes.\n",
|
|
SizeOfAllocation
|
|
));
|
|
}
|
|
|
|
if ( SizeOfAllocation > 0 ) {
|
|
|
|
heapAllocated = RtlAllocateHeap(
|
|
SrvXsPortMemoryHeap,
|
|
HEAP_NO_SERIALIZE,
|
|
SizeOfAllocation
|
|
);
|
|
|
|
if ( heapAllocated == NULL ) {
|
|
|
|
IF_DEBUG(ERRORS) {
|
|
KdPrint(( "SrvXsAllocateHeap: RtlAllocateHeap failed "
|
|
"to allocate %d bytes.\n",
|
|
SizeOfAllocation
|
|
));
|
|
}
|
|
|
|
*Status = STATUS_INSUFF_SERVER_RESOURCES;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Release the resource.
|
|
//
|
|
|
|
ExReleaseResourceLite( &SrvXsResource );
|
|
IF_DEBUG(XACTSRV) {
|
|
KdPrint(( "SrvXsAllocateHeap: SrvXsResource released.\n"));
|
|
}
|
|
|
|
return heapAllocated;
|
|
|
|
} // SrvXsAllocateHeap
|
|
|
|
|
|
VOID
|
|
SrvXsFreeHeap (
|
|
IN PVOID MemoryToFree OPTIONAL
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine frees heap allocated through SrvXsAllocateHeap.
|
|
|
|
Arguments:
|
|
|
|
MemoryToFree - pointer to the memory to be freed. If NULL, no memory
|
|
is freed.
|
|
|
|
Return Value:
|
|
|
|
none.
|
|
|
|
--*/
|
|
|
|
{
|
|
PAGED_CODE( );
|
|
|
|
//
|
|
// We need exclusive access to the resource in order to free
|
|
// heap and decrement the reference count.
|
|
//
|
|
|
|
ExAcquireResourceExclusiveLite( &SrvXsResource, TRUE );
|
|
IF_DEBUG(XACTSRV) {
|
|
KdPrint(( "SrvXsFreeHeap: SrvXsResource acquired.\n"));
|
|
}
|
|
|
|
//
|
|
// Free the allocated heap (if any).
|
|
//
|
|
|
|
if ( MemoryToFree != NULL ) {
|
|
RtlFreeHeap( SrvXsPortMemoryHeap, 0, MemoryToFree );
|
|
IF_DEBUG(XACTSRV) {
|
|
KdPrint(( "SrvXsFreeHeap: Heap %p freed.\n", MemoryToFree ));
|
|
}
|
|
}
|
|
|
|
//
|
|
// Decrement the shared memory reference count, and check whether XS
|
|
// shutdown is in progress. If so, complete XS cleanup if the
|
|
// reference count reaches 0.
|
|
//
|
|
|
|
ASSERT( SrvXsSharedMemoryReference > 0 );
|
|
SrvXsSharedMemoryReference--;
|
|
|
|
IF_DEBUG(XACTSRV) {
|
|
KdPrint(( "SrvXsFreeHeap: Decrement transaction count = %d.\n",
|
|
SrvXsSharedMemoryReference
|
|
));
|
|
}
|
|
|
|
//
|
|
// If SrvXsActive is FALSE, XACTSRV cleanup is in progress.
|
|
//
|
|
|
|
if ( !SrvXsActive ) {
|
|
SrvXsFreeSharedMemory( );
|
|
}
|
|
|
|
//
|
|
// Release the resource.
|
|
//
|
|
|
|
ExReleaseResourceLite( &SrvXsResource );
|
|
IF_DEBUG(XACTSRV) {
|
|
KdPrint(( "SrvXsFreeHeap: SrvXsResource released.\n"));
|
|
}
|
|
|
|
return;
|
|
|
|
} // SrvXsFreeHeap
|