/*++ Copyright (c) 1989-1999 Microsoft Corporation Module Name: smbmrxnp.c Abstract: This module implements the routines required for interaction with network provider router interface in NT Notes: This module has been builkt and tested only in UNICODE environment --*/ #include #include #include #include #include #include #include #include // include files from the smb inc directory #include #ifndef UNICODE_STRING typedef struct _UNICODE_STRING { USHORT Length; USHORT MaximumLength; PWSTR Buffer; } UNICODE_STRING; typedef UNICODE_STRING *PUNICODE_STRING; #endif #ifndef FILE_FULL_EA_INFORMATION typedef struct _FILE_FULL_EA_INFORMATION { ULONG NextEntryOffset; UCHAR Flags; UCHAR EaNameLength; USHORT EaValueLength; CHAR EaName[1]; } FILE_FULL_EA_INFORMATION, *PFILE_FULL_EA_INFORMATION; #endif #define MAX_EA_NAME_LEN sizeof("UserName\0") #define MAX_CONNECT_INFO_SIZE \ 3 * sizeof(FILE_FULL_EA_INFORMATION) + \ sizeof(SMBMRX_CONNECTINFO) + \ 4 * MAX_PATH + \ 3 * MAX_EA_NAME_LEN typedef struct _SMBMRXNP_ENUMERATION_HANDLE_ { INT LastIndex; } SMBMRXNP_ENUMERATION_HANDLE, *PSMBMRXNP_ENUMERATION_HANDLE; #ifdef DBG #define DbgP(_x_) DbgPrint _x_ #else #define DbgP(_x_) #endif ULONG _cdecl DbgPrint( LPTSTR Format, ... ); #define TRACE_TAG L"SMBMRXNP: " // The debug level for this module // the SMB mini redirector and provider name. The original constants // are defined in smbmrx.h UNICODE_STRING SmbMRxDeviceName = { sizeof(DD_SMBMRX_FS_DEVICE_NAME_U), sizeof(DD_SMBMRX_FS_DEVICE_NAME_U), DD_SMBMRX_FS_DEVICE_NAME_U }; UNICODE_STRING SmbMrxProviderName = { sizeof(SMBMRX_PROVIDER_NAME_U), sizeof(SMBMRX_PROVIDER_NAME_U), SMBMRX_PROVIDER_NAME_U }; DWORD OpenSharedMemory( PHANDLE phMutex, PHANDLE phMemory, PVOID *pMemory ) /*++ Routine Description: This routine opens the shared memory for exclusive manipulation Arguments: phMutex - the mutex handle phMemory - the memory handle pMemory - a ptr. to the shared memory which is set if successful Return Value: WN_SUCCESS -- if successful --*/ { DWORD dwStatus; DbgP((TEXT("OpenSharedMemory\n"))); *phMutex = 0; *phMemory = 0; *pMemory = NULL; *phMutex = OpenMutex(SYNCHRONIZE, FALSE, SMBMRXNP_MUTEX_NAME); if (*phMutex == NULL) { dwStatus = GetLastError(); DbgP((TEXT("OpenSharedMemory: OpenMutex failed\n"))); goto OpenSharedMemoryAbort1; } DbgP((TEXT("OpenSharedMemory: Calling WaitForSingleObject\n"))); WaitForSingleObject(*phMutex, INFINITE); *phMemory = OpenFileMapping(FILE_MAP_WRITE, FALSE, SMBMRXNP_SHARED_MEMORY_NAME); if (*phMemory == NULL) { dwStatus = GetLastError(); DbgP((TEXT("OpenSharedMemory: OpenFileMapping failed\n"))); goto OpenSharedMemoryAbort2; } *pMemory = MapViewOfFile(*phMemory, FILE_MAP_WRITE, 0, 0, 0); if (*pMemory == NULL) { dwStatus = GetLastError(); DbgP((TEXT("OpenSharedMemory: MapViewOfFile failed\n"))); goto OpenSharedMemoryAbort3; } DbgP((TEXT("OpenSharedMemory: return ERROR_SUCCESS\n"))); return ERROR_SUCCESS; OpenSharedMemoryAbort3: CloseHandle(*phMemory); OpenSharedMemoryAbort2: ReleaseMutex(*phMutex); CloseHandle(*phMutex); *phMutex = NULL; OpenSharedMemoryAbort1: DbgP((TEXT("OpenSharedMemory: return dwStatus: %d\n"), dwStatus)); return dwStatus; } VOID CloseSharedMemory( PHANDLE hMutex, PHANDLE hMemory, PVOID *pMemory ) /*++ Routine Description: This routine relinquishes control of the shared memory after exclusive manipulation Arguments: hMutex - the mutex handle hMemory - the memory handle pMemory - a ptr. to the shared memory which is set if successful Return Value: --*/ { DbgP((TEXT("CloseSharedMemory\n"))); if (*pMemory) { UnmapViewOfFile(*pMemory); *pMemory = NULL; } if (*hMemory) { CloseHandle(*hMemory); *hMemory = 0; } if (*hMutex) { if (ReleaseMutex(*hMutex) == FALSE) { DbgP((TEXT("CloseSharedMemory: ReleaseMutex error: %d\n"), GetLastError())); } CloseHandle(*hMutex); *hMutex = 0; } DbgP((TEXT("CloseSharedMemory: Return\n"))); } DWORD APIENTRY NPGetCaps( DWORD nIndex ) /*++ Routine Description: This routine returns the capabilities of the SMB Mini redirector network provider implementation Arguments: nIndex - category of capabilities desired Return Value: the appropriate capabilities --*/ { switch (nIndex) { case WNNC_SPEC_VERSION: return WNNC_SPEC_VERSION51; case WNNC_NET_TYPE: return WNNC_NET_RDR2_SAMPLE; case WNNC_DRIVER_VERSION: #define WNNC_DRIVER(major,minor) (major*0x00010000 + minor) return WNNC_DRIVER(1, 0); case WNNC_CONNECTION: return WNNC_CON_GETCONNECTIONS | WNNC_CON_CANCELCONNECTION | WNNC_CON_ADDCONNECTION | WNNC_CON_ADDCONNECTION3; case WNNC_ENUMERATION: return WNNC_ENUM_LOCAL; case WNNC_START: case WNNC_USER: case WNNC_DIALOG: case WNNC_ADMIN: default: return 0; } } 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; } 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 = 0; DbgP((TEXT("NPOpenEnum\n"))); *lphEnum = NULL; switch (dwScope) { case RESOURCE_CONNECTED: { *lphEnum = LocalAlloc( LMEM_ZEROINIT, sizeof(SMBMRXNP_ENUMERATION_HANDLE)); if (*lphEnum != NULL) { Status = WN_SUCCESS; } else { Status = WN_OUT_OF_MEMORY; } break; } break; case RESOURCE_CONTEXT: default: Status = WN_NOT_SUPPORTED; break; } DbgP((TEXT("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; LPNETRESOURCEW pBufferResource; DWORD StringOffset; DWORD AvailableBufferSize; HANDLE hMutex, hMemory; PSMBMRXNP_ENUMERATION_HANDLE pEnumHandle; PSMBMRXNP_SHARED_MEMORY pSharedMemory; DbgP((TEXT("NPEnumResource\n"))); DbgP((TEXT("NPEnumResource Count Requested %d\n"),*lpcCount)); AvailableBufferSize = *lpBufferSize; StringOffset = *lpBufferSize; pBufferResource = (LPNETRESOURCEW)lpBuffer; pEnumHandle = (PSMBMRXNP_ENUMERATION_HANDLE)hEnum; *lpcCount = 0; if (pEnumHandle->LastIndex >= SMBMRXNP_MAX_DEVICES) { return WN_NO_MORE_ENTRIES; } Status = OpenSharedMemory( &hMutex, &hMemory, (PVOID)&pSharedMemory); if (Status == WN_SUCCESS) { INT Index; PSMBMRXNP_NETRESOURCE pNetResource; DbgP((TEXT("NPEnumResource: Highest Index %d Number Of resources %d\n"), pSharedMemory->HighestIndexInUse,pSharedMemory->NumberOfResourcesInUse)); for (Index = pEnumHandle->LastIndex; Index <= pSharedMemory->HighestIndexInUse; Index++) { pNetResource = &pSharedMemory->NetResources[Index]; DbgP((TEXT("NPEnumResource: Examining Index %d\n"),Index)); if (pNetResource->InUse) { DWORD ResourceSize; ResourceSize = sizeof(NETRESOURCE) + pNetResource->LocalNameLength + sizeof(WCHAR) + pNetResource->RemoteNameLength + sizeof(WCHAR) + SmbMrxProviderName.Length + sizeof(WCHAR); if (AvailableBufferSize >= ResourceSize) { *lpcCount = *lpcCount + 1; AvailableBufferSize -= ResourceSize; pBufferResource->dwScope = RESOURCE_CONNECTED; pBufferResource->dwType = pNetResource->dwType; pBufferResource->dwDisplayType = pNetResource->dwDisplayType; pBufferResource->dwUsage = pNetResource->dwUsage; DbgP((TEXT("NPEnumResource: Copying local name Index %d\n"),Index)); // set up the strings in the resource StringOffset -= (pNetResource->LocalNameLength + sizeof(WCHAR)); pBufferResource->lpLocalName = (PWCHAR)((PBYTE)lpBuffer + StringOffset); CopyMemory(pBufferResource->lpLocalName, pNetResource->LocalName, pNetResource->LocalNameLength); pBufferResource->lpLocalName[ pNetResource->LocalNameLength/sizeof(WCHAR)] = L'\0'; DbgP((TEXT("NPEnumResource: Copying remote name Index %d\n"),Index)); StringOffset -= (pNetResource->RemoteNameLength + sizeof(WCHAR)); pBufferResource->lpRemoteName = (PWCHAR)((PBYTE)lpBuffer + StringOffset); CopyMemory(pBufferResource->lpRemoteName, pNetResource->RemoteName, pNetResource->RemoteNameLength); pBufferResource->lpRemoteName[ pNetResource->RemoteNameLength/sizeof(WCHAR)] = L'\0'; DbgP((TEXT("NPEnumResource: Copying provider name Index %d\n"),Index)); StringOffset -= (SmbMrxProviderName.Length + sizeof(WCHAR)); pBufferResource->lpProvider = (PWCHAR)((PBYTE)lpBuffer + StringOffset); CopyMemory(pBufferResource->lpProvider, SmbMrxProviderName.Buffer, SmbMrxProviderName.Length); pBufferResource->lpProvider[ SmbMrxProviderName.Length/sizeof(WCHAR)] = L'\0'; pBufferResource->lpComment = NULL; pBufferResource++; } else { DbgP((TEXT("NPEnumResource: Buffer Overflow Index %d\n"),Index)); Status = WN_MORE_DATA; break; } } } pEnumHandle->LastIndex = Index; if ((Status == WN_SUCCESS) && (pEnumHandle->LastIndex > pSharedMemory->HighestIndexInUse) && (*lpcCount == 0)) { Status = WN_NO_MORE_ENTRIES; } CloseSharedMemory( &hMutex, &hMemory, (PVOID)&pSharedMemory); } DbgP((TEXT("NPEnumResource returning Count %d\n"),*lpcCount)); DbgP((TEXT("NPEnumResource returning Status %lx\n"),Status)); return Status; } DWORD APIENTRY NPCloseEnum( HANDLE hEnum ) /*++ Routine Description: This routine closes the handle for enumeration of resources. Arguments: hEnum - the enumeration handle Return Value: WN_SUCCESS if successful, otherwise the appropriate error Notes: The sample only supports the notion of enumerating connected shares --*/ { DbgP((TEXT("NPCloseEnum\n"))); LocalFree(hEnum); return WN_SUCCESS; } 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_SMBMRX_USERMODE_DEV_NAME, 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; } ULONG FillInEaBuffer( LPTSTR pUserName, LPTSTR pPassword, PBYTE pEaData ) { PFILE_FULL_EA_INFORMATION thisEa = (PFILE_FULL_EA_INFORMATION) pEaData; PBYTE valuePtr = pEaData; PWKSTA_INFO_100 WkStaInfo; ULONG status; PWCHAR pDomain; // get the domain that this workstation is a member of status = NetWkstaGetInfo( NULL, 100, (PBYTE *) &WkStaInfo ); if ( status == ERROR_SUCCESS ) { pDomain = WkStaInfo->wki100_langroup; } else { pDomain = NULL; } DbgP((L"FillInEaBuffer - domain name=%s\n", pDomain)); thisEa->EaValueLength = 0; thisEa->NextEntryOffset = 0; // Set the user name EA if ( pUserName ) { thisEa->Flags = 0; thisEa->EaNameLength = sizeof("UserName"); CopyMemory( thisEa->EaName, "UserName\0", thisEa->EaNameLength + 1 ); valuePtr = (PBYTE) thisEa->EaName + thisEa->EaNameLength + 1; thisEa->EaValueLength = (USHORT)( *pUserName ? lstrlenW( pUserName ) : 1 ) * sizeof( WCHAR ); CopyMemory( valuePtr, pUserName, thisEa->EaValueLength ); thisEa->NextEntryOffset = (ULONG)(((PBYTE) valuePtr + thisEa->EaValueLength ) - (PBYTE) thisEa); thisEa->NextEntryOffset = ((thisEa->NextEntryOffset + 3) / sizeof(LONG)) * sizeof(LONG); } // Set the password EA. if ( pPassword ) { thisEa = (PFILE_FULL_EA_INFORMATION) ((PBYTE) thisEa + thisEa->NextEntryOffset); thisEa->Flags = 0; thisEa->EaNameLength = sizeof("Password"); CopyMemory( thisEa->EaName, "Password\0", thisEa->EaNameLength + 1 ); valuePtr = (PBYTE) thisEa->EaName + thisEa->EaNameLength + 1; thisEa->EaValueLength = (USHORT)( *pPassword ? lstrlenW( pPassword ) : 1 ) * sizeof( WCHAR ); CopyMemory( valuePtr, pPassword, thisEa->EaValueLength ); thisEa->NextEntryOffset = (ULONG)(((PBYTE) valuePtr + thisEa->EaValueLength ) - (PBYTE) thisEa); thisEa->NextEntryOffset = ((thisEa->NextEntryOffset + 3) / sizeof(LONG)) * sizeof(LONG); } // Set the domain EA if ( pDomain ) { thisEa = (PFILE_FULL_EA_INFORMATION) ((PBYTE) thisEa + thisEa->NextEntryOffset); thisEa->Flags = 0; thisEa->EaNameLength = sizeof("Domain"); RtlCopyMemory( thisEa->EaName, "Domain\0", thisEa->EaNameLength + 1 ); valuePtr = (PBYTE) thisEa->EaName + thisEa->EaNameLength + 1; thisEa->EaValueLength = (USHORT)( *pDomain ? lstrlenW( pDomain ) : 1 ) * sizeof( WCHAR ); RtlCopyMemory( valuePtr, pDomain, thisEa->EaValueLength ); thisEa->NextEntryOffset = 0; } thisEa->NextEntryOffset = 0; return (ULONG)(((PBYTE) valuePtr + thisEa->EaValueLength) - (PBYTE) pEaData); } 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: --*/ { 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 Notes: The current sample does not handle explicitly passesd in credentials. Normally the credential information is passed in as EA parameters to the associated mini redirector for further manipulation --*/ { DWORD Status = 0; UNICODE_STRING ConnectionName; PWCHAR pLocalName,pRemoteName; USHORT LocalNameLength,RemoteNameLength; HANDLE hConnection; ULONG TransferBytes; WCHAR NullStr[] = L"\0\0"; PWCHAR pUserName; PWCHAR pPassword; PWKSTA_USER_INFO_0 WkStaUserInfo; PSMBMRX_CONNECTINFO ConnectInfo; DbgP((TEXT("NPAddConnection3: Incoming UserName - %s, Password - %s\n"), lpUserName, lpPassword )); // if no user specified, get the current logged on user if ( lpUserName == NULL ) { Status = NetWkstaUserGetInfo( NULL, 0, (PBYTE *)&WkStaUserInfo ); if ( Status == ERROR_SUCCESS ) { pUserName = WkStaUserInfo->wkui0_username; } else { pUserName = NullStr; } } else { pUserName = lpUserName; } if ( lpPassword == NULL ) { pPassword = NullStr; // use default password pPassword[1] = '\0'; // reset empty flag } else if ( *lpPassword == L'\0' ) { pPassword = NullStr; pPassword[1] = '1'; // flag the password as "Empty" } else { pPassword = lpPassword; } Status = ERROR_SUCCESS; DbgP((TEXT("NPAddConnection3: Outgoing UserName - %s, Password - %s\n"), lpUserName, lpPassword )); // The SMB mini supports only DISK type resources. The other resources // are not supported. if ((lpNetResource->lpRemoteName == NULL) || (lpNetResource->lpRemoteName[0] != L'\\') || (lpNetResource->lpRemoteName[1] != L'\\') || (lpNetResource->dwType != RESOURCETYPE_DISK)) { return WN_BAD_NETNAME; } // // The remote name is in the UNC format \\Server\Share. This name // needs to be translated to an appropriate NT name in order to // issue the request to the underlying mini redirector to create the // connection. // // The NT style name is of the form // // \device\smbminiredirector\;:\Server\Share // // The additional ; is required by the new RDR for extensibility. // pLocalName = lpNetResource->lpLocalName; pRemoteName = lpNetResource->lpRemoteName; // skip past the first back slash since the name to be appended for the // NT name does not require this. pRemoteName++; if (pLocalName != NULL) { LocalNameLength = wcslen(pLocalName) * sizeof(WCHAR); } else { LocalNameLength = 0; } RemoteNameLength = (wcslen(pRemoteName) - 1) * sizeof(WCHAR); ConnectionName.MaximumLength = (USHORT)(SmbMRxDeviceName.Length + (USHORT)RemoteNameLength + ((pLocalName != NULL) ? (LocalNameLength + sizeof(WCHAR)) : 0) + // space for ; sizeof(WCHAR)); ConnectionName.Length = ConnectionName.MaximumLength; ConnectionName.Buffer = LocalAlloc( LMEM_ZEROINIT, ConnectionName.Length + sizeof(WCHAR)); if (ConnectionName.Buffer == NULL) { return GetLastError(); } // Copy the name into the buffer CopyMemory( ConnectionName.Buffer, SmbMRxDeviceName.Buffer, SmbMRxDeviceName.Length); wcscat(ConnectionName.Buffer, L"\\"); wcscat(ConnectionName.Buffer, L";"); if (pLocalName != NULL) { wcscat(ConnectionName.Buffer, pLocalName); } wcscat(ConnectionName.Buffer, pRemoteName); ConnectInfo = (PSMBMRX_CONNECTINFO) LocalAlloc( LMEM_ZEROINIT, MAX_CONNECT_INFO_SIZE ); if ( ConnectInfo ) { ConnectInfo->ConnectionNameOffset = 0; ConnectInfo->ConnectionNameLength = ConnectionName.Length; CopyMemory( ConnectInfo->InfoArea, ConnectionName.Buffer, ConnectionName.Length ); ConnectInfo->EaDataOffset = ConnectInfo->ConnectionNameOffset + ConnectInfo->ConnectionNameLength; // check for the "no password" flag if ( pPassword[0] == L'\0' && pPassword[1] == L'1' ) { pPassword = NULL; } ConnectInfo->EaDataLength = FillInEaBuffer( pUserName, pPassword, (PBYTE) ConnectInfo->InfoArea + ConnectInfo->EaDataOffset ); TransferBytes = 0; Status = SendToMiniRdr( IOCTL_SMBMRX_ADDCONN, ConnectInfo, MAX_CONNECT_INFO_SIZE, NULL, &TransferBytes ); LocalFree( ConnectInfo ); } else { Status = WN_OUT_OF_MEMORY; } if ((Status == WN_SUCCESS) && (pLocalName != NULL)) { WCHAR TempBuf[64]; if (!QueryDosDeviceW( pLocalName, TempBuf, 64)) { if (GetLastError() != ERROR_FILE_NOT_FOUND) { // // Most likely failure occurred because our output // buffer is too small. It still means someone already // has an existing symbolic link for this device. // Status = ERROR_ALREADY_ASSIGNED; } else { // // ERROR_FILE_NOT_FOUND (translated from OBJECT_NAME_NOT_FOUND) // means it does not exist and we can redirect this device. // // Create a symbolic link object to the device we are redirecting // if (!DefineDosDeviceW( DDD_RAW_TARGET_PATH | DDD_NO_BROADCAST_SYSTEM, pLocalName, ConnectionName.Buffer)) { Status = GetLastError(); } else { Status = WN_SUCCESS; } } } else { // // QueryDosDevice successfully an existing symbolic link-- // somebody is already using this device. // Status = ERROR_ALREADY_ASSIGNED; } } else { DbgP((TEXT("SendToMiniRdr returned %lx\n"),Status)); } if (Status == WN_SUCCESS) { INT Index; HANDLE hMutex, hMemory; BOOLEAN FreeEntryFound = FALSE; PSMBMRXNP_SHARED_MEMORY pSharedMemory; // The connection was established and the local device mapping // added. Include this in the list of mapped devices. Status = OpenSharedMemory( &hMutex, &hMemory, (PVOID)&pSharedMemory); if (Status == WN_SUCCESS) { DbgP((TEXT("NPAddConnection3: Highest Index %d Number Of resources %d\n"), pSharedMemory->HighestIndexInUse,pSharedMemory->NumberOfResourcesInUse)); Index = 0; while (Index < pSharedMemory->HighestIndexInUse) { if (!pSharedMemory->NetResources[Index].InUse) { FreeEntryFound = TRUE; break; } Index++; } if (!FreeEntryFound && (pSharedMemory->HighestIndexInUse < SMBMRXNP_MAX_DEVICES)) { pSharedMemory->HighestIndexInUse += 1; Index = pSharedMemory->HighestIndexInUse; FreeEntryFound = TRUE; } if (FreeEntryFound) { PSMBMRXNP_NETRESOURCE pSmbMrxNetResource; pSharedMemory->NumberOfResourcesInUse += 1; pSmbMrxNetResource = &pSharedMemory->NetResources[Index]; pSmbMrxNetResource->InUse = TRUE; pSmbMrxNetResource->dwScope = lpNetResource->dwScope; pSmbMrxNetResource->dwType = lpNetResource->dwType; pSmbMrxNetResource->dwDisplayType = lpNetResource->dwDisplayType; pSmbMrxNetResource->dwUsage = RESOURCEUSAGE_CONNECTABLE; pSmbMrxNetResource->LocalNameLength = LocalNameLength; pSmbMrxNetResource->RemoteNameLength = wcslen(lpNetResource->lpRemoteName) * sizeof(WCHAR); pSmbMrxNetResource->ConnectionNameLength = ConnectionName.Length; // Copy the local name CopyMemory( pSmbMrxNetResource->LocalName, lpNetResource->lpLocalName, pSmbMrxNetResource->LocalNameLength); // Copy the remote name CopyMemory( pSmbMrxNetResource->RemoteName, lpNetResource->lpRemoteName, pSmbMrxNetResource->RemoteNameLength); // Copy the connection name CopyMemory( pSmbMrxNetResource->ConnectionName, ConnectionName.Buffer, pSmbMrxNetResource->ConnectionNameLength); // // Copy the Auth info // // WARNING : security hole using shared memory..Developers must use alternate methods to maintain use table. // lstrcpyn( pSmbMrxNetResource->UserName, pUserName, MAX_PATH); if ( *pPassword ) { lstrcpyn( pSmbMrxNetResource->Password, pPassword, MAX_PATH); } else { CopyMemory( pSmbMrxNetResource->Password, pPassword, 3 * sizeof(WCHAR) ); } } else { Status = WN_NO_MORE_DEVICES; } CloseSharedMemory( &hMutex, &hMemory, (PVOID)&pSharedMemory); } else { DbgP((TEXT("NpAddConnection3: OpenSharedMemory returned %lx\n"),Status)); } } return Status; } DWORD APIENTRY NPCancelConnection( LPWSTR lpName, BOOL fForce ) /*++ Routine Description: This routine cancels ( deletes ) a connection from the list of connections associated with this network provider Arguments: lpName - name of the connection fForce - forcefully delete the connection Return Value: WN_SUCCESS if successful, otherwise the appropriate error Notes: --*/ { BOOL bLocalName = TRUE; DWORD Status = 0; UNICODE_STRING Name; HANDLE hMutex, hMemory; PSMBMRXNP_SHARED_MEMORY pSharedMemory; if (*lpName == L'\\' && *(lpName + 1) == L'\\') { bLocalName = FALSE; } DbgP((TEXT("NPCancelConnection\n"))); DbgP((TEXT("NPCancelConnection: ConnectionName: %S\n"), lpName)); Name.MaximumLength = Name.Length = wcslen(lpName) * sizeof(WCHAR); Name.Buffer = lpName; Status = OpenSharedMemory( &hMutex, &hMemory, (PVOID)&pSharedMemory); if (Status == WN_SUCCESS) { INT Index; BOOL EntryFound = FALSE; PSMBMRXNP_NETRESOURCE pNetResource; DbgP((TEXT("NPCancelConnection: Highest Index %d Number Of resources %d\n"), pSharedMemory->HighestIndexInUse,pSharedMemory->NumberOfResourcesInUse)); for (Index = 0; Index <= pSharedMemory->HighestIndexInUse; Index++) { pNetResource = &pSharedMemory->NetResources[Index]; if (pNetResource->InUse) { UNICODE_STRING EntryName; if (bLocalName) { EntryName.MaximumLength = pNetResource->LocalNameLength; EntryName.Length = EntryName.MaximumLength; EntryName.Buffer = pNetResource->LocalName; } else { EntryName.MaximumLength = pNetResource->RemoteNameLength; EntryName.Length = EntryName.MaximumLength; EntryName.Buffer = pNetResource->RemoteName; } DbgP((TEXT("NPCancelConnection: Name %S EntryName %S\n"), lpName,EntryName.Buffer)); DbgP((TEXT("NPCancelConnection: Name Length %d Entry Name Length %d\n"), Name.Length,EntryName.Length)); if (Name.Length == EntryName.Length) { if ( _wcsnicmp(Name.Buffer, EntryName.Buffer, Name.Length) == 0 ) { EntryFound = TRUE; break; } } } } if (EntryFound) { PWCHAR pUserName; PWCHAR pPassword; PSMBMRX_CONNECTINFO ConnectInfo; UNICODE_STRING ConnectionName; ULONG TransferBytes; DbgP((TEXT("NPCancelConnection: Connection Found:\n"))); ConnectionName.Length = pNetResource->ConnectionNameLength; ConnectionName.MaximumLength = ConnectionName.Length; ConnectionName.Buffer = pNetResource->ConnectionName; pUserName = pNetResource->UserName; pPassword = pNetResource->Password; ConnectInfo = (PSMBMRX_CONNECTINFO) LocalAlloc( LMEM_ZEROINIT, MAX_CONNECT_INFO_SIZE ); if ( ConnectInfo ) { ConnectInfo->ConnectionNameOffset = 0; ConnectInfo->ConnectionNameLength = ConnectionName.Length; CopyMemory( ConnectInfo->InfoArea, ConnectionName.Buffer, ConnectionName.Length ); ConnectInfo->EaDataOffset = ConnectInfo->ConnectionNameOffset + ConnectInfo->ConnectionNameLength; // check for the "no password" flag if ( pPassword[0] == L'\0' && pPassword[1] == L'1' ) { pPassword = NULL; } ConnectInfo->EaDataLength = FillInEaBuffer( pUserName, pPassword, (PBYTE) ConnectInfo->InfoArea + ConnectInfo->EaDataOffset ); TransferBytes = 0; Status = SendToMiniRdr( IOCTL_SMBMRX_DELCONN, ConnectInfo, MAX_CONNECT_INFO_SIZE, NULL, &TransferBytes ); LocalFree( ConnectInfo ); } else { Status = WN_OUT_OF_MEMORY; } DbgP((TEXT("NPCancelConnection: SendToMiniRdr returned Status %lx\n"),Status)); if ( bLocalName ) { if (DefineDosDevice(DDD_REMOVE_DEFINITION | DDD_RAW_TARGET_PATH | DDD_EXACT_MATCH_ON_REMOVE, lpName, pNetResource->ConnectionName) == FALSE) { DbgP((TEXT("RemoveDosDevice: DefineDosDevice error: %d\n"), GetLastError())); Status = GetLastError(); } else { pNetResource->InUse = FALSE; if (Index == pSharedMemory->HighestIndexInUse) { pSharedMemory->HighestIndexInUse -= 1; pSharedMemory->NumberOfResourcesInUse -= 1; } } } } CloseSharedMemory( &hMutex, &hMemory, (PVOID)&pSharedMemory); } return Status; } DWORD APIENTRY NPGetConnection( LPWSTR lpLocalName, LPWSTR lpRemoteName, LPDWORD lpBufferSize ) /*++ Routine Description: This routine returns the information associated with a connection Arguments: lpLocalName - local name associated with the connection lpRemoteName - the remote name associated with the connection lpBufferSize - the remote name buffer size Return Value: WN_SUCCESS if successful, otherwise the appropriate error Notes: --*/ { DWORD Status = 0; UNICODE_STRING Name; HANDLE hMutex, hMemory; PSMBMRXNP_SHARED_MEMORY pSharedMemory; Name.MaximumLength = Name.Length = wcslen(lpLocalName) * sizeof(WCHAR); Name.Buffer = lpLocalName; Status = OpenSharedMemory( &hMutex, &hMemory, (PVOID)&pSharedMemory); if (Status == WN_SUCCESS) { INT Index; BOOL EntryFound = FALSE; PSMBMRXNP_NETRESOURCE pNetResource; for (Index = 0; Index <= pSharedMemory->HighestIndexInUse; Index++) { pNetResource = &pSharedMemory->NetResources[Index]; if (pNetResource->InUse) { UNICODE_STRING EntryName; EntryName.MaximumLength = pNetResource->LocalNameLength; EntryName.Length = EntryName.MaximumLength; EntryName.Buffer = pNetResource->LocalName; if (Name.Length == EntryName.Length) { if ( wcsncmp( Name.Buffer, EntryName.Buffer, Name.Length/sizeof(WCHAR)) == 0 ) { EntryFound = TRUE; break; } } } } if (EntryFound) { if (*lpBufferSize < pNetResource->RemoteNameLength) { *lpBufferSize = pNetResource->RemoteNameLength; Status = ERROR_BUFFER_OVERFLOW; } else { *lpBufferSize = pNetResource->RemoteNameLength; CopyMemory( lpRemoteName, pNetResource->RemoteName, pNetResource->RemoteNameLength); Status = WN_SUCCESS; } } else { Status = ERROR_NO_NET_OR_BAD_PATH; } CloseSharedMemory( &hMutex, &hMemory, (PVOID)&pSharedMemory); } return Status; } DWORD APIENTRY NPGetResourceParent( LPNETRESOURCE lpNetResource, LPVOID lpBuffer, LPDWORD lpBufferSize ) /*++ Routine Description: This routine returns the parent of a given resource Arguments: lpNetResource - the NETRESOURCE struct lpBuffer - the buffer for passing back the parent information lpBufferSize - the buffer size Return Value: WN_NOT_SUPPORTED Notes: The current sample does not handle this call. --*/ { 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: --*/ { DWORD dwStatus = 0; LPNETRESOURCE pOutNetResource; DbgP((TEXT("NPGetResourceInformation\n"))); return dwStatus; } DWORD APIENTRY NPGetUniversalName( LPCWSTR lpLocalPath, DWORD dwInfoLevel, LPVOID lpBuffer, LPDWORD lpBufferSize ) /*++ Routine Description: This routine returns the information associated net resource Arguments: lpLocalPath - the local path name dwInfoLevel - the desired info level lpBuffer - the buffer for the univeral name lpBufferSize - the buffer size Return Value: WN_SUCCESS if successful Notes: --*/ { DWORD dwStatus; DWORD BufferRequired = 0; DWORD UniversalNameLength = 0; DWORD RemoteNameLength = 0; DWORD RemainingPathLength = 0; LPWSTR pDriveLetter, pRemainingPath, SourceStrings[3]; WCHAR RemoteName[MAX_PATH], LocalPath[MAX_PATH], UniversalName[MAX_PATH], ReplacedChar; DbgP((TEXT("NPGetUniversalName: lpLocalPath: %S InfoLevel: %d\n"), lpLocalPath, dwInfoLevel)); if (dwInfoLevel != UNIVERSAL_NAME_INFO_LEVEL && dwInfoLevel != REMOTE_NAME_INFO_LEVEL) { DbgP((TEXT("NPGetUniversalName: bad dwInfoLevel value: %d\n"), dwInfoLevel)); return WN_BAD_LEVEL; } lstrcpynW(LocalPath, lpLocalPath, MAX_PATH); pDriveLetter = LocalPath; if (pRemainingPath = wcschr(pDriveLetter, L':')) { ReplacedChar = *(++pRemainingPath); *pRemainingPath = L'\0'; } RemoteNameLength = MAX_PATH; if ((dwStatus = NPGetConnection(pDriveLetter, RemoteName, &RemoteNameLength)) != WN_SUCCESS) { DbgP((TEXT("NPGetUniversalName: NPGetConnection return dwStatus: %d\n"), dwStatus)); return dwStatus; } if (pRemainingPath) { *pRemainingPath = ReplacedChar; } DbgP((TEXT("NPGetUniversalName: pRemainingPath: %S RemoteName: %S\n"), pRemainingPath, RemoteName)); lstrcpynW(UniversalName, RemoteName, MAX_PATH); if (pRemainingPath) { wcsncat(UniversalName, pRemainingPath, MAX_PATH - RemoteNameLength/sizeof(WCHAR) - 1); UniversalName[MAX_PATH-1] = L'\0'; } DbgP((TEXT("NPGetUniversalName: UniversalName: %S\n"), UniversalName)); // Determine if the provided buffer is large enough. UniversalNameLength = (wcslen(UniversalName) + 1) * sizeof(WCHAR); BufferRequired = UniversalNameLength; if (dwInfoLevel == UNIVERSAL_NAME_INFO_LEVEL) { BufferRequired += sizeof(UNIVERSAL_NAME_INFO); } else { RemoteNameLength = (wcslen(RemoteName) + 1) * sizeof(WCHAR); BufferRequired += sizeof(REMOTE_NAME_INFO) + RemoteNameLength; if (pRemainingPath) { RemainingPathLength = (wcslen(pRemainingPath) + 1) * sizeof(WCHAR); BufferRequired += RemainingPathLength; } } if (*lpBufferSize < BufferRequired) { DbgP((TEXT("NPGetUniversalName: WN_MORE_DATA BufferRequired: %d\n"), BufferRequired)); *lpBufferSize = BufferRequired; return WN_MORE_DATA; } if (dwInfoLevel == UNIVERSAL_NAME_INFO_LEVEL) { LPUNIVERSAL_NAME_INFOW pUniversalNameInfo; pUniversalNameInfo = (LPUNIVERSAL_NAME_INFOW)lpBuffer; pUniversalNameInfo->lpUniversalName = (PWCHAR)((PBYTE)lpBuffer + sizeof(UNIVERSAL_NAME_INFOW)); CopyMemory( pUniversalNameInfo->lpUniversalName, UniversalName, UniversalNameLength); } else { LPREMOTE_NAME_INFOW pRemoteNameInfo; pRemoteNameInfo = (LPREMOTE_NAME_INFOW)lpBuffer; pRemoteNameInfo->lpUniversalName = (PWCHAR)((PBYTE)lpBuffer + sizeof(REMOTE_NAME_INFOW)); pRemoteNameInfo->lpConnectionName = pRemoteNameInfo->lpUniversalName + UniversalNameLength; pRemoteNameInfo->lpRemainingPath = pRemoteNameInfo->lpConnectionName + RemoteNameLength; CopyMemory( pRemoteNameInfo->lpUniversalName, UniversalName, UniversalNameLength); CopyMemory( pRemoteNameInfo->lpConnectionName, RemoteName, RemoteNameLength); CopyMemory( pRemoteNameInfo->lpRemainingPath, pRemainingPath, RemainingPathLength); } DbgP((TEXT("NPGetUniversalName: WN_SUCCESS\n"))); return WN_SUCCESS; } 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 DbgPrint( 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; }