/* * cnrlink.c - CNRLink ADT module. */ /* Headers **********/ #include "project.h" #pragma hdrstop #include "cnrlink.h" #include "server.h" /* Constants ************/ /* WNetUseConnection() flag combinations */ #define ALL_CONNECT_IN_FLAGS (CONNECT_UPDATE_PROFILE |\ CONNECT_UPDATE_RECENT |\ CONNECT_TEMPORARY |\ CONNECT_INTERACTIVE |\ CONNECT_PROMPT |\ CONNECT_REDIRECT) #define ALL_CONNECT_OUT_FLAGS (CONNECT_REFCOUNT |\ CONNECT_LOCALDRIVE) /* Macros *********/ /* macros for accessing ICNRLINK data */ #define ICNRL_Remote_Name_PtrA(picnrl) \ ((LPSTR)(((PBYTE)(picnrl)) + (picnrl)->ucbNetNameOffset)) #define ICNRL_Device_PtrA(picnrl) \ ((LPSTR)(((PBYTE)(picnrl)) + (picnrl)->ucbDeviceOffset)) #define ICNRL_Remote_Name_PtrW(picnrl) \ ((LPWSTR)(((PBYTE)(picnrl)) + (picnrl)->ucbNetNameOffsetW)) #define ICNRL_Device_PtrW(picnrl) \ ((LPWSTR)(((PBYTE)(picnrl)) + (picnrl)->ucbDeviceOffsetW)) #define IS_ICNRL_ANSI(picnrl) \ ((PBYTE)(picnrl) + ((PICNRLINKW)(picnrl))->ucbNetNameOffset) == (PBYTE)&(((PICNRLINKW)(picnrl))->ucbNetNameOffsetW) #ifdef UNICODE #define ICNRL_Remote_Name_Ptr(picnrl) ICNRL_Remote_Name_PtrW(picnrl) #define ICNRL_Device_Ptr(picnrl) ICNRL_Device_PtrW(picnrl) #else #define ICNRL_Remote_Name_Ptr(picnrl) ICNRL_Remote_Name_PtrA(picnrl) #define ICNRL_Device_Ptr(picnrl) ICNRL_Device_PtrA(picnrl) #endif /* Types ********/ /* @doc INTERNAL @enum ICNRLINKFLAGS | Internal CNRLink structure flags. */ typedef enum _icnrlinkflags { /* @emem ICNRL_FL_VALID_DEVICE | If set, last redirected drive is valid. If clear, last redirected drive is not valid. */ ICNRL_FL_VALID_DEVICE = 0x0001, /* @emem ICNRL_FL_VALID_NET_TYPE | If set, net type is valid. If clear, net type is not valid. */ ICNRL_FL_VALID_NET_TYPE = 0x0002, /* @emem ALL_ICNRL_FLAGS | All internal CNRLink structure flags. */ ALL_ICNRL_FLAGS = (ICNRL_FL_VALID_DEVICE | ICNRL_FL_VALID_NET_TYPE) } ICNRLINKFLAGS; /* @doc INTERNAL @struct ICNRLINK | Internal definition of relocatable connectable network resource (CNR) link structure. An structure may contain an ICNRLINK structure. An ICNRLINK structure consists of a header described as below, followed by variable-length data. */ typedef struct _icnrlinkA { /* @field UINT | ucbSize | Length of ICNRLINK structure in bytes, including ucbSize field. */ UINT ucbSize; /* @field DWORD | dwFlags | A bit mask of flags from the enumeration. */ DWORD dwFlags; /* @field UINT | ucbNetNameOffset | Offset in bytes of CNR name string from base of structure. The CNR name string may be passed to WNetUseConnection() to add a connection to the CNR. Example CNRLink name string: "\\\\fredbird\\work". */ UINT ucbNetNameOffset; /* @field UINT | ucbDeviceOffset | Offset in bytes of last redirected local device string from base of structure. This field is only valid if ICNRL_FL_VALID_DEVICE is set in dwFlags. The last redirected local device string may be passed to WNetUseConnection() to add a redirected device connection to the CNR. Example last redirected local device string: "D:". */ UINT ucbDeviceOffset; /* @field DWORD | dwNetType | The network type as returned in a NETINFOSTRUCT. This field is only valid if ICNRL_FL_VALID_NET_TYPE is set in dwFlags. The net type is used to retrieve the host net resource's host NP's name to use in calling WNetUseConnection(). Example net type: WNNC_NET_NETWARE. */ DWORD dwNetType; } ICNRLINKA; DECLARE_STANDARD_TYPES(ICNRLINKA); #ifdef UNICODE typedef struct _icnrlinkW { /* @field UINT | ucbSize | Length of ICNRLINK structure in bytes, including ucbSize field. */ UINT ucbSize; /* @field DWORD | dwFlags | A bit mask of flags from the enumeration. */ DWORD dwFlags; /* @field UINT | ucbNetNameOffset | Offset in bytes of CNR name string from base of structure. The CNR name string may be passed to WNetUseConnection() to add a connection to the CNR. Example CNRLink name string: "\\\\fredbird\\work". */ UINT ucbNetNameOffset; /* @field UINT | ucbDeviceOffset | Offset in bytes of last redirected local device string from base of structure. This field is only valid if ICNRL_FL_VALID_DEVICE is set in dwFlags. The last redirected local device string may be passed to WNetUseConnection() to add a redirected device connection to the CNR. Example last redirected local device string: "D:". */ UINT ucbDeviceOffset; /* @field DWORD | dwNetType | The network type as returned in a NETINFOSTRUCT. This field is only valid if ICNRL_FL_VALID_NET_TYPE is set in dwFlags. The net type is used to retrieve the host net resource's host NP's name to use in calling WNetUseConnection(). Example net type: WNNC_NET_NETWARE. */ DWORD dwNetType; /* These members are for storing the unicode version of the strings */ UINT ucbNetNameOffsetW; UINT ucbDeviceOffsetW; } ICNRLINKW; DECLARE_STANDARD_TYPES(ICNRLINKW); #endif #ifdef UNICODE #define ICNRLINK ICNRLINKW #define PICNRLINK PICNRLINKW #define CICNRLINK CICNRLINKW #define PCICNRLINK PCICNRLINKW #else #define ICNRLINK ICNRLINKA #define PICNRLINK PICNRLINKA #define CICNRLINK CICNRLINKA #define PCICNRLINK PCICNRLINKA #endif /* Exported from MPR.DLL, but not in winnetwk.h */ #ifdef UNICODE DWORD APIENTRY WNetGetResourceInformationW (LPNETRESOURCE lpNetResource, LPVOID lpBuffer, LPDWORD cbBuffer, LPTSTR * lplpSystem); #define WNetGetResourceInformation WNetGetResourceInformationW #else DWORD APIENTRY WNetGetResourceInformationA (LPNETRESOURCE lpNetResource, LPVOID lpBuffer, LPDWORD cbBuffer, LPTSTR * lplpSystem); #define WNetGetResourceInformation WNetGetResourceInformationA #endif /***************************** Private Functions *****************************/ /* Module Prototypes ********************/ PRIVATE_CODE BOOL GetNetPathFromLocalPath(LPCTSTR, LPTSTR, LPCTSTR *, PBOOL, PDWORD); PRIVATE_CODE BOOL UnifyICNRLinkInfo(LPCTSTR, DWORD, LPCTSTR, DWORD, PICNRLINK *, PUINT); PRIVATE_CODE BOOL GetNetType(LPCTSTR, PDWORD); PRIVATE_CODE BOOL GetNetProviderName(PCICNRLINK, LPTSTR); PRIVATE_CODE COMPARISONRESULT CompareNetNames(LPCTSTR, LPCTSTR); PRIVATE_CODE BOOL SearchForRedirectedConnection(PCICNRLINK, LPTSTR); #if defined(DEBUG) || defined (VSTF) PRIVATE_CODE BOOL IsValidDevice(LPCTSTR); PRIVATE_CODE BOOL IsValidNetType(DWORD); PRIVATE_CODE BOOL IsValidPCICNRLINK(PCICNRLINK); #endif #if defined(DEBUG) PRIVATE_CODE BOOL IsValidNetProviderName(LPCTSTR); #endif #if 0 DWORD APIENTRY WNetGetNetworkInformationW( LPCWSTR lpProvider, LPNETINFOSTRUCT lpNetInfoStruct ) { if (wcsicmp(lpProvider, L"Microsoft Windows Network") == 0) { lpNetInfoStruct->wNetType = (WORD)WNNC_NET_LANMAN; return ERROR_SUCCESS; } else if (wcsicmp(lpProvider, L"Novell Network") == 0) { lpNetInfoStruct->wNetType = (WORD)WNNC_NET_NETWARE; return ERROR_SUCCESS; } else { return ERROR_NOT_SUPPORTED; } } #endif /* ** GetNetPathFromLocalPath() ** ** ** ** Arguments: ** ** Returns: ** ** Side Effects: none */ PRIVATE_CODE BOOL GetNetPathFromLocalPath(LPCTSTR pcszLocalPath, LPTSTR pszNetNameBuf, LPCTSTR *ppcszCommonPathSuffix, PBOOL pbIsShared, PDWORD pdwNetType) { BOOL bResult = TRUE; PCSERVERVTABLE pcsvt; ASSERT(IsDrivePath(pcszLocalPath)); ASSERT(IS_VALID_WRITE_BUFFER_PTR(pszNetNameBuf, STR, MAX_PATH_LEN)); ASSERT(IS_VALID_WRITE_PTR(ppcszCommonPathSuffix, LPCTSTR)); ASSERT(IS_VALID_WRITE_PTR(pbIsShared, BOOL)); ASSERT(IS_VALID_WRITE_PTR(pdwNetType, DWORD)); *pbIsShared = FALSE; if (GetServerVTable(&pcsvt)) { TCHAR rgchSharedPath[MAX_PATH_LEN]; ASSERT(lstrlen(pcszLocalPath) < ARRAYSIZE(rgchSharedPath)); lstrcpy(rgchSharedPath, pcszLocalPath); FOREVER { if ((pcsvt->GetNetResourceFromLocalPath)(rgchSharedPath, pszNetNameBuf, MAX_PATH_LEN, pdwNetType)) { ASSERT(lstrlen(pszNetNameBuf) < MAX_PATH_LEN); /* Determine common path suffix. */ *ppcszCommonPathSuffix = pcszLocalPath + lstrlen(rgchSharedPath); /* Skip any leading slash. */ if (IS_SLASH(**ppcszCommonPathSuffix)) *ppcszCommonPathSuffix = CharNext(*ppcszCommonPathSuffix); ASSERT(! IS_SLASH(**ppcszCommonPathSuffix)); // if it is terminated with a $ it is a hidden share, in that // case don't consider this shared *pbIsShared = pszNetNameBuf[lstrlen(pszNetNameBuf) -1] != TEXT('$'); break; } else { if (! DeleteLastDrivePathElement(rgchSharedPath)) break; } } } ASSERT(! bResult || ! *pbIsShared || (EVAL(IsUNCPath(pszNetNameBuf)) && IS_VALID_STRING_PTR(*ppcszCommonPathSuffix, CSTR) && EVAL(*ppcszCommonPathSuffix >= pcszLocalPath) && EVAL(IsStringContained(pcszLocalPath, *ppcszCommonPathSuffix)) && EVAL(IsValidNetType(*pdwNetType)))); return(bResult); } /* ** UnifyICNRLinkInfo() ** ** ** ** Arguments: ** ** Returns: ** ** Side Effects: none */ PRIVATE_CODE BOOL UnifyICNRLinkInfo(LPCTSTR pcszNetName, DWORD dwFlags, LPCTSTR pcszDevice, DWORD dwNetType, PICNRLINK *ppicnrl, PUINT pucbICNRLinkLen) { BOOL bResult; UINT ucbDataOffset; #ifdef UNICODE BOOL bUnicode; UINT cchChars; CHAR szAnsiNetName[MAX_PATH]; CHAR szAnsiDevice[MAX_PATH]; UINT cbAnsiNetName; UINT cbWideNetName; UINT cbAnsiDevice; UINT cbWideDevice; UINT cbChars; #endif ASSERT(IsUNCPath(pcszNetName)); ASSERT(FLAGS_ARE_VALID(dwFlags, ALL_ICNRL_FLAGS)); ASSERT(IS_FLAG_CLEAR(dwFlags, ICNRL_FL_VALID_DEVICE) || IsValidDevice(pcszDevice)); ASSERT(IS_FLAG_CLEAR(dwFlags, ICNRL_FL_VALID_NET_TYPE) || IsValidNetType(dwNetType)); ASSERT(IS_VALID_WRITE_PTR(ppicnrl, PCNRLINK)); ASSERT(IS_VALID_WRITE_PTR(pucbICNRLinkLen, UINT)); #ifdef UNICODE bUnicode = FALSE; cbAnsiNetName = WideCharToMultiByte(CP_ACP, 0, pcszNetName, -1, szAnsiNetName, MAX_PATH, 0, 0); if ( cbAnsiNetName == 0 ) { bUnicode = FALSE; } else { WCHAR szWideNetName[MAX_PATH]; cbChars = MultiByteToWideChar(CP_ACP, 0, szAnsiNetName, -1, szWideNetName, MAX_PATH); if ( cbChars == 0 || lstrcmp(pcszNetName,szWideNetName) != 0 ) { bUnicode = TRUE; } } if (IS_FLAG_SET(dwFlags, ICNRL_FL_VALID_DEVICE)) { cbAnsiDevice = WideCharToMultiByte(CP_ACP, 0, pcszDevice, -1, szAnsiDevice, MAX_PATH, 0, 0); if ( cbAnsiDevice == 0 ) { bUnicode = FALSE; } else { WCHAR szWideDevice[MAX_PATH]; cchChars = MultiByteToWideChar(CP_ACP, 0, szAnsiDevice, -1, szWideDevice, MAX_PATH); if ( cchChars == 0 || lstrcmp(pcszDevice,szWideDevice) != 0 ) { bUnicode = TRUE; } } } else { cbAnsiDevice = 0; } if ( bUnicode ) { ucbDataOffset = SIZEOF(ICNRLINKW); /* (+ 1) for null terminator. */ cbWideNetName = (lstrlen(pcszNetName) + 1) * sizeof(TCHAR); if (IS_FLAG_SET(dwFlags, ICNRL_FL_VALID_DEVICE)) cbWideDevice = (lstrlen(pcszDevice) + 1) * sizeof(TCHAR); else cbWideDevice = 0; } else { ucbDataOffset = SIZEOF(ICNRLINKA); cbWideNetName = 0; cbWideDevice = 0; } *pucbICNRLinkLen = ucbDataOffset + cbAnsiNetName + cbAnsiDevice; if ( bUnicode ) { *pucbICNRLinkLen = ALIGN_WORD_CNT(*pucbICNRLinkLen) + cbWideNetName + cbWideDevice; } #else /* Assume we won't overflow *pucbICNRLinkLen here. */ /* (+ 1) for null terminator. */ *pucbICNRLinkLen = SIZEOF(**ppicnrl) + (lstrlen(pcszNetName) + 1) * SIZEOF(TCHAR); if (IS_FLAG_SET(dwFlags, ICNRL_FL_VALID_DEVICE)) /* (+ 1) for null terminator. */ *pucbICNRLinkLen += (lstrlen(pcszDevice) + 1) * SIZEOF(TCHAR); ucbDataOffset = SIZEOF(ICNRLINKA); #endif bResult = AllocateMemory(*pucbICNRLinkLen, ppicnrl); if (bResult) { (*ppicnrl)->ucbSize = *pucbICNRLinkLen; (*ppicnrl)->dwFlags = dwFlags; if (IS_FLAG_SET(dwFlags, ICNRL_FL_VALID_NET_TYPE)) (*ppicnrl)->dwNetType = dwNetType; else (*ppicnrl)->dwNetType = 0; /* Append remote name. */ (*ppicnrl)->ucbNetNameOffset = ucbDataOffset; #ifdef UNICODE lstrcpyA(ICNRL_Remote_Name_PtrA(*ppicnrl), szAnsiNetName); ucbDataOffset += cbAnsiNetName; if (IS_FLAG_SET(dwFlags, ICNRL_FL_VALID_DEVICE)) { /* Append device name. */ (*ppicnrl)->ucbDeviceOffset = ucbDataOffset; lstrcpyA(ICNRL_Device_PtrA(*ppicnrl), szAnsiDevice); ucbDataOffset += cbAnsiDevice; } else { (*ppicnrl)->ucbDeviceOffset = 0; } if ( bUnicode ) { ucbDataOffset = ALIGN_WORD_CNT(ucbDataOffset); (*ppicnrl)->ucbNetNameOffsetW = ucbDataOffset; lstrcpy(ICNRL_Remote_Name_PtrW(*ppicnrl), pcszNetName); ucbDataOffset += cbWideNetName; if (IS_FLAG_SET(dwFlags, ICNRL_FL_VALID_DEVICE)) { /* Append device name. */ (*ppicnrl)->ucbDeviceOffsetW = ucbDataOffset; lstrcpy(ICNRL_Device_Ptr(*ppicnrl), pcszDevice); /* (+ 1) for null terminator. */ ucbDataOffset += cbWideDevice; } else { (*ppicnrl)->ucbDeviceOffsetW = 0; } } #else lstrcpy(ICNRL_Remote_Name_Ptr(*ppicnrl), pcszNetName); /* (+ 1) for null terminator. */ ucbDataOffset += lstrlen(pcszNetName) + 1; if (IS_FLAG_SET(dwFlags, ICNRL_FL_VALID_DEVICE)) { /* Append device name. */ (*ppicnrl)->ucbDeviceOffset = ucbDataOffset; lstrcpy(ICNRL_Device_Ptr(*ppicnrl), pcszDevice); #ifdef DEBUG /* (+ 1) for null terminator. */ ucbDataOffset += (lstrlen(pcszDevice) + 1) * SIZEOF(TCHAR); #endif } else (*ppicnrl)->ucbDeviceOffset = 0; #endif /* Do all the calculated lengths match? */ ASSERT(ucbDataOffset == (*ppicnrl)->ucbSize); ASSERT(ucbDataOffset == *pucbICNRLinkLen); } ASSERT(! bResult || (IS_VALID_STRUCT_PTR(*ppicnrl, CICNRLINK) && EVAL(*pucbICNRLinkLen == GetCNRLinkLen((PCCNRLINK)*ppicnrl)))); return(bResult); } /* ** GetNetType() ** ** ** ** Arguments: ** ** Returns: ** ** Side Effects: none */ PRIVATE_CODE BOOL GetNetType(LPCTSTR pcszCNRName, PDWORD pdwNetType) { BOOL bResult = FALSE; NETRESOURCE nrIn; NETRESOURCEBUF nrbufOut; DWORD dwcbBufLen = SIZEOF(nrbufOut); LPTSTR pszFileSysPath; DWORD dwNetResult; #ifdef DEBUG DWORD dwcmsTicks; #endif ASSERT(IsValidCNRName(pcszCNRName)); ASSERT(IS_VALID_WRITE_PTR(pdwNetType, DWORD)); /* RAIDRAID: (15691) We only support disk resource connections here. */ ZeroMemory(&nrIn, SIZEOF(nrIn)); nrIn.lpRemoteName = (LPTSTR)pcszCNRName; nrIn.dwType = RESOURCETYPE_DISK; #ifdef DEBUG dwcmsTicks = GetTickCount(); #endif dwNetResult = WNetGetResourceInformation(&nrIn, &(nrbufOut.rgbyte), &dwcbBufLen, &pszFileSysPath); #ifdef DEBUG dwcmsTicks = GetTickCount() - dwcmsTicks; TRACE_OUT((TEXT("GetRemotePathInfo(): WNetGetResourceInformation() on net resource %s took %lu.%03lu seconds."), pcszCNRName, (dwcmsTicks / 1000), (dwcmsTicks % 1000))); #endif if (dwNetResult == ERROR_SUCCESS) { if (nrbufOut.nr.lpProvider) { NETINFOSTRUCT nis; ASSERT(IS_VALID_STRING_PTR(nrbufOut.nr.lpProvider, STR)); nis.cbStructure = SIZEOF(nis); dwNetResult = WNetGetNetworkInformation(nrbufOut.nr.lpProvider, &nis); if (dwNetResult == ERROR_SUCCESS) { *pdwNetType = ((nis.wNetType) << 16); bResult = TRUE; TRACE_OUT((TEXT("GetNetType(): Net type for CNR %s is %#08lx."), pcszCNRName, *pdwNetType)); } else WARNING_OUT((TEXT("GetNetType(): WNetGetNetworkInformation() failed for %s NP, returning %lu."), nrbufOut.nr.lpProvider, dwNetResult)); } else WARNING_OUT((TEXT("GetNetType(): WNetGetResourceInformation() was unable to determine the NP for CNR %s."), pcszCNRName)); } else WARNING_OUT((TEXT("GetNetType(): WNetGetResourceInformation() failed for CNR %s, returning %lu."), pcszCNRName, dwNetResult)); ASSERT(! bResult || IsValidNetType(*pdwNetType)); return(bResult); } /* ** GetNetProviderName() ** ** ** ** Arguments: ** ** Returns: ** ** Side Effects: none */ PRIVATE_CODE BOOL GetNetProviderName(PCICNRLINK pcicnrl, LPTSTR pszNPNameBuf) { BOOL bResult = FALSE; ASSERT(IS_VALID_STRUCT_PTR(pcicnrl, CICNRLINK)); ASSERT(IS_VALID_WRITE_BUFFER_PTR(pszNPNameBuf, STR, MAX_PATH_LEN)); if (IS_FLAG_SET(pcicnrl->dwFlags, ICNRL_FL_VALID_NET_TYPE)) { DWORD dwcbNPNameBufLen; DWORD dwNetResult; dwcbNPNameBufLen = MAX_PATH_LEN; dwNetResult = WNetGetProviderName(pcicnrl->dwNetType, pszNPNameBuf, &dwcbNPNameBufLen); if (dwNetResult == ERROR_SUCCESS) { bResult = TRUE; #ifdef UNICODE // // Unicode builds need to accept both ansi and unicode ICNRLINK structures. // Note the use of '%S' (upper case). This will accept an ANSI string // in a UNICODE build environment. // if (IS_ICNRL_ANSI(pcicnrl)) TRACE_OUT((TEXT("GetNetProviderName(): NP for CNR %S is %s."), ICNRL_Remote_Name_PtrA(pcicnrl), pszNPNameBuf)); else #endif TRACE_OUT((TEXT("GetNetProviderName(): NP for CNR %s is %s."), ICNRL_Remote_Name_Ptr(pcicnrl), pszNPNameBuf)); } else WARNING_OUT((TEXT("GetNetProviderName(): WNetGetProviderName() failed for CNR %s's net type %#08lx, returning %lu."), TEXT(""), // ICNRL_Remote_Name_Ptr(pcicnrl), pcicnrl->dwNetType, dwNetResult)); } else WARNING_OUT((TEXT("GetNetProviderName(): Net type for CNR %s is not known. Unable to determine NP name."), TEXT(""))); // ICNRL_Remote_Name_Ptr(pcicnrl))); ASSERT(! bResult || IsValidNetProviderName(pszNPNameBuf)); return(bResult); } /* ** CompareNetNames() ** ** ** ** Arguments: ** ** Returns: ** ** Side Effects: none */ PRIVATE_CODE COMPARISONRESULT CompareNetNames(LPCTSTR pcszFirstNetName, LPCTSTR pcszSecondNetName) { ASSERT(IS_VALID_STRING_PTR(pcszFirstNetName, CSTR)); ASSERT(IS_VALID_STRING_PTR(pcszSecondNetName, CSTR)); return(MapIntToComparisonResult(lstrcmp(pcszFirstNetName, pcszSecondNetName))); } /* ** SearchForRedirectedConnection() ** ** ** ** Arguments: ** ** Returns: ** ** Side Effects: none */ PRIVATE_CODE BOOL SearchForRedirectedConnection(PCICNRLINK pcicnrl, LPTSTR pszRootPathBuf) { BOOL bResult = FALSE; HANDLE henum; DWORD dwNetResult; ASSERT(IS_VALID_STRUCT_PTR(pcicnrl, CICNRLINK)); ASSERT(IS_VALID_WRITE_BUFFER_PTR(pszRootPathBuf, STR, MAX_PATH_LEN)); #ifdef DEBUG #ifdef UNICODE { LPWSTR pszWideNetName; WCHAR szWideNetName[MAX_PATH]; if (IS_ICNRL_ANSI(pcicnrl)) { pszWideNetName = szWideNetName; MultiByteToWideChar(CP_ACP, 0, ICNRL_Remote_Name_PtrA(pcicnrl), -1, szWideNetName, MAX_PATH); } else { pszWideNetName = ICNRL_Remote_Name_PtrW(pcicnrl); } WARNING_OUT((TEXT("SearchForRedirectedConnection(): Enumerating local connections searching for redirected connection to CNR \"%s\"."), pszWideNetName)); } #else WARNING_OUT((TEXT("SearchForRedirectedConnection(): Enumerating local connections searching for redirected connection to CNR \"%s\"."), ICNRL_Remote_Name_Ptr(pcicnrl))); #endif #endif /* RAIDRAID: (15691) We only support container resources here. */ dwNetResult = WNetOpenEnum(RESOURCE_CONNECTED, RESOURCETYPE_DISK, RESOURCEUSAGE_CONTAINER | RESOURCEUSAGE_ATTACHED, NULL, &henum); if (dwNetResult == WN_SUCCESS) { DWORD dwc = 1; NETRESOURCEBUF nrbuf; DWORD dwcbBufLen = SIZEOF(nrbuf); while ((dwNetResult = WNetEnumResource(henum, &dwc, &(nrbuf.rgbyte), &dwcbBufLen)) == WN_SUCCESS) { /* Is this a redirected connection? */ if (nrbuf.nr.lpRemoteName != NULL) { if (nrbuf.nr.lpLocalName != NULL) { /* Yes. Is it a redirected connection to the desired CNR? */ #ifdef UNICODE WCHAR szWideNetName[MAX_PATH]; LPWSTR pszWideNetName; if (IS_ICNRL_ANSI(pcicnrl)) { pszWideNetName = szWideNetName; MultiByteToWideChar(CP_ACP, 0, ICNRL_Remote_Name_PtrA(pcicnrl), -1, szWideNetName, MAX_PATH); } else { pszWideNetName = ICNRL_Remote_Name_Ptr(pcicnrl); } if (CompareNetNames(pszWideNetName, nrbuf.nr.lpRemoteName) == CR_EQUAL) #else if (CompareNetNames(ICNRL_Remote_Name_Ptr(pcicnrl), nrbuf.nr.lpRemoteName) == CR_EQUAL) #endif { /* Yes. */ ASSERT(lstrlen(nrbuf.nr.lpLocalName) < MAX_PATH_LEN); lstrcpy(pszRootPathBuf, nrbuf.nr.lpLocalName); bResult = TRUE; TRACE_OUT((TEXT("SearchForRedirectedConnection(): Found CNR \"%s\" connected to %s."), nrbuf.nr.lpRemoteName, pszRootPathBuf)); break; } else /* No. */ TRACE_OUT((TEXT("SearchForRedirectedConnection(): Skipping unmatched enumerated connection to CNR \"%s\" on %s."), nrbuf.nr.lpRemoteName, nrbuf.nr.lpLocalName)); } else /* No. */ TRACE_OUT((TEXT("SearchForRedirectedConnection(): Skipping enumerated deviceless connection to CNR \"%s\"."), nrbuf.nr.lpRemoteName)); } else WARNING_OUT((TEXT("SearchForRedirectedConnection(): Skipping enumerated connection with no CNR name."))); } if (! bResult && dwNetResult != WN_NO_MORE_ENTRIES) WARNING_OUT((TEXT("SearchForRedirectedConnection(): WNetEnumResource() failed, returning %lu."), dwNetResult)); dwNetResult = WNetCloseEnum(henum); if (dwNetResult != WN_SUCCESS) WARNING_OUT((TEXT("SearchForRedirectedConnection(): WNetCloseEnum() failed, returning %lu."), dwNetResult)); } else WARNING_OUT((TEXT("SearchForRedirectedConnection(): WNetOpenEnum() failed, returning %lu."), dwNetResult)); return(bResult); } #if defined(DEBUG) || defined (VSTF) /* ** IsValidDevice() ** ** ** ** Arguments: ** ** Returns: ** ** Side Effects: none */ PRIVATE_CODE BOOL IsValidDevice(LPCTSTR pcszDevice) { /* Any valid string < MAX_PATH_LEN bytes long is a valid device name. */ return(IS_VALID_STRING_PTR(pcszDevice, CSTR) && EVAL(lstrlen(pcszDevice) < MAX_PATH_LEN)); } /* ** IsValidNetType() ** ** ** ** Arguments: ** ** Returns: ** ** Side Effects: none */ PRIVATE_CODE BOOL IsValidNetType(DWORD dwNetType) { BOOL bResult; switch (dwNetType & 0xffff0000) { default: WARNING_OUT((TEXT("IsValidNetType(): Unexpected net type %#08lx is neither NetWare nor LANMan."), dwNetType)); /* Fall through... */ case WNNC_NET_LANMAN: case WNNC_NET_NETWARE: bResult = TRUE; break; } if (dwNetType & 0x0000ffff) WARNING_OUT((TEXT("IsValidNetType(): Low word of net type %#08lx is non-zero."), dwNetType)); return(bResult); } /* ** IsValidPCICNRLINK() ** ** ** ** Arguments: ** ** Returns: ** ** Side Effects: none */ PRIVATE_CODE BOOL IsValidPCICNRLINK(PCICNRLINK pcicnrl) { BOOL bResult; if (IS_VALID_READ_PTR(pcicnrl, CICNRLINK) && IS_VALID_READ_BUFFER_PTR(pcicnrl, CICNRLINK, pcicnrl->ucbSize) && FLAGS_ARE_VALID(pcicnrl->dwFlags, ALL_ICNRL_FLAGS) && EVAL(IsValidCNRName(ICNRL_Remote_Name_Ptr(pcicnrl))) && EVAL(IsContained(pcicnrl, pcicnrl->ucbSize, ICNRL_Remote_Name_PtrA(pcicnrl), lstrlenA(ICNRL_Remote_Name_PtrA(pcicnrl)))) && (IS_FLAG_CLEAR(pcicnrl->dwFlags, ICNRL_FL_VALID_NET_TYPE) || EVAL(IsValidNetType(pcicnrl->dwNetType)))) { if (IS_FLAG_CLEAR(pcicnrl->dwFlags, ICNRL_FL_VALID_DEVICE)) { ASSERT(! pcicnrl->ucbDeviceOffset); bResult = TRUE; } else bResult = (EVAL(IsValidDevice(ICNRL_Device_Ptr(pcicnrl))) && EVAL(IsContained(pcicnrl, pcicnrl->ucbSize, ICNRL_Device_PtrA(pcicnrl), lstrlenA(ICNRL_Device_PtrA(pcicnrl))))); } else bResult = FALSE; return(bResult); } #endif #if defined(DEBUG) /* ** IsValidNetProviderName() ** ** ** ** Arguments: ** ** Returns: ** ** Side Effects: none */ PRIVATE_CODE BOOL IsValidNetProviderName(LPCTSTR pcszNetProvider) { /* Any string < MAX_PATH_LEN characters long is a valid NP name. */ return(IS_VALID_STRING_PTR(pcszNetProvider, CSTR) && lstrlen(pcszNetProvider) < MAX_PATH_LEN); } #endif /****************************** Public Functions *****************************/ /* ** CreateLocalCNRLink() ** ** ** ** Arguments: ** ** Returns: ** ** Side Effects: none ** ** If TRUE is returned: ** 1) *ppcnrl is only valid if *pucbCNRLinkLen > 0. ** 2) pszLocalBasePathBuf is valid. ** 3) *ppcszCommonPathSuffix is valid. ** ** If *pucbCNRLinkLen == 0, pszLocalBasePathBuf is a copy of pcszLocalPath, and ** *ppcszCommonPathSuffix points at the null terminator of pcszLocalPath. ** ** If *pucbCNRLinkLen > 0, pszLocalBasePathBuf is the closest shared local base ** path, and *ppcszCommonPathSuffix points at that path's suffix in ** pcszLocalPath. */ PUBLIC_CODE BOOL CreateLocalCNRLink(LPCTSTR pcszLocalPath, PCNRLINK *ppcnrl, PUINT pucbCNRLinkLen, LPTSTR pszLocalBasePathBuf, LPCTSTR *ppcszCommonPathSuffix) { BOOL bResult; TCHAR rgchNetName[MAX_PATH_LEN]; BOOL bShared; DWORD dwNetType; ASSERT(IsDrivePath(pcszLocalPath)); ASSERT(IS_VALID_WRITE_PTR(ppcnrl, PCNRLINK)); ASSERT(IS_VALID_WRITE_PTR(pucbCNRLinkLen, UINT)); ASSERT(IS_VALID_WRITE_BUFFER_PTR(pszLocalBasePathBuf, STR, MAX_PATH_LEN)); ASSERT(IS_VALID_WRITE_PTR(ppcszCommonPathSuffix, LPCTSTR)); bResult = GetNetPathFromLocalPath(pcszLocalPath, rgchNetName, ppcszCommonPathSuffix, &bShared, &dwNetType); if (bResult) { if (bShared) { bResult = UnifyICNRLinkInfo(rgchNetName, ICNRL_FL_VALID_NET_TYPE, NULL, dwNetType, (PICNRLINK *)ppcnrl, pucbCNRLinkLen); if (bResult) { UINT ucbLocalBasePathLen; /* Copy local base path into output buffer. */ ASSERT(*ppcszCommonPathSuffix >= pcszLocalPath); ucbLocalBasePathLen = (UINT)(*ppcszCommonPathSuffix - pcszLocalPath); CopyMemory(pszLocalBasePathBuf, pcszLocalPath, ucbLocalBasePathLen * sizeof(TCHAR)); pszLocalBasePathBuf[ucbLocalBasePathLen] = TEXT('\0'); } } else { /* Not shared. No CNRLink. */ *pucbCNRLinkLen = 0; /* Copy entire local path into output buffer. */ lstrcpy(pszLocalBasePathBuf, pcszLocalPath); /* Common path suffix is the empty string. */ *ppcszCommonPathSuffix = pcszLocalPath + lstrlen(pcszLocalPath); } } ASSERT(! bResult || (EVAL(IsDrivePath(pszLocalBasePathBuf)) && IS_VALID_STRING_PTR(*ppcszCommonPathSuffix, CSTR) && EVAL(IsStringContained(pcszLocalPath, *ppcszCommonPathSuffix)) && (! *pucbCNRLinkLen || (IS_VALID_STRUCT_PTR((PCICNRLINK)*ppcnrl, CICNRLINK) && EVAL(*pucbCNRLinkLen == GetCNRLinkLen(*ppcnrl)))))); return(bResult); } /* ** CreateRemoteCNRLink() ** ** ** ** Arguments: ** ** Returns: ** ** Side Effects: none */ PUBLIC_CODE BOOL CreateRemoteCNRLink(LPCTSTR pcszRemotePath, LPCTSTR pcszCNRName, PCNRLINK *ppcnrl, PUINT pucbCNRLinkLen) { BOOL bResult; /* "D:" + null terminator. */ TCHAR rgchDrive[3]; DWORD dwNetType; ASSERT(IsCanonicalPath(pcszRemotePath)); ASSERT(IsValidCNRName(pcszCNRName)); ASSERT(IS_VALID_WRITE_PTR(ppcnrl, PCNRLINK)); ASSERT(IS_VALID_WRITE_PTR(pucbCNRLinkLen, UINT)); /* Determine net provider. */ bResult = GetNetType(pcszCNRName, &dwNetType); if (bResult) { DWORD dwFlags = ICNRL_FL_VALID_NET_TYPE; /* Determine last redirected drive, if any. */ if (IsDrivePath(pcszRemotePath)) { MyLStrCpyN(rgchDrive, pcszRemotePath, ARRAYSIZE(rgchDrive)); SET_FLAG(dwFlags, ICNRL_FL_VALID_DEVICE); } else rgchDrive[0] = TEXT('\0'); bResult = UnifyICNRLinkInfo(pcszCNRName, dwFlags, rgchDrive, dwNetType, (PICNRLINK *)ppcnrl, pucbCNRLinkLen); } ASSERT(! bResult || (IS_VALID_STRUCT_PTR((PCICNRLINK)*ppcnrl, CICNRLINK) && EVAL(*pucbCNRLinkLen == GetCNRLinkLen(*ppcnrl)))); return(bResult); } /* ** DestroyCNRLink() ** ** ** ** Arguments: ** ** Returns: ** ** Side Effects: none */ PUBLIC_CODE void DestroyCNRLink(PCNRLINK pcnrl) { ASSERT(IS_VALID_STRUCT_PTR(pcnrl, CCNRLINK)); FreeMemory(pcnrl); return; } /* ** CompareCNRLinks() ** ** ** ** Arguments: ** ** Returns: ** ** Side Effects: none ** ** CNR link data is compared in the following order: ** ** 1) net name ** ** N.b., net types are ignored when comparing CNRLinks. */ PUBLIC_CODE COMPARISONRESULT CompareCNRLinks(PCCNRLINK pccnrlFirst, PCCNRLINK pccnrlSecond) { #ifdef UNICODE WCHAR szWideNetNameFirst[MAX_PATH]; LPWSTR pszWideNetNameFirst; WCHAR szWideNetNameSecond[MAX_PATH]; LPWSTR pszWideNetNameSecond; #endif ASSERT(IS_VALID_STRUCT_PTR(pccnrlFirst, CCNRLINK)); ASSERT(IS_VALID_STRUCT_PTR(pccnrlSecond, CCNRLINK)); #ifdef UNICODE if (IS_ICNRL_ANSI(pccnrlFirst)) { pszWideNetNameFirst = szWideNetNameFirst; MultiByteToWideChar(CP_ACP, 0, ICNRL_Remote_Name_PtrA((PCICNRLINK)pccnrlFirst), -1, szWideNetNameFirst, MAX_PATH); } else { pszWideNetNameFirst = ICNRL_Remote_Name_Ptr((PCICNRLINK)pccnrlFirst); } if (IS_ICNRL_ANSI(pccnrlSecond)) { pszWideNetNameSecond = szWideNetNameSecond; MultiByteToWideChar(CP_ACP, 0, ICNRL_Remote_Name_PtrA((PCICNRLINK)pccnrlSecond), -1, szWideNetNameSecond, MAX_PATH); } else { pszWideNetNameSecond = ICNRL_Remote_Name_Ptr((PCICNRLINK)pccnrlSecond); } return(CompareNetNames(pszWideNetNameFirst,pszWideNetNameSecond)); #else return(CompareNetNames(ICNRL_Remote_Name_Ptr((PCICNRLINK)pccnrlFirst), ICNRL_Remote_Name_Ptr((PCICNRLINK)pccnrlSecond))); #endif } /* ** GetLocalPathFromCNRLink() ** ** ** ** Arguments: ** ** Returns: ** ** Side Effects: none */ PUBLIC_CODE BOOL GetLocalPathFromCNRLink(PCCNRLINK pccnrl, LPTSTR pszLocalPathBuf, PDWORD pdwOutFlags) { BOOL bResult; PCSERVERVTABLE pcsvt; ASSERT(IS_VALID_STRUCT_PTR(pccnrl, CCNRLINK)); ASSERT(IS_VALID_WRITE_BUFFER_PTR(pszLocalPathBuf, STR, MAX_PATH_LEN)); ASSERT(IS_VALID_WRITE_PTR(pdwOutFlags, DWORD)); *pdwOutFlags = 0; bResult = GetServerVTable(&pcsvt); if (bResult) { DWORD dwNetType; BOOL bIsLocal; /* * Get local path for share. N.b., the share name must be in upper case * here for MSSHRUI.DLL. */ dwNetType = (IS_FLAG_SET(((PCICNRLINK)pccnrl)->dwFlags, ICNRL_FL_VALID_NET_TYPE) ? ((PCICNRLINK)pccnrl)->dwNetType : 0); #ifdef UNICODE { WCHAR szWideNetName[MAX_PATH]; LPWSTR pszWideNetName = szWideNetName; if (IS_ICNRL_ANSI(pccnrl)) { MultiByteToWideChar(CP_ACP, 0, ICNRL_Remote_Name_PtrA((PCICNRLINK)pccnrl), -1, szWideNetName, MAX_PATH); } else { pszWideNetName = ICNRL_Remote_Name_Ptr((PCICNRLINK)pccnrl); } bResult = (pcsvt->GetLocalPathFromNetResource)( pszWideNetName, dwNetType, pszLocalPathBuf, MAX_PATH_LEN, &bIsLocal); } #else bResult = (pcsvt->GetLocalPathFromNetResource)( ICNRL_Remote_Name_Ptr((PCICNRLINK)pccnrl), dwNetType, pszLocalPathBuf, MAX_PATH_LEN, &bIsLocal); #endif if (bIsLocal) SET_FLAG(*pdwOutFlags, CNR_FL_LOCAL); } ASSERT(FLAGS_ARE_VALID(*pdwOutFlags, ALL_CNR_FLAGS) && (! bResult || (EVAL(IS_FLAG_SET(*pdwOutFlags, CNR_FL_LOCAL)) && EVAL(IsLocalDrivePath(pszLocalPathBuf))))); return(bResult); } /* ** GetRemotePathFromCNRLink() ** ** ** ** Arguments: ** ** Returns: ** ** Side Effects: none */ PUBLIC_CODE void GetRemotePathFromCNRLink(PCCNRLINK pccnrl, LPTSTR pszRemotePathBuf) { ASSERT(IS_VALID_STRUCT_PTR(pccnrl, CCNRLINK)); ASSERT(IS_VALID_WRITE_BUFFER_PTR(pszRemotePathBuf, STR, MAX_PATH_LEN)); /* It's ok that this is broken for non-UNC CNR names. */ /* (- 1) for trailing slash. */ #ifdef UNICODE ASSERT(IS_ICNRL_ANSI(pccnrl) ? (lstrlenA(ICNRL_Remote_Name_PtrA((PCICNRLINK)pccnrl)) < MAX_PATH_LEN - 1) : (lstrlenW(ICNRL_Remote_Name_PtrW((PCICNRLINK)pccnrl)) < MAX_PATH_LEN - 1)); #else ASSERT(lstrlenA(ICNRL_Remote_Name_PtrA((PCICNRLINK)pccnrl)) < MAX_PATH_LEN - 1); #endif #ifdef UNICODE { WCHAR szWideNetName[MAX_PATH]; LPWSTR pszWideNetName; if (IS_ICNRL_ANSI(pccnrl)) { pszWideNetName = szWideNetName; MultiByteToWideChar(CP_ACP, 0, ICNRL_Remote_Name_PtrA((PCICNRLINK)pccnrl), -1, szWideNetName, MAX_PATH); } else { pszWideNetName = ICNRL_Remote_Name_Ptr((PCICNRLINK)pccnrl); } lstrcpy(pszRemotePathBuf, pszWideNetName); } #else lstrcpy(pszRemotePathBuf, ICNRL_Remote_Name_Ptr((PCICNRLINK)pccnrl)); #endif CatPath(pszRemotePathBuf, TEXT("\\")); return; } /* ** ConnectToCNR() ** ** ** ** Arguments: ** ** Returns: ** ** Side Effects: none */ PUBLIC_CODE BOOL ConnectToCNR(PCCNRLINK pccnrl, DWORD dwInFlags, HWND hwndOwner, LPTSTR pszRootPathBuf, PDWORD pdwOutFlags) { BOOL bResult = FALSE; BOOL bValidDevice; BOOL bRedirect; BOOL bTryLastDevice = FALSE; DWORD dwcbRootPathBufLen; LPTSTR pszNetName; LPTSTR pszDevice; #ifdef UNICODE WCHAR szWideNetName[MAX_PATH]; WCHAR szWideDevice[MAX_PATH]; #endif ASSERT(IS_VALID_STRUCT_PTR(pccnrl, CCNRLINK)); ASSERT(FLAGS_ARE_VALID(dwInFlags, ALL_CONNECT_IN_FLAGS)); ASSERT(IS_FLAG_CLEAR(dwInFlags, CONNECT_INTERACTIVE) || IS_VALID_HANDLE(hwndOwner, WND)); ASSERT(IS_VALID_WRITE_BUFFER_PTR(pszRootPathBuf, STR, MAX_PATH_LEN)); ASSERT(IS_VALID_WRITE_PTR(pdwOutFlags, DWORD)); *pdwOutFlags = 0; #ifdef UNICODE if (IS_ICNRL_ANSI(pccnrl)) { pszNetName = szWideNetName; MultiByteToWideChar(CP_ACP, 0, ICNRL_Remote_Name_PtrA((PCICNRLINK)pccnrl), -1, szWideNetName, MAX_PATH); } else { pszNetName = ICNRL_Remote_Name_Ptr((PCICNRLINK)pccnrl); } #else pszNetName = ICNRL_Remote_Name_Ptr((PCICNRLINK)pccnrl); #endif /* Do we have an old redirected device to try? */ bValidDevice = IS_FLAG_SET(((PCICNRLINK)pccnrl)->dwFlags, ICNRL_FL_VALID_DEVICE); #ifdef UNICODE if ( bValidDevice ) { if (IS_ICNRL_ANSI(pccnrl)) { pszDevice = szWideDevice; MultiByteToWideChar(CP_ACP, 0, ICNRL_Device_PtrA((PCICNRLINK)pccnrl), -1, szWideDevice, MAX_PATH); } else { pszDevice = ICNRL_Device_Ptr((PCICNRLINK)pccnrl); } } #else pszDevice = ICNRL_Device_Ptr((PCICNRLINK)pccnrl); #endif bRedirect = (bValidDevice || IS_FLAG_SET(dwInFlags, CONNECT_REDIRECT)); if (bRedirect) { if (bValidDevice) { DWORD dwNetResult; /* "X:" + null terminator */ TCHAR rgchDrive[2 + 1]; /* Yes. Is it already connected to the desired CNR? */ TRACE_OUT((TEXT("ConnectToCNR(): Calling WNetGetConnection() to check %s for CNR \"%s\"."), pszDevice, pszNetName)); dwcbRootPathBufLen = MAX_PATH_LEN; /* WNetGetConnection requires the device name to have no trailing ** backslash. */ MyLStrCpyN(rgchDrive, pszDevice, ARRAYSIZE(rgchDrive)); dwNetResult = WNetGetConnection(rgchDrive, pszRootPathBuf, &dwcbRootPathBufLen); if (dwNetResult == WN_SUCCESS) { if (CompareNetNames(pszNetName, pszRootPathBuf) == CR_EQUAL) { TRACE_OUT((TEXT("ConnectToCNR(): Found matching CNR \"%s\" on %s."), pszRootPathBuf, pszDevice)); ASSERT(lstrlenA(ICNRL_Device_PtrA((PCICNRLINK)pccnrl)) < MAX_PATH_LEN); lstrcpy(pszRootPathBuf, pszDevice); bResult = TRUE; } else TRACE_OUT((TEXT("ConnectToCNR(): Found unmatched CNR \"%s\" on %s."), pszRootPathBuf, pszDevice)); } else { TRACE_OUT((TEXT("ConnectToCNR(): WNetGetConnection() failed on %s."), pszDevice)); /* * Only attempt a connection to the last redirected device if that * device is not already in use. */ bTryLastDevice = (GetDriveType(pszDevice) == DRIVE_NO_ROOT_DIR); } } if (! bResult) /* See if the desired CNR is connected to any local device. */ bResult = SearchForRedirectedConnection((PCICNRLINK)pccnrl, pszRootPathBuf); /* * Assume that no reference count is maintained for redirected device * connections, so we do not have to add a found redirected device * connection again. */ } if (! bResult) { NETRESOURCE nr; TCHAR rgchNPName[MAX_PATH_LEN]; /* RAIDRAID: (15691) We only support disk resource connections here. */ ZeroMemory(&nr, SIZEOF(nr)); nr.lpRemoteName = pszNetName; nr.dwType = RESOURCETYPE_DISK; if (GetNetProviderName((PCICNRLINK)pccnrl, rgchNPName)) nr.lpProvider = rgchNPName; /* Shall we try the old device? */ if (bTryLastDevice) { /* Yes. */ ASSERT(bValidDevice); nr.lpLocalName = pszDevice; WARNING_OUT((TEXT("ConnectToCNR(): Calling WNetUseConnection() to attempt to connect %s to CNR \"%s\"."), nr.lpLocalName, nr.lpRemoteName)); } else { /* No. Shall we attempt to force a redirected connection? */ if (bValidDevice) { /* * Yes. N.b., the caller may already have set CONNECT_REDIRECT in * dwInFlags here. */ SET_FLAG(dwInFlags, CONNECT_REDIRECT); WARNING_OUT((TEXT("ConnectToCNR(): Calling WNetUseConnection() to establish auto-picked redirected connection to CNR \"%s\"."), nr.lpRemoteName)); } else /* No. */ WARNING_OUT((TEXT("ConnectToCNR(): Calling WNetUseConnection() to establish connection to CNR \"%s\"."), TEXT(""))); // nr.lpRemoteName)); ASSERT(! nr.lpLocalName); } dwcbRootPathBufLen = MAX_PATH_LEN; bResult = (WNetUseConnection(hwndOwner, &nr, NULL, NULL, dwInFlags, pszRootPathBuf, &dwcbRootPathBufLen, pdwOutFlags) == NO_ERROR); } if (bResult) CatPath(pszRootPathBuf, TEXT("\\")); ASSERT(! bResult || (IS_VALID_STRING_PTR(pszRootPathBuf, STR) && FLAGS_ARE_VALID(*pdwOutFlags, ALL_CONNECT_OUT_FLAGS))); return(bResult); } /* ** DisconnectFromCNR() ** ** ** ** Arguments: ** ** Returns: ** ** Side Effects: none */ PUBLIC_CODE BOOL DisconnectFromCNR(PCCNRLINK pccnrl) { DWORD dwNetResult; LPTSTR pszNetName; #ifdef UNICODE WCHAR szWideNetName[MAX_PATH]; #endif ASSERT(IS_VALID_STRUCT_PTR(pccnrl, CCNRLINK)); #ifdef UNICODE if (IS_ICNRL_ANSI(pccnrl)) { pszNetName = szWideNetName; MultiByteToWideChar(CP_ACP, 0, ICNRL_Remote_Name_PtrA((PCICNRLINK)pccnrl), -1, szWideNetName, MAX_PATH); } else { pszNetName = ICNRL_Remote_Name_Ptr((PCICNRLINK)pccnrl); } #else pszNetName = ICNRL_Remote_Name_Ptr((PCICNRLINK)pccnrl); #endif dwNetResult = WNetCancelConnection2(pszNetName, CONNECT_REFCOUNT, FALSE); if (dwNetResult == NO_ERROR) WARNING_OUT((TEXT("DisconnectFromCNR(): Reduced connection reference count on CNR \"%s\"."), pszNetName)); else WARNING_OUT((TEXT("DisconnectFromCNR(): Failed to reduce connection reference count on CNR \"%s\". WNetCancelConnection2() returned %lu."), pszNetName)); return(dwNetResult == NO_ERROR); } /* ** IsCNRAvailable() ** ** ** ** Arguments: ** ** Returns: ** ** Side Effects: none */ PUBLIC_CODE BOOL IsCNRAvailable(PCCNRLINK pccnrl) { TCHAR rgchCNRRoot[MAX_PATH_LEN]; LPTSTR pszNetName; #ifdef UNICODE WCHAR szWideNetName[MAX_PATH]; #endif ASSERT(IS_VALID_STRUCT_PTR(pccnrl, CCNRLINK)); #ifdef UNICODE if (IS_ICNRL_ANSI(pccnrl)) { pszNetName = szWideNetName; MultiByteToWideChar(CP_ACP, 0, ICNRL_Remote_Name_PtrA((PCICNRLINK)pccnrl), -1, szWideNetName, MAX_PATH); } else { pszNetName = ICNRL_Remote_Name_Ptr((PCICNRLINK)pccnrl); } #else pszNetName = ICNRL_Remote_Name_Ptr((PCICNRLINK)pccnrl); #endif ASSERT(lstrlen(pszNetName) < ARRAYSIZE(rgchCNRRoot) - 1); lstrcpy(rgchCNRRoot, pszNetName); CatPath(rgchCNRRoot, TEXT("\\")); return(PathExists(rgchCNRRoot)); } /* ** GetCNRLinkLen() ** ** ** ** Arguments: ** ** Returns: ** ** Side Effects: none */ PUBLIC_CODE UINT GetCNRLinkLen(PCCNRLINK pccnrl) { ASSERT(IS_VALID_STRUCT_PTR(pccnrl, CCNRLINK)); return(((PCICNRLINK)pccnrl)->ucbSize); } /* ** GetCNRNetType() ** ** ** ** Arguments: ** ** Returns: ** ** Side Effects: none */ PUBLIC_CODE BOOL GetCNRNetType(PCCNRLINK pccnrl, PCDWORD *ppcdwNetType) { BOOL bResult; ASSERT(IS_VALID_STRUCT_PTR(pccnrl, CCNRLINK)); bResult = IS_FLAG_SET(((PCICNRLINK)pccnrl)->dwFlags, ICNRL_FL_VALID_NET_TYPE); if (bResult) *ppcdwNetType = &(((PCICNRLINK)pccnrl)->dwNetType); ASSERT(! bResult || IsValidNetType(**ppcdwNetType)); return(bResult); } /* ** GetCNRName() ** ** ** ** Arguments: ** ** Returns: ** ** Side Effects: none */ PUBLIC_CODE BOOL GetCNRName(PCCNRLINK pccnrl, LPCSTR *ppcszCNRName) { ASSERT(IS_VALID_STRUCT_PTR(pccnrl, CCNRLINK)); *ppcszCNRName = ICNRL_Remote_Name_PtrA((PCICNRLINK)pccnrl); ASSERT(IS_VALID_STRING_PTRA(*ppcszCNRName, CSTR)); return(TRUE); } #ifdef UNICODE /* ** GetCNRNameW() ** ** ** ** Arguments: ** ** Returns: ** ** Side Effects: none */ PUBLIC_CODE BOOL GetCNRNameW(PCCNRLINK pccnrl, LPCWSTR *ppcszCNRName) { ASSERT(IS_VALID_STRUCT_PTR(pccnrl, CCNRLINK)); if (IS_ICNRL_ANSI(pccnrl)) *ppcszCNRName = NULL; else { *ppcszCNRName = ICNRL_Remote_Name_Ptr((PCICNRLINK)pccnrl); ASSERT(IS_VALID_STRING_PTR(*ppcszCNRName, CSTR)); } return(TRUE); } #endif /* ** GetLastRedirectedDevice() ** ** ** ** Arguments: ** ** Returns: ** ** Side Effects: none */ PUBLIC_CODE BOOL GetLastRedirectedDevice(PCCNRLINK pccnrl, LPCSTR *ppcszDevice) { BOOL bResult; ASSERT(IS_VALID_STRUCT_PTR(pccnrl, CCNRLINK)); bResult = IS_FLAG_SET(((PCICNRLINK)pccnrl)->dwFlags, ICNRL_FL_VALID_DEVICE); if (bResult) *ppcszDevice = ICNRL_Device_PtrA((PCICNRLINK)pccnrl); ASSERT(! bResult || IS_VALID_STRING_PTRA(*ppcszDevice, CSTR)); return(bResult); } #ifdef UNICODE /* ** GetLastRedirectedDeviceW() ** ** ** ** Arguments: ** ** Returns: ** ** Side Effects: none */ PUBLIC_CODE BOOL GetLastRedirectedDeviceW(PCCNRLINK pccnrl, LPCWSTR *ppcszDevice) { BOOL bResult; ASSERT(IS_VALID_STRUCT_PTR(pccnrl, CCNRLINK)); bResult = IS_FLAG_SET(((PCICNRLINK)pccnrl)->dwFlags, ICNRL_FL_VALID_DEVICE); if (bResult) if (IS_ICNRL_ANSI(pccnrl)) *ppcszDevice = NULL; else { *ppcszDevice = ICNRL_Device_Ptr((PCICNRLINK)pccnrl); ASSERT(! bResult || IS_VALID_STRING_PTR(*ppcszDevice, CSTR)); } return(bResult); } #endif #if defined(DEBUG) || defined (VSTF) /* ** IsValidPCCNRLINK() ** ** ** ** Arguments: ** ** Returns: ** ** Side Effects: none */ PUBLIC_CODE BOOL IsValidPCCNRLINK(PCCNRLINK pccnrl) { return(IS_VALID_STRUCT_PTR((PCICNRLINK)pccnrl, CICNRLINK)); } #endif #ifdef DEBUG /* ** DumpCNRLink() ** ** ** ** Arguments: ** ** Returns: ** ** Side Effects: none */ PUBLIC_CODE void DumpCNRLink(PCCNRLINK pccnrl) { ASSERT(IS_VALID_STRUCT_PTR(pccnrl, CCNRLINK)); PLAIN_TRACE_OUT((TEXT("%s%s[CNR link] ucbSize %#x"), INDENT_STRING, INDENT_STRING, ((PCICNRLINK)pccnrl)->ucbSize)); PLAIN_TRACE_OUT((TEXT("%s%s[CNR link] dwFLags = %#08lx"), INDENT_STRING, INDENT_STRING, ((PCICNRLINK)pccnrl)->dwFlags)); PLAIN_TRACE_OUT((TEXT("%s%s[CNR link] CNR name \"%s\""), INDENT_STRING, INDENT_STRING, ICNRL_Remote_Name_Ptr((PCICNRLINK)pccnrl))); if (IS_FLAG_SET(((PCICNRLINK)pccnrl)->dwFlags, ICNRL_FL_VALID_NET_TYPE)) PLAIN_TRACE_OUT((TEXT("%s%s[CNR link] net type %#08lx"), INDENT_STRING, INDENT_STRING, ((PCICNRLINK)pccnrl)->dwNetType)); else PLAIN_TRACE_OUT((TEXT("%s%s[CNR link] net type unknown"), INDENT_STRING, INDENT_STRING)); if (IS_FLAG_SET(((PCICNRLINK)pccnrl)->dwFlags, ICNRL_FL_VALID_DEVICE)) PLAIN_TRACE_OUT((TEXT("%s%s[CNR link] last redirected local device \"%s\""), INDENT_STRING, INDENT_STRING, ICNRL_Device_Ptr((PCICNRLINK)pccnrl))); else PLAIN_TRACE_OUT((TEXT("%s%s[CNR link] no last redirected local device"), INDENT_STRING, INDENT_STRING)); return; } #endif