Leaked source code of windows server 2003
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.
 
 
 
 
 
 

2101 lines
64 KiB

/*++
Copyright (c) 2000 Microsoft Corporation
Module Name:
drprov.c
Abstract:
This module implements the routines required for interaction with network
provider router interface in NT for RDP mini-redirector
Author:
Joy Chik 1/20/2000
--*/
#define TRC_FILE "drprov"
#include "drprov.h"
#include "drdbg.h"
DWORD GLOBAL_DEBUG_FLAGS=0x0;
//
// the RDP mini redirector and provider name. The original constants
// are defined in rdpdr.h
//
// The length does not include the null terminator
//
UNICODE_STRING DrDeviceName =
{RDPDR_DEVICE_NAME_U_LENGTH - sizeof(WCHAR),
RDPDR_DEVICE_NAME_U_LENGTH,
RDPDR_DEVICE_NAME_U};
extern UNICODE_STRING DrProviderName;
//
// Function prototypes defined in drenum.c
//
DWORD DrOpenMiniRdr(HANDLE *DrDeviceHandle);
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);
DWORD DrEnumServerInfo(IN PRDPDR_ENUMERATION_HANDLE pEnumHandle,
OUT LPDWORD lpcCount,
OUT LPNETRESOURCEW pBufferResource,
IN OUT LPDWORD lpBufferSize);
DWORD DrEnumShareInfo(IN PRDPDR_ENUMERATION_HANDLE pEnumHandle,
OUT LPDWORD lpcCount,
OUT LPNETRESOURCEW pBufferResource,
IN OUT LPDWORD lpBufferSize);
DWORD DrEnumConnectionInfo(IN PRDPDR_ENUMERATION_HANDLE pEnumHandle,
OUT LPDWORD lpcCount,
OUT LPNETRESOURCEW pBufferResource,
IN OUT LPDWORD lpBufferSize);
BOOL ValidateRemoteName(IN PWCHAR pRemoteName);
DWORD APIENTRY
NPGetCaps(
DWORD nIndex )
/*++
Routine Description:
This routine returns the capabilities of the RDP Mini redirector
network provider implementation
Arguments:
nIndex - category of capabilities desired
Return Value:
the appropriate capabilities
--*/
{
DBGMSG(DBG_TRACE, ("DRPROV: NPGetCaps, index: %d\n", nIndex));
switch (nIndex) {
case WNNC_SPEC_VERSION:
return WNNC_SPEC_VERSION51;
case WNNC_NET_TYPE:
return WNNC_NET_TERMSRV;
case WNNC_DRIVER_VERSION:
#define WNNC_DRIVER(major,minor) (major*0x00010000 + minor)
return (WNNC_DRIVER(RDPDR_MAJOR_VERSION, RDPDR_MINOR_VERSION));
case WNNC_USER:
return WNNC_USR_GETUSER;
case WNNC_CONNECTION:
return (WNNC_CON_GETCONNECTIONS |
WNNC_CON_CANCELCONNECTION |
WNNC_CON_ADDCONNECTION |
WNNC_CON_ADDCONNECTION3);
case WNNC_DIALOG:
return WNNC_DLG_GETRESOURCEINFORMATION;
//return (WNNC_DLG_SEARCHDIALOG |
// WNNC_DLG_FORMATNETNAME);
case WNNC_ADMIN:
return 0;
case WNNC_ENUMERATION:
return (WNNC_ENUM_LOCAL |
WNNC_ENUM_GLOBAL |
WNNC_ENUM_SHAREABLE);
case WNNC_START:
//
// JOYC: Need to figure what we should return here
//
return 1;
default:
return 0;
}
}
DWORD APIENTRY
NPOpenEnum(
DWORD dwScope,
DWORD dwType,
DWORD dwUsage,
LPNETRESOURCE lpNetResource,
LPHANDLE lphEnum )
/*++
Routine Description:
This routine opens a handle for enumeration of resources.
Arguments:
dwScope - the scope of enumeration
dwType - the type of resources to be enumerated
dwUsage - the usage parameter
lpNetResource - a pointer to the desired NETRESOURCE struct.
lphEnum - a pointer for passing back the enumeration handle
Return Value:
WN_SUCCESS if successful, otherwise the appropriate error
--*/
{
DWORD Status = WN_NOT_SUPPORTED;
RDPDR_ENUMERATION_HANDLE *pEnum;
DWORD ConsoleId, CurrentId;
DBGMSG(DBG_TRACE, ("DRPROV: NPOpenEnum, dwScope=%d, dwType=%d, dwUsage=%d\n",
dwScope, dwType, dwUsage));
//
// Basic parameter checking, make sure lphEnum is not NULL
//
if (lphEnum != NULL) {
*lphEnum = NULL;
}
else {
DBGMSG(DBG_TRACE, ("DRPROV: NPOpenEnum, null lphEnum parameter.\n"));
Status = WN_BAD_VALUE;
goto EXIT;
}
//
// Check if the request comes from console, if so, bail immediately
//
ConsoleId = WTSGetActiveConsoleSessionId();
if (ProcessIdToSessionId(GetCurrentProcessId(), &CurrentId)) {
if (ConsoleId == CurrentId) {
if (!(dwScope == RESOURCE_GLOBALNET && lpNetResource == NULL)) {
DBGMSG(DBG_TRACE, ("DRPROV: NPOpenEnum, console request, bail.\n"));
Status = WN_NOT_SUPPORTED;
goto EXIT;
}
}
}
//
// Allocating the enumeration handle
//
*lphEnum = MemAlloc(sizeof(RDPDR_ENUMERATION_HANDLE));
if (*lphEnum == NULL) {
DBGMSG(DBG_ERROR, ("DRPROV: NPOpenEnum, MemAlloc failed for enum handle.\n"));
Status = WN_OUT_OF_MEMORY;
goto EXIT;
}
RtlZeroMemory(*lphEnum, sizeof(RDPDR_ENUMERATION_HANDLE));
if (dwScope == RESOURCE_CONNECTED)
{
//
// we are looking for current uses
//
if (lpNetResource != NULL)
{
DBGMSG(DBG_ERROR, ("DRPROV: NPOpenEnum invalid parameter\n"));
Status = WN_BAD_VALUE;
goto EXIT;
}
pEnum = (PRDPDR_ENUMERATION_HANDLE)(*lphEnum);
pEnum->dwScope = dwScope;
pEnum->dwType = dwType;
pEnum->dwUsage = dwUsage;
pEnum->enumType = CONNECTION;
pEnum->enumIndex = 0;
Status = WN_SUCCESS;
DBGMSG(DBG_TRACE, ("DRPROV: NPOpenEnum, RESOURCE_CONNECTED.\n"));
goto EXIT;
}
else if (dwScope == RESOURCE_SHAREABLE)
{
//
// We are looking for shareable resources
// If we're not given a server, return an EMPTY_ENUM
//
if ((lpNetResource != NULL) &&
(lpNetResource->lpRemoteName != NULL) &&
(lpNetResource->lpRemoteName[0] == L'\\') &&
(lpNetResource->lpRemoteName[1] == L'\\'))
{
//
// Check if the lpRemoteName is what we recognize
if (ValidateRemoteName(lpNetResource->lpRemoteName)) {
pEnum = (PRDPDR_ENUMERATION_HANDLE)(*lphEnum);
pEnum->dwScope = dwScope;
pEnum->dwType = dwType;
pEnum->dwUsage = dwUsage;
pEnum->enumType = SHARE;
pEnum->enumIndex = 0;
pEnum->RemoteName.MaximumLength =
(wcslen(lpNetResource->lpRemoteName) + 1) * sizeof(WCHAR);
pEnum->RemoteName.Buffer =
MemAlloc(pEnum->RemoteName.MaximumLength);
if (pEnum->RemoteName.Buffer) {
pEnum->RemoteName.Length = pEnum->RemoteName.MaximumLength - sizeof(WCHAR);
wcscpy(pEnum->RemoteName.Buffer, lpNetResource->lpRemoteName);
DBGMSG(DBG_TRACE, ("DRPROV: NPOpenEnum, RESOURCE_SHARABLE for remote name: %ws\n",
lpNetResource->lpRemoteName));
Status = WN_SUCCESS;
goto EXIT;
}
else {
DBGMSG(DBG_TRACE, ("DRPROV: NPOpenEnum, MemAlloc failed for RemoteName\n"));
Status = WN_OUT_OF_MEMORY;
goto EXIT;
}
}
else {
DBGMSG(DBG_TRACE, ("DRPROV: NPOpenEnum, RESOURCE_SHAREABLE, RemoteName: %ws not supported\n",
lpNetResource->lpRemoteName));
Status = WN_NOT_SUPPORTED;
goto EXIT;
}
}
else
{
pEnum = (PRDPDR_ENUMERATION_HANDLE)(*lphEnum);
pEnum->dwScope = dwScope;
pEnum->dwType = dwType;
pEnum->dwUsage = dwUsage;
pEnum->enumType = EMPTY;
pEnum->enumIndex = 0;
DBGMSG(DBG_TRACE, ("DRPROV: NPOpenEnum, RESOURCE_SHAREABLE, NetResource empty\n"));
Status = WN_SUCCESS;
goto EXIT;
}
}
else if (dwScope == RESOURCE_GLOBALNET)
{
/* Look for the combination of all bits and substitute "All" for
* them. Ignore bits we don't know about.
*/
dwUsage &= (RESOURCEUSAGE_CONNECTABLE | RESOURCEUSAGE_CONTAINER);
if ( dwUsage == (RESOURCEUSAGE_CONNECTABLE | RESOURCEUSAGE_CONTAINER) )
{
dwUsage = 0 ;
}
/*
* we are looking for global resources out on the net
*/
if (lpNetResource == NULL || lpNetResource->lpRemoteName == NULL)
{
/*
* at top level, therefore enumerating servers. if user
* asked for connectable, well, there aint none.
*/
if (dwUsage == RESOURCEUSAGE_CONNECTABLE)
{
pEnum = (PRDPDR_ENUMERATION_HANDLE)(*lphEnum);
pEnum->dwScope = dwScope;
pEnum->dwType = dwType;
pEnum->dwUsage = dwUsage;
pEnum->enumType = EMPTY;
pEnum->enumIndex = 0;
DBGMSG(DBG_TRACE, ("DRPROV: NPOpenEnum, RESOURCE_GLOBALNET, empty node\n"));
Status = WN_SUCCESS;
goto EXIT;
}
else
{
// return server name, i.e. tsclient
pEnum = (PRDPDR_ENUMERATION_HANDLE)(*lphEnum);
pEnum->dwScope = dwScope;
pEnum->dwType = dwType;
pEnum->dwUsage = dwUsage;
pEnum->enumType = SERVER;
pEnum->enumIndex = 0;
DBGMSG(DBG_TRACE, ("DRPROV: NPOpenEnum, RESOURCE_GLOBALNET, enumerate server name.\n"));
Status = WN_SUCCESS;
goto EXIT;
}
}
else
{
/*
* we are assured of lpRemoteName != NULL.
* things get interesting here. the cases are as follows:
*
* if (dwUsage == 0)
* if have \\ in front
* return shares
* else
* return empty enum
* else if (dwUsage == CONNECTABLE)
* if have \\ in front
* return shares
* else
* empty enum
* else if (dwUsage == CONTAINER)
* if have \\ in front
* empty enum
* else
* return empty enum
*
*/
if (((dwUsage == RESOURCEUSAGE_CONNECTABLE) || (dwUsage == 0)) &&
((lpNetResource->lpRemoteName[0] == L'\\') &&
(lpNetResource->lpRemoteName[1] == L'\\')))
{
/* Confirm that this really is a computer name (i.e., a
* container we can enumerate).
*/
if (ValidateRemoteName(lpNetResource->lpRemoteName)) {
pEnum = (PRDPDR_ENUMERATION_HANDLE)(*lphEnum);
pEnum->dwScope = dwScope;
pEnum->dwType = dwType;
pEnum->dwUsage = dwUsage;
pEnum->enumType = SHARE;
pEnum->enumIndex = 0;
pEnum->RemoteName.MaximumLength =
(wcslen(lpNetResource->lpRemoteName) + 1) * sizeof(WCHAR);
pEnum->RemoteName.Buffer =
MemAlloc(pEnum->RemoteName.MaximumLength);
if (pEnum->RemoteName.Buffer) {
pEnum->RemoteName.Length = pEnum->RemoteName.MaximumLength - sizeof(WCHAR);
wcscpy(pEnum->RemoteName.Buffer, lpNetResource->lpRemoteName);
DBGMSG(DBG_TRACE, ("DRPROV: NPOpenEnum, RESOURCE_GLOBALNET for remote name: %ws\n",
lpNetResource->lpRemoteName));
Status = WN_SUCCESS;
goto EXIT;
}
else {
DBGMSG(DBG_TRACE, ("DRPROV: NPOpenEnum, MemAlloc failed for RemoteName\n"));
Status = WN_OUT_OF_MEMORY;
goto EXIT;
}
}
else {
DBGMSG(DBG_TRACE, ("DRPROV: NPOpenEnum, RESOURCE_GLOBALNET, RemoteName: %ws not supported\n",
lpNetResource->lpRemoteName));
Status = WN_NOT_SUPPORTED;
goto EXIT;
}
}
else if (((dwUsage == RESOURCEUSAGE_CONTAINER) || (dwUsage == 0)) &&
(lpNetResource->lpRemoteName[0] != L'\\'))
{
// return empty enum.
pEnum = (PRDPDR_ENUMERATION_HANDLE)(*lphEnum);
pEnum->dwScope = dwScope;
pEnum->dwType = dwType;
pEnum->dwUsage = dwUsage;
pEnum->enumType = EMPTY;
pEnum->enumIndex = 0;
DBGMSG(DBG_TRACE, ("DRPROV: NPOpenEnum, RESOURCE_GLOBALNET, empty node\n"));
Status = WN_SUCCESS;
goto EXIT;
}
else if (
// ask for share but aint starting from server
((dwUsage == RESOURCEUSAGE_CONNECTABLE) &&
(lpNetResource->lpRemoteName[0] != L'\\')) ||
// ask for server but is starting from server
((dwUsage == RESOURCEUSAGE_CONTAINER) &&
((lpNetResource->lpRemoteName[0] == L'\\') &&
(lpNetResource->lpRemoteName[1] == L'\\')))
)
{
// return empty
pEnum = (PRDPDR_ENUMERATION_HANDLE)(*lphEnum);
pEnum->dwScope = dwScope;
pEnum->dwType = dwType;
pEnum->dwUsage = dwUsage;
pEnum->enumType = EMPTY;
pEnum->enumIndex = 0;
DBGMSG(DBG_TRACE, ("DRPROV: NPOpenEnum, RESOURCE_GLOBALNET, empty node\n"));
Status = WN_SUCCESS;
goto EXIT;
}
else
{
// incorrect dwUsage
DBGMSG(DBG_TRACE, ("DRPROV: NPOpenEnum, invalid dwUsage parameter\n"));
Status = WN_BAD_VALUE;
goto EXIT;
}
}
}
else
{
// invalid dwScope
DBGMSG(DBG_TRACE, ("DRPROV: NPOpenEnum, invalid dwScope parameter\n"));
Status = WN_BAD_VALUE;
goto EXIT;
}
EXIT:
//
// clean up enumeration handle in failure case
if (Status != WN_SUCCESS && lphEnum != NULL && *lphEnum != NULL) {
MemFree(*lphEnum);
*lphEnum = NULL;
}
DBGMSG(DBG_TRACE, ("DRPROV: NPOpenEnum, return status: %x\n", Status));
return Status;
}
DWORD APIENTRY
NPEnumResource(
HANDLE hEnum,
LPDWORD lpcCount,
LPVOID lpBuffer,
LPDWORD lpBufferSize)
/*++
Routine Description:
This routine uses the handle obtained by a call to NPOpenEnum for
enuerating the connected shares
Arguments:
hEnum - the enumeration handle
lpcCount - the number of resources returned
lpBuffer - the buffere for passing back the entries
lpBufferSize - the size of the buffer
Return Value:
WN_SUCCESS if successful, otherwise the appropriate error
WN_NO_MORE_ENTRIES - if the enumeration has exhausted the entries
WN_MORE_DATA - if nmore data is available
--*/
{
DWORD status = WN_SUCCESS;
LPNETRESOURCEW pBufferResource;
PRDPDR_ENUMERATION_HANDLE pEnumHandle;
pEnumHandle = (PRDPDR_ENUMERATION_HANDLE)hEnum;
pBufferResource = (LPNETRESOURCEW)lpBuffer;
if (lpcCount == NULL || lpBuffer == NULL || lpBufferSize == NULL) {
DBGMSG(DBG_TRACE, ("DRPROV: NPEnumResource, Invalid parameter(s)\n"));
status = WN_BAD_VALUE;
goto EXIT;
}
if (pEnumHandle != NULL) {
DBGMSG(DBG_TRACE, ("DRPROV: NPEnumResource, EnumType: %d\n", pEnumHandle->enumType));
if ( pEnumHandle->enumType == SERVER ) {
status = DrEnumServerInfo(pEnumHandle, lpcCount, pBufferResource, lpBufferSize);
goto EXIT;
}
else if ( pEnumHandle->enumType == SHARE ) {
status = DrEnumShareInfo(pEnumHandle, lpcCount, pBufferResource, lpBufferSize);
goto EXIT;
}
else if ( pEnumHandle->enumType == CONNECTION ) {
status = DrEnumConnectionInfo(pEnumHandle, lpcCount, pBufferResource, lpBufferSize);
goto EXIT;
}
else if ( pEnumHandle->enumType == EMPTY) {
status = WN_NO_MORE_ENTRIES;
goto EXIT;
}
else {
DBGMSG(DBG_TRACE, ("DRPROV: NPEnumResource, invalid enum type\n"));
status = WN_BAD_HANDLE;
goto EXIT;
}
}
else {
DBGMSG(DBG_TRACE, ("DRPROV: NPEnumResource, NULL enum handle\n"));
status = WN_BAD_HANDLE;
goto EXIT;
}
EXIT:
DBGMSG(DBG_TRACE, ("DRPROV: NPEnumResource, return status: %x\n", status));
return status;
}
DWORD APIENTRY
NPCloseEnum(
HANDLE hEnum )
/*++
Routine Description:
This routine closes the handle for enumeration of resources.
Arguments:
hEnum - the enumeration handle
Return Value:
WN_SUCCESS if successful, otherwise the appropriate error
--*/
{
DWORD Status = WN_SUCCESS;
DBGMSG(DBG_TRACE, ("DRPROV: NPCloseEnum, handle: %p\n", hEnum));
if (hEnum != NULL) {
PRDPDR_ENUMERATION_HANDLE pEnumHandle = (PRDPDR_ENUMERATION_HANDLE)hEnum;
// free the enumeration buffer
if (pEnumHandle->pEnumBuffer != NULL) {
MemFree(pEnumHandle->pEnumBuffer);
}
// free the remote name
if (pEnumHandle->RemoteName.Buffer != NULL) {
MemFree(pEnumHandle->RemoteName.Buffer);
}
// free the enum handle
MemFree(hEnum);
hEnum = NULL;
}
Status = WN_SUCCESS;
return Status;
}
DWORD
OpenConnection(
PUNICODE_STRING pConnectionName,
DWORD Disposition,
DWORD CreateOption,
PFILE_FULL_EA_INFORMATION pEABuffer,
DWORD EABufferLength,
PHANDLE pConnectionHandle )
/*++
Routine Description:
This routine opens the connection. This routine is shared by NpAddConnection
and NPCancelConnection
Arguments:
pConnectionName - the connection name
Disposition - the Open disposition
CreateOption - the create option
pEABuffer - the EA buffer associated with the open
EABufferLength - the EA buffer length
pConnectionHandle - the placeholder for the connection handle
Return Value:
WN_SUCCESS if successful, otherwise the appropriate error
Notes:
--*/
{
NTSTATUS Status;
DWORD NPStatus;
IO_STATUS_BLOCK IoStatusBlock;
OBJECT_ATTRIBUTES ConnectionObjectAttributes;
DBGMSG(DBG_TRACE, ("DRPROV: OpenConnection, connectionName: %ws\n",
pConnectionName->Buffer));
ASSERT(pConnectionName != NULL);
ASSERT(pConnectionHandle != NULL);
InitializeObjectAttributes(
&ConnectionObjectAttributes,
pConnectionName,
OBJ_CASE_INSENSITIVE,
NULL,
NULL);
Status = NtCreateFile(
pConnectionHandle,
FILE_LIST_DIRECTORY | SYNCHRONIZE,
&ConnectionObjectAttributes,
&IoStatusBlock,
NULL,
FILE_ATTRIBUTE_NORMAL,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
Disposition,
CreateOption,
pEABuffer,
EABufferLength);
DBGMSG(DBG_TRACE, ("DRPROV: OpenConnection, NtCreateFile status: %x\n", Status));
if (Status != STATUS_SUCCESS) {
NPStatus = ERROR_BAD_NETPATH;
}
else {
NPStatus = WN_SUCCESS;
}
return NPStatus;
}
DWORD
CreateConnectionName(
PWCHAR pLocalName,
PWCHAR pRemoteName,
PUNICODE_STRING pConnectionName)
/*++
Routine Description:
This routine create connection name from the remote name
Arguments:
pLocalName - the local name for the connection
pRemoteName - the UNC remote name
pConnectionName - the connection name used to talk to mini redirector
Return Value:
WN_SUCCESS if successful, otherwise the appropriate error
Notes:
--*/
{
DWORD status;
DWORD LocalNameLength,RemoteNameLength;
DWORD dwSessionId;
WCHAR pSessionId[16];
WCHAR LocalName[MAX_PATH + 1];
ASSERT(pRemoteName != NULL);
ASSERT(pConnectionName != NULL);
DBGMSG(DBG_TRACE, ("DRPROV: CreateConnectionName, RemoteName: %ws\n",
pRemoteName));
if (pLocalName != NULL) {
DBGMSG(DBG_TRACE, ("DRPROV: CreateConnection Name, LocalName: %ws\n",
pLocalName));
}
//
// The remote name is in the UNC format \\Server\Share. This name
// needs to be translated to an appropriate NT name in order to
// issue the request to the underlying mini redirector to create the
// connection.
//
// The NT style name is of the form
//
// \device\rdpdr\;<DriveLetter>:<sessionid>\Server\Share
//
// The additional ; is required by the new RDR for extensibility.
//
// skip past the first back slash since the name to be appended for the
// NT name does not require this.
pRemoteName++;
RemoteNameLength = wcslen(pRemoteName) * sizeof(WCHAR);
if (pLocalName != NULL) {
// Local name should not be greater than MAX_PATH;
LocalNameLength = wcslen(pLocalName) * sizeof(WCHAR);
if (LocalNameLength <= MAX_PATH * sizeof(WCHAR)) {
wcscpy(LocalName, pLocalName);
}
else {
wcsncpy(LocalName, pLocalName, MAX_PATH);
LocalName[MAX_PATH] = L'\0';
}
// remove the trailing : in localname if there is one
if (LocalName[LocalNameLength/sizeof(WCHAR) - 1] == L':') {
LocalName[LocalNameLength/sizeof(WCHAR) - 1] = L'\0';
LocalNameLength -= sizeof(WCHAR);
}
} else {
LocalNameLength = 0;
}
//
// Get SessionId
//
dwSessionId = NtCurrentPeb()->SessionId;
swprintf(pSessionId, L"%d", dwSessionId);
pConnectionName->MaximumLength = (USHORT)(DrDeviceName.Length +
RemoteNameLength + LocalNameLength +
sizeof(WCHAR) * 3 + // account for \; and :
wcslen(pSessionId) * sizeof(WCHAR) +
sizeof(WCHAR)); // account of terminator null
pConnectionName->Buffer = MemAlloc(pConnectionName->MaximumLength);
if (pConnectionName->Buffer == NULL) {
DBGMSG(DBG_TRACE, ("DRPROV: CreateConnectionName, MemAlloc failed\n"));
status = WN_OUT_OF_MEMORY;
goto EXIT;
}
// Copy the name into the buffer
pConnectionName->Length = 0;
pConnectionName->Buffer[0] = L'\0';
RtlAppendUnicodeToString(pConnectionName, DrDeviceName.Buffer);
RtlAppendUnicodeToString(pConnectionName, L"\\;");
if (LocalNameLength != 0) {
RtlAppendUnicodeToString(pConnectionName, LocalName);
}
RtlAppendUnicodeToString(pConnectionName, L":");
RtlAppendUnicodeToString(pConnectionName, pSessionId);
RtlAppendUnicodeToString(pConnectionName, pRemoteName);
DBGMSG(DBG_TRACE, ("DRPROV: CreateConnectionName, %wZ\n", pConnectionName));
status = WN_SUCCESS;
EXIT:
return status;
}
BOOL ValidateRemoteName(PWCHAR pRemoteName)
/*++
Routine Description:
This routine checks if the remote name belongs to our provider
Arguments:
pRemoteName - the UNC remote name
Return Value:
TRUE if the remote name belongs to our provider, otherwise FALSE
Notes:
--*/
{
BOOL rc = FALSE;
DWORD status;
RDPDR_REQUEST_PACKET Rrp; // Redirector request packet
HANDLE DrDeviceHandle = INVALID_HANDLE_VALUE;
LPBYTE Buffer = NULL;
PRDPDR_SERVER_INFO pServerEntry;
if (DrOpenMiniRdr(&DrDeviceHandle) != WN_SUCCESS) {
//
// MPR doesn't like return device error in this case
// We'll just return 0 entries
//
DBGMSG(DBG_TRACE, ("DRPROV: ValidateRemoteName, DrOpenMiniRdr failed\n"));
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) {
UNICODE_STRING ServerName;
pServerEntry = ((PRDPDR_SERVER_INFO) Buffer);
ServerName.Length = pServerEntry->ServerName.Length;
ServerName.MaximumLength = pServerEntry->ServerName.MaximumLength;
ServerName.Buffer = (PWCHAR)((PCHAR)(pServerEntry) + pServerEntry->ServerName.BufferOffset);
if ((wcslen(pRemoteName) == ServerName.Length / sizeof(WCHAR)) &&
_wcsnicmp(pRemoteName, ServerName.Buffer,
ServerName.Length/sizeof(WCHAR)) == 0) {
rc = TRUE;
}
else {
DBGMSG(DBG_TRACE, ("DRPROV: ValidateRemoteName, remote name not for drprov, %wZ\n",
pRemoteName));
goto EXIT;
}
}
else {
DBGMSG(DBG_TRACE, ("DRENUM: ValidateRemoteName, DrDeviceControlGetInfo failed, %x\n", status));
goto EXIT;
}
EXIT:
if (DrDeviceHandle != INVALID_HANDLE_VALUE) {
CloseHandle(DrDeviceHandle);
}
if (Buffer != NULL) {
MemFree(Buffer);
}
DBGMSG(DBG_TRACE, ("DRPROV: ValidateRemoteName, return, %d\n", rc));
return rc;
}
DWORD APIENTRY
NPAddConnection(
LPNETRESOURCE lpNetResource,
LPWSTR lpPassword,
LPWSTR lpUserName )
/*++
Routine Description:
This routine adds a connection to the list of connections associated
with this network provider
Arguments:
lpNetResource - the NETRESOURCE struct
lpPassword - the password
lpUserName - the user name
Return Value:
WN_SUCCESS if successful, otherwise the appropriate error
Notes:
--*/
{
DBGMSG(DBG_TRACE, ("DRPROV: NPAddConnection.\n"));
return NPAddConnection3(NULL, lpNetResource, lpPassword, lpUserName, 0);
}
DWORD
TestAddConnection(
LPNETRESOURCE lpNetResource)
/*++
Routine Description:
This routine tests adding a connection to the list of connections associated
with this network provider
Arguments:
lpNetResource - the NETRESOURCE struct
Return Value:
WN_SUCCESS if successful, otherwise the appropriate error
--*/
{
DWORD Status = 0;
UNICODE_STRING ConnectionName;
HANDLE ConnectionHandle = INVALID_HANDLE_VALUE;
PWCHAR pRemoteName;
DBGMSG(DBG_TRACE, ("DRPROV: TestAddConnection\n"));
pRemoteName = lpNetResource->lpRemoteName;
// Create ConnectionName with NULL local name
Status = CreateConnectionName(NULL, pRemoteName, &ConnectionName);
if (Status != WN_SUCCESS) {
DBGMSG(DBG_TRACE, ("DRPROV: TestAddConnection, CreateConnectName failed\n"));
goto EXIT;
}
Status = OpenConnection(
&ConnectionName,
FILE_OPEN,
(FILE_CREATE_TREE_CONNECTION | FILE_SYNCHRONOUS_IO_NONALERT),
NULL,
0,
&ConnectionHandle);
if (Status != WN_SUCCESS) {
ConnectionHandle = INVALID_HANDLE_VALUE;
goto EXIT;
}
EXIT:
if (ConnectionHandle != INVALID_HANDLE_VALUE) {
NtClose(ConnectionHandle);
ConnectionHandle = INVALID_HANDLE_VALUE;
}
if (ConnectionName.Buffer != NULL) {
MemFree(ConnectionName.Buffer);
ConnectionName.Buffer = NULL;
}
return Status;
}
DWORD APIENTRY
NPAddConnection3(
HWND hwndOwner,
LPNETRESOURCE lpNetResource,
LPWSTR lpPassword,
LPWSTR lpUserName,
DWORD dwFlags )
/*++
Routine Description:
This routine adds a connection to the list of connections associated
with this network provider
Arguments:
hwndOwner - the owner handle
lpNetResource - the NETRESOURCE struct
lpPassword - the password
lpUserName - the user name
dwFlags - flags for the connection
Return Value:
WN_SUCCESS if successful, otherwise the appropriate error
Notes:
// JOYC: do we need to pass credential to the redirector?
// Seems the sessionId verification is enough
--*/
{
DWORD Status = 0;
UNICODE_STRING ConnectionName;
HANDLE ConnectionHandle;
PWCHAR pLocalName,pRemoteName;
DBGMSG(DBG_TRACE, ("DRPROV: NPAddConnection 3.\n"));
ConnectionName.Buffer = NULL;
ConnectionName.Length = 0;
ConnectionHandle = INVALID_HANDLE_VALUE;
//
// Make sure remote name starts with \\
//
if ((lpNetResource == NULL) ||
(lpNetResource->lpRemoteName == NULL) ||
(lpNetResource->lpRemoteName[0] != L'\\') ||
(lpNetResource->lpRemoteName[1] != L'\\')) {
DBGMSG(DBG_TRACE, ("DRPROV: invalid lpNetResource parameter.\n"));
Status = WN_BAD_NETNAME;
goto EXIT;
}
//
// The remote name is in the UNC format \\Server\Share. This name
// needs to be translated to an appropriate NT name in order to
// issue the request to the underlying mini redirector to create the
// connection.
//
// The NT style name is of the form
//
// \device\rdpdr\;<DriveLetter>:<sessionid>\Server\Share
//
// The additional ; is required by the new RDR for extensibility.
//
// Test if rdpdr provider recognize this remote name or not
Status = TestAddConnection(lpNetResource);
if (Status != WN_SUCCESS) {
DBGMSG(DBG_TRACE, ("DRPROV: NPAddConnection3, TestAddConnection failed\n"));
goto EXIT;
}
pLocalName = lpNetResource->lpLocalName;
pRemoteName = lpNetResource->lpRemoteName;
Status = CreateConnectionName(pLocalName, pRemoteName, &ConnectionName);
if (Status != WN_SUCCESS) {
DBGMSG(DBG_TRACE, ("DRPROV: NPAddConnection3, CreateConnectName failed\n"));
goto EXIT;
}
if ((Status == WN_SUCCESS) && (pLocalName != NULL)) {
WCHAR TempBuf[64];
DBGMSG(DBG_TRACE, ("DRPROV: NPAddConnection3, create dos symbolic link\n"));
if (!QueryDosDeviceW(pLocalName, TempBuf, 64)) {
if (GetLastError() == ERROR_FILE_NOT_FOUND) {
//
// ERROR_FILE_NOT_FOUND (translated from OBJECT_NAME_NOT_FOUND)
// means it does not exist and we can redirect this device.
goto Done;
}
else {
//
// Most likely failure occurred because our output
// buffer is too small. It still means someone already
// has an existing symbolic link for this device.
//
DBGMSG(DBG_TRACE, ("DRPROV: NPAddConnection3, DosName already assigned, %ws\n",
pLocalName));
Status = ERROR_ALREADY_ASSIGNED;
goto EXIT;
}
}
else {
//
// QueryDosDevice successfully an existing symbolic link--
// somebody is already using this device.
//
DBGMSG(DBG_TRACE, ("DRPROV: NPAddConnection3, DosName already assigned, %ws\n",
pLocalName));
Status = ERROR_ALREADY_ASSIGNED;
goto EXIT;
}
}
Done:
//
// We are not doing anything with username/password
//
Status = OpenConnection(
&ConnectionName,
FILE_OPEN,
(FILE_CREATE_TREE_CONNECTION | FILE_SYNCHRONOUS_IO_NONALERT),
NULL,
0,
&ConnectionHandle);
if (Status != WN_SUCCESS) {
ConnectionHandle = INVALID_HANDLE_VALUE;
}
else {
//
// Create a symbolic link object to the device we are redirecting
//
if (DefineDosDeviceW(
DDD_RAW_TARGET_PATH |
DDD_NO_BROADCAST_SYSTEM,
pLocalName,
ConnectionName.Buffer)) {
Status = WN_SUCCESS;
}
else {
Status = GetLastError();
DBGMSG(DBG_TRACE, ("DRPROV: NPAddConnection3, failed DefineDosDeviceW, %x.\n",
Status));
goto EXIT;
}
}
EXIT:
if (ConnectionHandle != INVALID_HANDLE_VALUE) {
NtClose(ConnectionHandle);
}
if (ConnectionName.Buffer != NULL) {
MemFree(ConnectionName.Buffer);
}
DBGMSG(DBG_TRACE, ("DRPROV: NPAddConnection3, return status: %x\n", Status));
return Status;
}
DWORD APIENTRY
NPCancelConnection(
LPWSTR lpName,
BOOL fForce )
/*++
Routine Description:
This routine cancels ( deletes ) a connection from the list of connections
associated with this network provider
Arguments:
lpName - name of the connection
fForce - forcefully delete the connection
Return Value:
WN_SUCCESS if successful, otherwise the appropriate error
Notes:
--*/
{
BOOL bLocalName = FALSE;
DWORD Status = 0;
NTSTATUS ntStatus;
HANDLE ConnectionHandle;
IO_STATUS_BLOCK IoStatusBlock;
UNICODE_STRING ConnectionName;
WCHAR TargetPath[MAX_PATH + 1];
DBGMSG(DBG_TRACE, ("DRPROV: NPCancelConnection.\n"));
ConnectionName.Buffer = NULL;
ConnectionName.Length = 0;
ConnectionHandle = INVALID_HANDLE_VALUE;
// lpName should contain at least two characters: either two back slashes or dos name
if (lpName == NULL || wcslen(lpName) == 0) {
DBGMSG(DBG_TRACE, ("DRPROV: NPCancelConnection, invalid lpName parameter.\n"));
Status = WN_BAD_VALUE;
goto EXIT;
}
// We get the UNC name
if (*lpName == L'\\' && *(lpName + 1) == L'\\') {
DBGMSG(DBG_TRACE, ("DRPROV: NPCancelConnection, lpName is UNC name, %ws.\n", *lpName));
bLocalName = FALSE;
// Setup the NT Device Name
Status = CreateConnectionName(NULL, lpName, &ConnectionName);
if (Status != WN_SUCCESS) {
DBGMSG(DBG_TRACE, ("DRPROV: NPCancelConnection, CreateConnectName failed\n"));
goto EXIT;
}
}
// We get the local name
else {
DBGMSG(DBG_TRACE, ("DRPROV: NPCancelConnection, lpName is local name, %ws.\n", *lpName));
bLocalName = TRUE;
// Find the NT devive path
if (QueryDosDevice(lpName, TargetPath, sizeof(TargetPath)/sizeof(WCHAR) - 1)) {
ConnectionName.Length = wcslen(TargetPath) * sizeof(WCHAR);
ConnectionName.MaximumLength = ConnectionName.Length + sizeof(WCHAR);
ConnectionName.Buffer = TargetPath;
}
else {
Status = WN_BAD_NETNAME;
DBGMSG(DBG_TRACE, ("DRPROV: NPCancelConnection, QueryDosDevice failed, %x.\n", Status));
goto EXIT;
}
}
Status = OpenConnection(
&ConnectionName,
FILE_OPEN,
(FILE_CREATE_TREE_CONNECTION | FILE_SYNCHRONOUS_IO_NONALERT),
NULL,
0,
&ConnectionHandle);
if (Status == WN_SUCCESS) {
// Request the driver to delete the connection entry
ntStatus = NtFsControlFile(
ConnectionHandle,
NULL,
NULL,
NULL,
&IoStatusBlock,
FSCTL_DR_DELETE_CONNECTION,
NULL,
0,
NULL,
0);
if (ntStatus == STATUS_SUCCESS) {
DBGMSG(DBG_TRACE, ("DRPROV: NPCancelConnection, Deleting dos symbolic link, %ws\n", lpName));
if (bLocalName) {
if (DefineDosDevice(
DDD_REMOVE_DEFINITION | DDD_RAW_TARGET_PATH | DDD_EXACT_MATCH_ON_REMOVE,
lpName,
ConnectionName.Buffer)) {
Status = WN_SUCCESS;
goto EXIT;
}
else {
Status = GetLastError();
DBGMSG(DBG_TRACE, ("DRPROV: NPCancelConnection failed to delete symbolic link, %x.\n",
Status));
goto EXIT;
}
}
}
else {
DBGMSG(DBG_TRACE, ("DRPROV: NPCancelConnection, failed NtFsControlFile, %x\n", ntStatus));
Status = WN_BAD_NETNAME;
goto EXIT;
}
}
else {
DBGMSG(DBG_TRACE, ("DRPROV: NPCancelConnection, OpenConnection %wZ failed, %x\n",
&ConnectionName, Status));
ConnectionHandle = INVALID_HANDLE_VALUE;
Status = WN_BAD_NETNAME;
goto EXIT;
}
EXIT:
if (bLocalName != TRUE && ConnectionName.Buffer != NULL) {
MemFree(ConnectionName.Buffer);
}
if (ConnectionHandle != INVALID_HANDLE_VALUE) {
NtClose(ConnectionHandle);
}
DBGMSG(DBG_TRACE, ("DRPROV: NPCancelConnection, return status: %x\n", Status));
return Status;
}
DWORD APIENTRY
NPGetConnection(
LPWSTR lpLocalName,
LPWSTR lpRemoteName,
LPDWORD lpBufferSize )
/*++
Routine Description:
This routine returns the information associated with a connection
Arguments:
lpLocalName - local name associated with the connection
lpRemoteName - the remote name associated with the connection
lpBufferSize - the remote name buffer size
Return Value:
WN_SUCCESS if successful, otherwise the appropriate error
Notes:
--*/
{
DWORD Status = 0;
NTSTATUS ntStatus;
HANDLE ConnectionHandle;
RDPDR_REQUEST_PACKET Rrp; // Redirector request packet
UNICODE_STRING ConnectionName;
WCHAR TargetPath[MAX_PATH + 1];
LPBYTE Buffer = NULL;
PRDPDR_CONNECTION_INFO ConnectionInfo;
DBGMSG(DBG_TRACE, ("DRPROV: NPGetConnection.\n"));
ConnectionName.Buffer = NULL;
ConnectionName.Length = 0;
ConnectionHandle = INVALID_HANDLE_VALUE;
if (lpLocalName == NULL || lpRemoteName == NULL || lpBufferSize == NULL) {
DBGMSG(DBG_TRACE, ("DRPROV: NPGetConnection, invalid parameter(s).\n"));
Status = WN_BAD_VALUE;
goto EXIT;
}
// Find the NT devive path
if (QueryDosDevice(lpLocalName, TargetPath, sizeof(TargetPath)/sizeof(WCHAR) - 1)) {
ConnectionName.Length = wcslen(TargetPath) * sizeof(WCHAR);
ConnectionName.MaximumLength = ConnectionName.Length + sizeof(WCHAR);
ConnectionName.Buffer = TargetPath;
}
else {
Status = GetLastError();
DBGMSG(DBG_TRACE, ("DRPROV: NPGetConnection, querydosdevice failed, %x\n", Status));
goto EXIT;
}
// Check if this connection belongs to rdpdr
if (wcsstr(TargetPath, RDPDR_DEVICE_NAME_U) != NULL) {
Status = OpenConnection(
&ConnectionName,
FILE_OPEN,
(FILE_CREATE_TREE_CONNECTION | FILE_SYNCHRONOUS_IO_NONALERT),
NULL,
0,
&ConnectionHandle);
if (Status == WN_SUCCESS) {
// Request the driver to retrieve the connection entry info
Rrp.SessionId = NtCurrentPeb()->SessionId;
Rrp.Parameters.Get.ResumeHandle = 0;
DBGMSG(DBG_TRACE, ("DRPROV: NPGetConnection, call DrDeviceControlGetInfo\n"));
//
// Make the request to the Redirector
//
if (DrDeviceControlGetInfo(
ConnectionHandle,
FSCTL_DR_GET_CONNECTION_INFO,
&Rrp,
sizeof(RDPDR_REQUEST_PACKET),
(LPBYTE *) &Buffer,
MAXULONG,
0,
NULL
) == WN_SUCCESS) {
UNICODE_STRING RemoteName;
ConnectionInfo = (PRDPDR_CONNECTION_INFO)Buffer;
RemoteName.Length = ConnectionInfo->RemoteName.Length;
RemoteName.MaximumLength = ConnectionInfo->RemoteName.MaximumLength;
RemoteName.Buffer = (PWCHAR)((PCHAR)(ConnectionInfo) +
ConnectionInfo->RemoteName.BufferOffset);
if (*lpBufferSize > RemoteName.Length) {
*lpBufferSize = RemoteName.Length + sizeof(WCHAR);
RtlCopyMemory(
lpRemoteName,
RemoteName.Buffer,
RemoteName.Length);
lpRemoteName[RemoteName.Length/sizeof(WCHAR)] = L'\0';
DBGMSG(DBG_TRACE, ("DRPROV: NPGetConnection, remote name %ws\n", lpRemoteName));
Status = WN_SUCCESS;
goto EXIT;
}
else {
DBGMSG(DBG_TRACE, ("DRPROV: NPGetConnection, buffer too small\n"));
*lpBufferSize = RemoteName.Length + sizeof(WCHAR);
Status = WN_MORE_DATA;
goto EXIT;
}
}
else {
DBGMSG(DBG_TRACE, ("DRPROV: NPGetConnection, DrDeviceControlGetInfo failed\n"));
Status = WN_BAD_NETNAME;
goto EXIT;
}
}
else {
DBGMSG(DBG_TRACE, ("DRPROV: NPGetConnection, OpenConnection failed, %x\n", Status));
ConnectionHandle = INVALID_HANDLE_VALUE;
Status = WN_BAD_NETNAME;
goto EXIT;
}
}
else {
DBGMSG(DBG_TRACE, ("DRPROV: NPGetConnection, DrDeviceControlGetInfo failed\n"));
Status = WN_BAD_NETNAME;
goto EXIT;
}
EXIT:
if (ConnectionHandle != INVALID_HANDLE_VALUE) {
NtClose(ConnectionHandle);
}
if (Buffer != NULL) {
MemFree(Buffer);
}
DBGMSG(DBG_TRACE, ("DRPROV: NPGetConnection, return status: %x\n", Status));
return Status;
}
DWORD APIENTRY
NPGetResourceParent(
LPNETRESOURCE lpNetResource,
LPVOID lpBuffer,
LPDWORD lpBufferSize )
/*++
Routine Description:
This routine returns the parent of a given resource
Arguments:
lpNetResource - the NETRESOURCE struct
lpBuffer - the buffer for passing back the parent information
lpBufferSize - the buffer size
Return Value:
WN_NOT_SUPPORTED
Notes:
The current sample does not handle this call.
--*/
{
//
// JOYC: Need to support this?
//
DBGMSG(DBG_TRACE, ("DRPROV: NPGetResourceParent.\n"));
return WN_NOT_SUPPORTED;
}
DWORD APIENTRY
NPGetResourceInformation(
LPNETRESOURCE lpNetResource,
LPVOID lpBuffer,
LPDWORD lpBufferSize,
LPWSTR *lplpSystem )
/*++
Routine Description:
This routine returns the information associated net resource
Arguments:
lpNetResource - the NETRESOURCE struct
lpBuffer - the buffer for passing back the resource information
lpBufferSize - the buffer size
lplpSystem -
Return Value:
Notes:
--*/
{
DWORD Status = 0;
LPNETRESOURCE pOutNetResource;
UNICODE_STRING RemoteName;
UNICODE_STRING SystemPath;
BOOL fResourceTypeDisk = FALSE ;
WORD wSlashCount = 0;
BYTE *BufferResourceStart, *BufferResourceEnd;
PWCHAR pCurPos;
DBGMSG(DBG_TRACE, ("DRPROV: NPGetConnection.\n"));
RemoteName.Buffer = NULL;
RemoteName.Length = RemoteName.MaximumLength = 0;
if (lpBuffer == NULL || lpBufferSize == NULL) {
DBGMSG(DBG_TRACE, ("DRPROV: NPGetResourceInformation, invalid parameter(s).\n"));
Status = WN_BAD_VALUE;
goto EXIT;
}
pOutNetResource = (LPNETRESOURCE)lpBuffer;
BufferResourceStart = (PBYTE)lpBuffer;
BufferResourceEnd = ((PBYTE)(pOutNetResource)) + *lpBufferSize;
SystemPath.Buffer = NULL;
SystemPath.Length = SystemPath.MaximumLength = 0;
//
// JOYC: Do we need to check if we are the right provider from lpProvider?
// And the dwType?
//
if (lpNetResource == NULL || lpNetResource->lpRemoteName == NULL) {
if (*lpBufferSize >= sizeof(NETRESOURCEW)) {
//
// Handle this as if we are at the root of our provider hierarchy.
//
pOutNetResource->dwScope = RESOURCE_GLOBALNET;
pOutNetResource->dwType = RESOURCETYPE_ANY;
pOutNetResource->dwDisplayType = RESOURCEDISPLAYTYPE_NETWORK;
pOutNetResource->dwUsage = RESOURCEUSAGE_CONTAINER;
pOutNetResource->lpLocalName = NULL;
pOutNetResource->lpRemoteName = NULL;
// JOYC: need to set this to our provider?
pOutNetResource->lpProvider = NULL;
pOutNetResource->lpComment = NULL;
*lpBufferSize = sizeof(NETRESOURCEW);
if (lplpSystem) {
*lplpSystem = NULL;
}
DBGMSG(DBG_TRACE, ("DRPROV: NPGetResourceInformation, NULL remote Name\n"));
Status = WN_SUCCESS;
goto EXIT;
}
else {
DBGMSG(DBG_TRACE, ("DRPROV: NPGetResourceInformation, buffer too small.\n"));
*lpBufferSize = sizeof(NETRESOURCEW);
Status = WN_MORE_DATA;
goto EXIT;
}
}
//
// Find out if we are looking at a \\server, \\server\vol, or
// \\server\vol\dir . . .
//
wSlashCount = 0;
pCurPos = lpNetResource->lpRemoteName;
while (*pCurPos != '\0') {
if (*pCurPos == L'\\') {
wSlashCount++;
}
// Get the system path
if (wSlashCount == 4) {
SystemPath.Buffer = pCurPos;
SystemPath.Length =
(USHORT) (wcslen(lpNetResource->lpRemoteName) * sizeof(WCHAR) -
(SystemPath.Buffer - lpNetResource->lpRemoteName) * sizeof(WCHAR));
SystemPath.MaximumLength = SystemPath.Length + sizeof(WCHAR);
break;
}
pCurPos++;
}
if ( wSlashCount > 2 )
fResourceTypeDisk = TRUE;
//
// Open a connection handle to \\server\vol\...
//
// Setup remote name
pCurPos = lpNetResource->lpRemoteName;
if (SystemPath.Length != 0) {
RemoteName.Length = (USHORT)((SystemPath.Buffer - pCurPos) * sizeof(WCHAR));
RemoteName.MaximumLength = RemoteName.Length + sizeof(WCHAR);
}
else {
RemoteName.Length = wcslen(pCurPos) * sizeof(WCHAR);
RemoteName.MaximumLength = RemoteName.Length + sizeof(WCHAR);
}
RemoteName.Buffer = MemAlloc(RemoteName.MaximumLength);
if (RemoteName.Buffer == NULL) {
Status = GetLastError();
DBGMSG(DBG_TRACE, ("DRPROV: NPGetResourceInformation, MemAlloc failed.\n"));
goto EXIT;
}
RtlCopyMemory(RemoteName.Buffer, pCurPos, RemoteName.Length);
RemoteName.Buffer[RemoteName.Length/sizeof(WCHAR)] = L'\0';
DBGMSG(DBG_TRACE, ("DRPROV: NPGetResourceInformation, RemoteName, %ws\n", RemoteName.Buffer));
if (fResourceTypeDisk) {
UNICODE_STRING ConnectionName;
HANDLE ConnectionHandle;
ConnectionName.Buffer = NULL;
ConnectionName.Length = 0;
ConnectionHandle = INVALID_HANDLE_VALUE;
// Setup the NT Device Name
Status = CreateConnectionName(NULL, RemoteName.Buffer, &ConnectionName);
if (Status == WN_SUCCESS) {
Status = OpenConnection(&ConnectionName,
FILE_OPEN,
(FILE_CREATE_TREE_CONNECTION | FILE_SYNCHRONOUS_IO_NONALERT),
NULL,
0,
&ConnectionHandle);
if (ConnectionName.Buffer != NULL) {
MemFree(ConnectionName.Buffer);
}
if (Status == WN_SUCCESS) {
CloseHandle(ConnectionHandle);
}
else {
DBGMSG(DBG_TRACE, ("DRPROV: NPGetResourceInformation, OpenConnection failed"));
goto EXIT;
}
}
else {
DBGMSG(DBG_TRACE, ("DRPROV: NPGetResourceInformation, CreateConnectionName failed\n"));
goto EXIT;
}
}
else {
RDPDR_REQUEST_PACKET Rrp; // Redirector request packet
HANDLE DrDeviceHandle = 0;
PRDPDR_SERVER_INFO pServerEntry;
LPBYTE Buffer = NULL;
UNICODE_STRING ServerName;
if (DrOpenMiniRdr(&DrDeviceHandle) != WN_SUCCESS) {
DBGMSG(DBG_TRACE, ("DRPROV: NPGetResourceInformation, failed to Open rdpdr\n"));
Status = WN_BAD_NETNAME;
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);
CloseHandle(DrDeviceHandle);
if (Status != WN_SUCCESS) {
DBGMSG(DBG_TRACE, ("DRPROV: NPGetResourceInformation, DrDeviceControlGetInfo failed\n"));
Status = WN_BAD_NETNAME;
goto EXIT;
}
pServerEntry = ((PRDPDR_SERVER_INFO) Buffer);
ServerName.Length = pServerEntry->ServerName.Length;
ServerName.MaximumLength = pServerEntry->ServerName.MaximumLength;
ServerName.Buffer = (PWCHAR)((PCHAR)(pServerEntry) + pServerEntry->ServerName.BufferOffset);
if ((RemoteName.Length == ServerName.Length) &&
_wcsnicmp(RemoteName.Buffer, ServerName.Buffer,
ServerName.Length/sizeof(WCHAR)) == 0) {
if (Buffer != NULL) {
MemFree(Buffer);
}
Status = WN_SUCCESS;
}
else {
DBGMSG(DBG_TRACE, ("DRPROV: NPGetResourceInformation, invalid net name, %wZ\n",
RemoteName));
if (Buffer != NULL) {
MemFree(Buffer);
}
Status = WN_BAD_NETNAME;
goto EXIT;
}
}
if (Status == WN_SUCCESS)
{
//
// The resource exists, setup info.
//
*lpBufferSize = sizeof(NETRESOURCEW) +
RemoteName.Length + sizeof(WCHAR) +
DrProviderName.Length + sizeof(WCHAR) +
SystemPath.Length + sizeof(WCHAR);
if ((unsigned) (BufferResourceEnd - BufferResourceStart) > *lpBufferSize) {
pOutNetResource->dwScope = 0;
pOutNetResource->dwType = fResourceTypeDisk ?
RESOURCETYPE_DISK :
RESOURCETYPE_ANY;
pOutNetResource->dwDisplayType = fResourceTypeDisk ?
RESOURCEDISPLAYTYPE_SHARE :
RESOURCEDISPLAYTYPE_SERVER;
pOutNetResource->dwUsage = fResourceTypeDisk ?
RESOURCEUSAGE_CONNECTABLE |
RESOURCEUSAGE_NOLOCALDEVICE :
RESOURCEUSAGE_CONTAINER;
pOutNetResource->lpLocalName = NULL;
// Setup remote name
BufferResourceEnd -= RemoteName.Length + sizeof(WCHAR);
pOutNetResource->lpRemoteName = (PWCHAR) (BufferResourceStart + sizeof(NETRESOURCE));
RtlCopyMemory(pOutNetResource->lpRemoteName, RemoteName.Buffer,
RemoteName.Length);
pOutNetResource->lpRemoteName[RemoteName.Length /
sizeof(WCHAR)] = L'\0';
DBGMSG(DBG_TRACE, ("DRPROV: NPGetResourceInformation, RemoteName, %ws\n",
pOutNetResource->lpRemoteName));
// Setup provider name
BufferResourceEnd -= DrProviderName.Length + sizeof(WCHAR);
pOutNetResource->lpProvider = (PWCHAR) ((PBYTE)(pOutNetResource->lpRemoteName) +
RemoteName.Length + sizeof(WCHAR));
RtlCopyMemory(pOutNetResource->lpProvider, DrProviderName.Buffer,
DrProviderName.Length);
pOutNetResource->lpProvider[DrProviderName.Length /
sizeof(WCHAR)] = L'\0';
pOutNetResource->lpComment = NULL;
// Setup system path
if (lplpSystem) {
if (SystemPath.Length) {
BufferResourceEnd -= SystemPath.Length + sizeof(WCHAR);
*lplpSystem = (PWCHAR) ((PBYTE)(pOutNetResource->lpProvider) +
DrProviderName.Length + sizeof(WCHAR));
RtlCopyMemory(*lplpSystem, SystemPath.Buffer,
SystemPath.Length);
(*lplpSystem)[SystemPath.Length / sizeof(WCHAR)] = L'\0';
DBGMSG(DBG_TRACE, ("DRPROV: NPGetResourceInformation, SystemPath, %ws\n",
*lplpSystem));
}
else {
DBGMSG(DBG_TRACE, ("DRPROV: NPGetResourceInformation, SystemPath null\n"));
*lplpSystem = NULL;
}
}
else {
DBGMSG(DBG_TRACE, ("DRPROV: NPGetResourceInformation, user doesn't require systempath\n"));
}
Status = WN_SUCCESS;
goto EXIT;
}
else {
DBGMSG(DBG_TRACE, ("DRPROV: NPGetResourceInfo, buffer too small\n"));
Status = WN_MORE_DATA;
goto EXIT;
}
}
else {
DBGMSG(DBG_TRACE, ("DRPROV: NPGetResourceInformation, bad net name.\n"));
Status = WN_BAD_NETNAME;
goto EXIT;
}
EXIT:
if (RemoteName.Buffer != NULL) {
MemFree(RemoteName.Buffer);
}
return Status;
}
DWORD APIENTRY
NPGetUser(
IN LPTSTR lpName,
OUT LPTSTR lpUserName,
IN OUT LPDWORD lpBufferSize
)
/*++
Routine Description:
This function determines the user name that created the connection.
Arguments:
lpName - Name of the local drive or the remote name that the user has made
a connection to. If NULL, return currently logged on user.
lpUserName - The buffer to be filled in with the requested user name.
lpBufferSize - Contains the length (in chars not bytes )of the lpUserName
buffer. If the length is insufficient, this place is used to
inform the user the actual length needed.
Return Value:
WN_SUCCESS - Successful. OR
The appropriate network error code.
--*/
{
DWORD Status = WN_SUCCESS;
WCHAR NameBuffer[USERNAMELEN + 1];
DWORD NumOfChars = USERNAMELEN + 1;
DBGMSG(DBG_TRACE, ("DRPROV: NPGetUser.\n"));
if (lpUserName == NULL || lpBufferSize == NULL) {
DBGMSG(DBG_TRACE, ("DRPROV: NPGetUser, invalid parameter(s)\n"));
Status = WN_BAD_VALUE;
goto EXIT;
}
//
// Get the name of the currently logged on user.
//
if (!GetUserName( NameBuffer, &(NumOfChars))) {
Status = GetLastError();
DBGMSG(DBG_TRACE, ("DRPROV: NPGetUser, failed to get user name, %x\n", Status));
goto EXIT;
}
//
// Check to see if the buffer passed in is of the required length.
//
if ( *lpBufferSize < NumOfChars ) {
DBGMSG(DBG_TRACE, ("DRPROV: NPGetUser, buffer too small.\n"));
*lpBufferSize = NumOfChars;
Status = WN_MORE_DATA;
goto EXIT;
}
//
// Copy the user name.
//
wcscpy(lpUserName, NameBuffer);
EXIT:
DBGMSG(DBG_TRACE, ("DRPROV: NPGetUser, return status: %x\n", Status));
return Status;
}
DWORD APIENTRY
NPGetUniversalName(
LPCWSTR lpLocalPath,
DWORD dwInfoLevel,
LPVOID lpBuffer,
LPDWORD lpBufferSize )
/*++
Routine Description:
This routine returns the information associated net resource
Arguments:
lpLocalPath - the local path name
dwInfoLevel - the desired info level
lpBuffer - the buffer for the univeral name
lpBufferSize - the buffer size
Return Value:
WN_SUCCESS if successful
Notes:
--*/
{
DWORD Status = WN_SUCCESS;
DWORD BufferRequired = 0;
DWORD UniversalNameLength = 0;
DWORD RemoteNameLength = 0;
DWORD RemainingPathLength = 0;
LPWSTR pDriveLetter,
pRemainingPath,
SourceStrings[3];
WCHAR RemoteName[MAX_PATH],
LocalPath[MAX_PATH],
UniversalName[MAX_PATH],
ReplacedChar;
DBGMSG(DBG_TRACE, ("DRPROV: NPGetUniversalName\n"));
// parameter checking
if (dwInfoLevel != UNIVERSAL_NAME_INFO_LEVEL &&
dwInfoLevel != REMOTE_NAME_INFO_LEVEL) {
DBGMSG(DBG_TRACE, ("DRPROV: NPGetUniversalName, bad InfoLevel, %d\n", dwInfoLevel));
Status = WN_BAD_LEVEL;
goto EXIT;
}
if (lpLocalPath == NULL || lpBuffer == NULL || lpBufferSize == NULL) {
DBGMSG(DBG_TRACE, ("DRPROV: NPGetUniversalName, invalid parameter(s)\n"));
Status = WN_BAD_VALUE;
goto EXIT;
}
// Get the local name
wcscpy(LocalPath, lpLocalPath);
pDriveLetter = LocalPath;
if (pRemainingPath = wcschr(pDriveLetter, L':')) {
ReplacedChar = *(++pRemainingPath);
*pRemainingPath = L'\0';
}
// Get the remote name by calling NPGetConnection
if ((Status = NPGetConnection(pDriveLetter, RemoteName, &RemoteNameLength)) != WN_SUCCESS) {
// MPR expects WN_BAD_LOCALNAME to bypass us.
if (Status == WN_BAD_NETNAME) {
Status = WN_BAD_LOCALNAME;
}
DBGMSG(DBG_TRACE, ("DRPROV: NPGetUniversalName, NPGetConnection failed\n"));
goto EXIT;
}
if (pRemainingPath) {
*pRemainingPath = ReplacedChar;
}
wcscpy(UniversalName, RemoteName);
if (pRemainingPath)
wcscat(UniversalName, pRemainingPath);
// Determine if the provided buffer is large enough.
UniversalNameLength = (wcslen(UniversalName) + 1) * sizeof(WCHAR);
BufferRequired = UniversalNameLength;
if (dwInfoLevel == UNIVERSAL_NAME_INFO_LEVEL) {
BufferRequired += sizeof(UNIVERSAL_NAME_INFO);
}
else {
RemoteNameLength = (wcslen(RemoteName) + 1) * sizeof(WCHAR);
BufferRequired += sizeof(REMOTE_NAME_INFO) + RemoteNameLength;
if (pRemainingPath) {
RemainingPathLength = (wcslen(pRemainingPath) + 1) * sizeof(WCHAR);
BufferRequired += RemainingPathLength;
}
}
if (*lpBufferSize < BufferRequired) {
DBGMSG(DBG_TRACE, ("DRPROV: NPGetUniversalName, buffer too small\n"));
*lpBufferSize = BufferRequired;
Status = WN_MORE_DATA;
goto EXIT;
}
if (dwInfoLevel == UNIVERSAL_NAME_INFO_LEVEL) {
LPUNIVERSAL_NAME_INFOW pUniversalNameInfo;
pUniversalNameInfo = (LPUNIVERSAL_NAME_INFOW)lpBuffer;
pUniversalNameInfo->lpUniversalName = (PWCHAR)((PBYTE)lpBuffer + sizeof(UNIVERSAL_NAME_INFOW));
RtlCopyMemory(
pUniversalNameInfo->lpUniversalName,
UniversalName,
UniversalNameLength);
DBGMSG(DBG_TRACE, ("DRPROV: NPGetUniversalName, UniversalName, %ws\n", UniversalName));
Status = WN_SUCCESS;
}
else {
LPREMOTE_NAME_INFOW pRemoteNameInfo;
pRemoteNameInfo = (LPREMOTE_NAME_INFOW)lpBuffer;
pRemoteNameInfo->lpUniversalName = (PWCHAR)((PBYTE)lpBuffer + sizeof(REMOTE_NAME_INFOW));
pRemoteNameInfo->lpConnectionName = pRemoteNameInfo->lpUniversalName + UniversalNameLength;
pRemoteNameInfo->lpRemainingPath = pRemoteNameInfo->lpConnectionName + RemoteNameLength;
RtlCopyMemory(
pRemoteNameInfo->lpUniversalName,
UniversalName,
UniversalNameLength);
RtlCopyMemory(
pRemoteNameInfo->lpConnectionName,
RemoteName,
RemoteNameLength);
RtlCopyMemory(
pRemoteNameInfo->lpRemainingPath,
pRemainingPath,
RemainingPathLength);
DBGMSG(DBG_TRACE, ("DRPROV: NPGetUniversalName, UniversalName, %ws\n", UniversalName));
DBGMSG(DBG_TRACE, ("DRPROV: NPGetUniversalName, RemoteName, %ws\n", RemoteName));
DBGMSG(DBG_TRACE, ("DRPROV: NPGetUniversalName, Remaining Path, %ws\n", pRemainingPath));
Status = WN_SUCCESS;
}
EXIT:
DBGMSG(DBG_TRACE, ("DRPROV: NPGetUniversalName, return status, %x\n", Status));
return Status;
}