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.
2054 lines
72 KiB
2054 lines
72 KiB
/*++
|
|
|
|
Copyright (c) 1989 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
NtConnct.c
|
|
|
|
Abstract:
|
|
|
|
This module implements the nt version of the high level routines dealing with
|
|
connections including both the routines for establishing connections and the
|
|
winnet connection apis.
|
|
|
|
Author:
|
|
|
|
Joe Linn [JoeLinn] 1-mar-95
|
|
|
|
Revision History:
|
|
|
|
Balan Sethu Raman [SethuR] --
|
|
|
|
--*/
|
|
|
|
#include "precomp.h"
|
|
#pragma hdrstop
|
|
#include <ntddnfs2.h>
|
|
#include <ntddmup.h>
|
|
#include "fsctlbuf.h"
|
|
#include "prefix.h"
|
|
#include <lmuse.h> //need the lm constants here......because of wkssvc
|
|
#include "usrcnnct.h" //just to get the stovepipe definition
|
|
#include "secext.h"
|
|
#include "nb30.h" // to get ADAPTER_STATUS definition
|
|
#include "vcsndrcv.h"
|
|
|
|
//
|
|
// The Bug check file id for this module
|
|
//
|
|
|
|
#define BugCheckFileId (RDBSS_BUG_CHECK_NTCONNCT)
|
|
|
|
//
|
|
// The local trace mask for this part of the module
|
|
//
|
|
|
|
#define Dbg (DEBUG_TRACE_CONNECT)
|
|
|
|
VOID
|
|
MRxSmbGetConnectInfoLevel3Fields(
|
|
IN OUT PLMR_CONNECTION_INFO_3 ConnectionInfo,
|
|
IN PSMBCEDB_SERVER_ENTRY pServerEntry,
|
|
IN BOOL fAgentCall
|
|
);
|
|
|
|
extern NTSTATUS
|
|
MRxEnumerateTransportBindings(
|
|
IN PLMR_REQUEST_PACKET pLmrRequestPacket,
|
|
IN ULONG LmrRequestPacketLength,
|
|
OUT PVOID pBindingBuffer,
|
|
IN OUT ULONG BindingBufferLength);
|
|
|
|
BOOLEAN
|
|
MRxSmbShowConnection(
|
|
IN LUID LogonId,
|
|
IN PV_NET_ROOT VNetRoot
|
|
);
|
|
|
|
#ifdef _WIN64
|
|
typedef struct _UNICODE_STRING_32 {
|
|
USHORT Length;
|
|
USHORT MaximumLength;
|
|
WCHAR * POINTER_32 Buffer;
|
|
} UNICODE_STRING_32, *PUNICODE_STRING_32;
|
|
|
|
typedef struct _LMR_CONNECTION_INFO_0_32 {
|
|
UNICODE_STRING_32 UNCName; // Name of UNC connection
|
|
ULONG ResumeKey; // Resume key for this entry.
|
|
} LMR_CONNECTION_INFO_0_32, *PLMR_CONNECTION_INFO_0_32;
|
|
|
|
typedef struct _LMR_CONNECTION_INFO_1_32 {
|
|
UNICODE_STRING_32 UNCName; // Name of UNC connection
|
|
ULONG ResumeKey; // Resume key for this entry.
|
|
|
|
DEVICE_TYPE SharedResourceType; // Type of shared resource
|
|
ULONG ConnectionStatus; // Status of the connection
|
|
ULONG NumberFilesOpen; // Number of opened files
|
|
} LMR_CONNECTION_INFO_1_32, *PLMR_CONNECTION_INFO_1_32;
|
|
|
|
typedef struct _LMR_CONNECTION_INFO_2_32 {
|
|
UNICODE_STRING_32 UNCName; // Name of UNC connection
|
|
ULONG ResumeKey; // Resume key for this entry.
|
|
DEVICE_TYPE SharedResourceType; // Type of shared resource
|
|
ULONG ConnectionStatus; // Status of the connection
|
|
ULONG NumberFilesOpen; // Number of opened files
|
|
|
|
UNICODE_STRING_32 UserName; // User who created connection.
|
|
UNICODE_STRING_32 DomainName; // Domain of user who created connection.
|
|
ULONG Capabilities; // Bit mask of remote abilities.
|
|
UCHAR UserSessionKey[MSV1_0_USER_SESSION_KEY_LENGTH]; // User session key
|
|
UCHAR LanmanSessionKey[MSV1_0_LANMAN_SESSION_KEY_LENGTH]; // Lanman session key
|
|
} LMR_CONNECTION_INFO_2_32, *PLMR_CONNECTION_INFO_2_32;
|
|
|
|
typedef struct _LMR_CONNECTION_INFO_3_32 {
|
|
UNICODE_STRING_32 UNCName; // Name of UNC connection
|
|
ULONG ResumeKey; // Resume key for this entry.
|
|
DEVICE_TYPE SharedResourceType; // Type of shared resource
|
|
ULONG ConnectionStatus; // Status of the connection
|
|
ULONG NumberFilesOpen; // Number of opened files
|
|
|
|
UNICODE_STRING_32 UserName; // User who created connection.
|
|
UNICODE_STRING_32 DomainName; // Domain of user who created connection.
|
|
ULONG Capabilities; // Bit mask of remote abilities.
|
|
UCHAR UserSessionKey[MSV1_0_USER_SESSION_KEY_LENGTH]; // User session key
|
|
UCHAR LanmanSessionKey[MSV1_0_LANMAN_SESSION_KEY_LENGTH]; // Lanman session key
|
|
UNICODE_STRING_32 TransportName; // Transport connection is active on
|
|
ULONG Throughput; // Throughput of connection.
|
|
ULONG Delay; // Small packet overhead.
|
|
LARGE_INTEGER TimeZoneBias; // Time zone delta in 100ns units.
|
|
BOOL IsSpecialIpcConnection; // True IFF there is a special IPC connection active.
|
|
BOOL Reliable; // True iff the connection is reliable
|
|
BOOL ReadAhead; // True iff readahead is active on connection.
|
|
BOOL Core;
|
|
BOOL MsNet103;
|
|
BOOL Lanman10;
|
|
BOOL WindowsForWorkgroups;
|
|
BOOL Lanman20;
|
|
BOOL Lanman21;
|
|
BOOL WindowsNt;
|
|
BOOL MixedCasePasswords;
|
|
BOOL MixedCaseFiles;
|
|
BOOL LongNames;
|
|
BOOL ExtendedNegotiateResponse;
|
|
BOOL LockAndRead;
|
|
BOOL NtSecurity;
|
|
BOOL SupportsEa;
|
|
BOOL NtNegotiateResponse;
|
|
BOOL CancelSupport;
|
|
BOOL UnicodeStrings;
|
|
BOOL LargeFiles;
|
|
BOOL NtSmbs;
|
|
BOOL RpcRemoteAdmin;
|
|
BOOL NtStatusCodes;
|
|
BOOL LevelIIOplock;
|
|
BOOL UtcTime;
|
|
BOOL UserSecurity;
|
|
BOOL EncryptsPasswords;
|
|
} LMR_CONNECTION_INFO_3_32, *PLMR_CONNECTION_INFO_3_32;
|
|
|
|
VOID
|
|
MRxSmbGetConnectInfoLevel3FieldsThunked(
|
|
IN OUT PLMR_CONNECTION_INFO_3_32 ConnectionInfo,
|
|
IN PSMBCEDB_SERVER_ENTRY pServerEntry,
|
|
BOOL fAgentCall
|
|
);
|
|
|
|
BOOLEAN
|
|
MRxSmbPackStringIntoConnectInfoThunked(
|
|
IN PUNICODE_STRING_32 String,
|
|
IN PUNICODE_STRING Source,
|
|
IN OUT PCHAR * BufferStart,
|
|
IN OUT PCHAR * BufferEnd,
|
|
IN ULONG BufferDisplacement,
|
|
IN OUT PULONG TotalBytes
|
|
);
|
|
|
|
BOOLEAN
|
|
MRxSmbPackConnectEntryThunked (
|
|
IN OUT PRX_CONTEXT RxContext,
|
|
IN ULONG Level,
|
|
IN OUT PCHAR *BufferStart,
|
|
IN OUT PCHAR *BufferEnd,
|
|
IN PV_NET_ROOT VNetRoot,
|
|
IN OUT ULONG BufferDisplacement,
|
|
OUT PULONG TotalBytesNeeded
|
|
);
|
|
#endif
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text(PAGE, MRxSmbPackStringIntoConnectInfo)
|
|
#pragma alloc_text(PAGE, MRxSmbPackConnectEntry)
|
|
#pragma alloc_text(PAGE, MRxSmbGetConnectInfoLevel3Fields)
|
|
#pragma alloc_text(PAGE, MRxSmbEnumerateConnections)
|
|
#pragma alloc_text(PAGE, MRxSmbGetConnectionInfo)
|
|
#pragma alloc_text(PAGE, MRxSmbDeleteConnection)
|
|
#pragma alloc_text(PAGE, MRxEnumerateTransports)
|
|
#pragma alloc_text(PAGE, MRxEnumerateTransportBindings)
|
|
#ifdef _WIN64
|
|
#pragma alloc_text(PAGE, MRxSmbGetConnectInfoLevel3FieldsThunked)
|
|
#pragma alloc_text(PAGE, MRxSmbPackStringIntoConnectInfoThunked)
|
|
#pragma alloc_text(PAGE, MRxSmbPackConnectEntryThunked)
|
|
#endif
|
|
#endif
|
|
|
|
BOOLEAN
|
|
MRxSmbPackStringIntoConnectInfo(
|
|
IN PUNICODE_STRING String,
|
|
IN PUNICODE_STRING Source,
|
|
IN OUT PCHAR * BufferStart,
|
|
IN OUT PCHAR * BufferEnd,
|
|
IN ULONG BufferDisplacement,
|
|
IN OUT PULONG TotalBytes
|
|
)
|
|
/*
|
|
|
|
Routine Description:
|
|
|
|
This code copies a string to the end of the buffer IF THERE'S ROOM. the buffer
|
|
displacement is used to map the buffer back into the user's space in case we
|
|
have posted.
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
*/
|
|
{
|
|
LONG size;
|
|
|
|
PAGED_CODE();
|
|
|
|
ASSERT (*BufferStart <= *BufferEnd);
|
|
|
|
//
|
|
// is there room for the string?
|
|
//
|
|
|
|
size = Source->Length;
|
|
|
|
if ((*BufferEnd - *BufferStart) < size) {
|
|
String->Length = 0;
|
|
return(FALSE);
|
|
} else {
|
|
String->Length = Source->Length;
|
|
String->MaximumLength = Source->Length;
|
|
|
|
*BufferEnd -= size;
|
|
if (TotalBytes!=NULL) { *TotalBytes += size; }
|
|
RtlCopyMemory(*BufferEnd, Source->Buffer, size);
|
|
(PCHAR )(String->Buffer) = *BufferEnd;
|
|
(PCHAR )(String->Buffer) -= BufferDisplacement;
|
|
return(TRUE);
|
|
}
|
|
}
|
|
|
|
#ifdef _WIN64
|
|
BOOLEAN
|
|
MRxSmbPackStringIntoConnectInfoThunked(
|
|
IN PUNICODE_STRING_32 String,
|
|
IN PUNICODE_STRING Source,
|
|
IN OUT PCHAR * BufferStart,
|
|
IN OUT PCHAR * BufferEnd,
|
|
IN ULONG BufferDisplacement,
|
|
IN OUT PULONG TotalBytes
|
|
)
|
|
/*
|
|
|
|
Routine Description:
|
|
|
|
This code copies a string to the end of the buffer IF THERE'S ROOM. the buffer
|
|
displacement is used to map the buffer back into the user's space in case we
|
|
have posted.
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
*/
|
|
{
|
|
LONG size;
|
|
|
|
PAGED_CODE();
|
|
|
|
ASSERT (*BufferStart <= *BufferEnd);
|
|
|
|
//
|
|
// is there room for the string?
|
|
//
|
|
|
|
size = Source->Length;
|
|
|
|
if ((*BufferEnd - *BufferStart) < size) {
|
|
String->Length = 0;
|
|
return(FALSE);
|
|
} else {
|
|
String->Length = Source->Length;
|
|
String->MaximumLength = Source->Length;
|
|
|
|
*BufferEnd -= size;
|
|
if (TotalBytes!=NULL) { *TotalBytes += size; }
|
|
RtlCopyMemory(*BufferEnd, Source->Buffer, size);
|
|
(WCHAR * POINTER_32)(String->Buffer) = (WCHAR * POINTER_32)(*BufferEnd);
|
|
(WCHAR * POINTER_32)(String->Buffer) -= BufferDisplacement;
|
|
return(TRUE);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
UNICODE_STRING MRxSmbPackConnectNull = {0,0,NULL};
|
|
|
|
BOOLEAN
|
|
MRxSmbPackConnectEntry (
|
|
IN OUT PRX_CONTEXT RxContext,
|
|
IN ULONG Level,
|
|
IN OUT PCHAR *BufferStart,
|
|
IN OUT PCHAR *BufferEnd,
|
|
IN PV_NET_ROOT VNetRoot,
|
|
IN OUT ULONG BufferDisplacement,
|
|
OUT PULONG TotalBytesNeeded
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine packs a connectlistentry into the buffer provided updating
|
|
all relevant pointers. The way that this works is that constant length stuff is
|
|
copied to the front of the buffer and variable length stuff to the end. The
|
|
"start and end" pointers are updated. You have to calculate the totalbytes correctly
|
|
no matter what but a last can be setup incompletely as long as you return false.
|
|
|
|
the way that this works is that it calls down into the minirdr on the devfcb
|
|
interface. it calls down twice and passes a structure back and forth thru the
|
|
context to maintain state.
|
|
|
|
Arguments:
|
|
|
|
IN ULONG Level - Level of information requested.
|
|
|
|
IN OUT PCHAR *BufferStart - Supplies the output buffer.
|
|
Updated to point to the next buffer
|
|
IN OUT PCHAR *BufferEnd - Supplies the end of the buffer. Updated to
|
|
point before the start of the
|
|
strings being packed.
|
|
IN PNET_ROOT NetRoot - Supplies the NetRoot to enumerate.
|
|
|
|
IN OUT PULONG TotalBytesNeeded - Updated to account for the length of this
|
|
entry
|
|
|
|
Return Value:
|
|
|
|
BOOLEAN - True if the entry was successfully packed into the buffer.
|
|
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status;
|
|
BOOLEAN ReturnValue = TRUE;
|
|
|
|
//PWCHAR ConnectName; // Buffer to hold the packed name
|
|
UNICODE_STRING ConnectName; // Buffer to hold the packed name
|
|
//ULONG NameLength;
|
|
ULONG BufferSize;
|
|
PLMR_CONNECTION_INFO_3 ConnectionInfo = (PLMR_CONNECTION_INFO_3)*BufferStart;
|
|
PNET_ROOT NetRoot = (PNET_ROOT)VNetRoot->NetRoot;
|
|
PSMBCEDB_SERVER_ENTRY pServerEntry;
|
|
PSMBCEDB_SESSION_ENTRY pSessionEntry;
|
|
PSMBCE_V_NET_ROOT_CONTEXT pVNetRootContext = SmbCeGetAssociatedVNetRootContext((PMRX_V_NET_ROOT)VNetRoot);
|
|
|
|
PAGED_CODE();
|
|
|
|
RxDbgTrace(+1, Dbg, ("PackC\n"));
|
|
|
|
switch (Level) {
|
|
case 0:
|
|
BufferSize = sizeof(LMR_CONNECTION_INFO_0);
|
|
break;
|
|
case 1:
|
|
BufferSize = sizeof(LMR_CONNECTION_INFO_1);
|
|
break;
|
|
case 2:
|
|
BufferSize = sizeof(LMR_CONNECTION_INFO_2);
|
|
break;
|
|
case 3:
|
|
BufferSize = sizeof(LMR_CONNECTION_INFO_3);
|
|
break;
|
|
default:
|
|
return FALSE;
|
|
}
|
|
|
|
if (pVNetRootContext == NULL) {
|
|
return TRUE;
|
|
}
|
|
|
|
ConnectName.Buffer = RxAllocatePoolWithTag(NonPagedPool,
|
|
NetRoot->PrefixEntry.Prefix.Length + sizeof(WCHAR),
|
|
'mNxR');
|
|
|
|
if( ConnectName.Buffer == NULL ) {
|
|
return FALSE;
|
|
}
|
|
|
|
try {
|
|
pServerEntry = pVNetRootContext->pServerEntry;
|
|
pSessionEntry = pVNetRootContext->pSessionEntry;
|
|
|
|
ASSERT((pServerEntry != NULL) && (pSessionEntry != NULL));
|
|
|
|
*BufferStart = ((PUCHAR)*BufferStart) + BufferSize;
|
|
*TotalBytesNeeded += BufferSize;
|
|
|
|
//
|
|
// Initialize the name to "\" then add in the rest
|
|
//
|
|
|
|
ConnectName.Buffer[0] = L'\\';
|
|
|
|
RtlCopyMemory(&ConnectName.Buffer[1], NetRoot->PrefixEntry.Prefix.Buffer, NetRoot->PrefixEntry.Prefix.Length);
|
|
|
|
ConnectName.Length = (sizeof(WCHAR)) + NetRoot->PrefixEntry.Prefix.Length;
|
|
ConnectName.MaximumLength = ConnectName.Length;
|
|
|
|
//
|
|
// Update the total number of bytes needed for this structure.
|
|
//
|
|
|
|
*TotalBytesNeeded += ConnectName.Length;
|
|
|
|
if (*BufferStart > *BufferEnd) {
|
|
try_return( ReturnValue = FALSE);
|
|
}
|
|
|
|
ConnectionInfo->ResumeKey = NetRoot->SerialNumberForEnum;
|
|
|
|
if (Level > 0) {
|
|
ULONG ConnectionStatus = 0;
|
|
|
|
ConnectionInfo->SharedResourceType = NetRoot->DeviceType;
|
|
|
|
RxDbgTrace(0, Dbg, ("PackC data---> netroot netrootcondifiton %08lx %08lx\n",
|
|
NetRoot,NetRoot->Condition));
|
|
|
|
MRxSmbUpdateNetRootState((PMRX_NET_ROOT)NetRoot);
|
|
|
|
ConnectionInfo->ConnectionStatus = NetRoot->MRxNetRootState;
|
|
|
|
ConnectionInfo->NumberFilesOpen = NetRoot->NumberOfSrvOpens;
|
|
RxDbgTrace(0, Dbg, ("PackC data---> length restype resumek connstatus numfiles %08lx %08lx %08lx %08lx %08lx\n",
|
|
ConnectionInfo->UNCName.Length,
|
|
ConnectionInfo->SharedResourceType,
|
|
ConnectionInfo->ResumeKey,
|
|
ConnectionInfo->ConnectionStatus,
|
|
ConnectionInfo->NumberFilesOpen));
|
|
}
|
|
|
|
if (Level > 1) {
|
|
|
|
ULONG DialectFlags = pServerEntry->Server.DialectFlags;
|
|
|
|
if (!BooleanFlagOn(
|
|
pSessionEntry->Session.Flags,
|
|
SMBCE_SESSION_FLAGS_LANMAN_SESSION_KEY_USED)) {
|
|
RtlCopyMemory(
|
|
ConnectionInfo->UserSessionKey,
|
|
pSessionEntry->Session.UserSessionKey,
|
|
MSV1_0_USER_SESSION_KEY_LENGTH);
|
|
} else {
|
|
ASSERT(MSV1_0_USER_SESSION_KEY_LENGTH >= MSV1_0_LANMAN_SESSION_KEY_LENGTH);
|
|
|
|
RtlZeroMemory(
|
|
ConnectionInfo->UserSessionKey,
|
|
MSV1_0_USER_SESSION_KEY_LENGTH);
|
|
|
|
RtlCopyMemory(
|
|
ConnectionInfo->UserSessionKey,
|
|
pSessionEntry->Session.LanmanSessionKey,
|
|
MSV1_0_LANMAN_SESSION_KEY_LENGTH);
|
|
}
|
|
|
|
RtlCopyMemory(
|
|
ConnectionInfo->LanmanSessionKey,
|
|
pSessionEntry->Session.LanmanSessionKey,
|
|
MSV1_0_LANMAN_SESSION_KEY_LENGTH);
|
|
|
|
ConnectionInfo->Capabilities = 0;
|
|
|
|
if (DialectFlags & DF_UNICODE) {
|
|
ConnectionInfo->Capabilities |= CAPABILITY_UNICODE;
|
|
}
|
|
|
|
if (DialectFlags & DF_RPC_REMOTE) {
|
|
ConnectionInfo->Capabilities |= CAPABILITY_RPC;
|
|
}
|
|
|
|
if ((DialectFlags & DF_NT_SMBS) && (DialectFlags & DF_RPC_REMOTE)) {
|
|
ConnectionInfo->Capabilities |= CAPABILITY_SAM_PROTOCOL;
|
|
}
|
|
|
|
if (DialectFlags & DF_MIXEDCASE) {
|
|
ConnectionInfo->Capabilities |= CAPABILITY_CASE_SENSITIVE_PASSWDS;
|
|
}
|
|
|
|
if (DialectFlags & DF_LANMAN10) {
|
|
ConnectionInfo->Capabilities |= CAPABILITY_REMOTE_ADMIN_PROTOCOL;
|
|
}
|
|
|
|
ASSERT (!RxContext->PostRequest);
|
|
RxDbgTrace(0, Dbg, ("PackC data---> capabilities %08lx \n", ConnectionInfo->Capabilities));
|
|
}
|
|
|
|
if (!MRxSmbPackStringIntoConnectInfo(
|
|
&ConnectionInfo->UNCName,
|
|
&ConnectName,
|
|
BufferStart,
|
|
BufferEnd,
|
|
BufferDisplacement,
|
|
NULL)) {
|
|
if (Level > 1) {
|
|
ConnectionInfo->UserName.Length = 0;
|
|
ConnectionInfo->UserName.Buffer = NULL;
|
|
}
|
|
|
|
try_return( ReturnValue = FALSE);
|
|
}
|
|
|
|
if (Level > 1) {
|
|
WCHAR UserNameBuffer[UNLEN + 1];
|
|
WCHAR UserDomainNameBuffer[UNLEN + 1];
|
|
|
|
UNICODE_STRING UserName,UserDomainName;
|
|
|
|
UserName.Length = UserName.MaximumLength = UNLEN * sizeof(WCHAR);
|
|
UserName.Buffer = UserNameBuffer;
|
|
UserDomainName.Length = UserDomainName.MaximumLength = UNLEN * sizeof(WCHAR);
|
|
UserDomainName.Buffer = UserDomainNameBuffer;
|
|
|
|
Status = SmbCeGetUserNameAndDomainName(
|
|
pSessionEntry,
|
|
&UserName,
|
|
&UserDomainName);
|
|
|
|
if (NT_SUCCESS(Status)) {
|
|
if (!MRxSmbPackStringIntoConnectInfo(
|
|
&ConnectionInfo->UserName,
|
|
&UserName,
|
|
BufferStart,
|
|
BufferEnd,
|
|
BufferDisplacement,
|
|
TotalBytesNeeded)) {
|
|
try_return( ReturnValue = FALSE);
|
|
}
|
|
|
|
if (!MRxSmbPackStringIntoConnectInfo(
|
|
&ConnectionInfo->DomainName,
|
|
&UserDomainName,
|
|
BufferStart,
|
|
BufferEnd,
|
|
BufferDisplacement,
|
|
TotalBytesNeeded)) {
|
|
try_return( ReturnValue = FALSE);
|
|
}
|
|
} else {
|
|
try_return( ReturnValue = FALSE);
|
|
}
|
|
}
|
|
|
|
if (Level > 2) {
|
|
MRxSmbGetConnectInfoLevel3Fields(ConnectionInfo,pServerEntry, FALSE);
|
|
|
|
if ((pServerEntry->pTransport != NULL) &&
|
|
!SmbCeIsServerInDisconnectedMode(pServerEntry)) {
|
|
NTSTATUS RefTransportStatus;
|
|
|
|
RefTransportStatus = SmbCeReferenceServerTransport(&pServerEntry->pTransport);
|
|
|
|
if (RefTransportStatus == STATUS_SUCCESS) {
|
|
PUNICODE_STRING RxCeTransportName = &pServerEntry->pTransport->pTransport->RxCeTransport.Name;
|
|
|
|
if (!MRxSmbPackStringIntoConnectInfo(
|
|
&ConnectionInfo->TransportName,
|
|
RxCeTransportName,
|
|
BufferStart,
|
|
BufferEnd,
|
|
BufferDisplacement,
|
|
TotalBytesNeeded)) {
|
|
ReturnValue = FALSE;
|
|
}
|
|
|
|
SmbCeDereferenceServerTransport(&pServerEntry->pTransport);
|
|
}
|
|
}
|
|
}
|
|
|
|
try_exit:
|
|
NOTHING;
|
|
|
|
} finally {
|
|
RxFreePool(ConnectName.Buffer);
|
|
}
|
|
RxDbgTrace(-1, Dbg, ("PackC...%08lx\n",ReturnValue));
|
|
|
|
return ReturnValue;
|
|
}
|
|
|
|
#ifdef _WIN64
|
|
BOOLEAN
|
|
MRxSmbPackConnectEntryThunked (
|
|
IN OUT PRX_CONTEXT RxContext,
|
|
IN ULONG Level,
|
|
IN OUT PCHAR *BufferStart,
|
|
IN OUT PCHAR *BufferEnd,
|
|
IN PV_NET_ROOT VNetRoot,
|
|
IN OUT ULONG BufferDisplacement,
|
|
OUT PULONG TotalBytesNeeded
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine packs a connectlistentry into the buffer provided updating
|
|
all relevant pointers. The way that this works is that constant length stuff is
|
|
copied to the front of the buffer and variable length stuff to the end. The
|
|
"start and end" pointers are updated. You have to calculate the totalbytes correctly
|
|
no matter what but a last can be setup incompletely as long as you return false.
|
|
|
|
the way that this works is that it calls down into the minirdr on the devfcb
|
|
interface. it calls down twice and passes a structure back and forth thru the
|
|
context to maintain state.
|
|
|
|
Arguments:
|
|
|
|
IN ULONG Level - Level of information requested.
|
|
|
|
IN OUT PCHAR *BufferStart - Supplies the output buffer.
|
|
Updated to point to the next buffer
|
|
IN OUT PCHAR *BufferEnd - Supplies the end of the buffer. Updated to
|
|
point before the start of the
|
|
strings being packed.
|
|
IN PNET_ROOT NetRoot - Supplies the NetRoot to enumerate.
|
|
|
|
IN OUT PULONG TotalBytesNeeded - Updated to account for the length of this
|
|
entry
|
|
|
|
Return Value:
|
|
|
|
BOOLEAN - True if the entry was successfully packed into the buffer.
|
|
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status;
|
|
BOOLEAN ReturnValue = TRUE;
|
|
|
|
//PWCHAR ConnectName; // Buffer to hold the packed name
|
|
UNICODE_STRING ConnectName; // Buffer to hold the packed name
|
|
//ULONG NameLength;
|
|
ULONG BufferSize;
|
|
PLMR_CONNECTION_INFO_3_32 ConnectionInfo = (PLMR_CONNECTION_INFO_3_32)*BufferStart;
|
|
PNET_ROOT NetRoot = (PNET_ROOT)VNetRoot->NetRoot;
|
|
PSMBCEDB_SERVER_ENTRY pServerEntry;
|
|
PSMBCEDB_SESSION_ENTRY pSessionEntry;
|
|
PSMBCE_V_NET_ROOT_CONTEXT pVNetRootContext = SmbCeGetAssociatedVNetRootContext((PMRX_V_NET_ROOT)VNetRoot);
|
|
|
|
PAGED_CODE();
|
|
|
|
RxDbgTrace(+1, Dbg, ("PackC\n"));
|
|
|
|
switch (Level) {
|
|
case 0:
|
|
BufferSize = sizeof(LMR_CONNECTION_INFO_0_32);
|
|
break;
|
|
case 1:
|
|
BufferSize = sizeof(LMR_CONNECTION_INFO_1_32);
|
|
break;
|
|
case 2:
|
|
BufferSize = sizeof(LMR_CONNECTION_INFO_2_32);
|
|
break;
|
|
case 3:
|
|
BufferSize = sizeof(LMR_CONNECTION_INFO_3_32);
|
|
break;
|
|
default:
|
|
return FALSE;
|
|
}
|
|
|
|
if (pVNetRootContext == NULL) {
|
|
return TRUE;
|
|
}
|
|
|
|
ConnectName.Buffer = RxAllocatePoolWithTag(NonPagedPool,
|
|
NetRoot->PrefixEntry.Prefix.Length + sizeof(WCHAR),
|
|
'mNxR');
|
|
|
|
if( ConnectName.Buffer == NULL ) {
|
|
return FALSE;
|
|
}
|
|
|
|
try {
|
|
pServerEntry = pVNetRootContext->pServerEntry;
|
|
pSessionEntry = pVNetRootContext->pSessionEntry;
|
|
|
|
ASSERT((pServerEntry != NULL) && (pSessionEntry != NULL));
|
|
|
|
*BufferStart = ((PUCHAR)*BufferStart) + BufferSize;
|
|
*TotalBytesNeeded += BufferSize;
|
|
|
|
//
|
|
// Initialize the name to "\" then add in the rest
|
|
//
|
|
|
|
ConnectName.Buffer[0] = L'\\';
|
|
|
|
RtlCopyMemory(&ConnectName.Buffer[1], NetRoot->PrefixEntry.Prefix.Buffer, NetRoot->PrefixEntry.Prefix.Length);
|
|
|
|
ConnectName.Length = (sizeof(WCHAR)) + NetRoot->PrefixEntry.Prefix.Length;
|
|
ConnectName.MaximumLength = ConnectName.Length;
|
|
|
|
//
|
|
// Update the total number of bytes needed for this structure.
|
|
//
|
|
|
|
*TotalBytesNeeded += ConnectName.Length;
|
|
|
|
if (*BufferStart > *BufferEnd) {
|
|
try_return( ReturnValue = FALSE);
|
|
}
|
|
|
|
ConnectionInfo->ResumeKey = NetRoot->SerialNumberForEnum;
|
|
|
|
if (Level > 0) {
|
|
ULONG ConnectionStatus = 0;
|
|
|
|
ConnectionInfo->SharedResourceType = NetRoot->DeviceType;
|
|
|
|
RxDbgTrace(0, Dbg, ("PackC data---> netroot netrootcondifiton %08lx %08lx\n",
|
|
NetRoot,NetRoot->Condition));
|
|
|
|
MRxSmbUpdateNetRootState((PMRX_NET_ROOT)NetRoot);
|
|
|
|
ConnectionInfo->ConnectionStatus = NetRoot->MRxNetRootState;
|
|
|
|
ConnectionInfo->NumberFilesOpen = NetRoot->NumberOfSrvOpens;
|
|
RxDbgTrace(0, Dbg, ("PackC data---> length restype resumek connstatus numfiles %08lx %08lx %08lx %08lx %08lx\n",
|
|
ConnectionInfo->UNCName.Length,
|
|
ConnectionInfo->SharedResourceType,
|
|
ConnectionInfo->ResumeKey,
|
|
ConnectionInfo->ConnectionStatus,
|
|
ConnectionInfo->NumberFilesOpen));
|
|
}
|
|
|
|
if (Level > 1) {
|
|
|
|
ULONG DialectFlags = pServerEntry->Server.DialectFlags;
|
|
|
|
if (!BooleanFlagOn(
|
|
pSessionEntry->Session.Flags,
|
|
SMBCE_SESSION_FLAGS_LANMAN_SESSION_KEY_USED)) {
|
|
RtlCopyMemory(
|
|
ConnectionInfo->UserSessionKey,
|
|
pSessionEntry->Session.UserSessionKey,
|
|
MSV1_0_USER_SESSION_KEY_LENGTH);
|
|
} else {
|
|
ASSERT(MSV1_0_USER_SESSION_KEY_LENGTH >= MSV1_0_LANMAN_SESSION_KEY_LENGTH);
|
|
|
|
RtlZeroMemory(
|
|
ConnectionInfo->UserSessionKey,
|
|
MSV1_0_USER_SESSION_KEY_LENGTH);
|
|
|
|
RtlCopyMemory(
|
|
ConnectionInfo->UserSessionKey,
|
|
pSessionEntry->Session.LanmanSessionKey,
|
|
MSV1_0_LANMAN_SESSION_KEY_LENGTH);
|
|
}
|
|
|
|
RtlCopyMemory(
|
|
ConnectionInfo->LanmanSessionKey,
|
|
pSessionEntry->Session.LanmanSessionKey,
|
|
MSV1_0_LANMAN_SESSION_KEY_LENGTH);
|
|
|
|
ConnectionInfo->Capabilities = 0;
|
|
|
|
if (DialectFlags & DF_UNICODE) {
|
|
ConnectionInfo->Capabilities |= CAPABILITY_UNICODE;
|
|
}
|
|
|
|
if (DialectFlags & DF_RPC_REMOTE) {
|
|
ConnectionInfo->Capabilities |= CAPABILITY_RPC;
|
|
}
|
|
|
|
if ((DialectFlags & DF_NT_SMBS) && (DialectFlags & DF_RPC_REMOTE)) {
|
|
ConnectionInfo->Capabilities |= CAPABILITY_SAM_PROTOCOL;
|
|
}
|
|
|
|
if (DialectFlags & DF_MIXEDCASE) {
|
|
ConnectionInfo->Capabilities |= CAPABILITY_CASE_SENSITIVE_PASSWDS;
|
|
}
|
|
|
|
if (DialectFlags & DF_LANMAN10) {
|
|
ConnectionInfo->Capabilities |= CAPABILITY_REMOTE_ADMIN_PROTOCOL;
|
|
}
|
|
|
|
ASSERT (!RxContext->PostRequest);
|
|
RxDbgTrace(0, Dbg, ("PackC data---> capabilities %08lx \n", ConnectionInfo->Capabilities));
|
|
}
|
|
|
|
if (!MRxSmbPackStringIntoConnectInfoThunked(
|
|
&ConnectionInfo->UNCName,
|
|
&ConnectName,
|
|
BufferStart,
|
|
BufferEnd,
|
|
BufferDisplacement,
|
|
NULL)) {
|
|
if (Level > 1) {
|
|
ConnectionInfo->UserName.Length = 0;
|
|
ConnectionInfo->UserName.Buffer = NULL;
|
|
}
|
|
|
|
try_return( ReturnValue = FALSE);
|
|
}
|
|
|
|
if (Level > 1) {
|
|
WCHAR UserNameBuffer[UNLEN + 1];
|
|
WCHAR UserDomainNameBuffer[UNLEN + 1];
|
|
|
|
UNICODE_STRING UserName,UserDomainName;
|
|
|
|
UserName.Length = UserName.MaximumLength = UNLEN * sizeof(WCHAR);
|
|
UserName.Buffer = UserNameBuffer;
|
|
UserDomainName.Length = UserDomainName.MaximumLength = UNLEN * sizeof(WCHAR);
|
|
UserDomainName.Buffer = UserDomainNameBuffer;
|
|
|
|
Status = SmbCeGetUserNameAndDomainName(
|
|
pSessionEntry,
|
|
&UserName,
|
|
&UserDomainName);
|
|
|
|
if (NT_SUCCESS(Status)) {
|
|
if (!MRxSmbPackStringIntoConnectInfoThunked(
|
|
&ConnectionInfo->UserName,
|
|
&UserName,
|
|
BufferStart,
|
|
BufferEnd,
|
|
BufferDisplacement,
|
|
TotalBytesNeeded)) {
|
|
try_return( ReturnValue = FALSE);
|
|
}
|
|
|
|
if (!MRxSmbPackStringIntoConnectInfoThunked(
|
|
&ConnectionInfo->DomainName,
|
|
&UserDomainName,
|
|
BufferStart,
|
|
BufferEnd,
|
|
BufferDisplacement,
|
|
TotalBytesNeeded)) {
|
|
try_return( ReturnValue = FALSE);
|
|
}
|
|
} else {
|
|
try_return( ReturnValue = FALSE);
|
|
}
|
|
}
|
|
|
|
if (Level > 2) {
|
|
MRxSmbGetConnectInfoLevel3FieldsThunked(ConnectionInfo,pServerEntry, FALSE);
|
|
|
|
if ((pServerEntry->pTransport != NULL) &&
|
|
!SmbCeIsServerInDisconnectedMode(pServerEntry)) {
|
|
NTSTATUS RefTransportStatus;
|
|
|
|
RefTransportStatus = SmbCeReferenceServerTransport(&pServerEntry->pTransport);
|
|
|
|
if (RefTransportStatus == STATUS_SUCCESS) {
|
|
PUNICODE_STRING RxCeTransportName = &pServerEntry->pTransport->pTransport->RxCeTransport.Name;
|
|
|
|
if (!MRxSmbPackStringIntoConnectInfoThunked(
|
|
&ConnectionInfo->TransportName,
|
|
RxCeTransportName,
|
|
BufferStart,
|
|
BufferEnd,
|
|
BufferDisplacement,
|
|
TotalBytesNeeded)) {
|
|
ReturnValue = FALSE;
|
|
}
|
|
|
|
SmbCeDereferenceServerTransport(&pServerEntry->pTransport);
|
|
}
|
|
}
|
|
}
|
|
|
|
try_exit:
|
|
NOTHING;
|
|
|
|
} finally {
|
|
RxFreePool(ConnectName.Buffer);
|
|
}
|
|
RxDbgTrace(-1, Dbg, ("PackC...%08lx\n",ReturnValue));
|
|
|
|
return ReturnValue;
|
|
}
|
|
#endif
|
|
|
|
VOID
|
|
MRxSmbGetConnectInfoLevel3Fields(
|
|
IN OUT PLMR_CONNECTION_INFO_3 ConnectionInfo,
|
|
IN PSMBCEDB_SERVER_ENTRY pServerEntry,
|
|
BOOL fAgentCall
|
|
)
|
|
{
|
|
ULONG DialectFlags = pServerEntry->Server.DialectFlags;
|
|
|
|
NTSTATUS Status;
|
|
RXCE_CONNECTION_INFO QueryConnectionInfo;
|
|
PSMBCE_SERVER_VC_TRANSPORT pVcTransport = (PSMBCE_SERVER_VC_TRANSPORT)pServerEntry->pTransport;
|
|
PSMBCE_VC pVc;
|
|
|
|
PAGED_CODE();
|
|
|
|
ConnectionInfo->Throughput = 0;
|
|
ConnectionInfo->Delay = 0;
|
|
ConnectionInfo->Reliable = FALSE;
|
|
ConnectionInfo->ReadAhead = TRUE;
|
|
ConnectionInfo->IsSpecialIpcConnection = FALSE;
|
|
|
|
if ((pServerEntry->Header.State == SMBCEDB_ACTIVE) &&
|
|
(pVcTransport != NULL) &&
|
|
(!SmbCeIsServerInDisconnectedMode(pServerEntry)||fAgentCall)) {
|
|
pVc = &pVcTransport->Vcs[0];
|
|
|
|
Status = RxCeQueryInformation(
|
|
&pVc->RxCeVc,
|
|
RxCeConnectionEndpointInformation,
|
|
&QueryConnectionInfo,
|
|
sizeof(QueryConnectionInfo));
|
|
|
|
if (NT_SUCCESS(Status)) {
|
|
ConnectionInfo->Reliable = !QueryConnectionInfo.Unreliable;
|
|
|
|
if (QueryConnectionInfo.Delay.QuadPart != 0) {
|
|
if (QueryConnectionInfo.Delay.QuadPart == -1) {
|
|
ConnectionInfo->Delay = 0;
|
|
} else if (QueryConnectionInfo.Delay.HighPart != 0xffffffff) {
|
|
ConnectionInfo->Delay = 0xffffffff;
|
|
} else {
|
|
ConnectionInfo->Delay = -1 * QueryConnectionInfo.Delay.LowPart;
|
|
}
|
|
} else {
|
|
ConnectionInfo->Delay = 0;
|
|
}
|
|
|
|
if (QueryConnectionInfo.Throughput.QuadPart == -1) {
|
|
ConnectionInfo->Throughput = 0;
|
|
} else if (QueryConnectionInfo.Throughput.HighPart != 0) {
|
|
ConnectionInfo->Throughput = 0xffffffff;
|
|
} else {
|
|
ConnectionInfo->Throughput = QueryConnectionInfo.Throughput.LowPart;
|
|
}
|
|
}
|
|
}
|
|
|
|
ConnectionInfo->TimeZoneBias = pServerEntry->Server.TimeZoneBias;
|
|
ConnectionInfo->Core = (DialectFlags & DF_CORE) != 0;
|
|
ConnectionInfo->MsNet103 = (DialectFlags & DF_OLDRAWIO) != 0;
|
|
ConnectionInfo->Lanman10 = (DialectFlags & DF_LANMAN10) != 0;
|
|
ConnectionInfo->WindowsForWorkgroups = (DialectFlags & DF_WFW) != 0;
|
|
ConnectionInfo->Lanman20 = (DialectFlags & DF_LANMAN20) != 0;
|
|
ConnectionInfo->Lanman21 = (DialectFlags & DF_LANMAN21) != 0;
|
|
ConnectionInfo->WindowsNt = (DialectFlags & DF_NTPROTOCOL) != 0;
|
|
ConnectionInfo->MixedCasePasswords = (DialectFlags & DF_MIXEDCASEPW) != 0;
|
|
ConnectionInfo->MixedCaseFiles = (DialectFlags & DF_MIXEDCASE) != 0;
|
|
ConnectionInfo->LongNames = (DialectFlags & DF_LONGNAME) != 0;
|
|
ConnectionInfo->ExtendedNegotiateResponse = (DialectFlags & DF_EXTENDNEGOT) != 0;
|
|
ConnectionInfo->LockAndRead = (DialectFlags & DF_LOCKREAD) != 0;
|
|
ConnectionInfo->NtSecurity = (DialectFlags & DF_SECURITY) != 0;
|
|
ConnectionInfo->SupportsEa = (DialectFlags & DF_SUPPORTEA) != 0;
|
|
ConnectionInfo->NtNegotiateResponse = (DialectFlags & DF_NTNEGOTIATE) != 0;
|
|
ConnectionInfo->CancelSupport = (DialectFlags & DF_CANCEL) != 0;
|
|
ConnectionInfo->UnicodeStrings = (DialectFlags & DF_UNICODE) != 0;
|
|
ConnectionInfo->LargeFiles = (DialectFlags & DF_LARGE_FILES) != 0;
|
|
ConnectionInfo->NtSmbs = (DialectFlags & DF_NT_SMBS) != 0;
|
|
ConnectionInfo->RpcRemoteAdmin = (DialectFlags & DF_RPC_REMOTE) != 0;
|
|
ConnectionInfo->NtStatusCodes = (DialectFlags & DF_NT_STATUS) != 0;
|
|
ConnectionInfo->LevelIIOplock = (DialectFlags & DF_OPLOCK_LVL2) != 0;
|
|
ConnectionInfo->UtcTime = (DialectFlags & DF_TIME_IS_UTC) != 0;
|
|
ConnectionInfo->UserSecurity = (pServerEntry->Server.SecurityMode==SECURITY_MODE_USER_LEVEL);
|
|
ConnectionInfo->EncryptsPasswords = pServerEntry->Server.EncryptPasswords;
|
|
|
|
return;
|
|
}
|
|
|
|
#ifdef _WIN64
|
|
VOID
|
|
MRxSmbGetConnectInfoLevel3FieldsThunked(
|
|
IN OUT PLMR_CONNECTION_INFO_3_32 ConnectionInfo,
|
|
IN PSMBCEDB_SERVER_ENTRY pServerEntry,
|
|
BOOL fAgentCall
|
|
)
|
|
{
|
|
ULONG DialectFlags = pServerEntry->Server.DialectFlags;
|
|
|
|
NTSTATUS Status;
|
|
RXCE_CONNECTION_INFO QueryConnectionInfo;
|
|
PSMBCE_SERVER_VC_TRANSPORT pVcTransport = (PSMBCE_SERVER_VC_TRANSPORT)pServerEntry->pTransport;
|
|
PSMBCE_VC pVc;
|
|
|
|
PAGED_CODE();
|
|
|
|
ConnectionInfo->Throughput = 0;
|
|
ConnectionInfo->Delay = 0;
|
|
ConnectionInfo->Reliable = FALSE;
|
|
ConnectionInfo->ReadAhead = TRUE;
|
|
ConnectionInfo->IsSpecialIpcConnection = FALSE;
|
|
|
|
if ((pServerEntry->Header.State == SMBCEDB_ACTIVE) &&
|
|
(pVcTransport != NULL) &&
|
|
(!SmbCeIsServerInDisconnectedMode(pServerEntry)||fAgentCall)) {
|
|
pVc = &pVcTransport->Vcs[0];
|
|
|
|
Status = RxCeQueryInformation(
|
|
&pVc->RxCeVc,
|
|
RxCeConnectionEndpointInformation,
|
|
&QueryConnectionInfo,
|
|
sizeof(QueryConnectionInfo));
|
|
|
|
if (NT_SUCCESS(Status)) {
|
|
ConnectionInfo->Reliable = !QueryConnectionInfo.Unreliable;
|
|
|
|
if (QueryConnectionInfo.Delay.QuadPart != 0) {
|
|
if (QueryConnectionInfo.Delay.QuadPart == -1) {
|
|
ConnectionInfo->Delay = 0;
|
|
} else if (QueryConnectionInfo.Delay.HighPart != 0xffffffff) {
|
|
ConnectionInfo->Delay = 0xffffffff;
|
|
} else {
|
|
ConnectionInfo->Delay = -1 * QueryConnectionInfo.Delay.LowPart;
|
|
}
|
|
} else {
|
|
ConnectionInfo->Delay = 0;
|
|
}
|
|
|
|
if (QueryConnectionInfo.Throughput.QuadPart == -1) {
|
|
ConnectionInfo->Throughput = 0;
|
|
} else if (QueryConnectionInfo.Throughput.HighPart != 0) {
|
|
ConnectionInfo->Throughput = 0xffffffff;
|
|
} else {
|
|
ConnectionInfo->Throughput = QueryConnectionInfo.Throughput.LowPart;
|
|
}
|
|
}
|
|
}
|
|
|
|
ConnectionInfo->TimeZoneBias = pServerEntry->Server.TimeZoneBias;
|
|
ConnectionInfo->Core = (DialectFlags & DF_CORE) != 0;
|
|
ConnectionInfo->MsNet103 = (DialectFlags & DF_OLDRAWIO) != 0;
|
|
ConnectionInfo->Lanman10 = (DialectFlags & DF_LANMAN10) != 0;
|
|
ConnectionInfo->WindowsForWorkgroups = (DialectFlags & DF_WFW) != 0;
|
|
ConnectionInfo->Lanman20 = (DialectFlags & DF_LANMAN20) != 0;
|
|
ConnectionInfo->Lanman21 = (DialectFlags & DF_LANMAN21) != 0;
|
|
ConnectionInfo->WindowsNt = (DialectFlags & DF_NTPROTOCOL) != 0;
|
|
ConnectionInfo->MixedCasePasswords = (DialectFlags & DF_MIXEDCASEPW) != 0;
|
|
ConnectionInfo->MixedCaseFiles = (DialectFlags & DF_MIXEDCASE) != 0;
|
|
ConnectionInfo->LongNames = (DialectFlags & DF_LONGNAME) != 0;
|
|
ConnectionInfo->ExtendedNegotiateResponse = (DialectFlags & DF_EXTENDNEGOT) != 0;
|
|
ConnectionInfo->LockAndRead = (DialectFlags & DF_LOCKREAD) != 0;
|
|
ConnectionInfo->NtSecurity = (DialectFlags & DF_SECURITY) != 0;
|
|
ConnectionInfo->SupportsEa = (DialectFlags & DF_SUPPORTEA) != 0;
|
|
ConnectionInfo->NtNegotiateResponse = (DialectFlags & DF_NTNEGOTIATE) != 0;
|
|
ConnectionInfo->CancelSupport = (DialectFlags & DF_CANCEL) != 0;
|
|
ConnectionInfo->UnicodeStrings = (DialectFlags & DF_UNICODE) != 0;
|
|
ConnectionInfo->LargeFiles = (DialectFlags & DF_LARGE_FILES) != 0;
|
|
ConnectionInfo->NtSmbs = (DialectFlags & DF_NT_SMBS) != 0;
|
|
ConnectionInfo->RpcRemoteAdmin = (DialectFlags & DF_RPC_REMOTE) != 0;
|
|
ConnectionInfo->NtStatusCodes = (DialectFlags & DF_NT_STATUS) != 0;
|
|
ConnectionInfo->LevelIIOplock = (DialectFlags & DF_OPLOCK_LVL2) != 0;
|
|
ConnectionInfo->UtcTime = (DialectFlags & DF_TIME_IS_UTC) != 0;
|
|
ConnectionInfo->UserSecurity = (pServerEntry->Server.SecurityMode==SECURITY_MODE_USER_LEVEL);
|
|
ConnectionInfo->EncryptsPasswords = pServerEntry->Server.EncryptPasswords;
|
|
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
NTSTATUS
|
|
MRxSmbEnumerateConnections (
|
|
IN PRX_CONTEXT RxContext,
|
|
OUT PBOOLEAN PostToFsp
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine enumerates the connections on all minirdrs. we may have to do
|
|
it by minirdr.
|
|
|
|
Arguments:
|
|
|
|
IN PRX_CONTEXT RxContext - Describes the Fsctl and Context
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status;
|
|
PLOWIO_CONTEXT LowIoContext = &RxContext->LowIoContext;
|
|
|
|
BOOLEAN Wait = BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_WAIT);
|
|
BOOLEAN InFSD = !BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_IN_FSP);
|
|
|
|
PLMR_REQUEST_PACKET InputBuffer = LowIoContext->ParamsFor.FsCtl.pInputBuffer;
|
|
PUCHAR OriginalOutputBuffer = LowIoContext->ParamsFor.FsCtl.pOutputBuffer;
|
|
ULONG OutputBufferLength = LowIoContext->ParamsFor.FsCtl.OutputBufferLength;
|
|
ULONG InputBufferLength = LowIoContext->ParamsFor.FsCtl.InputBufferLength;
|
|
|
|
PUCHAR OutputBuffer;
|
|
ULONG BufferDisplacement;
|
|
|
|
ULONG Level, ResumeHandle;
|
|
|
|
PCHAR BufferStart;
|
|
PCHAR BufferEnd;
|
|
PCHAR PreviousBufferStart;
|
|
|
|
PLIST_ENTRY ListEntry;
|
|
LUID LogonId;
|
|
BOOLEAN TableLockHeld = FALSE;
|
|
ULONG TotalBytesNeeded = 0;
|
|
|
|
PAGED_CODE();
|
|
|
|
RxDbgTrace(+1, Dbg, ("MRxSmbEnumerateConnections [Start] -> %08lx\n", 0));
|
|
|
|
OutputBuffer = RxMapUserBuffer( RxContext, RxContext->CurrentIrp );
|
|
BufferDisplacement = (ULONG)(OutputBuffer - OriginalOutputBuffer);
|
|
BufferStart = OutputBuffer;
|
|
BufferEnd = OutputBuffer+OutputBufferLength;
|
|
|
|
if (InFSD && RxContext->CurrentIrp->RequestorMode != KernelMode) {
|
|
ASSERT(BufferDisplacement==0);
|
|
|
|
try {
|
|
ProbeForWrite(InputBuffer,InputBufferLength,sizeof(UCHAR));
|
|
ProbeForWrite(OutputBuffer,OutputBufferLength,sizeof(UCHAR));
|
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
}
|
|
|
|
try {
|
|
try {
|
|
if (InputBufferLength < sizeof(LMR_REQUEST_PACKET)) {
|
|
try_return(Status = STATUS_BUFFER_TOO_SMALL);
|
|
}
|
|
|
|
if (InputBuffer->Version != REQUEST_PACKET_VERSION) {
|
|
try_return(Status = STATUS_INVALID_PARAMETER);
|
|
}
|
|
|
|
Level = InputBuffer->Level;
|
|
ResumeHandle = InputBuffer->Parameters.Get.ResumeHandle;
|
|
LogonId = InputBuffer->LogonId;
|
|
RxDbgTrace(0, Dbg, ("MRxSmbEnumerateConnections Level -> %08lx\n", Level));
|
|
|
|
#ifdef _WIN64
|
|
if (IoIs32bitProcess(RxContext->CurrentIrp)) {
|
|
switch (Level) {
|
|
case 0:
|
|
if ( OutputBufferLength < sizeof(LMR_CONNECTION_INFO_0_32)) {
|
|
try_return(Status = STATUS_BUFFER_TOO_SMALL);
|
|
}
|
|
break;
|
|
case 1:
|
|
if (OutputBufferLength < sizeof(LMR_CONNECTION_INFO_1_32)) {
|
|
try_return(Status = STATUS_BUFFER_TOO_SMALL);
|
|
}
|
|
break;
|
|
case 2:
|
|
if (OutputBufferLength < sizeof(LMR_CONNECTION_INFO_2_32)) {
|
|
try_return(Status = STATUS_BUFFER_TOO_SMALL);
|
|
}
|
|
break;
|
|
case 3:
|
|
if (OutputBufferLength < sizeof(LMR_CONNECTION_INFO_3_32)) {
|
|
try_return(Status = STATUS_BUFFER_TOO_SMALL);
|
|
}
|
|
break;
|
|
default:
|
|
try_return(Status = STATUS_INVALID_INFO_CLASS);
|
|
}
|
|
} else {
|
|
switch (Level) {
|
|
case 0:
|
|
if ( OutputBufferLength < sizeof(LMR_CONNECTION_INFO_0)) {
|
|
try_return(Status = STATUS_BUFFER_TOO_SMALL);
|
|
}
|
|
break;
|
|
case 1:
|
|
if (OutputBufferLength < sizeof(LMR_CONNECTION_INFO_1)) {
|
|
try_return(Status = STATUS_BUFFER_TOO_SMALL);
|
|
}
|
|
break;
|
|
case 2:
|
|
if (OutputBufferLength < sizeof(LMR_CONNECTION_INFO_2)) {
|
|
try_return(Status = STATUS_BUFFER_TOO_SMALL);
|
|
}
|
|
break;
|
|
case 3:
|
|
if (OutputBufferLength < sizeof(LMR_CONNECTION_INFO_3)) {
|
|
try_return(Status = STATUS_BUFFER_TOO_SMALL);
|
|
}
|
|
break;
|
|
default:
|
|
try_return(Status = STATUS_INVALID_INFO_CLASS);
|
|
}
|
|
}
|
|
#else
|
|
switch (Level) {
|
|
case 0:
|
|
if ( OutputBufferLength < sizeof(LMR_CONNECTION_INFO_0)) {
|
|
try_return(Status = STATUS_BUFFER_TOO_SMALL);
|
|
}
|
|
break;
|
|
case 1:
|
|
if (OutputBufferLength < sizeof(LMR_CONNECTION_INFO_1)) {
|
|
try_return(Status = STATUS_BUFFER_TOO_SMALL);
|
|
}
|
|
break;
|
|
case 2:
|
|
if (OutputBufferLength < sizeof(LMR_CONNECTION_INFO_2)) {
|
|
try_return(Status = STATUS_BUFFER_TOO_SMALL);
|
|
}
|
|
break;
|
|
case 3:
|
|
if (OutputBufferLength < sizeof(LMR_CONNECTION_INFO_3)) {
|
|
try_return(Status = STATUS_BUFFER_TOO_SMALL);
|
|
}
|
|
break;
|
|
default:
|
|
try_return(Status = STATUS_INVALID_INFO_CLASS);
|
|
}
|
|
#endif
|
|
InputBuffer->Parameters.Get.EntriesRead = 0;
|
|
InputBuffer->Parameters.Get.TotalEntries = 0;
|
|
|
|
RxAcquirePrefixTableLockExclusive( &RxNetNameTable, TRUE);
|
|
TableLockHeld = TRUE;
|
|
|
|
if (IsListEmpty( &RxNetNameTable.MemberQueue )) {
|
|
try_return(Status = RX_MAP_STATUS(SUCCESS));
|
|
}
|
|
|
|
//must do the list forwards!!!!!
|
|
ListEntry = RxNetNameTable.MemberQueue.Flink;
|
|
for (;ListEntry != &RxNetNameTable.MemberQueue;) {
|
|
PVOID Container;
|
|
PRX_PREFIX_ENTRY PrefixEntry;
|
|
PNET_ROOT NetRoot;
|
|
PV_NET_ROOT VNetRoot;
|
|
PUNICODE_STRING VNetRootName;
|
|
|
|
PrefixEntry = CONTAINING_RECORD( ListEntry, RX_PREFIX_ENTRY, MemberQLinks );
|
|
ListEntry = ListEntry->Flink;
|
|
ASSERT (NodeType(PrefixEntry) == RDBSS_NTC_PREFIX_ENTRY);
|
|
Container = PrefixEntry->ContainingRecord;
|
|
RxDbgTrace(0, Dbg, ("---> ListE PfxE Container Name %08lx %08lx %08lx %wZ\n",
|
|
ListEntry, PrefixEntry, Container, &PrefixEntry->Prefix));
|
|
|
|
switch (NodeType(Container)) {
|
|
case RDBSS_NTC_NETROOT :
|
|
continue;
|
|
|
|
case RDBSS_NTC_SRVCALL :
|
|
continue;
|
|
|
|
case RDBSS_NTC_V_NETROOT :
|
|
VNetRoot = (PV_NET_ROOT)Container;
|
|
NetRoot = (PNET_ROOT)VNetRoot->NetRoot;
|
|
VNetRootName = &VNetRoot->PrefixEntry.Prefix;
|
|
|
|
if ((VNetRoot->SerialNumberForEnum >= ResumeHandle) &&
|
|
(VNetRootName->Buffer[1] != L';') &&
|
|
(VNetRoot->Condition == Condition_Good) &&
|
|
MRxSmbShowConnection(LogonId,VNetRoot) &&
|
|
VNetRoot->IsExplicitConnection) {
|
|
break;
|
|
} else {
|
|
continue;
|
|
}
|
|
|
|
default:
|
|
continue;
|
|
}
|
|
|
|
RxDbgTrace(0, Dbg, (" ImplicitConnectionFound!!!\n"));
|
|
|
|
InputBuffer->Parameters.Get.TotalEntries ++ ;
|
|
|
|
PreviousBufferStart = BufferStart;
|
|
#ifdef _WIN64
|
|
if (IoIs32bitProcess(RxContext->CurrentIrp)) {
|
|
if (MRxSmbPackConnectEntryThunked(RxContext,Level,
|
|
&BufferStart,
|
|
&BufferEnd,
|
|
VNetRoot,
|
|
BufferDisplacement,
|
|
&TotalBytesNeeded)) {
|
|
InputBuffer->Parameters.Get.EntriesRead ++ ;
|
|
RxDbgTrace(0, Dbg, (" Processed %wZ\n",
|
|
&((PLMR_CONNECTION_INFO_0)PreviousBufferStart)->UNCName
|
|
));
|
|
} else {
|
|
break;
|
|
}
|
|
} else {
|
|
if (MRxSmbPackConnectEntry(RxContext,Level,
|
|
&BufferStart,
|
|
&BufferEnd,
|
|
VNetRoot,
|
|
BufferDisplacement,
|
|
&TotalBytesNeeded)) {
|
|
InputBuffer->Parameters.Get.EntriesRead ++ ;
|
|
RxDbgTrace(0, Dbg, (" Processed %wZ\n",
|
|
&((PLMR_CONNECTION_INFO_0)PreviousBufferStart)->UNCName
|
|
));
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
#else
|
|
if (MRxSmbPackConnectEntry(RxContext,Level,
|
|
&BufferStart,
|
|
&BufferEnd,
|
|
VNetRoot,
|
|
BufferDisplacement,
|
|
&TotalBytesNeeded)) {
|
|
InputBuffer->Parameters.Get.EntriesRead ++ ;
|
|
RxDbgTrace(0, Dbg, (" Processed %wZ\n",
|
|
&((PLMR_CONNECTION_INFO_0)PreviousBufferStart)->UNCName
|
|
));
|
|
} else {
|
|
break;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
InputBuffer->Parameters.Get.TotalBytesNeeded = TotalBytesNeeded;
|
|
RxContext->InformationToReturn = sizeof(LMR_REQUEST_PACKET);
|
|
|
|
try_return(Status = RX_MAP_STATUS(SUCCESS));
|
|
|
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
try_exit:NOTHING;
|
|
|
|
} finally {
|
|
|
|
if (TableLockHeld) {
|
|
RxReleasePrefixTableLock( &RxNetNameTable );
|
|
}
|
|
|
|
RxDbgTraceUnIndent(-1,Dbg);
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
MRxSmbGetConnectionInfo (
|
|
IN PRX_CONTEXT RxContext,
|
|
OUT PBOOLEAN PostToFsp
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine gets the connection info for a single vnetroot.
|
|
|
|
There is some happiness here about the output buffer. What happens is that we
|
|
pick up the output buffer in the usual way. However, there are all sorts of
|
|
pointers in the return structure and these pointers must obviously be in terms
|
|
of the original process. so, if we post then we have to apply a fixup!
|
|
|
|
Arguments:
|
|
|
|
IN PRX_CONTEXT RxContext - Describes the Fsctl and Context
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS if successful
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status;
|
|
PLOWIO_CONTEXT LowIoContext = &RxContext->LowIoContext;
|
|
|
|
RxCaptureFobx;
|
|
|
|
BOOLEAN Wait = BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_WAIT);
|
|
BOOLEAN InFSD = !BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_IN_FSP);
|
|
|
|
PLMR_REQUEST_PACKET InputBuffer = LowIoContext->ParamsFor.FsCtl.pInputBuffer;
|
|
PUCHAR OriginalOutputBuffer = LowIoContext->ParamsFor.FsCtl.pOutputBuffer;
|
|
ULONG OutputBufferLength = LowIoContext->ParamsFor.FsCtl.OutputBufferLength;
|
|
ULONG InputBufferLength = LowIoContext->ParamsFor.FsCtl.InputBufferLength;
|
|
|
|
PUCHAR OutputBuffer;
|
|
ULONG BufferDisplacement;
|
|
|
|
ULONG Level;
|
|
|
|
PCHAR BufferStart;
|
|
PCHAR OriginalBufferStart;
|
|
PCHAR BufferEnd;
|
|
|
|
BOOLEAN TableLockHeld = FALSE;
|
|
|
|
PNET_ROOT NetRoot;
|
|
PV_NET_ROOT VNetRoot;
|
|
|
|
ULONG TotalBytesNeeded = 0;
|
|
|
|
PAGED_CODE();
|
|
|
|
RxDbgTrace(+1, Dbg, ("MRxSmbGetConnectionInfo [Start] -> %08lx\n", 0));
|
|
|
|
OutputBuffer = RxMapUserBuffer( RxContext, RxContext->CurrentIrp );
|
|
BufferDisplacement = (ULONG)(OutputBuffer - OriginalOutputBuffer);
|
|
BufferStart = OutputBuffer;
|
|
OriginalBufferStart = BufferStart;
|
|
BufferEnd = OutputBuffer+OutputBufferLength;
|
|
|
|
if (InFSD && RxContext->CurrentIrp->RequestorMode != KernelMode) {
|
|
ASSERT(BufferDisplacement==0);
|
|
|
|
try {
|
|
ProbeForWrite(InputBuffer,InputBufferLength,sizeof(UCHAR));
|
|
ProbeForWrite(OutputBuffer,OutputBufferLength,sizeof(UCHAR));
|
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
}
|
|
|
|
try {
|
|
try {
|
|
PSMBCE_V_NET_ROOT_CONTEXT pVNetRootContext;
|
|
|
|
ASSERT (NodeType(capFobx)==RDBSS_NTC_V_NETROOT);
|
|
VNetRoot = (PV_NET_ROOT)capFobx;
|
|
NetRoot = (PNET_ROOT)(VNetRoot->NetRoot);
|
|
|
|
if (NetRoot == NULL) {
|
|
try_return(Status = STATUS_ALREADY_DISCONNECTED);
|
|
}
|
|
|
|
if (InputBufferLength < sizeof(LMR_REQUEST_PACKET)) {
|
|
try_return(Status = STATUS_BUFFER_TOO_SMALL);
|
|
}
|
|
|
|
if (InputBuffer->Version != REQUEST_PACKET_VERSION) {
|
|
try_return(Status = STATUS_INVALID_PARAMETER);
|
|
}
|
|
|
|
// if the level is asking for the session key, determine whether we are able
|
|
// to give it out yet.
|
|
pVNetRootContext = SmbCeGetAssociatedVNetRootContext((PMRX_V_NET_ROOT)VNetRoot);
|
|
if( InputBuffer->Level > 2 &&
|
|
pVNetRootContext->pSessionEntry->Session.SessionKeyState != SmbSessionKeyAvailible )
|
|
{
|
|
try_return(Status = STATUS_ACCESS_DENIED);
|
|
}
|
|
|
|
Level = InputBuffer->Level;
|
|
RxDbgTrace(0, Dbg, ("MRxSmbGetConnectionInfo Level -> %08lx\n", Level));
|
|
|
|
#ifdef _WIN64
|
|
if (IoIs32bitProcess(RxContext->CurrentIrp)) {
|
|
switch (Level) {
|
|
case 0:
|
|
if ( OutputBufferLength < sizeof(LMR_CONNECTION_INFO_0_32)) {
|
|
try_return(Status = STATUS_BUFFER_TOO_SMALL);
|
|
}
|
|
break;
|
|
case 1:
|
|
if (OutputBufferLength < sizeof(LMR_CONNECTION_INFO_1_32)) {
|
|
try_return(Status = STATUS_BUFFER_TOO_SMALL);
|
|
}
|
|
break;
|
|
case 2:
|
|
if (OutputBufferLength < sizeof(LMR_CONNECTION_INFO_2_32)) {
|
|
try_return(Status = STATUS_BUFFER_TOO_SMALL);
|
|
}
|
|
break;
|
|
case 3:
|
|
if (OutputBufferLength < sizeof(LMR_CONNECTION_INFO_3_32)) {
|
|
try_return(Status = STATUS_BUFFER_TOO_SMALL);
|
|
}
|
|
break;
|
|
default:
|
|
try_return(Status = STATUS_INVALID_INFO_CLASS);
|
|
}
|
|
} else {
|
|
switch (Level) {
|
|
case 0:
|
|
if ( OutputBufferLength < sizeof(LMR_CONNECTION_INFO_0)) {
|
|
try_return(Status = STATUS_BUFFER_TOO_SMALL);
|
|
}
|
|
break;
|
|
case 1:
|
|
if (OutputBufferLength < sizeof(LMR_CONNECTION_INFO_1)) {
|
|
try_return(Status = STATUS_BUFFER_TOO_SMALL);
|
|
}
|
|
break;
|
|
case 2:
|
|
if (OutputBufferLength < sizeof(LMR_CONNECTION_INFO_2)) {
|
|
try_return(Status = STATUS_BUFFER_TOO_SMALL);
|
|
}
|
|
break;
|
|
case 3:
|
|
if (OutputBufferLength < sizeof(LMR_CONNECTION_INFO_3)) {
|
|
try_return(Status = STATUS_BUFFER_TOO_SMALL);
|
|
}
|
|
break;
|
|
default:
|
|
try_return(Status = STATUS_INVALID_INFO_CLASS);
|
|
}
|
|
}
|
|
#else
|
|
switch (Level) {
|
|
case 0:
|
|
if ( OutputBufferLength < sizeof(LMR_CONNECTION_INFO_0)) {
|
|
try_return(Status = STATUS_BUFFER_TOO_SMALL);
|
|
}
|
|
break;
|
|
case 1:
|
|
if (OutputBufferLength < sizeof(LMR_CONNECTION_INFO_1)) {
|
|
try_return(Status = STATUS_BUFFER_TOO_SMALL);
|
|
}
|
|
break;
|
|
case 2:
|
|
if (OutputBufferLength < sizeof(LMR_CONNECTION_INFO_2)) {
|
|
try_return(Status = STATUS_BUFFER_TOO_SMALL);
|
|
}
|
|
break;
|
|
case 3:
|
|
if (OutputBufferLength < sizeof(LMR_CONNECTION_INFO_3)) {
|
|
try_return(Status = STATUS_BUFFER_TOO_SMALL);
|
|
}
|
|
break;
|
|
default:
|
|
try_return(Status = STATUS_INVALID_INFO_CLASS);
|
|
}
|
|
#endif
|
|
|
|
InputBuffer->Parameters.Get.TotalEntries = 1;
|
|
|
|
RxAcquirePrefixTableLockExclusive( &RxNetNameTable, TRUE);
|
|
TableLockHeld = TRUE;
|
|
|
|
#ifdef _WIN64
|
|
if (IoIs32bitProcess(RxContext->CurrentIrp)) {
|
|
if (MRxSmbPackConnectEntryThunked(RxContext,Level,
|
|
&BufferStart,
|
|
&BufferEnd,
|
|
VNetRoot,
|
|
BufferDisplacement,
|
|
&TotalBytesNeeded)) {
|
|
|
|
InputBuffer->Parameters.Get.EntriesRead = 1;
|
|
RxDbgTrace(0, Dbg, (" Processed %wZ\n",
|
|
&((PLMR_CONNECTION_INFO_0)OriginalBufferStart)->UNCName
|
|
));
|
|
}
|
|
} else {
|
|
if (MRxSmbPackConnectEntry(RxContext,Level,
|
|
&BufferStart,
|
|
&BufferEnd,
|
|
VNetRoot,
|
|
BufferDisplacement,
|
|
&TotalBytesNeeded)) {
|
|
|
|
InputBuffer->Parameters.Get.EntriesRead = 1;
|
|
RxDbgTrace(0, Dbg, (" Processed %wZ\n",
|
|
&((PLMR_CONNECTION_INFO_0)OriginalBufferStart)->UNCName
|
|
));
|
|
}
|
|
}
|
|
#else
|
|
if (MRxSmbPackConnectEntry(RxContext,Level,
|
|
&BufferStart,
|
|
&BufferEnd,
|
|
VNetRoot,
|
|
BufferDisplacement,
|
|
&TotalBytesNeeded)) {
|
|
|
|
InputBuffer->Parameters.Get.EntriesRead = 1;
|
|
RxDbgTrace(0, Dbg, (" Processed %wZ\n",
|
|
&((PLMR_CONNECTION_INFO_0)OriginalBufferStart)->UNCName
|
|
));
|
|
}
|
|
#endif
|
|
|
|
InputBuffer->Parameters.Get.TotalBytesNeeded = TotalBytesNeeded;
|
|
RxContext->InformationToReturn = InputBuffer->Parameters.Get.TotalBytesNeeded;
|
|
try_return(Status = RX_MAP_STATUS(SUCCESS));
|
|
|
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
try_exit:NOTHING;
|
|
|
|
} finally {
|
|
if (TableLockHeld) {
|
|
RxReleasePrefixTableLock( &RxNetNameTable );
|
|
}
|
|
RxDbgTraceUnIndent(-1,Dbg);
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
MRxSmbDeleteConnection (
|
|
IN PRX_CONTEXT RxContext,
|
|
OUT PBOOLEAN PostToFsp
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine deletes a single vnetroot. joejoe
|
|
|
|
Arguments:
|
|
|
|
IN PRX_CONTEXT RxContext - Describes the Fsctl and Context....for later when i need the buffers
|
|
|
|
Return Value:
|
|
|
|
RXSTATUS
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status;
|
|
PLOWIO_CONTEXT LowIoContext = &RxContext->LowIoContext;
|
|
|
|
RxCaptureFobx;
|
|
|
|
BOOLEAN Wait = BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_WAIT);
|
|
BOOLEAN InFSD = !BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_IN_FSP);
|
|
|
|
PLMR_REQUEST_PACKET InputBuffer = LowIoContext->ParamsFor.FsCtl.pInputBuffer;
|
|
ULONG InputBufferLength = LowIoContext->ParamsFor.FsCtl.InputBufferLength;
|
|
|
|
ULONG Level;
|
|
|
|
//PLIST_ENTRY ListEntry;
|
|
BOOLEAN TableLockHeld = FALSE;
|
|
|
|
PMRX_NET_ROOT NetRoot = NULL;
|
|
PMRX_V_NET_ROOT VNetRoot = NULL;
|
|
PSMBCE_V_NET_ROOT_CONTEXT VNetRootContext = NULL;
|
|
|
|
PAGED_CODE();
|
|
|
|
RxDbgTrace(+1, Dbg, ("MRxSmbDeleteConnection Fobx %08lx\n", capFobx));
|
|
ASSERT( (FSCTL_LMR_DELETE_CONNECTION&3)==METHOD_BUFFERED );
|
|
//no probing for buffered!
|
|
|
|
if (!Wait) {
|
|
//just post right now!
|
|
*PostToFsp = TRUE;
|
|
return(RX_MAP_STATUS(PENDING));
|
|
}
|
|
|
|
try {
|
|
|
|
if (NodeType(capFobx)==RDBSS_NTC_V_NETROOT) {
|
|
VNetRoot = (PMRX_V_NET_ROOT)capFobx;
|
|
VNetRootContext = (PSMBCE_V_NET_ROOT_CONTEXT)VNetRoot->Context;
|
|
NetRoot = (PMRX_NET_ROOT)VNetRoot->pNetRoot;
|
|
} else {
|
|
ASSERT(FALSE);
|
|
try_return(Status = STATUS_INVALID_DEVICE_REQUEST);
|
|
NetRoot = (PMRX_NET_ROOT)capFobx;
|
|
VNetRoot = NULL;
|
|
}
|
|
|
|
if (InputBufferLength < sizeof(LMR_REQUEST_PACKET)) {
|
|
try_return(Status = STATUS_BUFFER_TOO_SMALL);
|
|
}
|
|
|
|
if (InputBuffer->Version != REQUEST_PACKET_VERSION) {
|
|
try_return(Status = STATUS_INVALID_PARAMETER);
|
|
}
|
|
|
|
Level = InputBuffer->Level;
|
|
RxDbgTrace(0, Dbg, ("MRxSmbDeleteConnection Level(ofForce) -> %08lx\n", Level));
|
|
|
|
if (Level <= USE_LOTS_OF_FORCE) {
|
|
if (Level == USE_LOTS_OF_FORCE) {
|
|
//SmbCeFinalizeAllExchangesForNetRoot(VNetRoot->pNetRoot);
|
|
}
|
|
|
|
if (VNetRootContext != NULL && Level == USE_LOTS_OF_FORCE) {
|
|
// Prevent any new connection from reusing the session if this is the last connection on
|
|
// this session right now
|
|
SmbCeDecrementNumberOfActiveVNetRootOnSession(VNetRootContext);
|
|
|
|
// Recover the count which will be taken away when VNetRoot is finalized
|
|
InterlockedIncrement(&VNetRootContext->pSessionEntry->Session.NumberOfActiveVNetRoot);
|
|
}
|
|
|
|
// The boolean ForceFilesClosed is now a tristate. If the state is 0xff then
|
|
// we take off the extra reference on vnetroot made during xxx_CONNECT
|
|
Status = RxFinalizeConnection(
|
|
(PNET_ROOT)NetRoot,
|
|
(PV_NET_ROOT)VNetRoot,
|
|
(Level==USE_LOTS_OF_FORCE)?TRUE:
|
|
((Level==USE_NOFORCE)?FALSE:0xff));
|
|
} else {
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
try_return(Status);
|
|
|
|
try_exit:NOTHING;
|
|
|
|
} finally {
|
|
|
|
if (TableLockHeld) {
|
|
RxReleasePrefixTableLock( &RxNetNameTable );
|
|
}
|
|
|
|
RxDbgTraceUnIndent(-1,Dbg);
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
MRxEnumerateTransports(
|
|
IN PRX_CONTEXT RxContext,
|
|
OUT PBOOLEAN pPostToFsp)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine invokes the underlying connection engine method to bind to a transport
|
|
or unbind from it in the context of FSP.
|
|
|
|
Arguments:
|
|
|
|
RxContext - the context
|
|
|
|
pPostToFsp - set to TRUE if the routine cannot be completed in the context of the FSD.
|
|
|
|
Return Value:
|
|
|
|
returns RxStatus(PENDING) if invoked in FSD.
|
|
returns the status value from the connection engine if invoked in FSP.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status;
|
|
PLOWIO_CONTEXT LowIoContext = &RxContext->LowIoContext;
|
|
|
|
RxCaptureFobx;
|
|
|
|
BOOLEAN Wait = BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_WAIT);
|
|
BOOLEAN InFSD = !BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_IN_FSP);
|
|
|
|
PLMR_REQUEST_PACKET pLmrRequestBuffer = LowIoContext->ParamsFor.FsCtl.pInputBuffer;
|
|
PUCHAR pTransportEnumerationBuffer = LowIoContext->ParamsFor.FsCtl.pOutputBuffer;
|
|
ULONG EnumerationBufferLength = LowIoContext->ParamsFor.FsCtl.OutputBufferLength;
|
|
ULONG LmrRequestBufferLength = LowIoContext->ParamsFor.FsCtl.InputBufferLength;
|
|
|
|
PAGED_CODE();
|
|
|
|
RxDbgTrace(+1, Dbg, ("RxEnumerateTransports [Start] ->\n"));
|
|
|
|
//
|
|
// This routine is invoked as part of ioinit on a remote boot client.
|
|
// In that case, previous mode is kernel and the buffers are in kernel
|
|
// space, so we can't probe the buffers.
|
|
//
|
|
|
|
if (RxContext->CurrentIrp->RequestorMode != KernelMode) {
|
|
try {
|
|
ProbeForWrite(pLmrRequestBuffer,LmrRequestBufferLength,sizeof(UCHAR));
|
|
ProbeForWrite(pTransportEnumerationBuffer,EnumerationBufferLength,sizeof(UCHAR));
|
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
|
return STATUS_ACCESS_VIOLATION;
|
|
}
|
|
}
|
|
|
|
try {
|
|
try {
|
|
if (LmrRequestBufferLength < sizeof(LMR_REQUEST_PACKET)) {
|
|
try_return(Status = STATUS_BUFFER_TOO_SMALL);
|
|
}
|
|
|
|
if (pLmrRequestBuffer->Version != REQUEST_PACKET_VERSION) {
|
|
try_return(Status = STATUS_INVALID_PARAMETER);
|
|
}
|
|
|
|
Status = MRxEnumerateTransportBindings(
|
|
pLmrRequestBuffer,
|
|
LmrRequestBufferLength,
|
|
pTransportEnumerationBuffer,
|
|
EnumerationBufferLength);
|
|
|
|
RxContext->InformationToReturn = sizeof(LMR_REQUEST_PACKET);
|
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
|
return STATUS_ACCESS_VIOLATION;
|
|
}
|
|
|
|
try_exit:NOTHING;
|
|
|
|
} finally {
|
|
RxDbgTraceUnIndent(-1,Dbg);
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
#define ADAPTER_STATUS_LENGTH_IN_BYTES (26)
|
|
UNICODE_STRING NullAdapterStatus = {
|
|
ADAPTER_STATUS_LENGTH_IN_BYTES,
|
|
ADAPTER_STATUS_LENGTH_IN_BYTES,
|
|
L"000000000000\0"};
|
|
|
|
#define HexDigit(a) ((CHAR)( (a) > 9 ? ((a) + 'A' - 0xA) : ((a) + '0') ))
|
|
|
|
NTSTATUS
|
|
MRxEnumerateTransportBindings(
|
|
IN PLMR_REQUEST_PACKET pLmrRequestPacket,
|
|
IN ULONG LmrRequestPacketLength,
|
|
OUT PVOID pBindingBuffer,
|
|
IN OUT ULONG BindingBufferLength)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine enables the specified transport.
|
|
|
|
Arguments:
|
|
|
|
pLmrRequestPacket - the LM Request Packet for enumerating bindings to transports.
|
|
|
|
LmrRequestPacketLength - length of the LM request.
|
|
|
|
pBindingBuffer - the buffer for returning transport bindings
|
|
|
|
BindingBufferLength -- length of the buffer in which bindings are returned.
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS - if the call was successfull.
|
|
|
|
Notes:
|
|
|
|
The workstation service and other clients of LMR_FSCTL's expect the variable length
|
|
data to be packed in a specific way, i.e., the variable length data is copied from
|
|
the end while the fixed length data is copied from the left. Any changes to the format
|
|
in which the data is packed should be accompanied by the corresponding changes for
|
|
unpacking in these services.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS ReturnStatus = STATUS_SUCCESS;
|
|
NTSTATUS Status;
|
|
PSMBCE_TRANSPORT pTransport;
|
|
ULONG TransportsPreviouslyReturned;
|
|
PVOID pVariableLengthInfo;
|
|
ULONG VariableLengthInfoOffset;
|
|
PSMBCE_TRANSPORT_ARRAY pTransportArray;
|
|
|
|
PAGED_CODE();
|
|
|
|
try {
|
|
// Ensure that the buffer can hold atleast one entry
|
|
if (BindingBufferLength < sizeof(WKSTA_TRANSPORT_INFO_0)) {
|
|
try_return(ReturnStatus = STATUS_BUFFER_TOO_SMALL);
|
|
}
|
|
|
|
VariableLengthInfoOffset = BindingBufferLength;
|
|
TransportsPreviouslyReturned = pLmrRequestPacket->Parameters.Get.ResumeHandle;
|
|
pLmrRequestPacket->Parameters.Get.EntriesRead = 0;
|
|
|
|
// Skip the transports that were previously returned
|
|
pTransportArray = SmbCeReferenceTransportArray();
|
|
|
|
if (pTransportArray == NULL || pTransportArray->Count == 0) {
|
|
if (pTransportArray != NULL) {
|
|
SmbCeDereferenceTransportArray(pTransportArray);
|
|
}
|
|
|
|
RxDbgTrace(0, Dbg, ("MRxEnumerateTransportBindings : Transport not available.\n"));
|
|
try_return(ReturnStatus = STATUS_NETWORK_UNREACHABLE);
|
|
}
|
|
|
|
if (TransportsPreviouslyReturned < pTransportArray->Count) {
|
|
// The subsequent entries have not been returned. Obtain the information
|
|
// for them.
|
|
WKSTA_TRANSPORT_INFO_0 UNALIGNED *pTransportInfo = (WKSTA_TRANSPORT_INFO_0 UNALIGNED *)pBindingBuffer;
|
|
|
|
LONG RemainingLength = (LONG)BindingBufferLength;
|
|
PCHAR pBufferEnd = (PCHAR)pBindingBuffer + BindingBufferLength;
|
|
PCHAR pBufferStart = (PCHAR)pBindingBuffer;
|
|
ULONG Length;
|
|
ULONG TransportsPacked = 0;
|
|
ULONG CurrentTransport;
|
|
ULONG LengthRequired = 0;
|
|
|
|
CurrentTransport = TransportsPreviouslyReturned;
|
|
|
|
while(CurrentTransport < pTransportArray->Count) {
|
|
RXCE_TRANSPORT_INFORMATION TransportInformation;
|
|
|
|
pTransport = pTransportArray->SmbCeTransports[CurrentTransport++];
|
|
|
|
Status = RxCeQueryTransportInformation(
|
|
&pTransport->RxCeTransport,
|
|
&TransportInformation);
|
|
|
|
if (Status == STATUS_SUCCESS) {
|
|
ULONG BufferSize;
|
|
|
|
if (pTransport->RxCeTransport.Name.Length > UNLEN * sizeof(WCHAR)) {
|
|
Status = STATUS_BUFFER_OVERFLOW;
|
|
}
|
|
|
|
BufferSize = sizeof(WKSTA_TRANSPORT_INFO_0) +
|
|
ADAPTER_STATUS_LENGTH_IN_BYTES +
|
|
(pTransport->RxCeTransport.Name.Length + sizeof(WCHAR));
|
|
|
|
RemainingLength -= BufferSize;
|
|
LengthRequired += BufferSize;
|
|
|
|
if (Status == STATUS_SUCCESS && RemainingLength >= 0) {
|
|
PCHAR pName;
|
|
PWCHAR pAdapter;
|
|
ADAPTER_STATUS AdapterStatus;
|
|
|
|
// Copy the values for the current binding into the output buffer.
|
|
pTransportInfo->wkti0_quality_of_service =
|
|
TransportInformation.QualityOfService;
|
|
|
|
pTransportInfo->wkti0_wan_ish =
|
|
TransportInformation.ServiceFlags & TDI_SERVICE_ROUTE_DIRECTED;
|
|
|
|
pTransportInfo->wkti0_number_of_vcs = TransportInformation.ConnectionCount;
|
|
|
|
VariableLengthInfoOffset -= (pTransport->RxCeTransport.Name.Length + sizeof(WCHAR));
|
|
|
|
pName = ((PCHAR)pBindingBuffer + VariableLengthInfoOffset);
|
|
|
|
pTransportInfo->wkti0_transport_name = (LPWSTR)pName;
|
|
|
|
// Copy the variable length data, i.e. the transport name and in the case of
|
|
// NETBIOS provides the adapter address
|
|
RtlCopyMemory(
|
|
pName,
|
|
pTransport->RxCeTransport.Name.Buffer,
|
|
pTransport->RxCeTransport.Name.Length);
|
|
|
|
pName += pTransport->RxCeTransport.Name.Length;
|
|
*((PWCHAR)pName) = L'\0';
|
|
|
|
VariableLengthInfoOffset -= ADAPTER_STATUS_LENGTH_IN_BYTES;
|
|
|
|
pAdapter = (PWCHAR)((PCHAR)pBindingBuffer + VariableLengthInfoOffset);
|
|
pTransportInfo->wkti0_transport_address = pAdapter;
|
|
|
|
Status = RxCeQueryAdapterStatus(
|
|
&pTransport->RxCeTransport,
|
|
&AdapterStatus);
|
|
|
|
if (NT_SUCCESS(Status) ||
|
|
(Status == STATUS_BUFFER_OVERFLOW)) {
|
|
ULONG i;
|
|
|
|
for (i = 0; i < 6; i++) {
|
|
*pAdapter++ = HexDigit((AdapterStatus.adapter_address[i] >> 4) & 0x0F);
|
|
*pAdapter++ = HexDigit(AdapterStatus.adapter_address[i] & 0x0F);
|
|
}
|
|
|
|
*pAdapter = L'\0';
|
|
} else {
|
|
RtlCopyMemory(
|
|
pAdapter,
|
|
NullAdapterStatus.Buffer,
|
|
ADAPTER_STATUS_LENGTH_IN_BYTES);
|
|
}
|
|
|
|
// Increment the number of transports that have been returned.
|
|
pLmrRequestPacket->Parameters.Get.ResumeHandle++;
|
|
pLmrRequestPacket->Parameters.Get.EntriesRead++;
|
|
pTransportInfo++;
|
|
} else {
|
|
pTransportInfo->wkti0_transport_name = NULL;
|
|
pTransportInfo->wkti0_transport_address = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (RemainingLength < 0) {
|
|
ReturnStatus = STATUS_MORE_ENTRIES;
|
|
pLmrRequestPacket->Parameters.Get.TotalBytesNeeded = LengthRequired;
|
|
}
|
|
} else {
|
|
ReturnStatus = STATUS_NO_MORE_FILES;
|
|
}
|
|
|
|
SmbCeDereferenceTransportArray(pTransportArray);
|
|
|
|
try_exit:NOTHING;
|
|
|
|
} finally {
|
|
RxDbgTraceUnIndent(-1,Dbg);
|
|
}
|
|
|
|
return ReturnStatus;
|
|
}
|
|
|
|
BOOLEAN
|
|
MRxSmbShowConnection(
|
|
IN LUID LogonId,
|
|
IN PV_NET_ROOT VNetRoot
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Returns whether the given V_NET_ROOT should be returned
|
|
from an LMR_ENUMERATE_CONNECTIONS call.
|
|
|
|
Arguments:
|
|
|
|
IN LUID LogonId - LogonId of caller asking for enumeration of connections
|
|
|
|
IN PVNET_ROOT VNetRoot - Supplies the NetRoot to enumerate.
|
|
|
|
Return Value:
|
|
|
|
BOOLEAN - True if the entry should be returned to the caller
|
|
|
|
|
|
--*/
|
|
{
|
|
PSMBCE_V_NET_ROOT_CONTEXT pVNetRootContext = SmbCeGetAssociatedVNetRootContext((PMRX_V_NET_ROOT)VNetRoot);
|
|
|
|
// If no Context, not session specific
|
|
if( pVNetRootContext == NULL ) {
|
|
return TRUE;
|
|
}
|
|
|
|
if( RtlEqualLuid( &LogonId, &pVNetRootContext->pSessionEntry->Session.LogonId ) ) {
|
|
return TRUE;
|
|
}
|
|
else {
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
|