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; + } +} +*/