/*++ Copyright (c) 1997 Microsoft Corporation Module Name: lpc.c Abstract: This module contains the code necessary to support sites using lpc upcalls from the dfs driver. Author: Jim Harper (JHarper) 11-Dec-97 Revision History: --*/ #include "dfsprocs.h" #include "dfslpc.h" #include #pragma hdrstop #include "fsctrl.h" #include "ipsup.h" typedef struct { WORK_QUEUE_ITEM WorkQueueItem; } DFS_CONNECT_ARG, *PDFS_CONNECT_ARG; typedef struct { WORK_QUEUE_ITEM WorkQueueItem; DFS_IPADDRESS IpAddress; } DFS_REQUEST_ARG, *PDFS_REQUEST_ARG; VOID DfsLpcConnect ( IN PDFS_CONNECT_ARG DfsConnectArg ); #define Dbg 0x2000 #ifdef ALLOC_PRAGMA #pragma alloc_text( PAGE, DfsLpcConnect ) #pragma alloc_text( PAGE, DfsLpcIpRequest ) #pragma alloc_text( PAGE, DfsLpcDomRequest ) #pragma alloc_text( PAGE, DfsLpcDisconnect ) #endif VOID DfsLpcConnect ( IN PDFS_CONNECT_ARG DfsConnectArg) { NTSTATUS status = STATUS_SUCCESS; SECURITY_QUALITY_OF_SERVICE dynamicQos; PDFS_LPC_INFO pLpcInfo = &DfsData.DfsLpcInfo; DebugTrace(+1, Dbg, "DfsLpcConnect(Name=%wZ)\n", &pLpcInfo->LpcPortName); DebugTrace( 0, Dbg, "DfsLpcConnect(Handle=0x%x)\n", &pLpcInfo->LpcPortHandle); PAGED_CODE(); dynamicQos.Length = sizeof(SECURITY_QUALITY_OF_SERVICE); dynamicQos.ImpersonationLevel = SecurityAnonymous; dynamicQos.ContextTrackingMode = SECURITY_STATIC_TRACKING; dynamicQos.EffectiveOnly = TRUE; ExAcquireResourceExclusiveLite( &pLpcInfo->LpcPortResource, TRUE ); ASSERT(pLpcInfo->LpcPortName.Buffer != NULL); pLpcInfo->LpcPortState = LPC_STATE_INITIALIZED; status = NtConnectPort( &pLpcInfo->LpcPortHandle, &pLpcInfo->LpcPortName, &dynamicQos, NULL, // ClientView NULL, // ServerView NULL, // MaxMessageLength NULL, // ConnectionInformation NULL // ConnectionInformationLength ); DebugTrace(-1, Dbg, "DfsLpcConnect: NtConnectPort returned 0x%x\n", ULongToPtr( status )); if (!NT_SUCCESS(status)) { pLpcInfo->LpcPortState = LPC_STATE_UNINITIALIZED; if ( pLpcInfo->LpcPortHandle != NULL ) { NtClose( pLpcInfo->LpcPortHandle); pLpcInfo->LpcPortHandle = NULL; } if (pLpcInfo->LpcPortName.Buffer != NULL) { ExFreePool(pLpcInfo->LpcPortName.Buffer); RtlInitUnicodeString(&pLpcInfo->LpcPortName, NULL); } } ExReleaseResourceLite( &pLpcInfo->LpcPortResource ); ExFreePool(DfsConnectArg); return; } NTSTATUS DfsLpcIpRequest ( PDFS_IPADDRESS pIpAddress) { NTSTATUS status; DFSSRV_REQUEST_MESSAGE requestMessage; DFSSRV_REPLY_MESSAGE replyMessage; PDFS_LPC_INFO pLpcInfo = &DfsData.DfsLpcInfo; PAGED_CODE(); requestMessage.Message.GetSiteName.IpAddress = *pIpAddress; // // 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.MessageType = DFSSRV_MESSAGE_GET_SITE_NAME; // // Send the message and wait for a response message. // status = NtRequestWaitReplyPort( pLpcInfo->LpcPortHandle, (PPORT_MESSAGE)&requestMessage, (PPORT_MESSAGE)&replyMessage ); if ( !NT_SUCCESS(status) ) { goto exit; } // // Check the status returned in the reply. // status = replyMessage.Message.Result.Status; exit: return status; } NTSTATUS DfsLpcDomRequest ( PUNICODE_STRING pFtName) { NTSTATUS status; DFSSRV_REQUEST_MESSAGE requestMessage; DFSSRV_REPLY_MESSAGE replyMessage; PDFS_LPC_INFO pLpcInfo = &DfsData.DfsLpcInfo; PAGED_CODE(); if ( pFtName->Length > ((MAX_FTNAME_LEN - 1) * sizeof(WCHAR))) { return STATUS_INSUFFICIENT_RESOURCES; } RtlZeroMemory(requestMessage.Message.GetFtDfs.FtName, MAX_FTNAME_LEN * sizeof(WCHAR)); RtlCopyMemory(requestMessage.Message.GetFtDfs.FtName, pFtName->Buffer, pFtName->Length); // // 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.MessageType = DFSSRV_MESSAGE_GET_DOMAIN_REFERRAL; // // Send the message and wait for a response message. // status = NtRequestWaitReplyPort( pLpcInfo->LpcPortHandle, (PPORT_MESSAGE)&requestMessage, (PPORT_MESSAGE)&replyMessage ); if ( !NT_SUCCESS(status) ) { goto exit; } // // Check the status returned in the reply. // status = replyMessage.Message.Result.Status; exit: return status; } NTSTATUS DfsLpcSpcRequest( PUNICODE_STRING pSpcName, ULONG TypeFlags) { NTSTATUS status; DFSSRV_REQUEST_MESSAGE requestMessage; DFSSRV_REPLY_MESSAGE replyMessage; PDFS_LPC_INFO pLpcInfo = &DfsData.DfsLpcInfo; PAGED_CODE(); if ( pSpcName->Length > ((MAX_SPCNAME_LEN - 1) * sizeof(WCHAR))) { pSpcName = NULL; } RtlZeroMemory(requestMessage.Message.GetSpcName.SpcName, MAX_SPCNAME_LEN * sizeof(WCHAR)); if (pSpcName != NULL) { RtlCopyMemory(requestMessage.Message.GetSpcName.SpcName, pSpcName->Buffer, pSpcName->Length); } requestMessage.Message.GetSpcName.Flags = TypeFlags; // // 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.MessageType = DFSSRV_MESSAGE_GET_SPC_ENTRY; // // Send the message and wait for a response message. // status = NtRequestWaitReplyPort( pLpcInfo->LpcPortHandle, (PPORT_MESSAGE)&requestMessage, (PPORT_MESSAGE)&replyMessage ); if ( !NT_SUCCESS(status) ) { goto exit; } // // Check the status returned in the reply. // status = replyMessage.Message.Result.Status; exit: return status; } VOID DfsLpcDisconnect ( ) { NTSTATUS status; PDFS_LPC_INFO pLpcInfo = &DfsData.DfsLpcInfo; PAGED_CODE(); // // Acquire exclusive access to the port resource, to prevent new // requests from being started. // ExAcquireResourceExclusiveLite( &pLpcInfo->LpcPortResource, TRUE ); pLpcInfo->LpcPortState = LPC_STATE_UNINITIALIZED; if (pLpcInfo->LpcPortHandle != NULL) { NtClose( pLpcInfo->LpcPortHandle); pLpcInfo->LpcPortHandle = NULL; } if (pLpcInfo->LpcPortName.Buffer != NULL) { ExFreePool(pLpcInfo->LpcPortName.Buffer); RtlInitUnicodeString(&pLpcInfo->LpcPortName, NULL); } ExReleaseResourceLite( &pLpcInfo->LpcPortResource ); return; } NTSTATUS PktFsctrlDfsSrvConnect( IN PIRP Irp, IN PVOID InputBuffer, IN ULONG InputBufferLength) { NTSTATUS status = STATUS_SUCCESS; PDFS_SRV_DFSSRV_CONNECT_ARG arg; PDFS_CONNECT_ARG DfsConnectArg = NULL; PDFS_LPC_INFO pLpcInfo = &DfsData.DfsLpcInfo; STD_FSCTRL_PROLOGUE(DfsFsctrlDfsSrvConnect, TRUE, FALSE); if (InputBufferLength < sizeof(DFS_SRV_DFSSRV_CONNECT_ARG)) { status = STATUS_INVALID_PARAMETER; goto exit_with_status; } // // unmarshal the arguments... // arg = (PDFS_SRV_DFSSRV_CONNECT_ARG) InputBuffer; OFFSET_TO_POINTER(arg->PortName.Buffer, arg); if (!UNICODESTRING_IS_VALID(arg->PortName, InputBuffer, InputBufferLength)) { status = STATUS_INVALID_PARAMETER; goto exit_with_status; } DfsConnectArg = ExAllocatePoolWithTag( NonPagedPool, sizeof(DFS_CONNECT_ARG), ' sfD'); if (DfsConnectArg == NULL) { status = STATUS_INSUFFICIENT_RESOURCES; goto exit_with_status; } ExAcquireResourceExclusiveLite( &pLpcInfo->LpcPortResource, TRUE ); #if 0 if (pLpcInfo->LpcPortName.Buffer != NULL) { ExFreePool(pLpcInfo->LpcPortName.Buffer); RtlInitUnicodeString(&pLpcInfo->LpcPortName, NULL); } if ( pLpcInfo->LpcPortHandle != NULL ) { NtClose( pLpcInfo->LpcPortHandle); pLpcInfo->LpcPortHandle = NULL; } #endif pLpcInfo->LpcPortName.Buffer = ExAllocatePoolWithTag( PagedPool, arg->PortName.Length, ' sfD'); if (pLpcInfo->LpcPortName.Buffer == NULL) { status = STATUS_INSUFFICIENT_RESOURCES; ExFreePool(DfsConnectArg); ExReleaseResourceLite( &pLpcInfo->LpcPortResource ); goto exit_with_status; } pLpcInfo->LpcPortName.Length = arg->PortName.Length; pLpcInfo->LpcPortName.MaximumLength = arg->PortName.Length; RtlCopyMemory( pLpcInfo->LpcPortName.Buffer, arg->PortName.Buffer, arg->PortName.Length); ExInitializeWorkItem( &DfsConnectArg->WorkQueueItem, DfsLpcConnect, DfsConnectArg); ExQueueWorkItem( &DfsConnectArg->WorkQueueItem, CriticalWorkQueue ); pLpcInfo->LpcPortState = LPC_STATE_INITIALIZING; ExReleaseResourceLite( &pLpcInfo->LpcPortResource ); exit_with_status: DfsCompleteRequest( Irp, status ); DebugTrace(-1, Dbg, "DfsFsctrlDfsSrvConnect: Exit -> %08lx\n", ULongToPtr( status ) ); return status; }