From 82d60412041bd05f13da3bc9937d1e561744c71c Mon Sep 17 00:00:00 2001 From: Peter Scott Date: Thu, 15 Sep 2011 01:52:08 -0400 Subject: [PATCH] Windows: AFS Redirector Network Provider In Windows a network file system must have a matching network provider dll that interfaces with the Multiple Provider Router (MPR) to support the WNet APIs called by the Windows Explorer Shell and other applications. The WNet APIs are primarily used to support driver letter mapping but they also have a number of other functions including universal name mapping, path formatting, and path parsing. Jeffrey Altman contributed to the development of the AFSRDFSProvider.dll interface. Change-Id: I9476003e05f12684676e8c7331a0a8dd13d98686 Reviewed-on: http://gerrit.openafs.org/5439 Tested-by: BuildBot Reviewed-by: Rod Widdowson Tested-by: Rod Widdowson Reviewed-by: Jeffrey Altman Tested-by: Jeffrey Altman --- src/WINNT/afsrdr/npdll/AFSRDFSProvder.vcproj | 105 + .../afsrdr/npdll/AFSRDFSProvder.vcproj.vspscc | 10 + src/WINNT/afsrdr/npdll/AFS_Npdll.DEF | 24 + src/WINNT/afsrdr/npdll/AFS_Npdll.c | 3951 +++++++++++++++++ src/WINNT/afsrdr/npdll/AFS_Npdll.h | 35 + src/WINNT/afsrdr/npdll/AFS_Npdll.rc | 42 + src/WINNT/afsrdr/npdll/AFS_NpdllMain.C | 77 + src/WINNT/afsrdr/npdll/SOURCES | 31 + src/WINNT/afsrdr/npdll/tests/enumresources.c | 322 ++ 9 files changed, 4597 insertions(+) create mode 100644 src/WINNT/afsrdr/npdll/AFSRDFSProvder.vcproj create mode 100644 src/WINNT/afsrdr/npdll/AFSRDFSProvder.vcproj.vspscc create mode 100644 src/WINNT/afsrdr/npdll/AFS_Npdll.DEF create mode 100644 src/WINNT/afsrdr/npdll/AFS_Npdll.c create mode 100644 src/WINNT/afsrdr/npdll/AFS_Npdll.h create mode 100644 src/WINNT/afsrdr/npdll/AFS_Npdll.rc create mode 100644 src/WINNT/afsrdr/npdll/AFS_NpdllMain.C create mode 100644 src/WINNT/afsrdr/npdll/SOURCES create mode 100644 src/WINNT/afsrdr/npdll/tests/enumresources.c diff --git a/src/WINNT/afsrdr/npdll/AFSRDFSProvder.vcproj b/src/WINNT/afsrdr/npdll/AFSRDFSProvder.vcproj new file mode 100644 index 0000000000..905c317cb1 --- /dev/null +++ b/src/WINNT/afsrdr/npdll/AFSRDFSProvder.vcproj @@ -0,0 +1,105 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/WINNT/afsrdr/npdll/AFSRDFSProvder.vcproj.vspscc b/src/WINNT/afsrdr/npdll/AFSRDFSProvder.vcproj.vspscc new file mode 100644 index 0000000000..f1eb364032 --- /dev/null +++ b/src/WINNT/afsrdr/npdll/AFSRDFSProvder.vcproj.vspscc @@ -0,0 +1,10 @@ +"" +{ +"FILE_VERSION" = "9237" +"ENLISTMENT_CHOICE" = "NEVER" +"PROJECT_FILE_RELATIVE_PATH" = "relative:AFSRDFSProvider" +"NUMBER_OF_EXCLUDED_FILES" = "0" +"ORIGINAL_PROJECT_FILE_PATH" = "" +"NUMBER_OF_NESTED_PROJECTS" = "0" +"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROVIDER" +} diff --git a/src/WINNT/afsrdr/npdll/AFS_Npdll.DEF b/src/WINNT/afsrdr/npdll/AFS_Npdll.DEF new file mode 100644 index 0000000000..64cca3bc76 --- /dev/null +++ b/src/WINNT/afsrdr/npdll/AFS_Npdll.DEF @@ -0,0 +1,24 @@ +SECTIONS .AFSNP READ WRITE SHARED + +EXPORTS + DllMain @1 + NPLogonNotify @7 + NPPasswordChangeNotify @8 + NPGetConnection @12 + NPGetCaps @13 + NPAddConnection @17 + NPCancelConnection @18 + NPOpenEnum @33 + NPEnumResource @34 + NPCloseEnum @35 + NPFormatNetworkName @36 + NPAddConnection3 @38 + NPGetUniversalName @40 + NPGetResourceParent @41 + NPGetConnectionPerformance @49 + NPGetResourceInformation @52 + NPGetConnection3 @54 + +; NPGetUser @16 +; NPGetReconnectFlags @53 +; I_SystemFocusDialog @15 diff --git a/src/WINNT/afsrdr/npdll/AFS_Npdll.c b/src/WINNT/afsrdr/npdll/AFS_Npdll.c new file mode 100644 index 0000000000..56e9ef1663 --- /dev/null +++ b/src/WINNT/afsrdr/npdll/AFS_Npdll.c @@ -0,0 +1,3951 @@ +/* + * Copyright (c) 2008, 2009, 2010, 2011 Kernel Drivers, LLC. + * Copyright (c) 2009, 2010, 2011 Your File System, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, + * this list of conditions and the following disclaimer in the + * documentation + * and/or other materials provided with the distribution. + * - Neither the names of Kernel Drivers, LLC and Your File System, Inc. + * nor the names of their contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission from Kernel Drivers, LLC and Your File System, Inc. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _WIN32_WINNT +#define _WIN32_WINNT 0x0500 +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define AFS_DEBUG_TRACE 1 + +#ifndef WNNC_NET_OPENAFS +#define WNNC_NET_OPENAFS 0x00390000 +#endif + +#include "AFSUserDefines.h" +#include "AFSUserIoctl.h" +#include "AFSUserStructs.h" +#include "AFSProvider.h" +#include "AFS_Npdll.h" + +#include "stdio.h" + +#ifndef MAX_PATH +#define MAX_PATH 260 +#endif + +#define SCRATCHSZ 1024 + +// +// Common information +// + +ULONG _cdecl AFSDbgPrint( PWCHAR Format, ... ); + +#define WNNC_DRIVER( major, minor ) ( major * 0x00010000 + minor ) + +#define OPENAFS_PROVIDER_NAME L"OpenAFS Network" +#define OPENAFS_PROVIDER_NAME_LENGTH 30 + +#define MAX_PROVIDER_NAME_LENGTH 256 + +static ULONG cbProviderNameLength = OPENAFS_PROVIDER_NAME_LENGTH; + +static wchar_t wszProviderName[MAX_PROVIDER_NAME_LENGTH+1] = OPENAFS_PROVIDER_NAME; + +static BOOL bProviderNameRead = FALSE; + +#define OPENAFS_SERVER_NAME L"AFS" +#define OPENAFS_SERVER_NAME_LENGTH 6 + +#define OPENAFS_SERVER_COMMENT L"AFS Root" +#define OPENAFS_SERVER_COMMENT_LENGTH 16 + +#define MAX_SERVER_NAME_LENGTH 30 + +static ULONG cbServerNameLength = 0; + +static ULONG cbServerNameUNCLength = 0; + +static ULONG cbServerCommentLength = OPENAFS_SERVER_COMMENT_LENGTH; + +static wchar_t wszServerName[MAX_SERVER_NAME_LENGTH+1]; + +static wchar_t wszServerNameUNC[MAX_SERVER_NAME_LENGTH+3]; + +static wchar_t wszServerComment[] = OPENAFS_SERVER_COMMENT; + +static BOOL bServerNameRead = FALSE; + +LARGE_INTEGER +AFSRetrieveAuthId( void); + +void +ReadProviderNameString( void) +{ + HKEY hk; + DWORD code; + DWORD dwLen = 0; + + if ( bProviderNameRead ) + return; + + code = RegOpenKeyExW( HKEY_LOCAL_MACHINE, + L"SYSTEM\\CurrentControlSet\\Services\\AFSRedirector\\NetworkProvider", + 0, KEY_QUERY_VALUE, &hk); + + if ( code == ERROR_SUCCESS) { + + dwLen = sizeof(wszProviderName); + + code = RegQueryValueExW( hk, L"Name", NULL, NULL, + (LPBYTE) wszProviderName, &dwLen); + + if ( code == ERROR_SUCCESS) + { + + wszProviderName[MAX_PROVIDER_NAME_LENGTH] = '\0'; + + cbProviderNameLength = wcslen( wszProviderName) * sizeof( WCHAR); + } + + RegCloseKey( hk); + } + + bProviderNameRead = TRUE; +} + +void +ReadServerNameString( void) +{ + HKEY hk; + DWORD code; + DWORD dwLen = 0; + + if ( bServerNameRead ) + return; + + code = RegOpenKeyExW( HKEY_LOCAL_MACHINE, + L"SYSTEM\\CurrentControlSet\\Services\\TransarcAFSDaemon\\Parameters", + 0, KEY_QUERY_VALUE, &hk); + + if ( code == ERROR_SUCCESS) { + + dwLen = sizeof(wszProviderName); + + code = RegQueryValueExW( hk, L"NetbiosName", NULL, NULL, + (LPBYTE) wszServerName, &dwLen); + + if ( code == ERROR_SUCCESS) + { + + wszServerName[MAX_SERVER_NAME_LENGTH] = '\0'; + + cbServerNameLength = wcslen( wszServerName) * sizeof( WCHAR); + + wszServerNameUNC[0] = wszServerNameUNC[1] = L'\\'; + + memcpy(&wszServerNameUNC[2], wszServerName, (cbServerNameLength + 1) * sizeof( WCHAR)); + + cbServerNameUNCLength = cbServerNameLength + 2 * sizeof( WCHAR); + } + + RegCloseKey( hk); + } + + bServerNameRead = TRUE; +} + + + +/* returns TRUE if the file system is disabled or not installed */ +BOOL +NPIsFSDisabled( void) +{ + HKEY hk; + DWORD code; + DWORD dwLen = 0; + DWORD dwStart = SERVICE_DISABLED; + + code = RegOpenKeyExW( HKEY_LOCAL_MACHINE, + L"SYSTEM\\CurrentControlSet\\Services\\AFSRedirector", + 0, KEY_QUERY_VALUE, &hk); + + if ( code != ERROR_SUCCESS) + + return TRUE; + + + dwLen = sizeof(dwStart); + + code = RegQueryValueExW( hk, L"Start", NULL, NULL, + (LPBYTE) &dwStart, &dwLen); + + RegCloseKey( hk); + + return ( dwStart == SERVICE_DISABLED); +} + + +#define try_return(S) { S; goto try_exit; } + +#define __Enter + +#define NOTHING + +typedef struct _UNICODE_STRING { + USHORT Length; + USHORT MaximumLength; + PWSTR Buffer; +} UNICODE_STRING, *PUNICODE_STRING; + +HANDLE +OpenRedirector( void); + +typedef struct _AFS_ENUM_CB +{ + + DWORD CurrentIndex; + + DWORD Scope; + + DWORD Type; + + WCHAR *RemoteName; + +} AFSEnumerationCB; + + +// +// Recursively evaluate drivestr to find the final +// dos drive letter to which the source is mapped. +// +static BOOL +DriveSubstitution(LPCWSTR drivestr, LPWSTR subststr, size_t substlen) +{ + WCHAR drive[3]; + WCHAR device[MAX_PATH + 1]; + HRESULT hr = S_OK; + + memset( subststr, 0, substlen); + drive[0] = drivestr[0]; + drive[1] = drivestr[1]; + drive[2] = 0; + + if ( QueryDosDevice(drive, device, MAX_PATH) ) + { +#ifdef AFS_DEBUG_TRACE + AFSDbgPrint( L"DriveSubstitution QueryDosDevice %s [%s -> %s]\n", + drivestr, + drive, + device); +#endif + if ( device[0] == L'\\' && + device[1] == L'?' && + device[2] == L'?' && + device[3] == L'\\' && + iswalpha(device[4]) && + device[5] == L':') + { + drive[0] = device[4]; + drive[1] = L':'; + drive[2] = L'\0'; + + if ( !DriveSubstitution(drive, subststr, substlen) ) + { + + subststr[0] = drive[0]; + subststr[1] = L':'; + subststr[2] = L'\0'; + + } + + hr = S_OK; + + if ( device[6] ) + { + hr = StringCchCat( subststr, substlen, &device[6]); + } + if ( SUCCEEDED(hr) && drivestr[2] ) + { + hr = StringCchCat( subststr, substlen, &drivestr[2]); + } + + if ( SUCCEEDED(hr) || hr == STRSAFE_E_INSUFFICIENT_BUFFER) + { + +#ifdef AFS_DEBUG_TRACE + AFSDbgPrint( L"DriveSubstitution %s -> %s\n", + drivestr, + subststr); +#endif + return TRUE; + } + } + else if ( device[0] == L'\\' && + device[1] == L'?' && + device[2] == L'?' && + device[3] == L'\\' && + device[4] == L'U' && + device[5] == L'N' && + device[6] == L'C' && + device[7] == L'\\') + { + + subststr[0] = L'\\'; + + hr = StringCbCopyN(&subststr[1], substlen - sizeof(WCHAR), &device[7], MAX_PATH); + + if ( SUCCEEDED(hr) || hr == STRSAFE_E_INSUFFICIENT_BUFFER) + { + if ( drivestr[2] ) + { + hr = StringCchCat( subststr, substlen, &drivestr[2]); + } + else + { + hr = S_OK; + } + + if ( SUCCEEDED(hr) || hr == STRSAFE_E_INSUFFICIENT_BUFFER) + { + +#ifdef AFS_DEBUG_TRACE + AFSDbgPrint( L"DriveSubstitution %s -> %s\n", + drivestr, + subststr); +#endif + return TRUE; + } + } + +#ifdef AFS_DEBUG_TRACE + AFSDbgPrint( L"DriveSubstitution StringCbCopyN 1 hr 0x%X\n", + hr); +#endif + } + else if ( _wcsnicmp( AFS_RDR_DEVICE_NAME, device, sizeof( AFS_RDR_DEVICE_NAME) / sizeof( WCHAR) - 1) == 0) + { + // + // \Device\AFSRedirector\;X:\\afs\cellname + // + + hr = StringCbCopyN( subststr, substlen, + &device[3 + sizeof( AFS_RDR_DEVICE_NAME) / sizeof( WCHAR)], + MAX_PATH * sizeof( WCHAR)); + + if ( SUCCEEDED(hr) || hr == STRSAFE_E_INSUFFICIENT_BUFFER) + { + + if ( drivestr[2] ) + { + hr = StringCchCat( subststr, substlen, &drivestr[2]); + } + else + { + hr = S_OK; + } + + if ( SUCCEEDED(hr) || hr == STRSAFE_E_INSUFFICIENT_BUFFER) + { + +#ifdef AFS_DEBUG_TRACE + AFSDbgPrint( L"DriveSubstitution %s -> %s\n", + drivestr, + subststr); +#endif + return TRUE; + } + } + +#ifdef AFS_DEBUG_TRACE + AFSDbgPrint( L"DriveSubstitution StringCbCopyN 2 hr 0x%X\n", + hr); +#endif + } + +#ifdef AFS_DEBUG_TRACE + AFSDbgPrint( L"DriveSubstitution no substitution or match %s !! %s\n", + drivestr, + device); +#endif + } + else + { +#ifdef AFS_DEBUG_TRACE + AFSDbgPrint( L"DriveSubstitution QueryDosDevice failed %s gle 0x%X\n", + drivestr, + GetLastError()); +#endif + } + + + + return FALSE; +} + + +static const WCHAR * +NPGetCapsQueryString( DWORD nIndex) +{ + switch ( nIndex) { + case WNNC_SPEC_VERSION: + return L"WNNC_SPEC_VERSION"; + + case WNNC_NET_TYPE: + return L"WNNC_NET_TYPE"; + + case WNNC_DRIVER_VERSION: + return L"WNNC_DRIVER_VERSION"; + + case WNNC_USER: + return L"WNNC_USER"; + + case WNNC_CONNECTION: + return L"WNNC_CONNECTION"; + + case WNNC_DIALOG: + return L"WNNC_DIALOG"; + + case WNNC_ADMIN: + return L"WNNC_ADMIN"; + + case WNNC_ENUMERATION: + return L"WNNC_ENUMERATION"; + + case WNNC_START: + return L"WNNC_START"; + + case WNNC_CONNECTION_FLAGS: + return L"WNNC_CONNECTION_FLAGS"; + + default: + return L"UNKNOWN"; + } +} + +// +// This is the only function which must be exported, everything else is optional +// + +DWORD +APIENTRY +NPGetCaps( DWORD nIndex ) +{ + + DWORD rc = 0; + +#ifdef AFS_DEBUG_TRACE + AFSDbgPrint( L"NPGetCaps Index %u %s\n", nIndex, + NPGetCapsQueryString( nIndex)); +#endif + switch( nIndex) + { + case WNNC_SPEC_VERSION: + { + + rc = WNNC_SPEC_VERSION51; + break; + } + + case WNNC_NET_TYPE: + { + rc = WNNC_NET_OPENAFS; + break; + } + + case WNNC_DRIVER_VERSION: + { + + rc = WNNC_DRIVER(1, 0); + break; + } + + case WNNC_CONNECTION: + { + + // + // No support for: + // WNNC_CON_GETPERFORMANCE + // WNNC_CON_DEFER + // + + rc = WNNC_CON_GETCONNECTIONS | + WNNC_CON_CANCELCONNECTION | + WNNC_CON_ADDCONNECTION | + WNNC_CON_ADDCONNECTION3; + + break; + } + + case WNNC_ENUMERATION: + { + rc = WNNC_ENUM_LOCAL | + WNNC_ENUM_CONTEXT | + WNNC_ENUM_GLOBAL | + WNNC_ENUM_SHAREABLE; + break; + } + + case WNNC_START: + { + + rc = WNNC_WAIT_FOR_START; + + break; + } + + case WNNC_DIALOG: + { + + // + // No support for: + // WNNC_DLG_DEVICEMODE + // WNNC_DLG_PROPERTYDIALOG + // WNNC_DLG_SEARCHDIALOG + // WNNC_DLG_PERMISSIONEDITOR + // + + rc = WNNC_DLG_FORMATNETWORKNAME | + WNNC_DLG_GETRESOURCEINFORMATION | + WNNC_DLG_GETRESOURCEPARENT; + + break; + } + + case WNNC_USER: + { + // + // No support for: + // WNNC_USR_GETUSER + // + + break; + } + + case WNNC_ADMIN: + { + // + // No support for: + // WNNC_ADM_GETDIRECTORYTYPE + // WNNC_ADM_DIRECTORYNOTIFY + // used by the old File Manager + // + break; + } + } + + return rc; +} + +DWORD +APIENTRY +NPAddConnection( LPNETRESOURCE lpNetResource, + LPWSTR lpPassword, + LPWSTR lpUserName ) +{ + +#ifdef AFS_DEBUG_TRACE + AFSDbgPrint( L"NPAddConnection forwarding to NPAddConnection3\n"); +#endif + return NPAddConnection3( NULL, lpNetResource, lpPassword, lpUserName, 0 ); +} + +DWORD +APIENTRY +NPAddConnection3( HWND hwndOwner, + LPNETRESOURCE lpNetResource, + LPWSTR lpPassword, + LPWSTR lpUserName, + DWORD dwFlags ) +{ + + DWORD dwStatus = WN_SUCCESS; + WCHAR wchRemoteName[MAX_PATH+1]; + WCHAR wchLocalName[3]; + DWORD dwCopyBytes = 0; + AFSNetworkProviderConnectionCB *pConnectCB = NULL; + DWORD dwError = 0; + DWORD dwBufferSize = 0; + HANDLE hControlDevice = NULL; + HANDLE hToken = NULL; + LARGE_INTEGER liAuthId = {0,0}; + + __Enter + { + if ( NPIsFSDisabled()) + { + +#ifdef AFS_DEBUG_TRACE + AFSDbgPrint( L"NPAddConnection3 AFSRDFS is disabled, returning WN_BAD_NETNAME\n"); +#endif + + return WN_BAD_NETNAME; + } + + if ((lpNetResource->lpRemoteName == NULL) || + (lpNetResource->lpRemoteName[0] != L'\\') || + (lpNetResource->lpRemoteName[1] != L'\\') || + ((lpNetResource->dwType != RESOURCETYPE_DISK) && + (lpNetResource->dwType != RESOURCETYPE_ANY))) + { + +#ifdef AFS_DEBUG_TRACE + AFSDbgPrint( L"NPAddConnection3 invalid input, returning WN_BAD_NETNAME\n"); +#endif + return WN_BAD_NETNAME; + } + +#ifdef AFS_DEBUG_TRACE + AFSDbgPrint( L"NPAddConnection3 processing\n"); +#endif + if( lpNetResource->lpLocalName != NULL) + { + + wchLocalName[0] = towupper(lpNetResource->lpLocalName[0]); + wchLocalName[1] = L':'; + wchLocalName[2] = L'\0'; + } + + StringCchCopy(wchRemoteName, MAX_PATH+1, lpNetResource->lpRemoteName); + wchRemoteName[MAX_PATH] = L'\0'; + + // + // Allocate our buffer to pass to the redirector filter + // + + dwBufferSize = sizeof( AFSNetworkProviderConnectionCB) + (wcslen( wchRemoteName) * sizeof( WCHAR)); + + pConnectCB = (AFSNetworkProviderConnectionCB *)HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwBufferSize); + + if( pConnectCB == NULL) + { + + try_return( dwStatus = WN_OUT_OF_MEMORY); + } + + if( lpNetResource->lpLocalName != NULL) + { + + pConnectCB->LocalName = towupper(wchLocalName[0]); + +#ifdef AFS_DEBUG_TRACE + AFSDbgPrint( L"NPAddConnection3 Adding mapping for drive %s remote name %s\n", + wchLocalName, + wchRemoteName); +#endif + } + else + { + + pConnectCB->LocalName = L'\0'; + +#ifdef AFS_DEBUG_TRACE + AFSDbgPrint( L"NPAddConnection3 Adding mapping for NO drive remote name %s\n", + wchRemoteName); +#endif + } + + pConnectCB->Version = AFS_NETWORKPROVIDER_INTERFACE_VERSION_1; + + pConnectCB->RemoteNameLength = wcslen( wchRemoteName) * sizeof( WCHAR); + + memcpy( pConnectCB->RemoteName, + wchRemoteName, + pConnectCB->RemoteNameLength); + + pConnectCB->Type = lpNetResource->dwType; + + pConnectCB->AuthenticationId = AFSRetrieveAuthId(); + +#ifdef AFS_DEBUG_TRACE + AFSDbgPrint( L"NPAddConnection3 Retrieved authentication id %08lX-%08lX\n", + pConnectCB->AuthenticationId.HighPart, + pConnectCB->AuthenticationId.LowPart); +#endif + + hControlDevice = OpenRedirector(); + + if( hControlDevice == NULL) + { + +#ifdef AFS_DEBUG_TRACE + AFSDbgPrint( L"NPAddConnection3 OpenRedirector failure, returning WN_NET_ERROR\n"); +#endif + + try_return( dwStatus = WN_NET_ERROR); + } + + dwError = DeviceIoControl( hControlDevice, + IOCTL_AFS_ADD_CONNECTION, + pConnectCB, + dwBufferSize, + &dwStatus, + sizeof( DWORD), + &dwCopyBytes, + NULL); + + if( !dwError) + { +#ifdef AFS_DEBUG_TRACE + AFSDbgPrint( L"NPAddConnection3 Failed to add connection to file system %d\n", GetLastError()); +#endif + try_return( dwStatus = WN_OUT_OF_MEMORY); + } + + // + // The status returned from the driver will indicate how it was handled + // + + if( dwStatus == WN_SUCCESS && + lpNetResource->lpLocalName != NULL) + { + + WCHAR TempBuf[MAX_PATH+1]; + + if( !QueryDosDeviceW( wchLocalName, + TempBuf, + MAX_PATH+1)) + { + + if( GetLastError() != ERROR_FILE_NOT_FOUND) + { + +#ifdef AFS_DEBUG_TRACE + AFSDbgPrint( L"NPAddConnection3 QueryDosDeviceW failed with file not found\n"); +#endif + NPCancelConnection( wchLocalName, TRUE); + + dwStatus = ERROR_ALREADY_ASSIGNED; + } + else + { + + UNICODE_STRING uniConnectionName; + UNICODE_STRING uniDeviceName; + + uniDeviceName.Length = (wcslen( AFS_RDR_DEVICE_NAME) * sizeof( WCHAR)); + uniDeviceName.MaximumLength = uniDeviceName.Length; + uniDeviceName.Buffer = AFS_RDR_DEVICE_NAME; + + // + // Create a symbolic link object to the device we are redirecting + // + + uniConnectionName.MaximumLength = (USHORT)( uniDeviceName.Length + + pConnectCB->RemoteNameLength + + 8 + // Local name and \; + sizeof(WCHAR)); // Space for NULL-termination. + + // + // Don't include NULL-termination. + // + + uniConnectionName.Length = uniConnectionName.MaximumLength - sizeof(WCHAR); + + uniConnectionName.Buffer = LocalAlloc( LMEM_ZEROINIT, + uniConnectionName.MaximumLength); + + if( uniConnectionName.Buffer == NULL) + { + + try_return( dwStatus = GetLastError()); + } + + CopyMemory( uniConnectionName.Buffer, + uniDeviceName.Buffer, + uniDeviceName.Length); + + StringCchCatW( uniConnectionName.Buffer, + uniConnectionName.MaximumLength, + L"\\;" ); + + StringCchCatW( uniConnectionName.Buffer, + uniConnectionName.MaximumLength, + wchLocalName); + + StringCchCatW( uniConnectionName.Buffer, + uniConnectionName.MaximumLength, + wchRemoteName); + +#ifdef AFS_DEBUG_TRACE + AFSDbgPrint( L"NPAddConnection3 DefineDosDevice Local %s connection name %s\n", + wchLocalName, + uniConnectionName.Buffer); +#endif + + if( !DefineDosDeviceW( DDD_RAW_TARGET_PATH | + DDD_NO_BROADCAST_SYSTEM, + wchLocalName, + uniConnectionName.Buffer)) + { +#ifdef AFS_DEBUG_TRACE + AFSDbgPrint( L"NPAddConnection3 Failed to assign drive\n"); +#endif + dwStatus = GetLastError(); + } + else + { + + dwStatus = WN_SUCCESS; + } + + LocalFree( uniConnectionName.Buffer); + } + } + else + { + +#ifdef AFS_DEBUG_TRACE + AFSDbgPrint( L"NPAddConnection3 QueryDosDeviceW %Z already existed\n", TempBuf); +#endif + NPCancelConnection( wchLocalName, TRUE); + + dwStatus = ERROR_ALREADY_ASSIGNED; + } + } + +try_exit: + + if ( hControlDevice != NULL) + { + + CloseHandle( hControlDevice); + } + + if( pConnectCB != NULL) + { + + HeapFree( GetProcessHeap( ), 0, (PVOID) pConnectCB); + } + } + + return dwStatus; +} + +DWORD +APIENTRY +NPCancelConnection( LPWSTR lpName, + BOOL fForce) +{ + + WCHAR wchRemoteName[MAX_PATH+1]; + DWORD dwRemoteNameLength = (MAX_PATH+1) * sizeof(WCHAR); + DWORD dwStatus = WN_NOT_CONNECTED; + DWORD dwCopyBytes = 0; + AFSNetworkProviderConnectionCB *pConnectCB = NULL; + AFSCancelConnectionResultCB stCancelConn; + DWORD dwError = 0; + DWORD dwBufferSize = 0; + BOOL bLocalName = TRUE; + HANDLE hControlDevice = NULL; + WCHAR *pwchLocalName = NULL; + + __Enter + { + + if ( NPIsFSDisabled()) + { + +#ifdef AFS_DEBUG_TRACE + AFSDbgPrint( L"NPCancelConnection AFSRDFS is disabled, returning WN_NOT_CONNECTED\n"); +#endif + + try_return( dwStatus = WN_NOT_CONNECTED); + } + + if( *lpName == L'\\' && + *(lpName + 1) == L'\\') + { + + bLocalName = FALSE; + } + + if( bLocalName) + { + + // + // Get the remote name for the connection, if we are handling it + // + + dwStatus = NPGetConnection( lpName, + wchRemoteName, + &dwRemoteNameLength); + + if( dwStatus != WN_SUCCESS || + dwRemoteNameLength == 0) + { + +#ifdef AFS_DEBUG_TRACE + AFSDbgPrint( L"NPCancelConnection Status 0x%x NameLength %u, returning WN_NOT_CONNECTED\n", + dwStatus, dwRemoteNameLength); +#endif + try_return( dwStatus = WN_NOT_CONNECTED); + } + } + else + { + + StringCchCopyW( wchRemoteName, MAX_PATH+1, lpName); + + dwRemoteNameLength = (wcslen( wchRemoteName) * sizeof( WCHAR)); + } + + wchRemoteName[ dwRemoteNameLength/sizeof( WCHAR)] = L'\0'; + + dwBufferSize = sizeof( AFSNetworkProviderConnectionCB) + dwRemoteNameLength; + + pConnectCB = (AFSNetworkProviderConnectionCB *)HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwBufferSize); + + if( pConnectCB == NULL) + { + + try_return( dwStatus = WN_OUT_OF_MEMORY); + } + + if( bLocalName) + { + + pConnectCB->LocalName = towupper(lpName[0]); + } + else + { + + pConnectCB->LocalName = L'\0'; + } + + pConnectCB->RemoteNameLength = (USHORT)dwRemoteNameLength; + + StringCchCopyW( pConnectCB->RemoteName, + MAX_PATH+1, + wchRemoteName); + + pConnectCB->Version = AFS_NETWORKPROVIDER_INTERFACE_VERSION_1; + + pConnectCB->AuthenticationId = AFSRetrieveAuthId(); + +#ifdef AFS_DEBUG_TRACE + AFSDbgPrint( L"NPCancelConnection Retrieved authentication id %08lX-%08lX\n", + pConnectCB->AuthenticationId.HighPart, + pConnectCB->AuthenticationId.LowPart); +#endif + + hControlDevice = OpenRedirector(); + + if( hControlDevice == NULL) + { + +#ifdef AFS_DEBUG_TRACE + AFSDbgPrint( L"NPCancelConnection OpenRedirector failure, returning WN_NET_ERROR\n"); +#endif + + try_return( dwStatus = WN_NET_ERROR); + } + + memset( &stCancelConn, + '\0', + sizeof( AFSCancelConnectionResultCB)); + + dwError = DeviceIoControl( hControlDevice, + IOCTL_AFS_CANCEL_CONNECTION, + pConnectCB, + dwBufferSize, + &stCancelConn, + sizeof( AFSCancelConnectionResultCB), + &dwCopyBytes, + NULL); + + if( !dwError) + { +#ifdef AFS_DEBUG_TRACE + DWORD gle = GetLastError(); + + AFSDbgPrint( L"NPCancelConnection Failed to cancel connection to file system - gle 0x%x\n", gle); +#endif + try_return( dwStatus = WN_NOT_CONNECTED); + } + + dwStatus = stCancelConn.Status; + +#ifdef AFS_DEBUG_TRACE + + AFSDbgPrint( L"NPCancelConnection Cancel connection to file system - Name %s Status %08lX\n", + lpName, + dwStatus); +#endif + + if( dwStatus == WN_SUCCESS && + ( bLocalName || + stCancelConn.LocalName != L'\0')) + { + + UNICODE_STRING uniConnectionName; + UNICODE_STRING uniDeviceName; + + uniDeviceName.Length = (wcslen( AFS_RDR_DEVICE_NAME) * sizeof( WCHAR)); + uniDeviceName.MaximumLength = uniDeviceName.Length; + uniDeviceName.Buffer = AFS_RDR_DEVICE_NAME; + + // + // Create a symbolic link object to the device we are redirecting + // + + uniConnectionName.MaximumLength = (USHORT)( uniDeviceName.Length + + dwRemoteNameLength + + 8 + // Local name and \; + sizeof(WCHAR)); // Space for NULL-termination. + + // + // Don't include NULL-termination. + // + + uniConnectionName.Length = uniConnectionName.MaximumLength - sizeof(WCHAR); + + uniConnectionName.Buffer = LocalAlloc( LMEM_ZEROINIT, + uniConnectionName.MaximumLength); + + if( uniConnectionName.Buffer == NULL) + { + + try_return( dwStatus = GetLastError()); + } + + CopyMemory( uniConnectionName.Buffer, + uniDeviceName.Buffer, + uniDeviceName.Length); + + StringCchCatW( uniConnectionName.Buffer, + uniConnectionName.MaximumLength, + L"\\;" ); + + if( !bLocalName) + { + + WCHAR wchLocalName[ 3]; + + wchLocalName[ 0] = stCancelConn.LocalName; + + wchLocalName[ 1] = L':'; + + wchLocalName[ 2] = L'\0'; + + StringCchCatW( uniConnectionName.Buffer, + uniConnectionName.MaximumLength, + wchLocalName); + + pwchLocalName = wchLocalName; + } + else + { + + StringCchCatW( uniConnectionName.Buffer, + uniConnectionName.MaximumLength, + lpName); + + pwchLocalName = lpName; + } + + StringCchCatW( uniConnectionName.Buffer, + uniConnectionName.MaximumLength, + wchRemoteName); + + if( !DefineDosDevice( DDD_REMOVE_DEFINITION | DDD_RAW_TARGET_PATH | DDD_EXACT_MATCH_ON_REMOVE, + pwchLocalName, + uniConnectionName.Buffer)) + { + +#ifdef AFS_DEBUG_TRACE + DWORD gle = GetLastError(); + + AFSDbgPrint( L"NPCancelConnection Failed to cancel connection to system - gle 0x%x Name %s connection %wZ\n", + gle, + pwchLocalName, + &uniConnectionName); +#endif + } + else + { +#ifdef AFS_DEBUG_TRACE + + AFSDbgPrint( L"NPCancelConnection Canceled connection to system - Name %s connection %wZ\n", + pwchLocalName, + &uniConnectionName); +#endif + } + } + +try_exit: + + if ( hControlDevice != NULL) + { + + CloseHandle( hControlDevice); + } + + + if( pConnectCB != NULL) + { + + HeapFree( GetProcessHeap( ), 0, (PVOID) pConnectCB); + } + + } + + return dwStatus; +} + +DWORD +APIENTRY +NPGetConnection( LPWSTR lpLocalName, + LPWSTR lpRemoteName, + LPDWORD lpBufferSize) +{ + + DWORD dwStatus = WN_NOT_CONNECTED; + WCHAR wchLocalName[3]; + WCHAR wchSubstName[MAX_PATH + 1]; + AFSNetworkProviderConnectionCB *pConnectCB = NULL; + DWORD dwError = 0; + DWORD dwBufferSize = 0; + HANDLE hControlDevice = NULL; + DWORD dwPassedSize; + + __Enter + { + + if ( NPIsFSDisabled()) + { + +#ifdef AFS_DEBUG_TRACE + AFSDbgPrint( L"NPGetConnection AFSRDFS is disabled, returning WN_NOT_CONNECTED\n"); +#endif + + try_return( dwStatus = WN_NOT_CONNECTED); + } + + if( lstrlen( lpLocalName) == 0) + { +#ifdef AFS_DEBUG_TRACE + AFSDbgPrint( L"NPGetConnection No local name, returning WN_BAD_LOCALNAME\n"); +#endif + try_return( dwStatus = WN_BAD_LOCALNAME); + } + + if ( lpBufferSize == NULL) + { +#ifdef AFS_DEBUG_TRACE + AFSDbgPrint( L"NPGetConnection No output size, returning WN_BAD_LOCALNAME\n"); +#endif + try_return( dwStatus = WN_BAD_VALUE); + } + + dwPassedSize = *lpBufferSize; + + if ( !DriveSubstitution( lpLocalName, wchSubstName, sizeof( wchSubstName))) + { + wchLocalName[0] = towupper(lpLocalName[0]); + wchLocalName[1] = L':'; + wchLocalName[2] = L'\0'; + +#ifdef AFS_DEBUG_TRACE + AFSDbgPrint( L"NPGetConnection Requesting connection for %s\n", + wchLocalName); +#endif + } + else + { + ReadServerNameString(); + + if ( wchSubstName[0] != L'\\' && + wchSubstName[1] == L':') + { + + wchLocalName[0] = towupper(wchSubstName[0]); + wchLocalName[1] = L':'; + wchLocalName[2] = L'\0'; + +#ifdef AFS_DEBUG_TRACE + AFSDbgPrint( L"NPGetConnection Requesting connection for drive substitution %s -> %s\n", + wchSubstName, + wchLocalName); +#endif + } + else if ( _wcsnicmp( wchSubstName, wszServerNameUNC, cbServerNameUNCLength / sizeof( WCHAR)) == 0 && + ( wchSubstName[cbServerNameUNCLength / sizeof( WCHAR)] == L'\\' || + wchSubstName[cbServerNameUNCLength / sizeof( WCHAR)] == 0)) + { + HRESULT hr; + WCHAR *pwch; + DWORD dwCount = 0; + +#ifdef AFS_DEBUG_TRACE + AFSDbgPrint( L"NPGetConnection drive substitution %s is AFS\n", + wchSubstName); +#endif + + if ( lpRemoteName == NULL || + dwPassedSize == 0) + { + + *lpBufferSize = wcslen( wchSubstName) * sizeof( WCHAR) + sizeof( WCHAR); + + try_return( dwStatus = WN_MORE_DATA); + + } + + hr = StringCbCopyN(lpRemoteName, *lpBufferSize, wchSubstName, sizeof( wchSubstName)); + + if ( SUCCEEDED(hr)) + { + + for ( dwCount = 0, pwch = lpRemoteName; *pwch; pwch++ ) + { + if ( *pwch == L'\\' ) + { + dwCount++; + + if ( dwCount == 4) + { + *pwch = L'\0'; + + break; + } + } + + } + + *lpBufferSize = wcslen( lpRemoteName) * sizeof( WCHAR) + sizeof( WCHAR); + + try_return( dwStatus = WN_SUCCESS); + } + else if ( hr == STRSAFE_E_INSUFFICIENT_BUFFER) + { + + *lpBufferSize = wcslen( wchSubstName) * sizeof( WCHAR) + sizeof( WCHAR); + + for ( dwCount = 0, pwch = lpRemoteName; *pwch; pwch++ ) + { + if ( *pwch == L'\\' ) + { + dwCount++; + + if ( dwCount == 4) + { + *pwch = L'\0'; + + *lpBufferSize = wcslen( lpRemoteName) * sizeof( WCHAR) + sizeof( WCHAR); + + try_return( dwStatus = WN_SUCCESS); + } + } + + } + + try_return( dwStatus = WN_MORE_DATA); + } + else + { + +#ifdef AFS_DEBUG_TRACE + AFSDbgPrint( L"NPGetConnection StringCbCopyN failure 0x%X\n", + hr); +#endif + try_return( dwStatus = WN_NET_ERROR); + } + } + else + { + +#ifdef AFS_DEBUG_TRACE + AFSDbgPrint( L"NPGetConnection drive substitution %s is not AFS\n", + wchSubstName); +#endif + try_return( dwStatus = WN_NOT_CONNECTED); + } + } + +#ifdef AFS_DEBUG_TRACE + AFSDbgPrint( L"NPGetConnection Requesting connection for %s\n", + wchLocalName); +#endif + + dwBufferSize = 0x1000; + + pConnectCB = (AFSNetworkProviderConnectionCB *)HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwBufferSize); + + if( pConnectCB == NULL) + { + + try_return( dwStatus = WN_OUT_OF_MEMORY); + } + + pConnectCB->LocalName = towupper(wchLocalName[0]); + + pConnectCB->RemoteNameLength = 0; + + pConnectCB->Version = AFS_NETWORKPROVIDER_INTERFACE_VERSION_1; + + pConnectCB->AuthenticationId = AFSRetrieveAuthId(); + +#ifdef AFS_DEBUG_TRACE + AFSDbgPrint( L"NPGetConnection Retrieved authentication id %08lX-%08lX\n", + pConnectCB->AuthenticationId.HighPart, + pConnectCB->AuthenticationId.LowPart); +#endif + + hControlDevice = OpenRedirector(); + + if( hControlDevice == NULL) + { + +#ifdef AFS_DEBUG_TRACE + AFSDbgPrint( L"NPGetConnection OpenRedirector failure, returning WN_NET_ERROR\n"); +#endif + + try_return( dwStatus = WN_NET_ERROR); + } + + dwError = DeviceIoControl( hControlDevice, + IOCTL_AFS_GET_CONNECTION, + pConnectCB, + dwBufferSize, + pConnectCB, + dwBufferSize, + lpBufferSize, + NULL); + + if( !dwError) + { +#ifdef AFS_DEBUG_TRACE + DWORD gle = GetLastError(); + + AFSDbgPrint( L"NPGetConnection Failed to get connection from file system for local %s gle 0x%x\n", + wchLocalName, gle); +#endif + try_return( dwStatus = WN_NOT_CONNECTED); + } + + // + // IOCTL_AFS_GET_CONNECTION returns a counted string + // + + if( lpRemoteName == NULL || + *lpBufferSize + sizeof( WCHAR) > dwPassedSize) + { + + *lpBufferSize += sizeof( WCHAR); + + try_return( dwStatus = WN_MORE_DATA); + } + + memcpy( lpRemoteName, + (void *)pConnectCB, + *lpBufferSize); + + lpRemoteName[ *lpBufferSize/sizeof( WCHAR)] = L'\0'; + + *lpBufferSize += sizeof( WCHAR); + +#ifdef AFS_DEBUG_TRACE + AFSDbgPrint( L"NPGetConnection local %s remote %s\n", + wchLocalName, + lpRemoteName); +#endif + dwStatus = WN_SUCCESS; + +try_exit: + + if ( hControlDevice != NULL) + { + + CloseHandle( hControlDevice); + } + + if( pConnectCB != NULL) + { + + HeapFree( GetProcessHeap( ), 0, (PVOID) pConnectCB); + } + } + + return dwStatus; +} + +DWORD +APIENTRY +NPGetConnection3( IN LPCWSTR lpLocalName, + IN DWORD dwLevel, + OUT LPVOID lpBuffer, + IN OUT LPDWORD lpBufferSize) +{ + + DWORD dwStatus = WN_NOT_CONNECTED; + WCHAR wchLocalName[3]; + WCHAR wchSubstName[MAX_PATH + 1]; + AFSNetworkProviderConnectionCB *pConnectCB = NULL; + DWORD dwError = 0; + DWORD dwBufferSize = 0; + HANDLE hControlDevice = NULL; + DWORD dwPassedSize; + DWORD *pConnectState =(DWORD *)lpBuffer; + + __Enter + { + + if ( NPIsFSDisabled()) + { + +#ifdef AFS_DEBUG_TRACE + AFSDbgPrint( L"NPGetConnection3 AFSRDFS is disabled, returning WN_NOT_CONNECTED\n"); +#endif + + try_return( dwStatus = WN_NOT_CONNECTED); + } + + if( lstrlen( lpLocalName) == 0) + { +#ifdef AFS_DEBUG_TRACE + AFSDbgPrint( L"NPGetConnection3 No local name, returning WN_BAD_LOCALNAME\n"); +#endif + try_return( dwStatus = WN_BAD_LOCALNAME); + } + + // + // LanMan NPGetConnection3 only responds to level 1 + // + + if ( dwLevel != 0x1) + { +#ifdef AFS_DEBUG_TRACE + AFSDbgPrint( L"NPGetConnection3 Level 0x%X returning WN_BAD_LEVEL\n", dwLevel); +#endif + try_return( dwStatus = WN_BAD_LEVEL); + } + + if ( lpBufferSize == NULL) + { +#ifdef AFS_DEBUG_TRACE + AFSDbgPrint( L"NPGetConnection3 No output size, returning WN_BAD_VALUE\n"); +#endif + try_return( dwStatus = WN_BAD_VALUE); + } + + dwPassedSize = *lpBufferSize; + + if ( dwPassedSize == 0 || + lpBuffer == NULL) + { + + *lpBufferSize = sizeof( DWORD); + + try_return( dwStatus = WN_MORE_DATA); + } + + if ( !DriveSubstitution( lpLocalName, wchSubstName, sizeof( wchSubstName))) + { + wchLocalName[0] = towupper(lpLocalName[0]); + wchLocalName[1] = L':'; + wchLocalName[2] = L'\0'; + +#ifdef AFS_DEBUG_TRACE + AFSDbgPrint( L"NPGetConnection3 Requesting connection for %s level 0x%X\n", + wchLocalName, + dwLevel); +#endif + } + else + { + + ReadServerNameString(); + + if ( wchSubstName[0] != L'\\' && + wchSubstName[1] == L':') + { + + wchLocalName[0] = towupper(wchSubstName[0]); + wchLocalName[1] = L':'; + wchLocalName[2] = L'\0'; + +#ifdef AFS_DEBUG_TRACE + AFSDbgPrint( L"NPGetConnection3 Requesting connection for drive substitution %s -> %s level 0x%x\n", + wchSubstName, + wchLocalName, + dwLevel); +#endif + } + else if ( _wcsnicmp( wchSubstName, wszServerNameUNC, cbServerNameUNCLength / sizeof( WCHAR)) == 0 && + ( wchSubstName[cbServerNameUNCLength / sizeof( WCHAR)] == L'\\' || + wchSubstName[cbServerNameUNCLength / sizeof( WCHAR)] == 0)) + { + +#ifdef AFS_DEBUG_TRACE + AFSDbgPrint( L"NPGetConnection3 drive substitution %s is AFS return connected\n", + wchSubstName); +#endif + *pConnectState = WNGETCON_CONNECTED; + + *lpBufferSize = sizeof( DWORD); + + try_return( dwStatus = WN_SUCCESS); + } + else + { + +#ifdef AFS_DEBUG_TRACE + AFSDbgPrint( L"NPGetConnection3 drive substitution %s is not AFS return not connected\n", + wchSubstName); +#endif + try_return( dwStatus = WN_NOT_CONNECTED); + } + } + + dwBufferSize = 0x1000; + + pConnectCB = (AFSNetworkProviderConnectionCB *)HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwBufferSize); + + if( pConnectCB == NULL) + { + + try_return( dwStatus = WN_OUT_OF_MEMORY); + } + + pConnectCB->LocalName = towupper(wchLocalName[0]); + + pConnectCB->RemoteNameLength = 0; + + pConnectCB->Version = AFS_NETWORKPROVIDER_INTERFACE_VERSION_1; + + pConnectCB->AuthenticationId = AFSRetrieveAuthId(); + +#ifdef AFS_DEBUG_TRACE + AFSDbgPrint( L"NPGetConnection3 Retrieved authentication id %08lX-%08lX\n", + pConnectCB->AuthenticationId.HighPart, + pConnectCB->AuthenticationId.LowPart); +#endif + + hControlDevice = OpenRedirector(); + + if( hControlDevice == NULL) + { + +#ifdef AFS_DEBUG_TRACE + AFSDbgPrint( L"NPGetConnection3 OpenRedirector failure, returning WN_NET_ERROR\n"); +#endif + + try_return( dwStatus = WN_NET_ERROR); + } + + dwError = DeviceIoControl( hControlDevice, + IOCTL_AFS_GET_CONNECTION, + pConnectCB, + dwBufferSize, + pConnectCB, + dwBufferSize, + &dwBufferSize, + NULL); + + if( !dwError) + { +#ifdef AFS_DEBUG_TRACE + DWORD gle = GetLastError(); + + AFSDbgPrint( L"NPGetConnection3 Failed to get connection from file system for local %s gle 0x%x\n", + wchLocalName, gle); +#endif + try_return( dwStatus = WN_NOT_CONNECTED); + } + + *lpBufferSize = sizeof( DWORD); + + if( sizeof( DWORD) > dwPassedSize) + { + + try_return( dwStatus = WN_MORE_DATA); + } + + *pConnectState = WNGETCON_CONNECTED; + +#ifdef AFS_DEBUG_TRACE + AFSDbgPrint( L"NPGetConnection3 local %s connect-state 0x%x\n", + wchLocalName, + *pConnectState); +#endif + dwStatus = WN_SUCCESS; + +try_exit: + + if ( hControlDevice != NULL) + { + + CloseHandle( hControlDevice); + } + + if( pConnectCB != NULL) + { + + HeapFree( GetProcessHeap( ), 0, (PVOID) pConnectCB); + } + } + + return dwStatus; +} + +DWORD +APIENTRY +NPGetConnectionPerformance( LPCWSTR lpRemoteName, + LPNETCONNECTINFOSTRUCT lpNetConnectInfo) +{ + + DWORD dwReturn = WN_SUCCESS; + AFSNetworkProviderConnectionCB *pConnectCB = NULL; + DWORD dwBufferSize = 0; + HANDLE hControlDevice = NULL; + DWORD dwError = 0; + + __Enter + { + + if ( NPIsFSDisabled()) + { + +#ifdef AFS_DEBUG_TRACE + AFSDbgPrint( L"NPGetConnectionPerformance AFSRDFS is disabled, returning WN_BAD_NETNAME\n"); +#endif + + return WN_NO_NETWORK; + } + + AFSDbgPrint( L"NPGetConnectionPerformance Entry for remote connection %S\n", + lpRemoteName); + + dwBufferSize = 0x1000; + + pConnectCB = (AFSNetworkProviderConnectionCB *)HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwBufferSize); + + if( pConnectCB == NULL) + { + try_return( dwReturn = WN_OUT_OF_MEMORY); + } + + pConnectCB->RemoteNameLength = wcslen( lpRemoteName) * sizeof( WCHAR); + + StringCbCopy( pConnectCB->RemoteName, + dwBufferSize - sizeof(AFSNetworkProviderConnectionCB), + lpRemoteName); + + pConnectCB->Version = AFS_NETWORKPROVIDER_INTERFACE_VERSION_1; + + pConnectCB->AuthenticationId = AFSRetrieveAuthId(); + + hControlDevice = OpenRedirector(); + + if( hControlDevice == NULL) + { + AFSDbgPrint( L"NPGetConnectionPerformance OpenRedirector failure, returning WN_NET_ERROR\n"); + + try_return( dwReturn = WN_NET_ERROR); + } + + dwError = DeviceIoControl( hControlDevice, + IOCTL_AFS_GET_CONNECTION_INFORMATION, + pConnectCB, + dwBufferSize, + pConnectCB, + dwBufferSize, + &dwBufferSize, + NULL); + + if( !dwError) + { +#ifdef AFS_DEBUG_TRACE + DWORD gle = GetLastError(); + + AFSDbgPrint( L"NPGetConnectionPerformance Failed to get connection info from file system for remote %S gle 0x%x\n", + lpRemoteName, + gle); +#endif + try_return( dwReturn = WN_NOT_CONNECTED); + } + + lpNetConnectInfo->dwFlags = WNCON_DYNAMIC; + + lpNetConnectInfo->dwSpeed = 500; + + lpNetConnectInfo->dwDelay = 0; + + lpNetConnectInfo->dwOptDataSize = 0x1000; + + AFSDbgPrint( L"NPGetConnectionPerformance Successfully returned information for remote connection %S\n", + lpRemoteName); + +try_exit: + + if ( hControlDevice != NULL) + { + CloseHandle( hControlDevice); + } + + if( pConnectCB != NULL) + { + HeapFree( GetProcessHeap( ), 0, (PVOID) pConnectCB); + } + } + + return dwReturn; +} + +static LPCWSTR +GetUsageString( DWORD dwUsage) +{ + static WCHAR Buffer[128] = L""; + // + // RESOURCEUSAGE_CONNECTABLE 0x00000001 + // RESOURCEUSAGE_CONTAINER 0x00000002 + // RESOURCEUSAGE_NOLOCALDEVICE 0x00000004 + // RESOURCEUSAGE_SIBLING 0x00000008 + // RESOURCEUSAGE_ATTACHED 0x00000010 + // RESOURCEUSAGE_ALL (RESOURCEUSAGE_CONNECTABLE | RESOURCEUSAGE_CONTAINER | RESOURCEUSAGE_ATTACHED) + // RESOURCEUSAGE_RESERVED 0x80000000 + // + + Buffer[0] = L'\0'; + + if ( dwUsage == RESOURCEUSAGE_ALL ) + { + return L"ALL"; + } + + if ( dwUsage == 0 ) + { + return L"NONE"; + } + + if ( dwUsage & RESOURCEUSAGE_CONNECTABLE ) + { + StringCbCat( Buffer, sizeof(Buffer), L"CONNECTABLE|"); + } + + if ( dwUsage & RESOURCEUSAGE_CONTAINER ) + { + StringCbCat( Buffer, sizeof(Buffer), L"CONTAINER|"); + } + + if ( dwUsage & RESOURCEUSAGE_NOLOCALDEVICE ) + { + StringCbCat( Buffer, sizeof(Buffer), L"NOLOCALDEVICE|"); + } + + if ( dwUsage & RESOURCEUSAGE_SIBLING ) + { + StringCbCat( Buffer, sizeof(Buffer), L"SIBLING|"); + } + + if ( dwUsage & RESOURCEUSAGE_ATTACHED ) + { + StringCbCat( Buffer, sizeof(Buffer), L"ATTACHED|"); + } + + if ( dwUsage & RESOURCEUSAGE_RESERVED ) + { + StringCbCat( Buffer, sizeof(Buffer), L"RESERVED|"); + } + + if ( dwUsage & ~(RESOURCEUSAGE_ALL|RESOURCEUSAGE_NOLOCALDEVICE|RESOURCEUSAGE_SIBLING|RESOURCEUSAGE_RESERVED) ) + { + StringCbCat( Buffer, sizeof(Buffer), L"UNKNOWN|"); + } + + Buffer[lstrlen(Buffer)-1] = L'\0'; + + return Buffer; +} + +static LPCWSTR +GetTypeString( DWORD dwType) +{ + static WCHAR Buffer[128] = L""; + + // + // RESOURCETYPE_ANY 0x00000000 + // RESOURCETYPE_DISK 0x00000001 + // RESOURCETYPE_PRINT 0x00000002 + // RESOURCETYPE_RESERVED 0x00000008 + // RESOURCETYPE_UNKNOWN 0xFFFFFFFF + // + + Buffer[0] = L'\0'; + + if ( dwType == RESOURCETYPE_ANY ) + { + return L"ANY"; + } + + if ( dwType == RESOURCETYPE_UNKNOWN ) + { + return L"UNKNOWN"; + } + + if ( dwType & RESOURCETYPE_DISK ) + { + StringCbCat( Buffer, sizeof(Buffer), L"DISK|"); + } + + if ( dwType & RESOURCETYPE_PRINT ) + { + StringCbCat( Buffer, sizeof(Buffer), L"PRINT|"); + } + + if ( dwType & RESOURCETYPE_RESERVED ) + { + StringCbCat( Buffer, sizeof(Buffer), L"RESERVED|"); + } + + if ( dwType & ~(RESOURCETYPE_DISK|RESOURCETYPE_PRINT|RESOURCETYPE_RESERVED) ) + { + StringCbCat( Buffer, sizeof(Buffer), L"UNKNOWN|"); + } + + Buffer[lstrlen(Buffer)-1] = L'\0'; + + return Buffer; +} + +static LPCWSTR +GetScopeString( DWORD dwScope) +{ + static WCHAR Buffer[128] = L""; + + // + // RESOURCE_CONNECTED 0x00000001 + // RESOURCE_GLOBALNET 0x00000002 + // RESOURCE_REMEMBERED 0x00000003 + // RESOURCE_RECENT 0x00000004 + // RESOURCE_CONTEXT 0x00000005 + // + + Buffer[0] = L'\0'; + + if ( dwScope == RESOURCE_CONNECTED ) + { + StringCbCat( Buffer, sizeof(Buffer), L"CONNECTED|"); + } + + if ( dwScope == RESOURCE_GLOBALNET ) + { + StringCbCat( Buffer, sizeof(Buffer), L"GLOBALNET|"); + } + + if ( dwScope == RESOURCE_REMEMBERED ) + { + StringCbCat( Buffer, sizeof(Buffer), L"REMEMBERED|"); + } + + if ( dwScope == RESOURCE_RECENT ) + { + StringCbCat( Buffer, sizeof(Buffer), L"RECENT|"); + } + + if ( dwScope == RESOURCE_CONTEXT ) + { + StringCbCat( Buffer, sizeof(Buffer), L"CONTEXT|"); + } + + if ( dwScope & ~(RESOURCE_CONNECTED|RESOURCE_GLOBALNET|RESOURCE_REMEMBERED|RESOURCE_RECENT|RESOURCE_CONTEXT) ) + { + StringCbCat( Buffer, sizeof(Buffer), L"UNKNOWN|"); + } + + Buffer[lstrlen(Buffer)-1] = L'\0'; + + return Buffer; +} + +static LPCWSTR +GetDisplayString( DWORD dwDisplay) +{ + // + // RESOURCEDISPLAYTYPE_GENERIC 0x00000000 + // RESOURCEDISPLAYTYPE_DOMAIN 0x00000001 + // RESOURCEDISPLAYTYPE_SERVER 0x00000002 + // RESOURCEDISPLAYTYPE_SHARE 0x00000003 + // RESOURCEDISPLAYTYPE_FILE 0x00000004 + // RESOURCEDISPLAYTYPE_GROUP 0x00000005 + // RESOURCEDISPLAYTYPE_NETWORK 0x00000006 + // RESOURCEDISPLAYTYPE_ROOT 0x00000007 + // RESOURCEDISPLAYTYPE_SHAREADMIN 0x00000008 + // RESOURCEDISPLAYTYPE_DIRECTORY 0x00000009 + // RESOURCEDISPLAYTYPE_TREE 0x0000000A + // RESOURCEDISPLAYTYPE_NDSCONTAINER 0x0000000B + // + + switch ( dwDisplay ) { + case RESOURCEDISPLAYTYPE_GENERIC: + return L"GENERIC"; + case RESOURCEDISPLAYTYPE_DOMAIN: + return L"DOMAIN"; + case RESOURCEDISPLAYTYPE_SERVER: + return L"SERVER"; + case RESOURCEDISPLAYTYPE_SHARE: + return L"SHARE"; + case RESOURCEDISPLAYTYPE_FILE: + return L"FILE"; + case RESOURCEDISPLAYTYPE_GROUP: + return L"GROUP"; + case RESOURCEDISPLAYTYPE_NETWORK: + return L"NETWORK"; + case RESOURCEDISPLAYTYPE_ROOT: + return L"ROOT"; + case RESOURCEDISPLAYTYPE_SHAREADMIN: + return L"SHAREADMIN"; + case RESOURCEDISPLAYTYPE_DIRECTORY: + return L"DIRECTORY"; + case RESOURCEDISPLAYTYPE_TREE: + return L"TREE"; + case RESOURCEDISPLAYTYPE_NDSCONTAINER: + return L"NDSCONTAINER"; + default: + return L"UNKNOWN"; + } +} + +DWORD +APIENTRY +NPOpenEnum( DWORD dwScope, + DWORD dwType, + DWORD dwUsage, + LPNETRESOURCE lpNetResource, + LPHANDLE lphEnum ) +{ + + DWORD dwStatus = WN_SUCCESS; + AFSEnumerationCB *pEnumCB = NULL; + +#ifdef AFS_DEBUG_TRACE + if ( lpNetResource == NULL) + { + AFSDbgPrint( L"NPOpenEnum Scope %s Type %s Usage %s NetResource: (Null)\n", + GetScopeString(dwScope), GetTypeString(dwType), GetUsageString(dwUsage)); + } + else + { + AFSDbgPrint( L"NPOpenEnum Scope %s Type %s Usage %s NetResource (0x%p): Scope %s Type %s Display %s Usage %s Local %s Remote \"%s\" Comment \"%s\"\n", + GetScopeString(dwScope), + GetTypeString(dwType), + GetUsageString(dwUsage), + lpNetResource, + GetScopeString(lpNetResource->dwScope), + GetTypeString(lpNetResource->dwType), + GetDisplayString(lpNetResource->dwDisplayType), + GetUsageString(lpNetResource->dwUsage), + lpNetResource->lpLocalName, + lpNetResource->lpRemoteName, + lpNetResource->lpComment); + } +#endif + + if ( dwUsage == 0 ) + { + dwUsage = RESOURCEUSAGE_ALL; + } + +#if 0 + if ( dwType == 0 || dwType == RESOURCEUSAGE_ATTACHED) + { + dwType |= RESOURCETYPE_DISK | RESOURCETYPE_PRINT; + } +#endif + + *lphEnum = HeapAlloc( GetProcessHeap( ), HEAP_ZERO_MEMORY, sizeof( AFSEnumerationCB)); + + if( *lphEnum == NULL) + { + + return WN_OUT_OF_MEMORY; + } + + pEnumCB = (AFSEnumerationCB *)*lphEnum; + + pEnumCB->CurrentIndex = 0; + + pEnumCB->Type = dwType; + + switch( dwScope ) + { + case RESOURCE_CONNECTED: + { + + pEnumCB->Scope = RESOURCE_CONNECTED; + + break; + } + + case RESOURCE_CONTEXT: + { + + pEnumCB->Scope = RESOURCE_CONTEXT; + + break; + } + + case RESOURCE_GLOBALNET: + { + + if( lpNetResource != NULL && + lpNetResource->lpRemoteName != NULL) + { + + pEnumCB->RemoteName = (WCHAR *)HeapAlloc( GetProcessHeap( ), HEAP_ZERO_MEMORY, 0x1000); + + if( pEnumCB->RemoteName == NULL) + { + + dwStatus = WN_OUT_OF_MEMORY; + HeapFree( GetProcessHeap( ), 0, (PVOID) *lphEnum ); + *lphEnum = NULL; + } + else + { + + StringCbCopy( pEnumCB->RemoteName, + 0x1000, + lpNetResource->lpRemoteName); + + } + } + + pEnumCB->Scope = RESOURCE_GLOBALNET; + + break; + } + + default: + +#ifdef AFS_DEBUG_TRACE + AFSDbgPrint( L"NPOpenEnum Processing (Scope %s 0x%x) Type %s Usage %s, returning WN_NOT_SUPPORTED\n", + GetScopeString(dwScope), dwScope, GetTypeString(dwType), GetUsageString(dwUsage)); +#endif + + dwStatus = WN_NOT_SUPPORTED; + HeapFree( GetProcessHeap( ), 0, (PVOID) *lphEnum ); + *lphEnum = NULL; + + break; + } + + return dwStatus; +} + + +DWORD +APIENTRY +NPEnumResource( HANDLE hEnum, + LPDWORD lpcCount, + LPVOID lpBuffer, + LPDWORD lpBufferSize) +{ + + DWORD dwStatus = WN_NO_MORE_ENTRIES; //WN_SUCCESS; + ULONG dwCopyBytes; + ULONG EntriesCopied; + ULONG EntriesRequested; + ULONG dwIndex; + LPNETRESOURCE pNetResource; + ULONG SpaceNeeded; + ULONG SpaceAvailable; + PWCHAR StringZone; + AFSNetworkProviderConnectionCB *pConnectionCB = NULL; + void *pConnectionCBBase = NULL; + DWORD dwError = 0; + UNICODE_STRING uniRemoteName; + HANDLE hControlDevice = NULL; + AFSEnumerationCB *pEnumCB = (AFSEnumerationCB *)hEnum; + + __Enter + { + + if ( lpBufferSize == NULL) + { +#ifdef AFS_DEBUG_TRACE + AFSDbgPrint( L"NPEnumResource No output size, returning WN_BAD_VALUE\n"); +#endif + try_return( dwStatus = WN_BAD_VALUE); + } + + ReadProviderNameString(); + + pNetResource = (LPNETRESOURCE) lpBuffer; + SpaceAvailable = *lpBufferSize; + EntriesRequested = *lpcCount; + *lpcCount = EntriesCopied = 0; + StringZone = (PWCHAR) ((char *)lpBuffer + *lpBufferSize); + +#ifdef AFS_DEBUG_TRACE + AFSDbgPrint( L"NPEnumResource Processing Remote name %s Scope %s Type %s Usage %s Index %d SpaceAvailable 0x%lX RequestedEntries %lu\n", + pEnumCB->RemoteName ? pEnumCB->RemoteName : L"(Null)", + GetScopeString(pEnumCB->Scope), + GetTypeString(pEnumCB->Type), + GetUsageString(pEnumCB->Type), + pEnumCB->CurrentIndex, + SpaceAvailable, + EntriesRequested); +#endif + + if ( NPIsFSDisabled()) + { + +#ifdef AFS_DEBUG_TRACE + AFSDbgPrint( L"NPEnumResource AFSRDFS is disabled, returning WN_NO_MORE_ENTRIES\n"); +#endif + + try_return( dwStatus = WN_NO_MORE_ENTRIES); + } + + pConnectionCB = (AFSNetworkProviderConnectionCB *)HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, 0x1000); + + if( pConnectionCB == NULL) + { + +#ifdef AFS_DEBUG_TRACE + AFSDbgPrint( L"NPEnumResource Out of Memory\n"); +#endif + + try_return( dwStatus = WN_OUT_OF_MEMORY); + } + + pConnectionCBBase = (void *)pConnectionCB; + + hControlDevice = OpenRedirector(); + + if( hControlDevice == NULL) + { + +#ifdef AFS_DEBUG_TRACE + AFSDbgPrint( L"NPEnumResource OpenRedirector failure, returning WN_NET_ERROR\n"); +#endif + + try_return( dwStatus = WN_NET_ERROR); + } + + // + // Handle the special cases here + // 0. Provider Network Root + // 1. Server Root + // + +#if 0 + if ( pEnumCB->Scope == RESOURCE_GLOBALNET) + { + + ReadServerNameString(); + + if ( pEnumCB->CurrentIndex == 0 && + pEnumCB->RemoteName == NULL) + { + + // Determine the space needed for this entry... + + SpaceNeeded = 2 * ( cbProviderNameLength + sizeof( WCHAR)); + + uniRemoteName.Length = (USHORT)cbProviderNameLength; + uniRemoteName.MaximumLength = uniRemoteName.Length; + uniRemoteName.Buffer = wszProviderName; + + if( SpaceNeeded + sizeof( NETRESOURCE) > SpaceAvailable) + { + + *lpBufferSize = SpaceNeeded + sizeof( NETRESOURCE); + +#ifdef AFS_DEBUG_TRACE + AFSDbgPrint( L"NPEnumResource Request MORE_DATA for entry %s Len %d\n", + &uniRemoteName, + *lpBufferSize); +#endif + try_return( dwStatus = WN_MORE_DATA); + } + +#ifdef AFS_DEBUG_TRACE + AFSDbgPrint( L"NPEnumResource Processing Entry %wZ\n", + &uniRemoteName); +#endif + + SpaceAvailable -= (SpaceNeeded + sizeof( NETRESOURCE)); + + pNetResource->dwScope = RESOURCE_GLOBALNET; + pNetResource->dwType = RESOURCETYPE_ANY; + pNetResource->dwDisplayType = RESOURCEDISPLAYTYPE_NETWORK; + pNetResource->dwUsage = RESOURCEUSAGE_CONTAINER | RESOURCEUSAGE_RESERVED; + + // setup string area at opposite end of buffer + StringZone = (PWCHAR)( (PBYTE) StringZone - SpaceNeeded); + + pNetResource->lpLocalName = NULL; + + // copy remote name + pNetResource->lpRemoteName = StringZone; + + StringCbCopy( StringZone, + cbProviderNameLength + sizeof( WCHAR), + wszProviderName); + + StringZone += cbProviderNameLength / sizeof(WCHAR) + 1; + + pNetResource->lpComment = NULL; + + // copy provider name + pNetResource->lpProvider = StringZone; + StringCbCopy( StringZone, + cbProviderNameLength + sizeof( WCHAR), + wszProviderName); + + StringZone += cbProviderNameLength / sizeof( WCHAR) + 1; + +#ifdef AFS_DEBUG_TRACE + AFSDbgPrint( L"NPEnumResource Entry (0x%p) Scope %s Type %s Display %s Usage %s Local %s Remote \"%s\" Comment \"%s\"\n", + pNetResource, + GetScopeString(pNetResource->dwScope), + GetTypeString(pNetResource->dwType), + GetDisplayString(pNetResource->dwDisplayType), + GetUsageString(pNetResource->dwUsage), + pNetResource->lpLocalName, + pNetResource->lpRemoteName, + pNetResource->lpComment); +#endif + + // setup the new end of buffer + StringZone = (PWCHAR)( (PBYTE) StringZone - SpaceNeeded); + + EntriesCopied++; + + pNetResource++; + + // do not change the index since we did not query the redirector + pEnumCB->CurrentIndex = 0; + + // remember that we returned the provider name + pEnumCB->RemoteName = (WCHAR *)HeapAlloc( GetProcessHeap( ), HEAP_ZERO_MEMORY, 0x1000); + + if( pEnumCB->RemoteName == NULL) + { + + try_return( dwStatus = WN_OUT_OF_MEMORY); + } + else + { + + StringCbCopy( pEnumCB->RemoteName, + 0x1000, + wszProviderName); + } + } + + if ( pEnumCB->CurrentIndex == 0 && + lstrlen( pEnumCB->RemoteName) == cbProviderNameLength / sizeof( WCHAR) && + _wcsnicmp( pEnumCB->RemoteName, wszProviderName, cbProviderNameLength / sizeof( WCHAR)) == 0 && + EntriesCopied < EntriesRequested) + { + + // + // After the network provider entry comes the server entry + // + + // Determine the space needed for this entry... + + SpaceNeeded = cbProviderNameLength + cbServerNameUNCLength + cbServerCommentLength + 3 * sizeof( WCHAR); + + uniRemoteName.Length = (USHORT)cbServerNameUNCLength; + uniRemoteName.MaximumLength = uniRemoteName.Length; + uniRemoteName.Buffer = wszServerNameUNC; + + if( SpaceNeeded + sizeof( NETRESOURCE) > SpaceAvailable) + { + + *lpBufferSize = SpaceNeeded + sizeof( NETRESOURCE); + +#ifdef AFS_DEBUG_TRACE + AFSDbgPrint( L"NPEnumResource Request MORE_DATA for entry %s Len %d\n", + &uniRemoteName, + *lpBufferSize); +#endif + try_return( dwStatus = WN_MORE_DATA); + } + +#ifdef AFS_DEBUG_TRACE + AFSDbgPrint( L"NPEnumResource Processing Entry %wZ\n", + &uniRemoteName); +#endif + + SpaceAvailable -= (SpaceNeeded + sizeof( NETRESOURCE)); + + pNetResource->dwScope = 0; + pNetResource->dwType = RESOURCETYPE_ANY; + pNetResource->dwDisplayType = RESOURCEDISPLAYTYPE_SERVER; + pNetResource->dwUsage = RESOURCEUSAGE_CONTAINER; + + // setup string area at opposite end of buffer + StringZone = (PWCHAR)( (PBYTE) StringZone - SpaceNeeded); + + pNetResource->lpLocalName = NULL; + + // copy remote name + pNetResource->lpRemoteName = StringZone; + + StringCbCopy( StringZone, + cbServerNameUNCLength + sizeof( WCHAR), + wszServerNameUNC); + + StringZone += cbServerNameUNCLength / sizeof(WCHAR) + 1; + + // copy comment + pNetResource->lpComment = StringZone; + + StringCbCopy( StringZone, + cbServerCommentLength + sizeof( WCHAR), + wszServerComment); + + StringZone += cbServerCommentLength / sizeof( WCHAR) + 1; + + // copy provider name + pNetResource->lpProvider = StringZone; + StringCbCopy( StringZone, + cbProviderNameLength + sizeof( WCHAR), + wszProviderName); + + StringZone += cbProviderNameLength / sizeof( WCHAR) + 1; + +#ifdef AFS_DEBUG_TRACE + AFSDbgPrint( L"NPEnumResource Entry (0x%p) Scope %s Type %s Display %s Usage %s Local %s Remote \"%s\" Comment \"%s\"\n", + pNetResource, + GetScopeString(pNetResource->dwScope), + GetTypeString(pNetResource->dwType), + GetDisplayString(pNetResource->dwDisplayType), + GetUsageString(pNetResource->dwUsage), + pNetResource->lpLocalName, + pNetResource->lpRemoteName, + pNetResource->lpComment); +#endif + + // setup the new end of buffer + StringZone = (PWCHAR)( (PBYTE) StringZone - SpaceNeeded); + + EntriesCopied++; + + pNetResource++; + + // do not update the index because we did not query the redirector + pEnumCB->CurrentIndex = 0; + + // remember that we returned the server + StringCbCopy( pEnumCB->RemoteName, + 0x1000, + wszServerNameUNC); + } + } +#endif + + // + // Setup what we are going to ask for + // + + pConnectionCB->Scope = pEnumCB->Scope; + + pConnectionCB->Type = pEnumCB->Type; + + pConnectionCB->CurrentIndex = pEnumCB->CurrentIndex; + + pConnectionCB->Version = AFS_NETWORKPROVIDER_INTERFACE_VERSION_1; + + // + // If this is a RESOURCE_GLOBALNET enumeration then pass down the remote name if + // there is one + // + + pConnectionCB->RemoteNameLength = 0; + + if( pEnumCB->Scope == RESOURCE_GLOBALNET && + pEnumCB->RemoteName != NULL) + { + + pConnectionCB->RemoteNameLength = wcslen( pEnumCB->RemoteName) * sizeof( WCHAR); + + StringCbCopy( pConnectionCB->RemoteName, + (0x1000 - sizeof(AFSNetworkProviderConnectionCB)) + sizeof(WCHAR), + pEnumCB->RemoteName); + } + + pConnectionCB->AuthenticationId = AFSRetrieveAuthId(); + +#ifdef AFS_DEBUG_TRACE + AFSDbgPrint( L"NPEnumResource Retrieved authentication id %08lX-%08lX\n", + pConnectionCB->AuthenticationId.HighPart, + pConnectionCB->AuthenticationId.LowPart); +#endif + + dwError = DeviceIoControl( hControlDevice, + IOCTL_AFS_LIST_CONNECTIONS, + pConnectionCB, + 0x1000, + pConnectionCB, + 0x1000, + &dwCopyBytes, + NULL); + + if( !dwError) + { +#ifdef AFS_DEBUG_TRACE + DWORD gle = GetLastError(); + + AFSDbgPrint( L"NPEnumResource Failed to list connections from file system - gle 0x%x\n", + gle); +#endif + try_return( dwStatus = WN_NOT_CONNECTED); + } + + if( dwCopyBytes == 0) + { + +#ifdef AFS_DEBUG_TRACE + AFSDbgPrint( L"NPEnumResource No More Entries\n"); +#endif + try_return( dwStatus = WN_NO_MORE_ENTRIES); + } + + dwIndex = pEnumCB->CurrentIndex; + + while( EntriesCopied < EntriesRequested) + { + + uniRemoteName.Length = (USHORT)pConnectionCB->RemoteNameLength; + uniRemoteName.MaximumLength = uniRemoteName.Length; + uniRemoteName.Buffer = pConnectionCB->RemoteName; + + // Determine the space needed for this entry... + + SpaceNeeded = 0; + + if( pConnectionCB->LocalName != 0) + { + + SpaceNeeded += 3 * sizeof(WCHAR); // local name + } + + SpaceNeeded += pConnectionCB->RemoteNameLength + sizeof( WCHAR); // remote name + + if( pConnectionCB->CommentLength > 0) + { + + SpaceNeeded += pConnectionCB->CommentLength + sizeof( WCHAR); // comment + } + + SpaceNeeded += cbProviderNameLength + sizeof( WCHAR); // provider name + + if( SpaceNeeded + sizeof( NETRESOURCE) > SpaceAvailable) + { + + if (EntriesCopied == 0) { + + dwStatus = WN_MORE_DATA; + + *lpBufferSize = SpaceNeeded + sizeof( NETRESOURCE); + +#ifdef AFS_DEBUG_TRACE + AFSDbgPrint( L"NPEnumResource Request MORE_DATA for entry %s Len %d\n", + &uniRemoteName, + *lpBufferSize); +#endif + + } else { + +#ifdef AFS_DEBUG_TRACE + AFSDbgPrint( L"NPEnumResource Return SUCCESS but more entries Index %d\n", + dwIndex); +#endif + + dwStatus = WN_SUCCESS; + } + + break; + } + + SpaceAvailable -= (SpaceNeeded + sizeof( NETRESOURCE)); + + pNetResource->dwScope = pConnectionCB->Scope; + pNetResource->dwType = pConnectionCB->Type; + + pNetResource->dwDisplayType = pConnectionCB->DisplayType; + + if ( pNetResource->dwType == RESOURCETYPE_ANY && + pNetResource->dwDisplayType == RESOURCEDISPLAYTYPE_SHARE) + { + + pNetResource->dwType = RESOURCETYPE_DISK; + } + pNetResource->dwUsage = pConnectionCB->Usage; + + // setup string area at opposite end of buffer + StringZone = (PWCHAR)( (PBYTE) StringZone - SpaceNeeded); + + // copy local name + if( pConnectionCB->LocalName != 0) + { + + pNetResource->lpLocalName = StringZone; + *StringZone++ = towupper(pConnectionCB->LocalName); + *StringZone++ = L':'; + *StringZone++ = L'\0'; + } + else + { + + pNetResource->lpLocalName = NULL; + } + +#ifdef AFS_DEBUG_TRACE + AFSDbgPrint( L"NPEnumResource Processing Entry %wZ\n", + &uniRemoteName); +#endif + + // copy remote name + pNetResource->lpRemoteName = StringZone; + + CopyMemory( StringZone, + pConnectionCB->RemoteName, + pConnectionCB->RemoteNameLength); + + StringZone += (pConnectionCB->RemoteNameLength / sizeof(WCHAR)); + + *StringZone++ = L'\0'; + + // copy comment + if( pConnectionCB->CommentLength > 0) + { + + pNetResource->lpComment = StringZone; + + CopyMemory( StringZone, + (void *)((char *)pConnectionCB + pConnectionCB->CommentOffset), + pConnectionCB->CommentLength); + + StringZone += (pConnectionCB->CommentLength / sizeof(WCHAR)); + + *StringZone++ = L'\0'; + } + else + { + + pNetResource->lpComment = NULL; + } + + // copy provider name + pNetResource->lpProvider = StringZone; + StringCbCopy( StringZone, + cbProviderNameLength + sizeof( WCHAR), + wszProviderName); + + StringZone += (cbProviderNameLength / sizeof( WCHAR) + 1); + +#ifdef AFS_DEBUG_TRACE + AFSDbgPrint( L"NPEnumResource Entry (0x%p) Scope %s Type %s Display %s Usage %s Local %s Remote \"%s\" Comment \"%s\"\n", + pNetResource, + GetScopeString(pNetResource->dwScope), + GetTypeString(pNetResource->dwType), + GetDisplayString(pNetResource->dwDisplayType), + GetUsageString(pNetResource->dwUsage), + pNetResource->lpLocalName, + pNetResource->lpRemoteName, + pNetResource->lpComment); +#endif + + // setup the new end of buffer + StringZone = (PWCHAR)( (PBYTE) StringZone - SpaceNeeded); + + EntriesCopied++; + + pNetResource++; + + dwIndex++; + + dwCopyBytes -= FIELD_OFFSET( AFSNetworkProviderConnectionCB, RemoteName) + + pConnectionCB->RemoteNameLength + + pConnectionCB->CommentLength; + + if( dwCopyBytes == 0) + { + + dwStatus = WN_SUCCESS; + + break; + } + + pConnectionCB = (AFSNetworkProviderConnectionCB *)((char *)pConnectionCB + + FIELD_OFFSET( AFSNetworkProviderConnectionCB, RemoteName) + + pConnectionCB->RemoteNameLength + + pConnectionCB->CommentLength); + } + + *lpcCount = EntriesCopied; + + // update entry index + pEnumCB->CurrentIndex = dwIndex; + +#ifdef AFS_DEBUG_TRACE + AFSDbgPrint( L"NPEnumResource Completed Count %d Index %d\n", + EntriesCopied, + dwIndex); +#endif + +try_exit: + + if ( hControlDevice != NULL) + { + + CloseHandle( hControlDevice); + } + + if( pConnectionCBBase != NULL) + { + + HeapFree( GetProcessHeap( ), 0, (PVOID) pConnectionCBBase); + } + } + + return dwStatus; +} + +/*++ + +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 + +Notes: + + The sample only supports the notion of enumerating connected shares + +--*/ + +DWORD APIENTRY +NPCloseEnum( HANDLE hEnum ) +{ + + AFSEnumerationCB *pEnumCB = (AFSEnumerationCB *)hEnum; + +#ifdef AFS_DEBUG_TRACE + AFSDbgPrint( L"NPCloseEnum\n"); +#endif + + if( pEnumCB->RemoteName != NULL) + { + + HeapFree( GetProcessHeap( ), 0, (PVOID) pEnumCB->RemoteName); + } + + HeapFree( GetProcessHeap( ), 0, (PVOID) hEnum ); + + return WN_SUCCESS; +} + +DWORD APIENTRY +NPGetResourceParent( LPNETRESOURCE lpNetResource, + LPVOID lpBuffer, + LPDWORD lpBufferSize ) +{ + + DWORD dwStatus = WN_ACCESS_DENIED; + WCHAR *pwchRemoteName = NULL, *pwchSearch = NULL, *pwchSystem = NULL; + LPNETRESOURCE lpOutResource = (LPNETRESOURCE) lpBuffer; + + if ( lpNetResource == NULL) + { +#ifdef AFS_DEBUG_TRACE + AFSDbgPrint( L"NPGetResourceParent NULL NETRESOURCE\n"); +#endif + return WN_MORE_DATA; + } + + if( lpNetResource->lpRemoteName == NULL) + { +#ifdef AFS_DEBUG_TRACE + AFSDbgPrint( L"NPGetResourceParent NULL NETRESOURCE\n"); +#endif + return WN_BAD_NETNAME; + } + + if ( lpNetResource->dwType != 0 && + lpNetResource->dwType != RESOURCETYPE_DISK) + { +#ifdef AFS_DEBUG_TRACE + AFSDbgPrint( L"NPGetResourceParent Bad dwType\n"); +#endif + return WN_BAD_VALUE; + } + + if ( lpBufferSize == NULL ) + { + +#ifdef AFS_DEBUG_TRACE + AFSDbgPrint( L"NPGetResourceParent Null lpBufferSize\n"); +#endif + return WN_BAD_VALUE; + } + +#ifdef AFS_DEBUG_TRACE + AFSDbgPrint( L"NPGetResourceParent For remote name %s\n", + lpNetResource->lpRemoteName); +#endif + + pwchRemoteName = lpNetResource->lpRemoteName; + + pwchSearch = pwchRemoteName + (wcslen( pwchRemoteName) - 1); + + while( pwchSearch != pwchRemoteName) + { + + if( *pwchSearch == L'\\') + { + + *pwchSearch = L'\0'; + + break; + } + + pwchSearch--; + } + + if( pwchSearch != pwchRemoteName) + { + +#ifdef AFS_DEBUG_TRACE + AFSDbgPrint( L"NPGetResourceParent Processing parent %s\n", + lpNetResource->lpRemoteName); +#endif + + dwStatus = NPGetResourceInformation( lpNetResource, + lpBuffer, + lpBufferSize, + &pwchSystem); + } + else + { + if ( lpOutResource == NULL || + *lpBufferSize < sizeof( NETRESOURCE) ) + { + *lpBufferSize = sizeof( NETRESOURCE); + + return WN_MORE_DATA; + } + + memset( lpOutResource, 0, sizeof( NETRESOURCE)); + + return WN_SUCCESS; + + } + + return dwStatus; +} + +DWORD APIENTRY +NPGetResourceInformation( LPNETRESOURCE lpNetResource, + LPVOID lpBuffer, + LPDWORD lpBufferSize, + LPWSTR *lplpSystem ) +{ + + DWORD dwStatus = WN_NOT_CONNECTED; + AFSNetworkProviderConnectionCB *pConnectCB = NULL; + DWORD dwError = 0; + DWORD dwBufferSize = 0; + HANDLE hControlDevice = NULL; + NETRESOURCE *pNetResource = (NETRESOURCE *)lpBuffer; + PWCHAR pStringZone = NULL; + UNICODE_STRING uniRemoteName; + DWORD ulRequiredLen = 0; + DWORD dwPassedSize; + + + __Enter + { + if ( lplpSystem) + { + *lplpSystem = NULL; + } + + ReadProviderNameString(); + + if ( NPIsFSDisabled()) + { + +#ifdef AFS_DEBUG_TRACE + AFSDbgPrint( L"NPGetResourceInformation AFSRDFS is disabled, returning WN_BAD_NETNAME\n"); +#endif + + try_return( dwStatus = WN_BAD_NETNAME); + } + + if ( lpNetResource == NULL || + lpBufferSize == NULL ) + { + +#ifdef AFS_DEBUG_TRACE + AFSDbgPrint( L"NPGetResourceInformaton Null lpNetResource or lpBufferSize\n"); +#endif + return WN_BAD_VALUE; + } + + if( lpNetResource->lpRemoteName == NULL) + { +#ifdef AFS_DEBUG_TRACE + AFSDbgPrint( L"NPGetResourceInformation No resource name\n"); +#endif + + try_return( dwStatus = WN_NOT_CONNECTED); + } + + dwPassedSize = *lpBufferSize; + + dwBufferSize = 0x1000; + + pConnectCB = (AFSNetworkProviderConnectionCB *)HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwBufferSize); + + if( pConnectCB == NULL) + { + + try_return( dwStatus = WN_OUT_OF_MEMORY); + } + + pConnectCB->RemoteNameLength = wcslen( lpNetResource->lpRemoteName) * sizeof( WCHAR); + + StringCbCopy( pConnectCB->RemoteName, + dwBufferSize - sizeof(AFSNetworkProviderConnectionCB), + lpNetResource->lpRemoteName); + + pConnectCB->Version = AFS_NETWORKPROVIDER_INTERFACE_VERSION_1; + + pConnectCB->AuthenticationId = AFSRetrieveAuthId(); + +#ifdef AFS_DEBUG_TRACE + AFSDbgPrint( L"NPGetResourceInformation Retrieved authentication id %08lX-%08lX\n", + pConnectCB->AuthenticationId.HighPart, + pConnectCB->AuthenticationId.LowPart); +#endif + + hControlDevice = OpenRedirector(); + + if( hControlDevice == NULL) + { + +#ifdef AFS_DEBUG_TRACE + AFSDbgPrint( L"NPGetResourceInformation OpenRedirector failure, returning WN_NET_ERROR\n"); +#endif + + try_return( dwStatus = WN_NET_ERROR); + } + + dwError = DeviceIoControl( hControlDevice, + IOCTL_AFS_GET_CONNECTION_INFORMATION, + pConnectCB, + dwBufferSize, + pConnectCB, + dwBufferSize, + lpBufferSize, + NULL); + + if( !dwError) + { +#ifdef AFS_DEBUG_TRACE + DWORD gle = GetLastError(); + + AFSDbgPrint( L"NPGetResourceInformation Failed to get connection info from file system for local %s gle 0x%x\n", + lpNetResource->lpRemoteName, gle); +#endif + try_return( dwStatus = WN_BAD_NETNAME); + } + + uniRemoteName.Length = (USHORT)pConnectCB->RemoteNameLength; + uniRemoteName.MaximumLength = uniRemoteName.Length; + uniRemoteName.Buffer = pConnectCB->RemoteName; + +#ifdef AFS_DEBUG_TRACE + AFSDbgPrint( L"NPGetResourceInformation For remote name %wZ Scope %08lX Type %08lX Usage %08lX\n", + &uniRemoteName, + pConnectCB->Scope, + pConnectCB->Type, + pConnectCB->Usage); +#endif + + // Determine the space needed for this entry... + + ulRequiredLen = sizeof( NETRESOURCE); + + ulRequiredLen += pConnectCB->RemoteNameLength + sizeof( WCHAR); + + ulRequiredLen += pConnectCB->CommentLength + sizeof( WCHAR); + + ulRequiredLen += cbProviderNameLength + sizeof( WCHAR); + + ulRequiredLen += pConnectCB->RemainingPathLength + sizeof( WCHAR); + + if( pNetResource == NULL || + ulRequiredLen > dwPassedSize) + { + + *lpBufferSize = ulRequiredLen; + + try_return( dwStatus = WN_MORE_DATA); + } + + pStringZone = (PWCHAR) ((char *)lpBuffer + sizeof( NETRESOURCE)); + + pNetResource->dwScope = 0 /* pConnectCB->Scope*/; + pNetResource->dwType = 0 /* pConnectCB->Type */; + + pNetResource->dwDisplayType = pConnectCB->DisplayType; + + pNetResource->dwUsage = pConnectCB->Usage; + + pNetResource->lpLocalName = NULL; + + // copy remote name + pNetResource->lpRemoteName = pStringZone; + + CopyMemory( pStringZone, + pConnectCB->RemoteName, + pConnectCB->RemoteNameLength); + + pStringZone += (pConnectCB->RemoteNameLength / sizeof(WCHAR)); + + *pStringZone++ = L'\0'; + + // copy comment + pNetResource->lpComment = pStringZone; + + CopyMemory( pStringZone, + (void *)((char *)pConnectCB + pConnectCB->CommentOffset), + pConnectCB->CommentLength); + + pStringZone += (pConnectCB->CommentLength / sizeof(WCHAR)); + + *pStringZone++ = L'\0'; + + // copy remaining path + if (pConnectCB->RemainingPathLength > 0) + { + *lplpSystem = pStringZone; + + CopyMemory( pStringZone, + (void *)((char *)pConnectCB + pConnectCB->RemainingPathOffset), + pConnectCB->RemainingPathLength); + + pStringZone += (pConnectCB->RemainingPathLength / sizeof(WCHAR)); + + *pStringZone++ = L'\0'; + +#ifdef AFS_DEBUG_TRACE + AFSDbgPrint( L"NPGetResourceInformation For remote name %s returning remaining path %s\n", + pNetResource->lpRemoteName, + *lplpSystem); +#endif + } + + // copy provider name + pNetResource->lpProvider = pStringZone; + + StringCbCopy( pStringZone, + cbProviderNameLength + sizeof( WCHAR), + wszProviderName); + + pStringZone += (cbProviderNameLength / sizeof( WCHAR) + 1); + + *lpBufferSize = ulRequiredLen; + + dwStatus = WN_SUCCESS; + +try_exit: + + if ( hControlDevice != NULL) + { + + CloseHandle( hControlDevice); + } + + if( pConnectCB != NULL) + { + + HeapFree( GetProcessHeap( ), 0, (PVOID) pConnectCB); + } + } + + return dwStatus; +} + +static VOID +SeparateRemainingPath( WCHAR * lpConnectionName, WCHAR **lppRemainingPath) +{ + WCHAR *pwch; + WCHAR wch1, wch2; + DWORD dwCount; + + // + // at this point the lpConnectionName contains the full name. We need to + // truncate it to \\server\share and move the remaining path back one position. + // + + for ( pwch = lpConnectionName, dwCount = 0; *pwch; pwch++) + { + if ( *pwch == L'\\') + { + dwCount++; + } + + if ( dwCount == 4) + { + break; + } + } + + if (*pwch == L'\\') + { + // + // Found the remaining path that must be moved + // + + *lppRemainingPath = pwch + 1; + + *pwch++ = 0; + + // + // Find the end + // + for ( ; *pwch; pwch++); + + // + // and work backwards moving the string + // and then make sure that there is at least + // a path separator. + // + + *(pwch + 1) = 0; + + for ( ;pwch > *lppRemainingPath; pwch--) + { + *pwch = *(pwch - 1); + } + + *pwch = L'\\'; + } +} + +DWORD APIENTRY +NPGetUniversalName( LPCWSTR lpLocalPath, + DWORD dwInfoLevel, + LPVOID lpBuffer, + LPDWORD lpBufferSize ) +{ + DWORD dwStatus = WN_NOT_CONNECTED; + WCHAR wchLocalName[3]; + WCHAR wchSubstName[MAX_PATH + 1]; + AFSNetworkProviderConnectionCB *pConnectCB = NULL; + DWORD dwError = 0; + DWORD dwBufferSize = 0; + DWORD dwPassedSize = *lpBufferSize; + DWORD dwRemainingLength = *lpBufferSize; + HANDLE hControlDevice = NULL; + DWORD dwLocalPathLength = 0; + DWORD dwRemainingPathLength = 0; + CHAR *pch; + + __Enter + { + +#ifdef AFS_DEBUG_TRACE + AFSDbgPrint( L"NPGetUniversalName local path %s level 0x%X\n", + lpLocalPath ? lpLocalPath : L"(Null)", + dwInfoLevel); +#endif + + if ( NPIsFSDisabled()) + { + +#ifdef AFS_DEBUG_TRACE + AFSDbgPrint( L"NPGetUniversalName AFSRDFS is disabled, returning WN_NOT_CONNECTED\n"); +#endif + + try_return( dwStatus = WN_NOT_CONNECTED); + } + + dwLocalPathLength = lstrlen( lpLocalPath); + + dwRemainingPathLength = dwLocalPathLength - 2; // no drive letter + + if( dwLocalPathLength == 0) + { + +#ifdef AFS_DEBUG_TRACE + AFSDbgPrint( L"NPGetUniversalName AFSRDFS is disabled, returning WN_BAD_LOCALNAME\n"); +#endif + + try_return( dwStatus = WN_BAD_LOCALNAME); + } + + if( lpBuffer == NULL || + lpBufferSize == NULL) + { +#ifdef AFS_DEBUG_TRACE + AFSDbgPrint( L"NPGetUniversalName No output buffer or size\n"); +#endif + try_return( dwStatus = WN_BAD_VALUE); + } + + memset(lpBuffer, 0, dwPassedSize); + + if ( !DriveSubstitution( lpLocalPath, wchSubstName, sizeof( wchSubstName))) + { + wchLocalName[0] = towupper(lpLocalPath[0]); + wchLocalName[1] = L':'; + wchLocalName[2] = L'\0'; + +#ifdef AFS_DEBUG_TRACE + AFSDbgPrint( L"NPGetUniversalName Requesting UNC for %s level 0x%X\n", + wchLocalName, + dwInfoLevel); +#endif + } + else + { + + ReadServerNameString(); + + if ( wchSubstName[0] != L'\\' && + wchSubstName[1] == L':') + { + + wchLocalName[0] = towupper(wchSubstName[0]); + wchLocalName[1] = L':'; + wchLocalName[2] = L'\0'; + +#ifdef AFS_DEBUG_TRACE + AFSDbgPrint( L"NPGetUniversalName Requesting UNC for drive substitution %s -> %s\n", + wchSubstName, + wchLocalName); +#endif + } + else if ( _wcsnicmp( wchSubstName, wszServerNameUNC, cbServerNameUNCLength / sizeof( WCHAR)) == 0 && + ( wchSubstName[cbServerNameUNCLength / sizeof( WCHAR)] == L'\\' || + wchSubstName[cbServerNameUNCLength / sizeof( WCHAR)] == 0)) + { + HRESULT hr; + +#ifdef AFS_DEBUG_TRACE + AFSDbgPrint( L"NPGetUniversalName drive substitution %s is AFS; Level 0x%x BufferSize 0x%x\n", + wchSubstName, + dwInfoLevel, + dwPassedSize); +#endif + + dwBufferSize = (wcslen( wchSubstName) + 1) * sizeof( WCHAR); + + switch( dwInfoLevel) + { + + case UNIVERSAL_NAME_INFO_LEVEL: + { + + UNIVERSAL_NAME_INFO *pUniversalInfo = (UNIVERSAL_NAME_INFO *)lpBuffer; + + *lpBufferSize = sizeof( UNIVERSAL_NAME_INFO) + dwBufferSize; + + if( dwPassedSize <= sizeof( UNIVERSAL_NAME_INFO)) + { + +#ifdef AFS_DEBUG_TRACE + AFSDbgPrint( L"NPGetUniversalName (UNIVERSAL_NAME_INFO) WN_MORE_DATA\n"); +#endif + + try_return( dwStatus = WN_MORE_DATA); + } + + dwRemainingLength -= sizeof( UNIVERSAL_NAME_INFO); + + pUniversalInfo->lpUniversalName = (LPTSTR)((char *)lpBuffer + sizeof( UNIVERSAL_NAME_INFO)); + + memcpy( pUniversalInfo->lpUniversalName, + wchSubstName, + min( dwBufferSize, dwRemainingLength)); + + dwRemainingLength -= min( dwBufferSize, dwRemainingLength); + +#ifdef AFS_DEBUG_TRACE + AFSDbgPrint( L"NPGetUniversalName (UNIVERSAL_NAME_INFO_LEVEL) lpBuffer: %p Name: (%p) \"%s\"\n", + lpBuffer, + pUniversalInfo->lpUniversalName, + pUniversalInfo->lpUniversalName); +#endif + + if ( dwPassedSize < *lpBufferSize) + { + + try_return( dwStatus = WN_MORE_DATA); + } + + try_return( dwStatus = WN_SUCCESS); + } + + case REMOTE_NAME_INFO_LEVEL: + { + + REMOTE_NAME_INFO *pRemoteInfo = (REMOTE_NAME_INFO *)lpBuffer; + + *lpBufferSize = sizeof( REMOTE_NAME_INFO) + 2 * dwBufferSize + sizeof( WCHAR); + + if( dwPassedSize <= sizeof( REMOTE_NAME_INFO)) + { + +#ifdef AFS_DEBUG_TRACE + AFSDbgPrint( L"NPGetUniversalName (REMOTE_NAME_INFO) WN_MORE_DATA\n"); +#endif + + try_return( dwStatus = WN_MORE_DATA); + } + + dwRemainingLength -= sizeof( REMOTE_NAME_INFO); + + pRemoteInfo->lpUniversalName = (LPTSTR)((char *)lpBuffer + sizeof( REMOTE_NAME_INFO)); + + memcpy( pRemoteInfo->lpUniversalName, + wchSubstName, + min( dwRemainingLength, dwBufferSize)); + + dwRemainingLength -= min( dwRemainingLength, dwBufferSize); + +#ifdef AFS_DEBUG_TRACE + AFSDbgPrint( L"NPGetUniversalName (REMOTE_NAME_INFO_LEVEL) UNI lpBuffer: %p Name: (%p) \"%s\"\n", + lpBuffer, + pRemoteInfo->lpUniversalName, + pRemoteInfo->lpUniversalName); +#endif + + if ( dwRemainingLength > dwBufferSize + sizeof( WCHAR)) + { + pRemoteInfo->lpConnectionName = (LPTSTR)((char *)pRemoteInfo->lpUniversalName + dwBufferSize); + + memcpy( pRemoteInfo->lpConnectionName, + wchSubstName, + min( dwRemainingLength, dwBufferSize)); + + dwRemainingLength -= min( dwRemainingLength, dwBufferSize) - sizeof( WCHAR); + + SeparateRemainingPath( pRemoteInfo->lpConnectionName, + &pRemoteInfo->lpRemainingPath); + } + +#ifdef AFS_DEBUG_TRACE + AFSDbgPrint( L"NPGetUniversalName (REMOTE_NAME_INFO_LEVEL) CONN lpBuffer: %p Name: (%p) \"%s\"\n", + lpBuffer, + pRemoteInfo->lpConnectionName, + pRemoteInfo->lpConnectionName ? pRemoteInfo->lpConnectionName : L"(null)"); + + AFSDbgPrint( L"NPGetUniversalName (REMOTE_NAME_INFO_LEVEL) REMAIN lpBuffer: %p Name: (%p) \"%s\"\n", + lpBuffer, + pRemoteInfo->lpRemainingPath, + pRemoteInfo->lpRemainingPath ? pRemoteInfo->lpRemainingPath : L"(null)"); +#endif + + if ( dwPassedSize < *lpBufferSize) + { + + try_return( dwStatus = WN_MORE_DATA); + } + + try_return( dwStatus = WN_SUCCESS); + } + + default: +#ifdef AFS_DEBUG_TRACE + AFSDbgPrint( L"NPGetUniversalName (UNKNOWN: 0x%X) WN_BAD_VALUE\n", + dwInfoLevel); +#endif + try_return( dwStatus = WN_BAD_VALUE); + } + } + else + { + +#ifdef AFS_DEBUG_TRACE + AFSDbgPrint( L"NPGetUniversalName drive substitution %s is not AFS\n", + wchSubstName); +#endif + try_return( dwStatus = WN_NOT_CONNECTED); + } + } + + dwBufferSize = 0x1000; + + pConnectCB = (AFSNetworkProviderConnectionCB *)HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwBufferSize); + + if( pConnectCB == NULL) + { + try_return( dwStatus = WN_OUT_OF_MEMORY); + } + + pConnectCB->LocalName = towupper(wchLocalName[0]); + + pConnectCB->RemoteNameLength = 0; + + pConnectCB->Version = AFS_NETWORKPROVIDER_INTERFACE_VERSION_1; + + pConnectCB->AuthenticationId = AFSRetrieveAuthId(); + +#ifdef AFS_DEBUG_TRACE + AFSDbgPrint( L"NPGetUniversalName Retrieved authentication id %08lX-%08lX\n", + pConnectCB->AuthenticationId.HighPart, + pConnectCB->AuthenticationId.LowPart); +#endif + + hControlDevice = OpenRedirector(); + + if( hControlDevice == NULL) + { + + try_return( dwStatus = WN_NET_ERROR); + } + + dwError = DeviceIoControl( hControlDevice, + IOCTL_AFS_GET_CONNECTION, + pConnectCB, + dwBufferSize, + pConnectCB, + dwBufferSize, + &dwBufferSize, + NULL); + + if( !dwError) + { +#ifdef AFS_DEBUG_TRACE + DWORD gle = GetLastError(); + + AFSDbgPrint( L"NPGetUniversalName Failed to get connection from file system for local %s gle 0x%x\n", + wchLocalName, gle); +#endif + try_return( dwStatus = WN_NOT_CONNECTED); + } + + switch( dwInfoLevel) + { + + case UNIVERSAL_NAME_INFO_LEVEL: + { + + UNIVERSAL_NAME_INFO *pUniversalInfo = (UNIVERSAL_NAME_INFO *)lpBuffer; + + *lpBufferSize = sizeof( UNIVERSAL_NAME_INFO) + dwBufferSize + sizeof( WCHAR); + + *lpBufferSize += dwRemainingPathLength * sizeof( WCHAR); + + if( dwPassedSize <= sizeof( UNIVERSAL_NAME_INFO)) + { + +#ifdef AFS_DEBUG_TRACE + AFSDbgPrint( L"NPGetUniversalName (UNIVERSAL_NAME_INFO) WN_MORE_DATA\n"); +#endif + + try_return( dwStatus = WN_MORE_DATA); + } + + dwRemainingLength -= sizeof( UNIVERSAL_NAME_INFO); + + pUniversalInfo->lpUniversalName = (LPTSTR)((char *)lpBuffer + sizeof( UNIVERSAL_NAME_INFO)); + + pch = (char *)pUniversalInfo->lpUniversalName; + + memcpy( pch, + pConnectCB, + min( dwBufferSize, dwRemainingLength)); + + pch += min( dwBufferSize, dwRemainingLength); + + dwRemainingLength -= min( dwBufferSize + sizeof(WCHAR), dwRemainingLength); + + memcpy( pch, + &lpLocalPath[2], + min(dwRemainingPathLength * sizeof( WCHAR), dwRemainingLength)); + + pch += min(dwRemainingPathLength * sizeof( WCHAR), dwRemainingLength); + + dwRemainingLength -= min(dwRemainingPathLength * sizeof( WCHAR), dwRemainingLength); + +#ifdef AFS_DEBUG_TRACE + AFSDbgPrint( L"NPGetUniversalName (UNIVERSAL_NAME_INFO_LEVEL) lpBuffer: %p Name: (%p) \"%s\"\n", + lpBuffer, + pUniversalInfo->lpUniversalName, + pUniversalInfo->lpUniversalName); +#endif + + if ( dwPassedSize < *lpBufferSize) + { + + try_return( dwStatus = WN_MORE_DATA); + } + + try_return( dwStatus = WN_SUCCESS); + } + + case REMOTE_NAME_INFO_LEVEL: + { + + REMOTE_NAME_INFO *pRemoteInfo = (REMOTE_NAME_INFO *)lpBuffer; + + *lpBufferSize = sizeof( REMOTE_NAME_INFO) + (2 * dwBufferSize + sizeof( WCHAR)) + 2 * sizeof( WCHAR); + + *lpBufferSize += 2 * dwRemainingPathLength * sizeof( WCHAR); + + if( dwPassedSize <= sizeof( REMOTE_NAME_INFO)) + { + +#ifdef AFS_DEBUG_TRACE + AFSDbgPrint( L"NPGetUniversalName (REMOTE_NAME_INFO) WN_MORE_DATA\n"); +#endif + + try_return( dwStatus = WN_MORE_DATA); + } + + dwRemainingLength -= sizeof( REMOTE_NAME_INFO); + + pRemoteInfo->lpUniversalName = (LPTSTR)((char *)lpBuffer + sizeof( REMOTE_NAME_INFO)); + + pch = (char *)pRemoteInfo->lpUniversalName; + + memcpy( pch, + pConnectCB, + min( dwBufferSize, dwRemainingLength)); + + pch += min( dwBufferSize, dwRemainingLength); + + dwRemainingLength -= min( dwBufferSize + sizeof( WCHAR), dwRemainingLength); + + memcpy( pch, + &lpLocalPath[2], + min(dwRemainingPathLength * sizeof( WCHAR), dwRemainingLength)); + + pch += min((dwRemainingPathLength + 1) * sizeof( WCHAR), dwRemainingLength); + + dwRemainingLength -= min((dwRemainingPathLength + 1) * sizeof( WCHAR), dwRemainingLength); + +#ifdef AFS_DEBUG_TRACE + AFSDbgPrint( L"NPGetUniversalName (REMOTE_NAME_INFO_LEVEL) UNI lpBuffer: %p Name: (%p) \"%s\"\n", + lpBuffer, + pRemoteInfo->lpUniversalName, + pRemoteInfo->lpUniversalName); +#endif + + if ( dwRemainingLength > dwBufferSize + sizeof( WCHAR)) + { + pRemoteInfo->lpConnectionName = (LPWSTR)pch; + + memcpy( pch, + pConnectCB, + min( dwBufferSize, dwRemainingLength)); + + pch += min( dwBufferSize + sizeof( WCHAR), dwRemainingLength); + + dwRemainingLength -= min( dwBufferSize + sizeof( WCHAR), dwRemainingLength); + } + + + if ( dwRemainingLength > dwRemainingPathLength + sizeof( WCHAR)) + { + pRemoteInfo->lpRemainingPath = (LPWSTR)pch; + + memcpy( pch, + &lpLocalPath[2], + min((dwRemainingPathLength + 1) * sizeof( WCHAR), dwRemainingLength)); + + pch += min((dwRemainingPathLength + 1) * sizeof( WCHAR), dwRemainingLength); + + dwRemainingLength -= min((dwLocalPathLength + 1) * sizeof( WCHAR), dwRemainingLength); + } + +#ifdef AFS_DEBUG_TRACE + AFSDbgPrint( L"NPGetUniversalName (REMOTE_NAME_INFO_LEVEL) CONN lpBuffer: %p Name: (%p) \"%s\"\n", + lpBuffer, + pRemoteInfo->lpConnectionName, + pRemoteInfo->lpConnectionName ? pRemoteInfo->lpConnectionName : L"(null)"); + + AFSDbgPrint( L"NPGetUniversalName (REMOTE_NAME_INFO_LEVEL) REMAIN lpBuffer: %p Name: (%p) \"%s\"\n", + lpBuffer, + pRemoteInfo->lpRemainingPath, + pRemoteInfo->lpRemainingPath ? pRemoteInfo->lpRemainingPath : L"(null)"); +#endif + + if ( dwPassedSize < *lpBufferSize) + { + + try_return( dwStatus = WN_MORE_DATA); + } + + try_return( dwStatus = WN_SUCCESS); + } + + default: +#ifdef AFS_DEBUG_TRACE + AFSDbgPrint( L"NPGetUniversalName (UNKNOWN: 0x%X) WN_BAD_VALUE\n", + dwInfoLevel); +#endif + try_return( dwStatus = WN_BAD_VALUE); + } + +try_exit: + +#ifdef AFS_DEBUG_TRACE + AFSDbgPrint( L"NPGetUniversalName BufferSize 0x%X\n", + *lpBufferSize); +#endif + if ( hControlDevice != NULL) + { + + CloseHandle( hControlDevice); + } + + if( pConnectCB != NULL) + { + + HeapFree( GetProcessHeap( ), 0, (PVOID) pConnectCB); + } + } + + return dwStatus; +} + + +static LPCWSTR +GetFormatFlags( DWORD dwFlags) +{ + static WCHAR Buffer[128] = L""; + + // + // WNFMT_MULTILINE 0x01 + // WNFMT_ABBREVIATED 0x02 + // WNFMT_INENUM 0x10 + // WNFMT_CONNECTION 0x20 + // + + Buffer[0] = L'\0'; + + if ( dwFlags & WNFMT_MULTILINE ) + { + StringCbCat( Buffer, sizeof(Buffer), L"MULTILINE|"); + } + + if ( dwFlags & WNFMT_INENUM ) + { + StringCbCat( Buffer, sizeof(Buffer), L"ABBREVIATED|"); + } + + if ( dwFlags & WNFMT_INENUM ) + { + StringCbCat( Buffer, sizeof(Buffer), L"INENUM|"); + } + + if ( dwFlags & WNFMT_CONNECTION ) + { + StringCbCat( Buffer, sizeof(Buffer), L"CONNECTION|"); + } + + if ( dwFlags & ~(WNFMT_MULTILINE|WNFMT_ABBREVIATED|WNFMT_INENUM|WNFMT_CONNECTION) ) + { + StringCbCat( Buffer, sizeof(Buffer), L"UNKNOWN|"); + } + + Buffer[lstrlen(Buffer)-1] = L'\0'; + + return Buffer; +} + +DWORD +NPFormatNetworkName( LPTSTR lpRemoteName, + LPTSTR lpFormattedName, + LPDWORD lpnLength, + DWORD dwFlags, + DWORD dwAveCharPerLine) +{ + + DWORD dwLen = 0, dwCurrentLen = 0; + LPTSTR pCurrentName = lpRemoteName; + +#ifdef AFS_DEBUG_TRACE + AFSDbgPrint( L"NPFormatNetworkName Remote %s Flags %s (0x%x) CharsPerLine %u\n", + lpRemoteName, + dwFlags, + GetFormatFlags( dwFlags), + dwAveCharPerLine); +#endif + + + // + // Walk back in the name until we hit a \ + // + + dwLen = wcslen( lpRemoteName); + + pCurrentName += (dwLen - 1); + + if ( pCurrentName[ 0] != L'\\') + { + + while( dwLen > 0) + { + + if( pCurrentName[ 0] == L'\\') + { + + pCurrentName++; + + break; + } + + pCurrentName--; + + dwLen--; + + dwCurrentLen++; + } + } + + if( *lpnLength < dwCurrentLen * sizeof( WCHAR)) + { + + *lpnLength = dwCurrentLen * sizeof( WCHAR); + +#ifdef AFS_DEBUG_TRACE + AFSDbgPrint( L"NPFormatNetworkName remote name %s WN_MORE_DATA\n", + lpRemoteName); +#endif + + return WN_MORE_DATA; + } + + StringCbCopy( lpFormattedName, + *lpnLength, + pCurrentName); + + *lpnLength = dwCurrentLen * sizeof( WCHAR); + +#ifdef AFS_DEBUG_TRACE + AFSDbgPrint( L"NPFormatNetworkName remote name %s as %s\n", + lpRemoteName, + lpFormattedName); +#endif + + return WN_SUCCESS; +} + +/************************************************************ +/ Unsupported entry points +/************************************************************/ + +// +// AuthGroup processing is implemented in src/WINNT/afsd/afslogon.c +// +DWORD APIENTRY +NPLogonNotify( + PLUID lpLogonId, + LPCWSTR lpAuthentInfoType, + LPVOID lpAuthentInfo, + LPCWSTR lpPreviousAuthentInfoType, + LPVOID lpPreviousAuthentInfo, + LPWSTR lpStationName, + LPVOID StationHandle, + LPWSTR *lpLogonScript) +{ + +#ifdef AFS_DEBUG_TRACE + AFSDbgPrint( L"NPLogonNotify, returning WN_NOT_SUPPORTED\n"); +#endif + + return WN_NOT_SUPPORTED; +} + +DWORD APIENTRY +NPPasswordChangeNotify ( + LPCWSTR lpAuthentInfoType, + LPVOID lpAuthentInfo, + LPCWSTR lpPreviousAuthentInfoType, + LPVOID lpPreviousAuthentInfo, + LPWSTR lpStationName, + LPVOID StationHandle, + DWORD dwChangeInfo ) +{ + +#ifdef AFS_DEBUG_TRACE + AFSDbgPrint( L"NPPasswordChangeNotify, returning WN_NOT_SUPPORTED\n"); +#endif + + SetLastError( WN_NOT_SUPPORTED ); + + return WN_NOT_SUPPORTED; +} + +DWORD APIENTRY +NPGetUser( LPTSTR lpName, + LPTSTR lpUserName, + LPDWORD lpBufferSize) +{ + + DWORD rc = WN_NOT_SUPPORTED; + + AFSDbgPrint( L"NPGetUser Entry Name %s\n", lpName); + + return rc; +} + + +DWORD +APIENTRY +NPGetReconnectFlags( LPWSTR lpRemoteName, + unsigned char *Parameter2) +{ + + DWORD dwStatus = WN_NOT_SUPPORTED; + + AFSDbgPrint( L"NPGetReconnectFlags RemoteName %s\n", + lpRemoteName); + + return dwStatus; +} + + +DWORD +APIENTRY +I_SystemFocusDialog( VOID) +{ + + DWORD dwStatus = WN_NOT_SUPPORTED; + + AFSDbgPrint( L"I_SystemFocusDialog\n"); + + return dwStatus; +} + +/************************************************************ +/ END Unsupported entry points +/************************************************************/ + + +HANDLE +OpenRedirector() +{ + + HANDLE hControlDevice = NULL; + WCHAR wchError[ 256]; + + hControlDevice = CreateFile( AFS_SYMLINK_W, + GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + 0, + NULL ); + + if( hControlDevice == INVALID_HANDLE_VALUE) + { + + hControlDevice = NULL; +#ifdef AFS_DEBUG_TRACE + AFSDbgPrint( L"Failed to open control device error: %d\n", + GetLastError()); +#endif + } +#if 0 + // + // only do this if you want network shares to fail to mount + // when the file system is not yet ready + // + else { + + AFSDriverStatusRespCB respCB; + DWORD dwBytes; + + memset( &respCB, '\0', sizeof( AFSDriverStatusRespCB)); + + if ( !DeviceIoControl( hControlDevice, + IOCTL_AFS_STATUS_REQUEST, + NULL, + 0, + (void *)&respCB, + sizeof( AFSDriverStatusRespCB), + &dwBytes, + NULL) || + dwBytes != sizeof(AFSDriverStatusRespCB) || + respCB.Status != AFS_DRIVER_STATUS_READY ) + { + + CloseHandle( hControlDevice); + + hControlDevice = NULL; + } + } +#endif + + return hControlDevice; +} + +LARGE_INTEGER +AFSRetrieveAuthId() +{ + + LARGE_INTEGER liAuthId = {0,0}; + HANDLE hToken = NULL; + TOKEN_STATISTICS stTokenInfo; + DWORD dwCopyBytes = 0; + + if ( !OpenThreadToken( GetCurrentThread(), + TOKEN_QUERY, + FALSE, // Impersonation + &hToken)) + { + if( !OpenProcessToken( GetCurrentProcess(), + TOKEN_QUERY, + &hToken)) + { + +#ifdef AFS_DEBUG_TRACE + AFSDbgPrint( L"AFSRetrieveAuthId Failed to retrieve Thread and Process tokens 0x%X\n", + GetLastError()); +#endif + } + else + { + +#ifdef AFS_DEBUG_TRACE + AFSDbgPrint( L"AFSRetrieveAuthId Retrieved Process Token\n"); +#endif + } + } + else + { + +#ifdef AFS_DEBUG_TRACE + AFSDbgPrint( L"AFSRetrieveAuthId Retrieved Thread Token\n"); +#endif + } + + if ( hToken != NULL) + { + + if( !GetTokenInformation( hToken, + TokenStatistics, + &stTokenInfo, + sizeof( TOKEN_STATISTICS), + &dwCopyBytes)) + { + +#ifdef AFS_DEBUG_TRACE + AFSDbgPrint( L"AFSRetrieveAuthId Failed to retrieve token information 0x%X\n", + GetLastError()); +#endif + } + else + { + + liAuthId.HighPart = stTokenInfo.AuthenticationId.HighPart; + liAuthId.LowPart = stTokenInfo.AuthenticationId.LowPart; + } + + CloseHandle( hToken); + } + + return liAuthId; +} + +static BOOL +Debug(void) +{ + static int init = 0; + static BOOL debug = 0; + + if ( !init ) { + HKEY hk; + + if (RegOpenKey (HKEY_LOCAL_MACHINE, + TEXT("SYSTEM\\CurrentControlSet\\Services\\AFSRedirector\\NetworkProvider"), &hk) == 0) + { + DWORD dwSize = sizeof(BOOL); + DWORD dwType = REG_DWORD; + RegQueryValueEx (hk, TEXT("Debug"), NULL, &dwType, (PBYTE)&debug, &dwSize); + RegCloseKey (hk); + } + init = 1; + } + + return debug; +} + +ULONG +_cdecl +AFSDbgPrint( + PWCHAR Format, + ... + ) +{ + HRESULT rc = S_OK; + WCHAR wszbuffer[512]; + va_list marker; + + if ( !Debug() ) + return 0; + + va_start( marker, Format ); + { + StringCbPrintf( wszbuffer, sizeof(wszbuffer), L"[%d-%08X] ", +#ifdef AMD64 + 64, +#else + 32, +#endif + GetCurrentThreadId()); + + rc = StringCbVPrintfW( &wszbuffer[ 14], sizeof(wszbuffer) - 14, Format, marker); + + if (SUCCEEDED(rc)) + OutputDebugString( wszbuffer ); + else + OutputDebugString(L"AFSDbgPrint Failed to create string\n"); + } + return SUCCEEDED(rc) ? 1 : 0; +} diff --git a/src/WINNT/afsrdr/npdll/AFS_Npdll.h b/src/WINNT/afsrdr/npdll/AFS_Npdll.h new file mode 100644 index 0000000000..4e4cbb5f1b --- /dev/null +++ b/src/WINNT/afsrdr/npdll/AFS_Npdll.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2008 Kernel Drivers, LLC. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, + * this list of conditions and the following disclaimer in the + * documentation + * and/or other materials provided with the distribution. + * - Neither the name of Kernel Drivers, LLC nor the names of its + * contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission from Kernel Drivers, LLC. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +void ReadProviderNameString( void); diff --git a/src/WINNT/afsrdr/npdll/AFS_Npdll.rc b/src/WINNT/afsrdr/npdll/AFS_Npdll.rc new file mode 100644 index 0000000000..77a014436c --- /dev/null +++ b/src/WINNT/afsrdr/npdll/AFS_Npdll.rc @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2008, 2009, 2010, 2011 Kernel Drivers, LLC. + * Copyright (c) 2009, 2010, 2011 Your File System, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, + * this list of conditions and the following disclaimer in the + * documentation + * and/or other materials provided with the distribution. + * - Neither the names of Kernel Drivers, LLC and Your File System, Inc. + * nor the names of their contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission from Kernel Drivers, LLC and Your File System, Inc. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* Define VERSIONINFO resource */ + +#define AFS_VERINFO_FILE_DESCRIPTION "AFS Redirector Network Provider" +#define AFS_VERINFO_NAME "AFSRDFSProvider" +#define AFS_VERINFO_FILENAME "AFSRDFSProvider.dll" + +#include "..\AFS_component_version_number.h" +#include "..\..\..\config\NTVersioninfo.rc" diff --git a/src/WINNT/afsrdr/npdll/AFS_NpdllMain.C b/src/WINNT/afsrdr/npdll/AFS_NpdllMain.C new file mode 100644 index 0000000000..ef1d6b912c --- /dev/null +++ b/src/WINNT/afsrdr/npdll/AFS_NpdllMain.C @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2008, 2009, 2010, 2011 Kernel Drivers, LLC. + * Copyright (c) 2009, 2010, 2011 Your File System, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, + * this list of conditions and the following disclaimer in the + * documentation + * and/or other materials provided with the distribution. + * - Neither the names of Kernel Drivers, LLC and Your File System, Inc. + * nor the names of their contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission from Kernel Drivers, LLC and Your File System, Inc. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#define _DECL_DLLMAIN +#include +#include "AFS_Npdll.h" + +// NOTE: +// +// Function: DllMain +// +// Return: TRUE => Success +// FALSE => Failure + +BOOL +WINAPI +DllMain( HINSTANCE hDLLInst, + DWORD fdwReason, + LPVOID lpvReserved) +{ + BOOL bStatus = TRUE; + WORD wVersionRequested; + + switch( fdwReason) + { + + case DLL_PROCESS_ATTACH: + ReadProviderNameString(); + break; + + case DLL_PROCESS_DETACH: + break; + + case DLL_THREAD_ATTACH: + break; + + case DLL_THREAD_DETACH: + break; + + default: + break; + } + + return( bStatus); +} diff --git a/src/WINNT/afsrdr/npdll/SOURCES b/src/WINNT/afsrdr/npdll/SOURCES new file mode 100644 index 0000000000..0baa11051a --- /dev/null +++ b/src/WINNT/afsrdr/npdll/SOURCES @@ -0,0 +1,31 @@ + +TARGETNAME=AFSRDFSProvider +TARGETPATH=..\build +TARGETTYPE=DYNLINK + +TARGETLIBS=$(DDK_LIB_PATH)\user32.lib \ + $(DDK_LIB_PATH)\kernel32.lib \ + $(DDK_LIB_PATH)\Advapi32.lib + + +UNICODE=1 +NET_C_DEFINES=-DUNICODE + +DLLBASE=0x1010000 + +USE_NTDLL=0 + +!IF $(FREEBUILD) +C_DEFINES=$(C_DEFINES) +!endif + +INCLUDES=$(IFSKIT_INC_PATH);..\Common; + +SOURCES= AFS_NpdllMain.c \ + AFS_Npdll.c \ + AFS_Npdll.rc + +UMTYPE=console +OPTIONAL_NTTEST= + +DLLDEF=AFS_Npdll.def diff --git a/src/WINNT/afsrdr/npdll/tests/enumresources.c b/src/WINNT/afsrdr/npdll/tests/enumresources.c new file mode 100644 index 0000000000..06036e8070 --- /dev/null +++ b/src/WINNT/afsrdr/npdll/tests/enumresources.c @@ -0,0 +1,322 @@ +/* + * This test code was obtained from + * http://msdn.microsoft.com/en-us/library/aa385341(VS.85).aspx + * + * No license specified. + */ + +#pragma comment(lib, "mpr.lib") + +#ifndef UNICODE +#define UNICODE +#endif + +#include +#include +#include + +BOOL WINAPI EnumerateFunc(DWORD dwScope, LPNETRESOURCE lpnr); +void DisplayStruct(int i, LPNETRESOURCE lpnrLocal); +BOOL WINAPI NetErrorHandler(HWND hwnd, DWORD dwErrorCode, LPSTR lpszFunction); + +int main() +{ + + LPNETRESOURCE lpnr = NULL; + + printf("Connected Resources\n"); + printf("-------------------\n"); + if (EnumerateFunc(RESOURCE_CONNECTED, lpnr) == FALSE) { + printf("Call to EnumerateFunc(CONNECTED) failed\n"); + return 1; + } + + printf("\n"); + printf("Context Resources\n"); + printf("-----------------\n"); + if (EnumerateFunc(RESOURCE_CONTEXT, lpnr) == FALSE) { + printf("Call to EnumerateFunc(CONTEXT) failed\n"); + return 1; + } + + printf("\n"); + printf("Global Resources\n"); + printf("----------------\n"); + if (EnumerateFunc(RESOURCE_GLOBALNET, lpnr) == FALSE) { + printf("Call to EnumerateFunc(GLOBALNET) failed\n"); + return 1; + } + + printf("\n"); + printf("Remembered Resources\n"); + printf("--------------------\n"); + if (EnumerateFunc(RESOURCE_REMEMBERED, lpnr) == FALSE) { + printf("Call to EnumerateFunc(REMEMBERED) failed\n"); + return 1; + } + + return 0; +} + +BOOL WINAPI EnumerateFunc(DWORD dwScope, LPNETRESOURCE lpnr) +{ + DWORD dwResult, dwResultEnum; + HANDLE hEnum; + DWORD cbBuffer = 16384; // 16K is a good size + DWORD cEntries = -1; // enumerate all possible entries + LPNETRESOURCE lpnrLocal; // pointer to enumerated structures + DWORD i; + // + // Call the WNetOpenEnum function to begin the enumeration. + // + dwResult = WNetOpenEnum(dwScope, // all network resources + RESOURCETYPE_DISK, // all resources + RESOURCEUSAGE_ALL, // enumerate all resources + lpnr, // NULL first time the function is called + &hEnum); // handle to the resource + + if (dwResult != NO_ERROR) { + printf("WnetOpenEnum failed with error %d\n", dwResult); + return FALSE; + } + // + // Call the GlobalAlloc function to allocate resources. + // + lpnrLocal = (LPNETRESOURCE) GlobalAlloc(GPTR, cbBuffer); + if (lpnrLocal == NULL) { + printf("WnetOpenEnum failed with error %d\n", dwResult); + return FALSE; + } + + do { + // + // Initialize the buffer. + // + ZeroMemory(lpnrLocal, cbBuffer); + // + // Call the WNetEnumResource function to continue + // the enumeration. + // + cEntries = -1; + dwResultEnum = WNetEnumResource(hEnum, // resource handle + &cEntries, // defined locally as -1 + lpnrLocal, // LPNETRESOURCE + &cbBuffer); // buffer size + // + // If the call succeeds, loop through the structures. + // + if (dwResultEnum == NO_ERROR) { + for (i = 0; i < cEntries; i++) { + // Call an application-defined function to + // display the contents of the NETRESOURCE structures. + // + DisplayStruct(i, &lpnrLocal[i]); + + // If the NETRESOURCE structure represents a container resource, + // call the EnumerateFunc function recursively. + + if (dwScope == RESOURCE_GLOBALNET && + RESOURCEUSAGE_CONTAINER == (lpnrLocal[i].dwUsage + & RESOURCEUSAGE_CONTAINER)) + if (!EnumerateFunc(dwScope, &lpnrLocal[i])) + printf("EnumerateFunc returned FALSE\n"); + } + } + // Process errors. + // + else if (dwResultEnum != ERROR_NO_MORE_ITEMS) { + printf("WNetEnumResource failed with error %d\n", dwResultEnum); + break; + } + } + // + // End do. + // + while (dwResultEnum != ERROR_NO_MORE_ITEMS); + // + // Call the GlobalFree function to free the memory. + // + GlobalFree((HGLOBAL) lpnrLocal); + // + // Call WNetCloseEnum to end the enumeration. + // + dwResult = WNetCloseEnum(hEnum); + + if (dwResult != NO_ERROR) { + // + // Process errors. + // + printf("WNetCloseEnum failed with error %d\n\n", dwResult); +// NetErrorHandler(hwnd, dwResult, (LPSTR)"WNetCloseEnum"); + return FALSE; + } + + return TRUE; +} + +void DisplayStruct(int i, LPNETRESOURCE lpnrLocal) +{ + printf("NETRESOURCE[%d] Scope: ", i); + switch (lpnrLocal->dwScope) { + case (RESOURCE_CONNECTED): + printf("connected\n"); + break; + case (RESOURCE_GLOBALNET): + printf("all resources\n"); + break; + case (RESOURCE_REMEMBERED): + printf("remembered\n"); + break; + case RESOURCE_RECENT: + printf("recent\n"); + break; + case RESOURCE_CONTEXT: + printf("context\n"); + break; + default: + printf("unknown scope %d\n", lpnrLocal->dwScope); + break; + } + + printf("NETRESOURCE[%d] Type: ", i); + switch (lpnrLocal->dwType) { + case (RESOURCETYPE_ANY): + printf("any\n"); + break; + case (RESOURCETYPE_DISK): + printf("disk\n"); + break; + case (RESOURCETYPE_PRINT): + printf("print\n"); + break; + case RESOURCETYPE_RESERVED: + printf("reserved\n"); + break; + default: + printf("unknown type %d\n", lpnrLocal->dwType); + break; + } + + printf("NETRESOURCE[%d] DisplayType: ", i); + switch (lpnrLocal->dwDisplayType) { + case (RESOURCEDISPLAYTYPE_GENERIC): + printf("generic\n"); + break; + case (RESOURCEDISPLAYTYPE_DOMAIN): + printf("domain\n"); + break; + case (RESOURCEDISPLAYTYPE_SERVER): + printf("server\n"); + break; + case (RESOURCEDISPLAYTYPE_SHARE): + printf("share\n"); + break; + case (RESOURCEDISPLAYTYPE_FILE): + printf("file\n"); + break; + case (RESOURCEDISPLAYTYPE_GROUP): + printf("group\n"); + break; + case (RESOURCEDISPLAYTYPE_NETWORK): + printf("network\n"); + break; + case RESOURCEDISPLAYTYPE_ROOT: + printf("root\n"); + break; + case RESOURCEDISPLAYTYPE_SHAREADMIN: + printf("share-admin\n"); + break; + case RESOURCEDISPLAYTYPE_DIRECTORY: + printf("directory\n"); + break; + case RESOURCEDISPLAYTYPE_TREE: + printf("tree\n"); + break; + case RESOURCEDISPLAYTYPE_NDSCONTAINER: + printf("nds-container\n"); + break; + default: + printf("unknown display type %d\n", lpnrLocal->dwDisplayType); + break; + } + + printf("NETRESOURCE[%d] Usage: 0x%x = ", i, lpnrLocal->dwUsage); + if (lpnrLocal->dwUsage & RESOURCEUSAGE_CONNECTABLE) + printf("connectable "); + if (lpnrLocal->dwUsage & RESOURCEUSAGE_CONTAINER) + printf("container "); + if (lpnrLocal->dwUsage & RESOURCEUSAGE_NOLOCALDEVICE) + printf("no-local "); + if (lpnrLocal->dwUsage & RESOURCEUSAGE_SIBLING) + printf("sibling "); + if (lpnrLocal->dwUsage & RESOURCEUSAGE_ATTACHED) + printf("attached "); + if (lpnrLocal->dwUsage & RESOURCEUSAGE_RESERVED) + printf("reserved "); + printf("\n"); + + printf("NETRESOURCE[%d] Localname: %S\n", i, lpnrLocal->lpLocalName); + printf("NETRESOURCE[%d] Remotename: %S\n", i, lpnrLocal->lpRemoteName); + printf("NETRESOURCE[%d] Comment: %S\n", i, lpnrLocal->lpComment); + printf("NETRESOURCE[%d] Provider: %S\n", i, lpnrLocal->lpProvider); + printf("\n"); +} + + +/* +BOOL WINAPI NetErrorHandler(HWND hwnd, + DWORD dwErrorCode, + LPSTR lpszFunction) +{ + DWORD dwWNetResult, dwLastError; + CHAR szError[256]; + CHAR szCaption[256]; + CHAR szDescription[256]; + CHAR szProvider[256]; + + // The following code performs standard error-handling. + + if (dwErrorCode != ERROR_EXTENDED_ERROR) + { + sprintf_s((LPSTR) szError, sizeof(szError), "%s failed; \nResult is %ld", + lpszFunction, dwErrorCode); + sprintf_s((LPSTR) szCaption, sizeof(szCaption), "%s error", lpszFunction); + MessageBox(hwnd, (LPSTR) szError, (LPSTR) szCaption, MB_OK); + return TRUE; + } + + // The following code performs error-handling when the + // ERROR_EXTENDED_ERROR return value indicates that the + // WNetGetLastError function can retrieve additional information. + + else + { + dwWNetResult = WNetGetLastError(&dwLastError, // error code + (LPSTR) szDescription, // buffer for error description + sizeof(szDescription), // size of error buffer + (LPSTR) szProvider, // buffer for provider name + sizeof(szProvider)); // size of name buffer + + // + // Process errors. + // + if(dwWNetResult != NO_ERROR) { + sprintf_s((LPSTR) szError, sizeof(szError), + "WNetGetLastError failed; error %ld", dwWNetResult); + MessageBox(hwnd, (LPSTR) szError, + "WNetGetLastError", MB_OK); + return FALSE; + } + + // + // Otherwise, print the additional error information. + // + sprintf_((LPSTR) szError, sizeof(szError), + "%s failed with code %ld;\n%s", + (LPSTR) szProvider, dwLastError, (LPSTR) szDescription); + sprintf_s((LPSTR) szCaption, sizeof(szCaption), "%s error", lpszFunction); + MessageBox(hwnd, (LPSTR) szError, (LPSTR) szCaption, MB_OK); + return TRUE; + } +} +*/