/*++ Copyright (c) 1989-1999 Microsoft Corporation Module Name: ifsmrxnp.c Abstract: This module implements the routines required for interaction with network provider router interface in NT Notes: This module has been built and tested only in UNICODE environment --*/ #include #include #include #include #include #include #include #include "nulmrx.h" #ifdef DBG #define DbgP(_x_) WideDbgPrint _x_ #else #define DbgP(_x_) #endif ULONG _cdecl WideDbgPrint( PWCHAR Format, ... ); #define TRACE_TAG L"NULMRXNP: " #define WNNC_DRIVER( major, minor ) ( major * 0x00010000 + minor ) DWORD APIENTRY NPGetCaps( DWORD nIndex ) /*++ Routine Description: This routine returns the capaboilities of the Null Mini redirector network provider implementation Arguments: nIndex - category of capabilities desired Return Value: the appropriate capabilities --*/ { DWORD rc = 0; DbgP(( L"GetNetCaps .....\n" )); switch ( nIndex ) { case WNNC_SPEC_VERSION: rc = WNNC_SPEC_VERSION51; break; case WNNC_NET_TYPE: rc = WNNC_NET_RDR2SAMPLE; break; case WNNC_DRIVER_VERSION: rc = WNNC_DRIVER(1, 0); break; case WNNC_CONNECTION: rc = WNNC_CON_GETCONNECTIONS | WNNC_CON_CANCELCONNECTION | WNNC_CON_ADDCONNECTION | WNNC_CON_ADDCONNECTION3; break; case WNNC_ENUMERATION: rc = WNNC_ENUM_LOCAL; break; case WNNC_START: rc = 1; break; case WNNC_USER: case WNNC_DIALOG: case WNNC_ADMIN: default: rc = 0; break; } return rc; } DWORD APIENTRY NPLogonNotify( PLUID lpLogonId, LPCWSTR lpAuthentInfoType, LPVOID lpAuthentInfo, LPCWSTR lpPreviousAuthentInfoType, LPVOID lpPreviousAuthentInfo, LPWSTR lpStationName, LPVOID StationHandle, LPWSTR *lpLogonScript) /*++ Routine Description: This routine handles the logon notifications Arguments: lpLogonId -- the associated LUID lpAuthenInfoType - the authentication information type lpAuthenInfo - the authentication Information lpPreviousAuthentInfoType - the previous aunthentication information type lpPreviousAuthentInfo - the previous authentication information lpStationName - the logon station name LPVOID - logon station handle lpLogonScript - the logon script to be executed. Return Value: WN_SUCCESS Notes: This capability has not been implemented in the sample. --*/ { *lpLogonScript = NULL; return WN_SUCCESS; } DWORD APIENTRY NPPasswordChangeNotify ( LPCWSTR lpAuthentInfoType, LPVOID lpAuthentInfo, LPCWSTR lpPreviousAuthentInfoType, LPVOID lpPreviousAuthentInfo, LPWSTR lpStationName, LPVOID StationHandle, DWORD dwChangeInfo ) /*++ Routine Description: This routine handles the password change notifications Arguments: lpAuthenInfoType - the authentication information type lpAuthenInfo - the authentication Information lpPreviousAuthentInfoType - the previous aunthentication information type lpPreviousAuthentInfo - the previous authentication information lpStationName - the logon station name LPVOID - logon station handle dwChangeInfo - the password change information. Return Value: WN_NOT_SUPPORTED Notes: This capability has not been implemented in the sample. --*/ { SetLastError( WN_NOT_SUPPORTED ); return WN_NOT_SUPPORTED; } ULONG SendToMiniRdr( IN ULONG IoctlCode, IN PVOID InputDataBuf, IN ULONG InputDataLen, IN PVOID OutputDataBuf, IN PULONG pOutputDataLen) /*++ Routine Description: This routine sends a device ioctl to the Mini Rdr. Arguments: IoctlCode - Function code for the Mini Rdr driver InputDataBuf - Input buffer pointer InputDataLen - Lenth of the input buffer OutputDataBuf - Output buffer pointer pOutputDataLen - Pointer to the length of the output buffer Return Value: WN_SUCCESS if successful, otherwise the appropriate error Notes: --*/ { HANDLE DeviceHandle; // The mini rdr device handle ULONG BytesRet; BOOL rc; ULONG Status; Status = WN_SUCCESS; // Grab a handle to the redirector device object DeviceHandle = CreateFile( DD_NULMRX_USERMODE_DEV_NAME_U, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, (LPSECURITY_ATTRIBUTES)NULL, OPEN_EXISTING, 0, (HANDLE) NULL ); if ( INVALID_HANDLE_VALUE != DeviceHandle ) { rc = DeviceIoControl( DeviceHandle, IoctlCode, InputDataBuf, InputDataLen, OutputDataBuf, *pOutputDataLen, pOutputDataLen, NULL ); if ( !rc ) { DbgP(( L"SendToMiniRdr: returning error from DeviceIoctl\n" )); Status = GetLastError( ); } else { DbgP(( L"SendToMiniRdr: The DeviceIoctl call succeded\n" )); } CloseHandle(DeviceHandle); } else { Status = GetLastError( ); DbgP(( L"SendToMiniRdr: error %lx opening device \n", Status )); } return Status; } DWORD APIENTRY NPAddConnection( LPNETRESOURCE lpNetResource, LPWSTR lpPassword, LPWSTR lpUserName ) /*++ Routine Description: This routine adds a connection to the list of connections associated with this network provider Arguments: lpNetResource - the NETRESOURCE struct lpPassword - the password lpUserName - the user name Return Value: WN_SUCCESS if successful, otherwise the appropriate error Notes: --*/ { DbgP(( L"NPAddConnection....\n" )); return NPAddConnection3( NULL, lpNetResource, lpPassword, lpUserName, 0 ); } DWORD APIENTRY NPAddConnection3( HWND hwndOwner, LPNETRESOURCE lpNetResource, LPWSTR lpPassword, LPWSTR lpUserName, DWORD dwFlags ) /*++ Routine Description: This routine adds a connection to the list of connections associated with this network provider Arguments: hwndOwner - the owner handle lpNetResource - the NETRESOURCE struct lpPassword - the password lpUserName - the user name dwFlags - flags for the connection Return Value: WN_SUCCESS if successful, otherwise the appropriate error --*/ { DWORD Status; WCHAR ConnectionName[128]; WCHAR wszScratch[128]; WCHAR LocalName[3]; DWORD CopyBytes = 0; DbgP(( L"NPAddConnection3....\n" )); DbgP(( L"Local Name: %s\n", lpNetResource->lpLocalName )); DbgP(( L"Remote Name: %s\n", lpNetResource->lpRemoteName )); Status = WN_SUCCESS; // \device\miniredirector\;:\Server\Share if ( lstrlen( lpNetResource->lpLocalName ) > 1 ) { if ( lpNetResource->lpLocalName[1] == L':' ) { // LocalName[0] = (WCHAR) CharUpper( (PWCHAR) MAKELONG( (USHORT) lpNetResource->lpLocalName[0], 0 ) ); LocalName[0] = (WCHAR) toupper(lpNetResource->lpLocalName[0]); LocalName[1] = L':'; LocalName[2] = L'\0'; lstrcpyn( ConnectionName, DD_NULMRX_FS_DEVICE_NAME_U, 126 ); wcsncat(ConnectionName, L"\\;", 3 ); wcsncat(ConnectionName, LocalName, 128-wcslen(ConnectionName)); } else { Status = WN_BAD_LOCALNAME; } } else { Status = WN_BAD_LOCALNAME; } if (Status == WN_SUCCESS) { if(lpNetResource->lpRemoteName[0] == L'\0') { Status = WN_BAD_NETNAME; } // format proper server name else if ( lpNetResource->lpRemoteName[0] == L'\\' && lpNetResource->lpRemoteName[1] == L'\\' ) { wcsncat( ConnectionName, lpNetResource->lpRemoteName + 1 , 128-wcslen(ConnectionName)); DbgP(( L"Full Connect Name: %s\n", ConnectionName )); DbgP(( L"Full Connect Name Length: %d\n", ( wcslen( ConnectionName ) + 1 ) * sizeof( WCHAR ) )); } else { Status = WN_BAD_NETNAME; } } if ( Status == WN_SUCCESS ) { if ( QueryDosDevice( LocalName, wszScratch, 128 ) ) { Status = WN_ALREADY_CONNECTED; } else if ( GetLastError( ) == ERROR_FILE_NOT_FOUND ) { HANDLE hFile; Status = SendToMiniRdr( IOCTL_NULMRX_ADDCONN, ConnectionName, ( lstrlen( ConnectionName ) + 1 ) * sizeof( WCHAR ), NULL, &CopyBytes ); if ( Status == WN_SUCCESS ) { if ( !DefineDosDevice( DDD_RAW_TARGET_PATH | DDD_NO_BROADCAST_SYSTEM, lpNetResource->lpLocalName, ConnectionName ) ) { Status = GetLastError( ); } } else { Status = WN_BAD_NETNAME; } } else { Status = WN_ALREADY_CONNECTED; } } return Status; } DWORD APIENTRY NPCancelConnection( LPWSTR lpName, BOOL fForce ) /*++ Routine Description: This routine cancels ( deletes ) a connection from the list of connections associated with this network provider Arguments: lpName - name of the connection fForce - forcefully delete the connection Return Value: WN_SUCCESS if successful, otherwise the appropriate error Notes: --*/ { WCHAR LocalName[3]; WCHAR RemoteName[128]; WCHAR ConnectionName[128]; ULONG CopyBytes; DWORD DisconnectResult; DWORD Status = WN_NOT_CONNECTED; if(lpName == NULL) return Status; if ( lstrlen( lpName ) > 1 ) { if ( lpName[1] == L':' ) { // LocalName[0] = (WCHAR) CharUpper( (PWCHAR) MAKELONG( (USHORT) lpName[0], 0 ) ); LocalName[0] = (WCHAR) toupper(lpName[0]); LocalName[1] = L':'; LocalName[2] = L'\0'; CopyBytes = 128 * sizeof(WCHAR); Status = SendToMiniRdr( IOCTL_NULMRX_GETCONN, LocalName, 3 * sizeof( WCHAR ), (PVOID) RemoteName, &CopyBytes ); if ( Status == WN_SUCCESS && CopyBytes > 0 && CopyBytes < 128 * sizeof(WCHAR) ) { RemoteName[CopyBytes/sizeof(WCHAR)] = L'\0'; lstrcpyn( ConnectionName, DD_NULMRX_FS_DEVICE_NAME_U, 126 ); wcsncat( ConnectionName, L"\\;", 3); wcsncat( ConnectionName, LocalName, 128-wcslen(ConnectionName) ); wcsncat( ConnectionName, RemoteName, 128-wcslen(ConnectionName) ); ConnectionName[127] = L'\0'; CopyBytes = 0; Status = SendToMiniRdr( IOCTL_NULMRX_DELCONN, ConnectionName, ( wcslen( ConnectionName ) + 1 ) * sizeof( WCHAR ), NULL, &CopyBytes ); if ( Status == WN_SUCCESS ) { if ( !DefineDosDevice( DDD_REMOVE_DEFINITION | DDD_RAW_TARGET_PATH | DDD_EXACT_MATCH_ON_REMOVE, LocalName, ConnectionName ) ) { Status = GetLastError( ); } } } else { Status = WN_NOT_CONNECTED; } } } return Status; } DWORD APIENTRY NPGetConnection( LPWSTR lpLocalName, LPWSTR lpRemoteName, LPDWORD lpBufferSize ) /*++ Routine Description: This routine returns the information associated with a connection Arguments: lpLocalName - local name associated with the connection lpRemoteName - the remote name associated with the connection lpBufferSize - the remote name buffer size Return Value: WN_SUCCESS if successful, otherwise the appropriate error Notes: --*/ { DWORD Status, len, i; ULONG CopyBytes; WCHAR RemoteName[128]; WCHAR LocalName[3]; Status = WN_NOT_CONNECTED; DbgP(( L"NPGetConnection....\n" )); if(lpLocalName == NULL) return Status; if ( wcslen( lpLocalName ) > 1 ) { if ( lpLocalName[1] == L':' ) { CopyBytes = 128*sizeof(WCHAR); // LocalName[0] = (WCHAR) CharUpper( (PWCHAR) MAKELONG( (USHORT) lpLocalName[0], 0 ) ); LocalName[0] = (WCHAR) toupper(lpLocalName[0]); LocalName[1] = L':'; LocalName[2] = L'\0'; Status = SendToMiniRdr( IOCTL_NULMRX_GETCONN, LocalName, 3 * sizeof( WCHAR ), (PVOID) RemoteName, &CopyBytes ); } } if ( Status == WN_SUCCESS ) { len = CopyBytes + sizeof(WCHAR); if ( *lpBufferSize > len ) { *lpRemoteName++ = L'\\'; CopyMemory( lpRemoteName, RemoteName, CopyBytes ); lpRemoteName[CopyBytes/sizeof(WCHAR)] = L'\0'; } else { Status = WN_MORE_DATA; *lpBufferSize = len; } } return Status; } DWORD APIENTRY NPOpenEnum( DWORD dwScope, DWORD dwType, DWORD dwUsage, LPNETRESOURCE lpNetResource, LPHANDLE lphEnum ) /*++ Routine Description: This routine opens a handle for enumeration of resources. The only capability implemented in the sample is for enumerating connected shares Arguments: dwScope - the scope of enumeration dwType - the type of resources to be enumerated dwUsage - the usage parameter lpNetResource - a pointer to the desired NETRESOURCE struct. lphEnum - aptr. for passing nack the enumeration handle Return Value: WN_SUCCESS if successful, otherwise the appropriate error Notes: The sample only supports the notion of enumerating connected shares The handle passed back is merely the index of the last entry returned --*/ { DWORD Status; DbgP((L"NPOpenEnum\n")); *lphEnum = NULL; switch ( dwScope ) { case RESOURCE_CONNECTED: { *lphEnum = HeapAlloc( GetProcessHeap( ), HEAP_ZERO_MEMORY, sizeof( ULONG ) ); if (*lphEnum ) { Status = WN_SUCCESS; } else { Status = WN_OUT_OF_MEMORY; } break; } break; case RESOURCE_CONTEXT: default: Status = WN_NOT_SUPPORTED; break; } DbgP((L"NPOpenEnum returning Status %lx\n",Status)); return(Status); } DWORD APIENTRY NPEnumResource( HANDLE hEnum, LPDWORD lpcCount, LPVOID lpBuffer, LPDWORD lpBufferSize) /*++ Routine Description: This routine uses the handle obtained by a call to NPOpenEnum for enuerating the connected shares Arguments: hEnum - the enumeration handle lpcCount - the number of resources returned lpBuffer - the buffere for passing back the entries lpBufferSize - the size of the buffer Return Value: WN_SUCCESS if successful, otherwise the appropriate error WN_NO_MORE_ENTRIES - if the enumeration has exhausted the entries WN_MORE_DATA - if nmore data is available Notes: The sample only supports the notion of enumerating connected shares The handle passed back is merely the index of the last entry returned --*/ { DWORD Status = WN_SUCCESS; BYTE ConnectionList[26]; ULONG CopyBytes; ULONG EntriesCopied; ULONG i; LPNETRESOURCE pNetResource; ULONG SpaceNeeded; ULONG SpaceAvailable; WCHAR LocalName[3]; WCHAR RemoteName[128]; PWCHAR StringZone; DbgP((L"NPEnumResource\n")); DbgP((L"NPEnumResource Count Requested %d\n", *lpcCount)); pNetResource = (LPNETRESOURCE) lpBuffer; SpaceAvailable = *lpBufferSize; EntriesCopied = 0; StringZone = (PWCHAR) ((PBYTE)lpBuffer + *lpBufferSize); CopyBytes = 26; Status = SendToMiniRdr( IOCTL_NULMRX_GETLIST, NULL, 0, (PVOID) ConnectionList, &CopyBytes ); i = *((PULONG)hEnum); if ( Status == WN_SUCCESS) { for ( i = *((PULONG) hEnum); EntriesCopied < *lpcCount && i < 26; i++ ) { if ( ConnectionList[i] ) { CopyBytes = 128*sizeof(WCHAR); LocalName[0] = L'A' + (WCHAR) i; LocalName[1] = L':'; LocalName[2] = L'\0'; Status = SendToMiniRdr( IOCTL_NULMRX_GETCONN, LocalName, 3 * sizeof(WCHAR), (PVOID) RemoteName, &CopyBytes ); // if something strange happended then just say there are no more entries if ( Status != WN_SUCCESS || CopyBytes == 0 ) { Status = WN_NO_MORE_ENTRIES; break; } // Determine the space needed for this entry... SpaceNeeded = sizeof( NETRESOURCE ); // resource struct SpaceNeeded += 3 * sizeof(WCHAR); // local name SpaceNeeded += 2 * sizeof(WCHAR) + CopyBytes; // remote name SpaceNeeded += 5 * sizeof(WCHAR); // comment SpaceNeeded += sizeof(NULMRX_PROVIDER_NAME_U); // provider name if ( SpaceNeeded > SpaceAvailable ) { break; } else { SpaceAvailable -= SpaceNeeded; pNetResource->dwScope = RESOURCE_CONNECTED; pNetResource->dwType = RESOURCETYPE_DISK; pNetResource->dwDisplayType = RESOURCEDISPLAYTYPE_SHARE; pNetResource->dwUsage = 0; // setup string area at opposite end of buffer SpaceNeeded -= sizeof( NETRESOURCE ); StringZone = (PWCHAR)( (PBYTE) StringZone - SpaceNeeded ); // copy local name pNetResource->lpLocalName = StringZone; *StringZone++ = L'A' + (WCHAR) i; *StringZone++ = L':'; *StringZone++ = L'\0'; // copy remote name pNetResource->lpRemoteName = StringZone; *StringZone++ = L'\\'; CopyMemory( StringZone, RemoteName, CopyBytes ); StringZone += CopyBytes / sizeof(WCHAR); *StringZone++ = L'\0'; // copy comment pNetResource->lpComment = StringZone; *StringZone++ = L'A'; *StringZone++ = L'_'; *StringZone++ = L'O'; *StringZone++ = L'K'; *StringZone++ = L'\0'; // copy provider name pNetResource->lpProvider = StringZone; lstrcpyn( StringZone, NULMRX_PROVIDER_NAME_U, sizeof(NULMRX_PROVIDER_NAME_U)/sizeof(WCHAR) ); EntriesCopied++; // set new bottom of string zone StringZone = (PWCHAR)( (PBYTE) StringZone - SpaceNeeded ); } pNetResource++; } } } else { Status = WN_NO_MORE_ENTRIES; } *lpcCount = EntriesCopied; if ( EntriesCopied == 0 && Status == WN_SUCCESS ) { if ( i > 25 ) { Status = WN_NO_MORE_ENTRIES; } else { DbgP((L"NPEnumResource More Data Needed - %d\n", SpaceNeeded)); Status = WN_MORE_DATA; *lpBufferSize = SpaceNeeded; } } // update entry index *(PULONG) hEnum = i; DbgP((L"NPEnumResource Entries returned - %d\n", EntriesCopied)); return Status; } DWORD APIENTRY NPCloseEnum( HANDLE hEnum ) /*++ Routine Description: This routine closes the handle for enumeration of resources. Arguments: hEnum - the enumeration handle Return Value: WN_SUCCESS if successful, otherwise the appropriate error Notes: The sample only supports the notion of enumerating connected shares --*/ { DbgP((L"NPCloseEnum\n")); HeapFree( GetProcessHeap( ), 0, (PVOID) hEnum ); return WN_SUCCESS; } DWORD APIENTRY NPGetResourceParent( LPNETRESOURCE lpNetResource, LPVOID lpBuffer, LPDWORD lpBufferSize ) /*++ Routine Description: This routine returns the information about net resource parent Arguments: lpNetResource - the NETRESOURCE struct lpBuffer - the buffer for passing back the parent information lpBufferSize - the buffer size Return Value: Notes: --*/ { DbgP(( L"NPGetResourceParent: WN_NOT_SUPPORTED\n" )); return WN_NOT_SUPPORTED; } DWORD APIENTRY NPGetResourceInformation( LPNETRESOURCE lpNetResource, LPVOID lpBuffer, LPDWORD lpBufferSize, LPWSTR *lplpSystem ) /*++ Routine Description: This routine returns the information associated net resource Arguments: lpNetResource - the NETRESOURCE struct lpBuffer - the buffer for passing back the parent information lpBufferSize - the buffer size lplpSystem - Return Value: Notes: --*/ { DbgP(( L"NPGetResourceInformation: WN_NOT_SUPPORTED\n" )); return WN_NOT_SUPPORTED; } DWORD APIENTRY NPGetUniversalName( LPCWSTR lpLocalPath, DWORD dwInfoLevel, LPVOID lpBuffer, LPDWORD lpBufferSize ) /*++ Routine Description: This routine returns the information associated net resource Arguments: lpLocalPath - the local path name dwInfoLevel - the desired info level lpBuffer - the buffer for the univeral name lpBufferSize - the buffer size Return Value: WN_SUCCESS if successful Notes: --*/ { DbgP(( L"NPGetUniversalName: WN_NOT_SUPPORTED\n" )); return WN_NOT_SUPPORTED; } int _cdecl _vsnwprintf( wchar_t *buffer, size_t count, wchar_t *format, va_list arg_ptr); // Format and write debug information to OutputDebugString ULONG _cdecl WideDbgPrint( LPTSTR Format, ... ) { ULONG rc = 0; TCHAR szbuffer[256]; va_list marker; va_start( marker, Format ); { rc = _vsnwprintf( szbuffer, 254, Format, marker ); szbuffer[255] = (TCHAR)0; OutputDebugString( TRACE_TAG ); OutputDebugString( szbuffer ); } return rc; }