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.
822 lines
28 KiB
822 lines
28 KiB
/*++
|
|
|
|
Copyright (c) 2000 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
drenum.c
|
|
|
|
Abstract:
|
|
|
|
This module implements the routines required for interaction with network
|
|
provider router interface in NT
|
|
|
|
Author:
|
|
|
|
Joy Chik 1/20/2000
|
|
|
|
--*/
|
|
|
|
#include <drprov.h>
|
|
#include "drdbg.h"
|
|
|
|
extern UNICODE_STRING DrProviderName;
|
|
extern UNICODE_STRING DrDeviceName;
|
|
extern DWORD GLOBAL_DEBUG_FLAGS;
|
|
|
|
DWORD
|
|
DrOpenMiniRdr(
|
|
OUT HANDLE *DrDeviceHandle
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine opens the RDP redirector File System Driver.
|
|
|
|
Arguments:
|
|
|
|
DrDeviceHandle - Device handle to the MiniRdr
|
|
|
|
Return Value:
|
|
|
|
STATUS - Success or reason for failure.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS ntstatus;
|
|
DWORD Status = WN_SUCCESS;
|
|
IO_STATUS_BLOCK IoStatusBlock;
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
UNICODE_STRING DeviceName;
|
|
|
|
DBGMSG(DBG_TRACE, ("DRPROV: DrOpenMiniRdr\n"));
|
|
|
|
//
|
|
// Open the redirector device.
|
|
//
|
|
RtlInitUnicodeString(&DeviceName, RDPDR_DEVICE_NAME_U);
|
|
|
|
InitializeObjectAttributes(
|
|
&ObjectAttributes,
|
|
&DeviceName,
|
|
OBJ_CASE_INSENSITIVE,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
ntstatus = NtOpenFile(
|
|
DrDeviceHandle,
|
|
SYNCHRONIZE,
|
|
&ObjectAttributes,
|
|
&IoStatusBlock,
|
|
FILE_SHARE_VALID_FLAGS,
|
|
FILE_SYNCHRONOUS_IO_NONALERT
|
|
);
|
|
|
|
// If we failed to open the rdpdr minirdr, we
|
|
// return as access denied
|
|
if (ntstatus != STATUS_SUCCESS) {
|
|
DBGMSG(DBG_TRACE, ("DRPROV: DrOpenMiniRdr failed with status: %x\n", ntstatus));
|
|
Status = WN_ACCESS_DENIED;
|
|
}
|
|
|
|
DBGMSG(DBG_TRACE, ("DRPROV: DrOpenMiniRdr, return status: %x\n", Status));
|
|
return Status;
|
|
}
|
|
|
|
DWORD
|
|
DrDeviceControlGetInfo(
|
|
IN HANDLE FileHandle,
|
|
IN ULONG DeviceControlCode,
|
|
IN PVOID RequestPacket,
|
|
IN ULONG RequestPacketLength,
|
|
OUT LPBYTE *OutputBuffer,
|
|
IN ULONG PreferedMaximumLength,
|
|
IN ULONG BufferHintSize,
|
|
OUT PULONG_PTR Information OPTIONAL
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function allocates the buffer and fill it with the information
|
|
that is retrieved from the redirector.
|
|
|
|
Arguments:
|
|
|
|
FileHandle - Supplies a handle to the file or device of which to get
|
|
information about.
|
|
|
|
DeviceControlCode - Supplies the NtFsControlFile or NtIoDeviceControlFile
|
|
function control code.
|
|
|
|
RequestPacket - Supplies a pointer to the device request packet.
|
|
|
|
RrequestPacketLength - Supplies the length of the device request packet.
|
|
|
|
OutputBuffer - Returns a pointer to the buffer allocated by this routine
|
|
which contains the use information requested. This pointer is set to
|
|
NULL if return code is not wn_success.
|
|
|
|
PreferedMaximumLength - Supplies the number of bytes of information to
|
|
return in the buffer. If this value is MAXULONG, we will try to
|
|
return all available information if there is enough memory resource.
|
|
|
|
BufferHintSize - Supplies the hint size of the output buffer so that the
|
|
memory allocated for the initial buffer will most likely be large
|
|
enough to hold all requested data.
|
|
|
|
Information - Returns the information code from the NtFsControlFile or
|
|
NtIoDeviceControlFile call.
|
|
|
|
Return Value:
|
|
|
|
STATUS - Success or reason for failure.
|
|
|
|
--*/
|
|
{
|
|
DWORD status;
|
|
NTSTATUS ntStatus;
|
|
DWORD OutputBufferLength;
|
|
DWORD TotalBytesNeeded = 1;
|
|
ULONG OriginalResumeKey;
|
|
PRDPDR_REQUEST_PACKET Rrp = (PRDPDR_REQUEST_PACKET) RequestPacket;
|
|
IO_STATUS_BLOCK IoStatusBlock;
|
|
|
|
DBGMSG(DBG_TRACE, ("DRPROV: DrDeviceControlGetINfo\n"));
|
|
|
|
//
|
|
// If PreferedMaximumLength is MAXULONG, then we are supposed to get all
|
|
// the information, regardless of size. Allocate the output buffer of a
|
|
// reasonable size and try to use it. If this fails, the Redirector FSD
|
|
// will say how much we need to allocate.
|
|
//
|
|
if (PreferedMaximumLength == MAXULONG) {
|
|
OutputBufferLength = (BufferHintSize) ? BufferHintSize :
|
|
INITIAL_ALLOCATION_SIZE;
|
|
}
|
|
else {
|
|
OutputBufferLength = PreferedMaximumLength;
|
|
}
|
|
|
|
if ((*OutputBuffer = (BYTE *)MemAlloc(OutputBufferLength)) == NULL) {
|
|
DBGMSG(DBG_TRACE, ("DRPROV: DrDeviceControlGetInfo, MemAlloc failed\n"));
|
|
status = WN_OUT_OF_MEMORY;
|
|
goto EXIT;
|
|
}
|
|
|
|
OriginalResumeKey = Rrp->Parameters.Get.ResumeHandle;
|
|
|
|
//
|
|
// Make the request of the Redirector
|
|
//
|
|
|
|
ntStatus = NtFsControlFile(
|
|
FileHandle,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&IoStatusBlock,
|
|
DeviceControlCode,
|
|
Rrp,
|
|
RequestPacketLength,
|
|
*OutputBuffer,
|
|
OutputBufferLength
|
|
);
|
|
|
|
if (ntStatus == STATUS_SUCCESS) {
|
|
TotalBytesNeeded = Rrp->Parameters.Get.TotalBytesNeeded;
|
|
status = WN_SUCCESS;
|
|
goto EXIT;
|
|
}
|
|
else {
|
|
if (ntStatus == STATUS_BUFFER_TOO_SMALL) {
|
|
DBGMSG(DBG_TRACE, ("DRPROV: DrDeviceControlGetInfo, buffer too small\n"));
|
|
TotalBytesNeeded = Rrp->Parameters.Get.TotalBytesNeeded;
|
|
status = WN_MORE_DATA;
|
|
}
|
|
else {
|
|
DBGMSG(DBG_TRACE, ("DRPROV: DrDeviceControlGetInfo, failed NtFsControlFile, %x\n", ntStatus));
|
|
status = WN_BAD_NETNAME;
|
|
goto EXIT;
|
|
}
|
|
}
|
|
|
|
if ((TotalBytesNeeded > OutputBufferLength) &&
|
|
(PreferedMaximumLength == MAXULONG)) {
|
|
//
|
|
// Initial output buffer allocated was too small and we need to return
|
|
// all data. First free the output buffer before allocating the
|
|
// required size plus a fudge factor just in case the amount of data
|
|
// grew.
|
|
//
|
|
|
|
MemFree(*OutputBuffer);
|
|
|
|
OutputBufferLength = TotalBytesNeeded + FUDGE_FACTOR_SIZE;
|
|
|
|
if ((*OutputBuffer = (BYTE *)MemAlloc(OutputBufferLength)) == NULL) {
|
|
DBGMSG(DBG_TRACE, ("DRPROV: DrDeviceControlGetInfo, MemAlloc failed\n"));
|
|
status = WN_OUT_OF_MEMORY;
|
|
goto EXIT;
|
|
}
|
|
|
|
//
|
|
// Try again to get the information from the redirector
|
|
//
|
|
Rrp->Parameters.Get.ResumeHandle = OriginalResumeKey;
|
|
|
|
//
|
|
// Make the request of the Redirector
|
|
//
|
|
ntStatus = NtFsControlFile(
|
|
FileHandle,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&IoStatusBlock,
|
|
DeviceControlCode,
|
|
Rrp,
|
|
RequestPacketLength,
|
|
*OutputBuffer,
|
|
OutputBufferLength
|
|
);
|
|
|
|
if (ntStatus == STATUS_SUCCESS)
|
|
{
|
|
TotalBytesNeeded = Rrp->Parameters.Get.TotalBytesNeeded;
|
|
status = WN_SUCCESS;
|
|
goto EXIT;
|
|
}
|
|
else {
|
|
if (ntStatus == STATUS_BUFFER_TOO_SMALL) {
|
|
DBGMSG(DBG_TRACE, ("DRPROV: DrDeviceControlGetInfo, buffer too small\n"));
|
|
status = WN_OUT_OF_MEMORY;
|
|
TotalBytesNeeded = Rrp->Parameters.Get.TotalBytesNeeded;
|
|
goto EXIT;
|
|
}
|
|
else {
|
|
DBGMSG(DBG_TRACE, ("DRPROV: DrDeviceControlGetInfo, failed NtFsControlFile, %x\n", ntStatus));
|
|
status = WN_BAD_NETNAME;
|
|
goto EXIT;
|
|
}
|
|
}
|
|
}
|
|
|
|
EXIT:
|
|
|
|
//
|
|
// If not successful in getting any data, or if TotalBytesNeeded is 0,
|
|
// Free the output buffer.
|
|
//
|
|
if ((status != WN_SUCCESS) || (TotalBytesNeeded == 0)) {
|
|
if (*OutputBuffer != NULL) {
|
|
MemFree(*OutputBuffer);
|
|
*OutputBuffer = NULL;
|
|
}
|
|
|
|
if (TotalBytesNeeded == 0) {
|
|
status = WN_NO_MORE_ENTRIES;
|
|
}
|
|
}
|
|
|
|
DBGMSG(DBG_TRACE, ("DRPROV: DrDeviceControlGetInfo, return status, %x\n", status));
|
|
return status;
|
|
}
|
|
|
|
|
|
DWORD
|
|
DrEnumServerInfo(PRDPDR_ENUMERATION_HANDLE pEnumHandle,
|
|
LPDWORD lpcCount,
|
|
LPNETRESOURCEW pBufferResource,
|
|
LPDWORD lpBufferSize)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function requests the redirector to enumerate the server info,
|
|
it then reckages it into the user supplied buffer and return
|
|
|
|
Arguments:
|
|
|
|
pEnumHandle - Supplies the enumeration handle. It's a structure the dll
|
|
used to store enumberation state and info.
|
|
|
|
lpcCount - On return, this contains the number of NETRESOURCE entries
|
|
returned back to user.
|
|
|
|
pBufferResource - On return, this contains all the netresource entries.
|
|
|
|
lpBufferSize - This contains the size of the buffer. On return, it
|
|
is the size of the network resource entries.
|
|
|
|
Return Value:
|
|
|
|
STATUS - Success or reason for failure.
|
|
|
|
--*/
|
|
{
|
|
DWORD status = WN_SUCCESS;
|
|
DWORD localCount = 0;
|
|
RDPDR_REQUEST_PACKET Rrp; // Redirector request packet
|
|
HANDLE DrDeviceHandle = INVALID_HANDLE_VALUE;
|
|
LPBYTE Buffer = NULL;
|
|
PRDPDR_SERVER_INFO pServerEntry;
|
|
|
|
DBGMSG(DBG_TRACE, ("DRENUM: DrEnumServerInfo\n"));
|
|
|
|
// Initialize enum count to 0
|
|
*lpcCount = 0;
|
|
|
|
if (pEnumHandle->enumIndex == 0) {
|
|
if (DrOpenMiniRdr(&DrDeviceHandle) != WN_SUCCESS) {
|
|
//
|
|
// MPR doesn't like return device error in this case
|
|
// We'll just return 0 entries
|
|
//
|
|
DBGMSG(DBG_TRACE, ("DRENUM: DrEnumServerInfo, DrOpenMiniRdr failed\n"));
|
|
status = WN_NO_MORE_ENTRIES;
|
|
DrDeviceHandle = INVALID_HANDLE_VALUE;
|
|
goto EXIT;
|
|
}
|
|
|
|
//
|
|
// Ask the redirector to enumerate the information of server
|
|
// established by the caller.
|
|
//
|
|
Rrp.SessionId = NtCurrentPeb()->SessionId;
|
|
Rrp.Parameters.Get.ResumeHandle = 0;
|
|
|
|
//
|
|
// Make the request to the Redirector
|
|
//
|
|
status = DrDeviceControlGetInfo(DrDeviceHandle,
|
|
FSCTL_DR_ENUMERATE_SERVERS,
|
|
&Rrp,
|
|
sizeof(RDPDR_REQUEST_PACKET),
|
|
(LPBYTE *) &Buffer,
|
|
MAXULONG,
|
|
0,
|
|
NULL);
|
|
|
|
if (status == WN_SUCCESS) {
|
|
pEnumHandle->pEnumBuffer = Buffer;
|
|
}
|
|
else {
|
|
DBGMSG(DBG_TRACE, ("DRENUM: DrEnumServerInfo, DrDeviceControlGetInfo failed, %x\n", status));
|
|
goto EXIT;
|
|
}
|
|
|
|
pServerEntry = ((PRDPDR_SERVER_INFO) Buffer);
|
|
|
|
if (*lpBufferSize >= sizeof(NETRESOURCEW) +
|
|
pServerEntry->ServerName.Length + sizeof(WCHAR) +
|
|
DrProviderName.Length + sizeof(WCHAR)) {
|
|
UNICODE_STRING ServerName;
|
|
|
|
ServerName.Length = pServerEntry->ServerName.Length;
|
|
ServerName.MaximumLength = pServerEntry->ServerName.MaximumLength;
|
|
ServerName.Buffer = (PWCHAR)((PCHAR)(pServerEntry) + pServerEntry->ServerName.BufferOffset);
|
|
|
|
pBufferResource->dwScope = pEnumHandle->dwScope;
|
|
pBufferResource->dwType = RESOURCETYPE_DISK;
|
|
pBufferResource->dwDisplayType = RESOURCEDISPLAYTYPE_SERVER;
|
|
pBufferResource->dwUsage = RESOURCEUSAGE_CONTAINER ;
|
|
pBufferResource->lpLocalName = NULL;
|
|
|
|
// Server name
|
|
pBufferResource->lpRemoteName = (PWCHAR) &pBufferResource[1];
|
|
RtlCopyMemory(pBufferResource->lpRemoteName,
|
|
ServerName.Buffer,
|
|
ServerName.Length);
|
|
pBufferResource->lpRemoteName[ServerName.Length /
|
|
sizeof(WCHAR)] = L'\0';
|
|
|
|
DBGMSG(DBG_TRACE, ("DRENUM: DrEnumServerInfo, ServerName, %ws\n",
|
|
pBufferResource->lpRemoteName));
|
|
|
|
// Provider name
|
|
pBufferResource->lpProvider = pBufferResource->lpRemoteName +
|
|
(ServerName.Length / sizeof(WCHAR) + 1);
|
|
RtlCopyMemory(pBufferResource->lpProvider, DrProviderName.Buffer,
|
|
DrProviderName.Length);
|
|
pBufferResource->lpProvider[DrProviderName.Length /
|
|
sizeof(WCHAR)] = L'\0';
|
|
|
|
pBufferResource->lpComment = NULL;
|
|
|
|
localCount = 1;
|
|
pEnumHandle->enumIndex++;
|
|
|
|
status = WN_SUCCESS;
|
|
goto EXIT;
|
|
}
|
|
else {
|
|
localCount = 0;
|
|
*lpBufferSize = sizeof(NETRESOURCEW) +
|
|
pServerEntry->ServerName.Length + sizeof(WCHAR) +
|
|
DrProviderName.Length + sizeof(WCHAR);
|
|
DBGMSG(DBG_TRACE, ("DRENUM: DrEnumServerInfo, buffer too small\n"));
|
|
status = WN_MORE_DATA;
|
|
goto EXIT;
|
|
}
|
|
} else {
|
|
localCount = 0;
|
|
status = WN_NO_MORE_ENTRIES;
|
|
goto EXIT;
|
|
}
|
|
|
|
EXIT:
|
|
|
|
*lpcCount = localCount;
|
|
if (DrDeviceHandle != INVALID_HANDLE_VALUE) {
|
|
CloseHandle(DrDeviceHandle);
|
|
}
|
|
|
|
DBGMSG(DBG_TRACE, ("DRENUM: DrEnumServerInfo, return status %x\n", status));
|
|
return status;
|
|
}
|
|
|
|
|
|
DWORD
|
|
DrEnumShareInfo(PRDPDR_ENUMERATION_HANDLE pEnumHandle,
|
|
LPDWORD lpcCount,
|
|
LPNETRESOURCEW pBufferResource,
|
|
LPDWORD lpBufferSize)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function requests the redirector to enumerate the share info,
|
|
it then reckages it into the user supplied buffer and return
|
|
|
|
Arguments:
|
|
|
|
pEnumHandle - Supplies the enumeration handle. It's a structure the dll
|
|
used to store enumberation state and info.
|
|
|
|
lpcCount - On return, this contains the number of NETRESOURCE entries
|
|
returned back to user.
|
|
|
|
pBufferResource - On return, this contains all the netresource entries.
|
|
|
|
lpBufferSize - This contains the size of the buffer. On return, it
|
|
is the size of the network resource entries.
|
|
|
|
Return Value:
|
|
|
|
STATUS - Success or reason for failure.
|
|
|
|
--*/
|
|
{
|
|
DWORD status = WN_SUCCESS;
|
|
DWORD localCount = 0;
|
|
HANDLE DrDeviceHandle = INVALID_HANDLE_VALUE;
|
|
RDPDR_REQUEST_PACKET Rrp; // Redirector request packet
|
|
LPBYTE Buffer = NULL;
|
|
PRDPDR_SHARE_INFO pShareEntry;
|
|
DWORD Entry, RemainingBufferSize;
|
|
BYTE *BufferResourceStart, *BufferResourceEnd;
|
|
|
|
DBGMSG(DBG_TRACE, ("DRENUM: DrEnumShareInfo\n"));
|
|
|
|
*lpcCount = 0;
|
|
BufferResourceStart = (PBYTE)pBufferResource;
|
|
BufferResourceEnd = ((PBYTE)(pBufferResource)) + *lpBufferSize;
|
|
|
|
if (pEnumHandle->RemoteName.Length == 0 || pEnumHandle->RemoteName.Buffer == NULL) {
|
|
DBGMSG(DBG_TRACE, ("DRENUM: DrEnumShareInfo, no RemoteName\n"));
|
|
status = WN_BAD_NETNAME;
|
|
goto EXIT;
|
|
}
|
|
|
|
if (pEnumHandle->enumIndex == 0) {
|
|
if (DrOpenMiniRdr(&DrDeviceHandle) != WN_SUCCESS) {
|
|
//
|
|
// MPR doesn't like return device error in this case
|
|
// We'll just return 0 entries
|
|
DBGMSG(DBG_TRACE, ("DRENUM: DrEnumShareInfo, DrOpenMiniRdr failed\n"));
|
|
status = WN_NO_MORE_ENTRIES;
|
|
DrDeviceHandle = INVALID_HANDLE_VALUE;
|
|
goto EXIT;
|
|
}
|
|
|
|
//
|
|
// Ask the redirector to enumerate the information of connections
|
|
// established by the caller.
|
|
//
|
|
Rrp.SessionId = NtCurrentPeb()->SessionId;
|
|
Rrp.Parameters.Get.ResumeHandle = 0;
|
|
|
|
//
|
|
// Make the request to the Redirector
|
|
//
|
|
status = DrDeviceControlGetInfo(DrDeviceHandle,
|
|
FSCTL_DR_ENUMERATE_SHARES,
|
|
&Rrp,
|
|
sizeof(RDPDR_REQUEST_PACKET),
|
|
(LPBYTE *) &Buffer,
|
|
MAXULONG,
|
|
0,
|
|
NULL);
|
|
|
|
if (status == WN_SUCCESS) {
|
|
pEnumHandle->totalEntries = Rrp.Parameters.Get.EntriesRead;
|
|
pEnumHandle->pEnumBuffer = Buffer;
|
|
}
|
|
else {
|
|
DBGMSG(DBG_TRACE, ("DRENUM: DrEnumShareInfo, DrDeviceControlGetInfo failed, %x\n", status));
|
|
goto EXIT;
|
|
}
|
|
}
|
|
else {
|
|
Buffer = pEnumHandle->pEnumBuffer;
|
|
|
|
if (Buffer == NULL) {
|
|
status = WN_NO_MORE_ENTRIES;
|
|
goto EXIT;
|
|
}
|
|
}
|
|
|
|
if (pEnumHandle->enumIndex == pEnumHandle->totalEntries) {
|
|
status = WN_NO_MORE_ENTRIES;
|
|
goto EXIT;
|
|
}
|
|
|
|
for (Entry = pEnumHandle->enumIndex; Entry < pEnumHandle->totalEntries; Entry++) {
|
|
pShareEntry = ((PRDPDR_SHARE_INFO) Buffer) + Entry;
|
|
|
|
if ((unsigned) (BufferResourceEnd - BufferResourceStart) >
|
|
sizeof(NETRESOURCEW) +
|
|
pShareEntry->ShareName.Length + sizeof(WCHAR) +
|
|
DrProviderName.Length + sizeof(WCHAR)) {
|
|
UNICODE_STRING ShareName;
|
|
|
|
pBufferResource[localCount].dwScope = pEnumHandle->dwScope;
|
|
pBufferResource[localCount].dwType = RESOURCETYPE_DISK;
|
|
pBufferResource[localCount].dwDisplayType = RESOURCEDISPLAYTYPE_SHARE;
|
|
pBufferResource[localCount].dwUsage = RESOURCEUSAGE_CONNECTABLE;
|
|
pBufferResource[localCount].lpLocalName = NULL;
|
|
|
|
ShareName.Length = pShareEntry->ShareName.Length;
|
|
ShareName.MaximumLength = pShareEntry->ShareName.MaximumLength;
|
|
ShareName.Buffer = (PWCHAR)((PCHAR)(pShareEntry) + pShareEntry->ShareName.BufferOffset);
|
|
|
|
// share name
|
|
BufferResourceEnd -= ShareName.Length + sizeof(WCHAR);
|
|
pBufferResource[localCount].lpRemoteName = (PWCHAR) (BufferResourceEnd);
|
|
RtlCopyMemory(pBufferResource[localCount].lpRemoteName,
|
|
ShareName.Buffer,
|
|
ShareName.Length);
|
|
pBufferResource[localCount].lpRemoteName[ShareName.Length /
|
|
sizeof(WCHAR)] = L'\0';
|
|
|
|
DBGMSG(DBG_TRACE, ("DRENUM: DrEnumShareInfo, ShareName, %ws\n",
|
|
pBufferResource[localCount].lpRemoteName));
|
|
|
|
// provider name
|
|
BufferResourceEnd -= DrProviderName.Length + sizeof(WCHAR);
|
|
pBufferResource[localCount].lpProvider = (PWCHAR) (BufferResourceEnd);
|
|
RtlCopyMemory(pBufferResource[localCount].lpProvider, DrProviderName.Buffer,
|
|
DrProviderName.Length);
|
|
pBufferResource[localCount].lpProvider[DrProviderName.Length /
|
|
sizeof(WCHAR)] = L'\0';
|
|
|
|
pBufferResource[localCount].lpComment = NULL;
|
|
|
|
localCount += 1;
|
|
BufferResourceStart = (PBYTE)(&pBufferResource[localCount]);
|
|
pEnumHandle->enumIndex++;
|
|
}
|
|
else {
|
|
// enumerated some entries, so return success
|
|
if (localCount) {
|
|
status = WN_SUCCESS;
|
|
break;
|
|
}
|
|
// can't even hold a single entry, return buffer too small
|
|
else {
|
|
*lpBufferSize = sizeof(NETRESOURCEW) +
|
|
pEnumHandle->RemoteName.Length +
|
|
pShareEntry->ShareName.Length + sizeof(WCHAR) +
|
|
DrProviderName.Length + sizeof(WCHAR);
|
|
DBGMSG(DBG_TRACE, ("DRENUM: DrEnumShareInfo, buffer too small\n"));
|
|
status = WN_MORE_DATA;
|
|
goto EXIT;
|
|
}
|
|
}
|
|
}
|
|
|
|
EXIT:
|
|
|
|
*lpcCount = localCount;
|
|
if (DrDeviceHandle != INVALID_HANDLE_VALUE) {
|
|
CloseHandle(DrDeviceHandle);
|
|
}
|
|
|
|
DBGMSG(DBG_TRACE, ("DRENUM: DrEnumShareInfo, return status %x\n", status));
|
|
return status;
|
|
}
|
|
|
|
DWORD
|
|
DrEnumConnectionInfo(PRDPDR_ENUMERATION_HANDLE pEnumHandle,
|
|
LPDWORD lpcCount,
|
|
LPNETRESOURCEW pBufferResource,
|
|
LPDWORD lpBufferSize)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function requests the redirector to enumerate the connection info,
|
|
it then reckages it into the user supplied buffer and return
|
|
|
|
Arguments:
|
|
|
|
pEnumHandle - Supplies the enumeration handle. It's a structure the dll
|
|
used to store enumberation state and info.
|
|
|
|
lpcCount - On return, this contains the number of NETRESOURCE entries
|
|
returned back to user.
|
|
|
|
pBufferResource - On return, this contains all the netresource entries.
|
|
|
|
lpBufferSize - This contains the size of the buffer. On return, it
|
|
is the size of the network resource entries.
|
|
|
|
Return Value:
|
|
|
|
STATUS - Success or reason for failure.
|
|
|
|
--*/
|
|
{
|
|
DWORD status = WN_SUCCESS;
|
|
DWORD localCount = 0;
|
|
HANDLE DrDeviceHandle = INVALID_HANDLE_VALUE;
|
|
RDPDR_REQUEST_PACKET Rrp; // Redirector request packet
|
|
LPBYTE Buffer = NULL;
|
|
PRDPDR_CONNECTION_INFO pConnectionEntry;
|
|
DWORD Entry, RemainingBufferSize;
|
|
BYTE *BufferResourceStart, *BufferResourceEnd;
|
|
|
|
DBGMSG(DBG_TRACE, ("DRENUM: DrEnumConnectionInfo\n"));
|
|
|
|
*lpcCount = 0;
|
|
BufferResourceStart = (PBYTE)pBufferResource;
|
|
BufferResourceEnd = ((PBYTE)(pBufferResource)) + *lpBufferSize;
|
|
|
|
if (pEnumHandle->enumIndex == 0) {
|
|
|
|
if (DrOpenMiniRdr(&DrDeviceHandle) != WN_SUCCESS) {
|
|
//
|
|
// MPR doesn't like return device error in this case
|
|
// We'll just return 0 entries
|
|
//
|
|
DBGMSG(DBG_TRACE, ("DRENUM: DrEnumConnectionInfo, DrOpenMiniRdr failed\n"));
|
|
status = WN_NO_MORE_ENTRIES;
|
|
DrDeviceHandle = INVALID_HANDLE_VALUE;
|
|
goto EXIT;
|
|
}
|
|
|
|
//
|
|
// Ask the redirector to enumerate the information of connections
|
|
// established by the caller.
|
|
//
|
|
Rrp.SessionId = NtCurrentPeb()->SessionId;
|
|
Rrp.Parameters.Get.ResumeHandle = 0;
|
|
|
|
//
|
|
// Make the request to the Redirector
|
|
//
|
|
status = DrDeviceControlGetInfo(DrDeviceHandle,
|
|
FSCTL_DR_ENUMERATE_CONNECTIONS,
|
|
&Rrp,
|
|
sizeof(RDPDR_REQUEST_PACKET),
|
|
(LPBYTE *) &Buffer,
|
|
MAXULONG,
|
|
0,
|
|
NULL);
|
|
|
|
if (status == WN_SUCCESS) {
|
|
pEnumHandle->totalEntries = Rrp.Parameters.Get.EntriesRead;
|
|
pEnumHandle->pEnumBuffer = Buffer;
|
|
}
|
|
else {
|
|
DBGMSG(DBG_TRACE, ("DRENUM: DrEnumConnectionInfo, DrDeviceControlGetInfo failed, %x\n", status));
|
|
goto EXIT;
|
|
}
|
|
}
|
|
else {
|
|
Buffer = pEnumHandle->pEnumBuffer;
|
|
|
|
if (Buffer == NULL) {
|
|
status = WN_NO_MORE_ENTRIES;
|
|
goto EXIT;
|
|
}
|
|
}
|
|
|
|
if (pEnumHandle->enumIndex == pEnumHandle->totalEntries) {
|
|
status = WN_NO_MORE_ENTRIES;
|
|
goto EXIT;
|
|
}
|
|
|
|
for (Entry = pEnumHandle->enumIndex; Entry < pEnumHandle->totalEntries; Entry++) {
|
|
pConnectionEntry = ((PRDPDR_CONNECTION_INFO) Buffer) + Entry;
|
|
|
|
if ((unsigned) (BufferResourceEnd - BufferResourceStart) >
|
|
sizeof(NETRESOURCEW) +
|
|
pConnectionEntry->RemoteName.Length + sizeof(WCHAR) +
|
|
pConnectionEntry->LocalName.Length + sizeof(WCHAR) +
|
|
DrProviderName.Length + sizeof(WCHAR)) {
|
|
UNICODE_STRING RemoteName;
|
|
UNICODE_STRING LocalName;
|
|
|
|
pBufferResource[localCount].dwScope = pEnumHandle->dwScope;
|
|
pBufferResource[localCount].dwType = RESOURCETYPE_DISK;
|
|
pBufferResource[localCount].dwDisplayType = RESOURCEDISPLAYTYPE_GENERIC;
|
|
pBufferResource[localCount].dwUsage = 0;
|
|
|
|
RemoteName.Length = pConnectionEntry->RemoteName.Length;
|
|
RemoteName.MaximumLength = pConnectionEntry->RemoteName.MaximumLength;
|
|
RemoteName.Buffer = (PWCHAR)((PCHAR)pConnectionEntry +
|
|
pConnectionEntry->RemoteName.BufferOffset);
|
|
|
|
LocalName.Length = pConnectionEntry->LocalName.Length;
|
|
LocalName.MaximumLength = pConnectionEntry->LocalName.MaximumLength;
|
|
LocalName.Buffer = (PWCHAR)((PCHAR)pConnectionEntry +
|
|
pConnectionEntry->LocalName.BufferOffset);
|
|
|
|
// Remote name
|
|
BufferResourceEnd -= RemoteName.Length + sizeof(WCHAR);
|
|
pBufferResource[localCount].lpRemoteName = (PWCHAR) (BufferResourceEnd);
|
|
RtlCopyMemory(pBufferResource[localCount].lpRemoteName,
|
|
RemoteName.Buffer,
|
|
RemoteName.Length);
|
|
pBufferResource[localCount].lpRemoteName[RemoteName.Length /
|
|
sizeof(WCHAR)] = L'\0';
|
|
|
|
DBGMSG(DBG_TRACE, ("DRENUM: DrEnumConnectionInfo, RemoteName, %ws\n",
|
|
pBufferResource[localCount].lpRemoteName));
|
|
|
|
// Local name
|
|
if (LocalName.Length != 0) {
|
|
BufferResourceEnd -= LocalName.Length + sizeof(WCHAR);
|
|
pBufferResource[localCount].lpLocalName = (PWCHAR) (BufferResourceEnd);
|
|
RtlCopyMemory(pBufferResource[localCount].lpLocalName,
|
|
LocalName.Buffer,
|
|
LocalName.Length);
|
|
pBufferResource[localCount].lpLocalName[LocalName.Length /
|
|
sizeof(WCHAR)] = L'\0';
|
|
|
|
DBGMSG(DBG_TRACE, ("DRENUM: DrEnumConnectionInfo, LocalName, %ws\n",
|
|
pBufferResource[localCount].lpLocalName));
|
|
}
|
|
else {
|
|
pBufferResource[localCount].lpLocalName = NULL;
|
|
}
|
|
|
|
// Provider name
|
|
BufferResourceEnd -= DrProviderName.Length + sizeof(WCHAR);
|
|
pBufferResource[localCount].lpProvider = (PWCHAR) (BufferResourceEnd);
|
|
RtlCopyMemory(pBufferResource[localCount].lpProvider, DrProviderName.Buffer,
|
|
DrProviderName.Length);
|
|
pBufferResource[localCount].lpProvider[DrProviderName.Length /
|
|
sizeof(WCHAR)] = L'\0';
|
|
|
|
pBufferResource[localCount].lpComment = NULL;
|
|
|
|
localCount += 1;
|
|
BufferResourceStart = (PBYTE)(&pBufferResource[localCount]);
|
|
pEnumHandle->enumIndex++;
|
|
|
|
} else {
|
|
// enumerated some entries, so return success
|
|
if (localCount) {
|
|
status = WN_SUCCESS;
|
|
break;
|
|
}
|
|
// can't even hold a single entry, return buffer too small
|
|
else {
|
|
*lpBufferSize = sizeof(NETRESOURCEW) +
|
|
pConnectionEntry->RemoteName.Length + sizeof(WCHAR) +
|
|
DrProviderName.Length + sizeof(WCHAR) +
|
|
pConnectionEntry->LocalName.Length + sizeof(WCHAR);
|
|
DBGMSG(DBG_TRACE, ("DRENUM: DrEnumConnectionInfo, buffer too small\n"));
|
|
status = WN_MORE_DATA;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
EXIT:
|
|
|
|
*lpcCount = localCount;
|
|
if (DrDeviceHandle != INVALID_HANDLE_VALUE) {
|
|
CloseHandle(DrDeviceHandle);
|
|
}
|
|
|
|
DBGMSG(DBG_TRACE, ("DRENUM: DrEnumConnectionInfo, return status %x\n", status));
|
|
return status;
|
|
}
|
|
|
|
|