/*++ Copyright (c) 1989-1996 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 builkt and tested only in UNICODE environment --*/ // Include files from the NT public directories #include #include #include #include #include #include #include #include // include files from the IFS inc directory #include #include // The debug level for this module DWORD IfsMRxNpDebugLevel = 7; // the IFS mini redirector and provider name. The original constants // are defined in ifsmrx.h UNICODE_STRING IfsMRxDeviceName = { DD_IFSMRX_FS_DEVICE_NAME_U_LENGTH, DD_IFSMRX_FS_DEVICE_NAME_U_LENGTH, DD_IFSMRX_FS_DEVICE_NAME_U }; UNICODE_STRING IfsMrxProviderName = { IFSMRX_PROVIDER_NAME_U_LENGTH, IFSMRX_PROVIDER_NAME_U_LENGTH, IFSMRX_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; TRACE_CALL(("OpenSharedMemory\n")); *phMutex = 0; *phMemory = 0; *pMemory = NULL; *phMutex = OpenMutex( SYNCHRONIZE, FALSE, IFSMRXNP_MUTEX_NAME); if (*phMutex == NULL) { dwStatus = GetLastError(); TRACE_ERROR(("OpenSharedMemory: CreateMutex failed\n")); goto OpenSharedMemoryAbort1; } TRACE_INFO(("OpenSharedMemory: Calling WaitForSingleObject\n")); WaitForSingleObject(*phMutex, INFINITE); *phMemory = OpenFileMapping( FILE_MAP_WRITE, FALSE, IFSMRXNP_SHARED_MEMORY_NAME); if (*phMemory == NULL) { dwStatus = GetLastError(); TRACE_ERROR(("OpenSharedMemory: OpenFileMapping failed\n")); goto OpenSharedMemoryAbort2; } *pMemory = MapViewOfFile(*phMemory, FILE_MAP_WRITE, 0, 0, 0); if (*pMemory == NULL) { dwStatus = GetLastError(); TRACE_ERROR(("OpenSharedMemory: MapViewOfFile failed\n")); goto OpenSharedMemoryAbort3; } TRACE_CALL(("OpenSharedMemory: return ERROR_SUCCESS\n")); return(ERROR_SUCCESS); OpenSharedMemoryAbort3: CloseHandle(*phMemory); OpenSharedMemoryAbort2: ReleaseMutex(*phMutex); CloseHandle(*phMutex); *phMutex = NULL; OpenSharedMemoryAbort1: TRACE_ERROR(("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: --*/ { TRACE_CALL(("CloseSharedMemory\n")); if (*pMemory) { UnmapViewOfFile(*pMemory); *pMemory = NULL; } if (*hMemory) { CloseHandle(*hMemory); *hMemory = 0; } if (*hMutex) { if (ReleaseMutex(*hMutex) == FALSE) { TRACE_ERROR(("CloseSharedMemory: ReleaseMutex error: %d\n", GetLastError())); } CloseHandle(*hMutex); *hMutex = 0; } TRACE_CALL(("CloseSharedMemory: Return\n")); } DWORD APIENTRY NPGetCaps( DWORD nIndex ) /*++ Routine Description: This routine returns the capaboilities of the IFS 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(0x00170000); case WNNC_DRIVER_VERSION: #define WNNC_DRIVER(major,minor) (major*0x00010000 + minor) return(WNNC_DRIVER(1, 0)); case WNNC_USER: return(0); case WNNC_CONNECTION: return(WNNC_CON_GETCONNECTIONS | WNNC_CON_CANCELCONNECTION | WNNC_CON_ADDCONNECTION | WNNC_CON_ADDCONNECTION3); case WNNC_DIALOG: return(0); case WNNC_ADMIN: return(0); case WNNC_ENUMERATION: return(WNNC_ENUM_LOCAL); case WNNC_START: return(1); 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; TRACE_CALL(("NPOpenEnum\n")); *lphEnum = NULL; switch (dwScope) { case RESOURCE_CONNECTED: { *lphEnum = LocalAlloc( LMEM_ZEROINIT, sizeof(IFSMRXNP_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; } TRACE_ERROR(("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; PIFSMRXNP_ENUMERATION_HANDLE pEnumHandle; LPNETRESOURCEW pBufferResource; DWORD StringOffset; DWORD AvailableBufferSize; HANDLE hMutex, hMemory; PIFSMRXNP_SHARED_MEMORY pSharedMemory; TRACE_CALL(("NPEnumResource\n")); TRACE_INFO(("NPEnumResource Count Requested %d\n",*lpcCount)); AvailableBufferSize = *lpBufferSize; StringOffset = *lpBufferSize; pBufferResource = (LPNETRESOURCEW)lpBuffer; pEnumHandle = (PIFSMRXNP_ENUMERATION_HANDLE)hEnum; *lpcCount = 0; if (pEnumHandle->LastIndex >= IFSMRXNP_MAX_DEVICES) { return(WN_NO_MORE_ENTRIES); } Status = OpenSharedMemory( &hMutex, &hMemory, (PVOID)&pSharedMemory); if (Status == WN_SUCCESS) { INT Index; PIFSMRXNP_NETRESOURCE pNetResource; TRACE_INFO(("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]; TRACE_INFO(("NPEnumResource: Examining Index %d\n",Index)); if (pNetResource->InUse) { DWORD ResourceSize; ResourceSize = sizeof(NETRESOURCE) + pNetResource->LocalNameLength + sizeof(WCHAR) + pNetResource->RemoteNameLength + sizeof(WCHAR) + IfsMrxProviderName.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; TRACE_INFO(("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); RtlCopyMemory( pBufferResource->lpLocalName, pNetResource->LocalName, pNetResource->LocalNameLength); pBufferResource->lpLocalName[ pNetResource->LocalNameLength/sizeof(WCHAR)] = L'\0'; TRACE_INFO(("NPEnumResource: Copying remote name Index %d\n",Index)); StringOffset -= (pNetResource->RemoteNameLength + sizeof(WCHAR)); pBufferResource->lpRemoteName = (PWCHAR)((PBYTE)lpBuffer + StringOffset); RtlCopyMemory( pBufferResource->lpRemoteName, pNetResource->RemoteName, pNetResource->RemoteNameLength); pBufferResource->lpRemoteName[ pNetResource->RemoteNameLength/sizeof(WCHAR)] = L'\0'; TRACE_INFO(("NPEnumResource: Copying provider name Index %d\n",Index)); StringOffset -= (IfsMrxProviderName.Length + sizeof(WCHAR)); pBufferResource->lpProvider = (PWCHAR)((PBYTE)lpBuffer + StringOffset); RtlCopyMemory( pBufferResource->lpProvider, IfsMrxProviderName.Buffer, IfsMrxProviderName.Length); pBufferResource->lpProvider[ IfsMrxProviderName.Length/sizeof(WCHAR)] = L'\0'; pBufferResource->lpComment = NULL; pBufferResource++; } else { TRACE_INFO(("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); } TRACE_INFO(("NPEnumResource returning Count %d\n",*lpcCount)); TRACE_CALL(("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 --*/ { TRACE_CALL(("NPCloseEnum\n")); LocalFree(hEnum); return(WN_SUCCESS); } DWORD OpenConnection( PUNICODE_STRING pConnectionName, DWORD Disposition, PFILE_FULL_EA_INFORMATION pEABuffer, DWORD EABufferLength, PHANDLE pConnectionHandle ) /*++ Routine Description: This routine opens the connection. This routine is shared by NpAddConnection and NPCancelConnection Arguments: pConnectionName - the connection name Disposition - the Open disposition pEABuffer - the EA buffer associated with the open EABufferLength - the EA buffer length pConnectionHandle - the placeholder for the connection handle Return Value: WN_SUCCESS if successful, otherwise the appropriate error Notes: --*/ { NTSTATUS Status; IO_STATUS_BLOCK IoStatusBlock; OBJECT_ATTRIBUTES ConnectionObjectAttributes; TRACE_CALL(("OpenConnection: ConnectionName: %S\n", pConnectionName->Buffer)); InitializeObjectAttributes( &ConnectionObjectAttributes, pConnectionName, OBJ_CASE_INSENSITIVE, NULL, NULL); Status = NtCreateFile( pConnectionHandle, SYNCHRONIZE, &ConnectionObjectAttributes, &IoStatusBlock, NULL, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, Disposition, (FILE_CREATE_TREE_CONNECTION | FILE_SYNCHRONOUS_IO_NONALERT), pEABuffer, EABufferLength); if (Status != STATUS_SUCCESS) { TRACE_ERROR(("OpenConnection: NtCreateFile Failed: NTStatus: %08x\n", Status)); return(WN_BAD_NETNAME); } TRACE_CALL(("OpenConnection: return SUCCESS\n")); return(WN_SUCCESS); } 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; OBJECT_ATTRIBUTES ConnectionAttributes; HANDLE ConnectionHandle = INVALID_HANDLE_VALUE; IO_STATUS_BLOCK IoStatusBlock; PWCHAR pLocalName,pRemoteName; USHORT LocalNameLength,RemoteNameLength; // The IFS 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\ifsminiredirector\;:\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)(IfsMRxDeviceName.Length + (USHORT)RemoteNameLength + ((pLocalName != NULL) ? (LocalNameLength + sizeof(WCHAR)) //+1 for ';' : 0) + sizeof(WCHAR)); ConnectionName.Length = ConnectionName.MaximumLength; ConnectionName.Buffer = LocalAlloc( LMEM_ZEROINIT, ConnectionName.Length); if (ConnectionName.Buffer == NULL) { return GetLastError(); } // Copy the name into the buffer RtlCopyMemory( ConnectionName.Buffer, IfsMRxDeviceName.Buffer, IfsMRxDeviceName.Length); wcscat(ConnectionName.Buffer, L"\\"); wcscat(ConnectionName.Buffer, L";"); if (pLocalName != NULL) { wcscat(ConnectionName.Buffer, pLocalName); } wcscat(ConnectionName.Buffer, pRemoteName); Status = OpenConnection( &ConnectionName, FILE_OPEN_IF, NULL, 0, &ConnectionHandle); 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 { TRACE_ERROR(("OpenConnection returned %lx\n",Status)); Status = RtlNtStatusToDosError(Status); } if (Status == WN_SUCCESS) { INT Index; HANDLE hMutex, hMemory; BOOLEAN FreeEntryFound = FALSE; PIFSMRXNP_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) { TRACE_INFO(("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 < IFSMRXNP_MAX_DEVICES)) { pSharedMemory->HighestIndexInUse += 1; Index = pSharedMemory->HighestIndexInUse; FreeEntryFound = TRUE; } if (FreeEntryFound) { PIFSMRXNP_NETRESOURCE pIfsMrxNetResource; pSharedMemory->NumberOfResourcesInUse += 1; pIfsMrxNetResource = &pSharedMemory->NetResources[Index]; pIfsMrxNetResource->InUse = TRUE; pIfsMrxNetResource->dwScope = lpNetResource->dwScope; pIfsMrxNetResource->dwType = lpNetResource->dwType; pIfsMrxNetResource->dwDisplayType = lpNetResource->dwDisplayType; pIfsMrxNetResource->dwUsage = RESOURCEUSAGE_CONNECTABLE; pIfsMrxNetResource->LocalNameLength = LocalNameLength; pIfsMrxNetResource->RemoteNameLength = wcslen(lpNetResource->lpRemoteName) * sizeof(WCHAR); pIfsMrxNetResource->ConnectionNameLength = ConnectionName.Length; // Copy the local name RtlCopyMemory( pIfsMrxNetResource->LocalName, lpNetResource->lpLocalName, pIfsMrxNetResource->LocalNameLength); // Copy the remote name RtlCopyMemory( pIfsMrxNetResource->RemoteName, lpNetResource->lpRemoteName, pIfsMrxNetResource->RemoteNameLength); // Copy the connection name RtlCopyMemory( pIfsMrxNetResource->ConnectionName, ConnectionName.Buffer, pIfsMrxNetResource->ConnectionNameLength); } else { Status = WN_NO_MORE_DEVICES; } CloseSharedMemory( &hMutex, &hMemory, (PVOID)&pSharedMemory); } else { TRACE_ERROR(("NpAddConnection3: OpenSharedMemory returned %lx\n",Status)); } } if (ConnectionHandle != INVALID_HANDLE_VALUE) { NtClose(ConnectionHandle); } 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; PIFSMRXNP_SHARED_MEMORY pSharedMemory; if (*lpName == L'\\' && *(lpName + 1) == L'\\') { bLocalName = FALSE; } TRACE_CALL(("NPCancelConnection\n")); TRACE_INFO(("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; PIFSMRXNP_NETRESOURCE pNetResource; TRACE_INFO(("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; } TRACE_INFO(("NPCancelConnection: Name %S EntryName %S\n", lpName,EntryName.Buffer)); TRACE_INFO(("NPCancelConnection: Name Length %d Entry Name Length %d\n", Name.Length,EntryName.Length)); if (Name.Length == EntryName.Length) { if (RtlEqualUnicodeString( &Name, &EntryName, TRUE)) { EntryFound = TRUE; break; } } } } if (EntryFound) { HANDLE ConnectionHandle; IO_STATUS_BLOCK IoStatusBlock; UNICODE_STRING ConnectionName; TRACE_INFO(("NPCancelConnection: Connection Found:\n")); ConnectionName.Length = pNetResource->ConnectionNameLength; ConnectionName.MaximumLength = ConnectionName.Length; ConnectionName.Buffer = pNetResource->ConnectionName; Status = OpenConnection( &ConnectionName, FILE_OPEN, NULL, 0, &ConnectionHandle); if (Status == WN_SUCCESS) { Status = NtFsControlFile( ConnectionHandle, NULL, NULL, NULL, &IoStatusBlock, FSCTL_IFSMRX_DELETE_CONNECTION, NULL, 0, NULL, 0); NtClose(ConnectionHandle); TRACE_ERROR(("NPCancelConnection: NtFsControlFile 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) { TRACE_ERROR(("RemoveDosDevice: DefineDosDevice error: %d\n", GetLastError())); Status = GetLastError(); } else { pNetResource->InUse = FALSE; if (Index == pSharedMemory->HighestIndexInUse) { pSharedMemory->HighestIndexInUse -= 1; pSharedMemory->NumberOfResourcesInUse -= 1; } } } else { Status = RtlNtStatusToDosError(Status); } } else { TRACE_ERROR(("NPCancelConnection: OpenConnection returned Status %lx\n",Status)); } } else { Status = WN_BAD_NETNAME; } 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; PIFSMRXNP_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; PIFSMRXNP_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 (RtlEqualUnicodeString( &Name, &EntryName, TRUE)) { EntryFound = TRUE; break; } } } } if (EntryFound) { if (*lpBufferSize < pNetResource->RemoteNameLength) { *lpBufferSize = pNetResource->RemoteNameLength; Status = ERROR_BUFFER_OVERFLOW; } else { *lpBufferSize = pNetResource->RemoteNameLength; RtlCopyMemory( 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; TRACE_CALL(("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; TRACE_CALL(("NPGetUniversalName: lpLocalPath: %S InfoLevel: %d\n", lpLocalPath, dwInfoLevel)); if (dwInfoLevel != UNIVERSAL_NAME_INFO_LEVEL && dwInfoLevel != REMOTE_NAME_INFO_LEVEL) { TRACE_ERROR(("NPGetUniversalName: bad dwInfoLevel value: %d\n", dwInfoLevel)); return(WN_BAD_LEVEL); } wcscpy(LocalPath, lpLocalPath); pDriveLetter = LocalPath; if (pRemainingPath = wcschr(pDriveLetter, L':')) { ReplacedChar = *(++pRemainingPath); *pRemainingPath = L'\0'; } if ((dwStatus = NPGetConnection(pDriveLetter, RemoteName, &RemoteNameLength)) != WN_SUCCESS) { TRACE_ERROR(("NPGetUniversalName: NPGetConnection return dwStatus: %d\n", dwStatus)); return(dwStatus); } if (pRemainingPath) { *pRemainingPath = ReplacedChar; } TRACE_INFO(("NPGetUniversalName: pRemainingPath: %S RemoteName: %S\n", pRemainingPath, RemoteName)); wcscpy(UniversalName, RemoteName); if (pRemainingPath) wcscat(UniversalName, pRemainingPath); TRACE_INFO(("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) { TRACE_ERROR(("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)); RtlCopyMemory( 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; RtlCopyMemory( pRemoteNameInfo->lpUniversalName, UniversalName, UniversalNameLength); RtlCopyMemory( pRemoteNameInfo->lpConnectionName, RemoteName, RemoteNameLength); RtlCopyMemory( pRemoteNameInfo->lpRemainingPath, pRemainingPath, RemainingPathLength); } TRACE_CALL(("NPGetUniversalName: WN_SUCCESS\n")); return(WN_SUCCESS); }