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
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;
|
|
}
|