Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

478 lines
16 KiB

  1. //+----------------------------------------------------------------------------
  2. //
  3. // File: vpndownload.cpp
  4. //
  5. // Module: CMDL32.EXE
  6. //
  7. // Synopsis: This file contains the code to handle the updating of VPN phonebooks.
  8. //
  9. // Copyright (c) 2000-2001 Microsoft Corporation
  10. //
  11. // Author: quintinb Created 11/03/00
  12. //
  13. //+----------------------------------------------------------------------------
  14. #include "cmdl.h"
  15. #include "gppswithalloc.cpp"
  16. #include "tunl_str.h"
  17. //+----------------------------------------------------------------------------
  18. //
  19. // Function: DownloadVpnFileFromUrl
  20. //
  21. // Synopsis: This function is responsible for downloading a VPN file update
  22. // from the given URL and storing the retreived data in a temp file.
  23. // The full path to the temp file is passed back to the caller via
  24. // the ppszVpnUpdateFile variable. The var must be freed by the caller.
  25. //
  26. // Arguments: LPCTSTR pszVpnUpdateUrl - URL to update the vpn file from
  27. // LPTSTR* ppszVpnUpdateFile - pointer to hold the file name of the
  28. // updated VPN file downloaded from the server.
  29. // Used by the caller to copy the temp file
  30. // over the existing file. The memory allocated
  31. // for this string must be freed by the caller.
  32. //
  33. // Returns: BOOL - TRUE if the download was successful
  34. //
  35. // History: quintinb Created 11/05/00
  36. //
  37. //+----------------------------------------------------------------------------
  38. BOOL DownloadVpnFileFromUrl(LPCTSTR pszVpnUpdateUrl, LPTSTR* ppszVpnUpdateFile)
  39. // REVIEW: shouldn't this support the /LAN flag and not do the download if it cannot find the CM connection active? What
  40. // about setting the socket option code?
  41. {
  42. BOOL bReturn = FALSE;
  43. BOOL bDeleteFileOnFailure = FALSE;
  44. HANDLE hFile = NULL;
  45. HINTERNET hInternet = NULL;
  46. HINTERNET hPage = NULL;
  47. DWORD dwSize = MAX_PATH;
  48. LPTSTR pszBuffer = NULL;
  49. BOOL bExitLoop = FALSE;
  50. if ((NULL == pszVpnUpdateUrl) || (TEXT('\0') == pszVpnUpdateUrl[0]))
  51. {
  52. goto Cleanup;
  53. }
  54. CMTRACE1("DownloadVpnFileFromUrl: URL is %s", pszVpnUpdateUrl);
  55. //
  56. // First, let's create the file that we are going to download the updated file
  57. // too. This requires us to figure out what the temporary directory path is
  58. // and then create a uniquely named file in it.
  59. //
  60. do
  61. {
  62. CmFree(pszBuffer);
  63. pszBuffer = (LPTSTR)CmMalloc((dwSize + 1)*sizeof(TCHAR));
  64. if (pszBuffer)
  65. {
  66. DWORD dwReturnedSize = GetTempPath (dwSize, pszBuffer);
  67. if (0 == dwReturnedSize)
  68. {
  69. //
  70. // An error occurred, lets report it and bail.
  71. //
  72. DWORD dwError = GetLastError();
  73. CMASSERTMSG(FALSE, TEXT("DownloadVpnFileFromUrl -- GetTempPath returned an error."));
  74. CMTRACE1(TEXT("DownloadVpnFileFromUrl -- GetTempPath failed, GLE = %d"), dwError);
  75. goto Cleanup;
  76. }
  77. else if (dwReturnedSize > dwSize)
  78. {
  79. //
  80. // Not big enough we will have to loop again.
  81. //
  82. dwSize = dwReturnedSize;
  83. if (1024*1024 < dwReturnedSize)
  84. {
  85. CMASSERTMSG(FALSE, TEXT("DownloadVpnFileFromUrl -- GetTempPath asked for more than 1MB of memory. Something is wrong, bailing."));
  86. goto Cleanup;
  87. }
  88. }
  89. else
  90. {
  91. //
  92. // We got what we wanted, it's time to leave the loop
  93. //
  94. bExitLoop = TRUE;
  95. }
  96. }
  97. else
  98. {
  99. CMASSERTMSG(FALSE, TEXT("DownloadVpnFileFromUrl -- CmMalloc failed for pszBuffer."));
  100. goto Cleanup;
  101. }
  102. } while(!bExitLoop);
  103. //
  104. // Okay, now we have the temp file path. Next let's get a temp file name in that directory.
  105. //
  106. *ppszVpnUpdateFile = (LPTSTR)CmMalloc((dwSize + 24)*sizeof(TCHAR)); // GetTempFileName doesn't provide sizing info, lame
  107. if (*ppszVpnUpdateFile)
  108. {
  109. dwSize = GetTempFileName(pszBuffer, TEXT("VPN"), 0, *ppszVpnUpdateFile);
  110. if ((0 == dwSize) || (TEXT('\0') == (*ppszVpnUpdateFile)[0]))
  111. {
  112. CMASSERTMSG(FALSE, TEXT("DownloadVpnFileFromUrl -- GetTempFileName failed."));
  113. goto Cleanup;
  114. }
  115. }
  116. else
  117. {
  118. CMASSERTMSG(FALSE, TEXT("DownloadVpnFileFromUrl -- CmMalloc failed for *ppszVpnUpdateFile"));
  119. goto Cleanup;
  120. }
  121. //
  122. // Free pszBuffer so we can use it to read in file data below
  123. //
  124. CmFree (pszBuffer);
  125. pszBuffer = NULL;
  126. //
  127. // Okay, we have a file name let's get a file handle to it that we can write too
  128. //
  129. hFile = CreateFile(*ppszVpnUpdateFile, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
  130. if (INVALID_HANDLE_VALUE != hFile)
  131. {
  132. //
  133. // We have created the file, let's make sure to delete it if we fail from here on out.
  134. //
  135. bDeleteFileOnFailure = TRUE;
  136. //
  137. // Initialize WININET
  138. //
  139. hInternet = InternetOpen(TEXT("Microsoft(R) Connection Manager Vpn File Update"), INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
  140. if (hInternet)
  141. {
  142. //
  143. // Open the URL
  144. //
  145. hPage = InternetOpenUrl(hInternet, pszVpnUpdateUrl, NULL, 0, 0, 0);
  146. if (hPage)
  147. {
  148. const DWORD c_dwBufferSize = 1024; // REVIEW: why did the original use 4096 on the stack, seems awfully large to me?
  149. pszBuffer = (LPTSTR)CmMalloc(c_dwBufferSize);
  150. if (pszBuffer)
  151. {
  152. bExitLoop = FALSE;
  153. do
  154. {
  155. if (InternetReadFile(hPage, pszBuffer, c_dwBufferSize, &dwSize))
  156. {
  157. //
  158. // We got data, write it to the temp file
  159. //
  160. if (0 == dwSize)
  161. {
  162. //
  163. // We succeeded with a zero read size. That means we hit
  164. // end of file and are done.
  165. //
  166. bReturn = TRUE;
  167. bExitLoop = TRUE;
  168. }
  169. if (FALSE == WriteFile(hFile, pszBuffer, dwSize, &dwSize, NULL))
  170. {
  171. bReturn = FALSE;
  172. CMASSERTMSG(FALSE, TEXT("DownloadVpnFileFromUrl -- WriteFile failed."));
  173. goto Cleanup;
  174. }
  175. }
  176. else
  177. {
  178. goto Cleanup;
  179. }
  180. } while (!bExitLoop);
  181. }
  182. else
  183. {
  184. CMASSERTMSG(FALSE, TEXT("DownloadVpnFileFromUrl -- unable to allocate the file buffer"));
  185. goto Cleanup;
  186. }
  187. }
  188. else
  189. {
  190. DWORD dwError = GetLastError();
  191. CMTRACE1(TEXT("DownloadVpnFileFromUrl -- InternetOpenUrl failed, GLE %s"), dwError);
  192. }
  193. }
  194. else
  195. {
  196. DWORD dwError = GetLastError();
  197. CMTRACE1(TEXT("DownloadVpnFileFromUrl -- InternetOpen failed, GLE %s"), dwError);
  198. }
  199. }
  200. Cleanup:
  201. //
  202. // Close our handles
  203. //
  204. if (hPage)
  205. {
  206. InternetCloseHandle(hPage);
  207. }
  208. if (hInternet)
  209. {
  210. InternetCloseHandle(hInternet);
  211. }
  212. if (hFile)
  213. {
  214. CloseHandle(hFile);
  215. }
  216. //
  217. // Free up the buffer we alloc-ed
  218. //
  219. CmFree(pszBuffer);
  220. //
  221. // Finally cleanup the temp file and temp file name if we failed
  222. //
  223. if (FALSE == bReturn)
  224. {
  225. if (bDeleteFileOnFailure && *ppszVpnUpdateFile)
  226. {
  227. DeleteFile(*ppszVpnUpdateFile);
  228. }
  229. CmFree(*ppszVpnUpdateFile);
  230. *ppszVpnUpdateFile = NULL;
  231. CMTRACE(TEXT("DownloadVpnFileFromUrl -- VPN file download failed!"));
  232. }
  233. else
  234. {
  235. CMTRACE(TEXT("DownloadVpnFileFromUrl -- VPN file download succeeded!"));
  236. }
  237. return bReturn;
  238. }
  239. //+----------------------------------------------------------------------------
  240. //
  241. // Function: OverwriteVpnFileWithUpdate
  242. //
  243. // Synopsis: This function is responsible for copying the given new vpn file
  244. // over the given existing vpn file. The code first makes a backup
  245. // copy of the existing file just in case something goes wrong with the
  246. // data overwrite. If a problem exists then it copies the original back
  247. // over to ensure nothing got corrupted in the failed copy.
  248. //
  249. // Arguments: LPCTSTR pszExistingVpnFile - full path to the existing VPN file
  250. // LPCTSTR pszNewVpnFile - full path to the temp VPN file to overwrite
  251. // the existing file with.
  252. //
  253. // Returns: BOOL - TRUE if the update was successful
  254. //
  255. // History: quintinb Created 11/03/00
  256. //
  257. //+----------------------------------------------------------------------------
  258. BOOL OverwriteVpnFileWithUpdate(LPCTSTR pszExistingVpnFile, LPCTSTR pszNewVpnFile)
  259. {
  260. if ((NULL == pszExistingVpnFile) || (NULL == pszNewVpnFile) ||
  261. (TEXT('\0') == pszExistingVpnFile[0]) || (TEXT('\0') == pszNewVpnFile[0]))
  262. {
  263. CMASSERTMSG(FALSE, TEXT("OverwriteVpnFileWithUpdate -- invalid parameter passed."));
  264. return FALSE;
  265. }
  266. BOOL bReturn = FALSE;
  267. //
  268. // We first want to make a backup copy of the original file
  269. //
  270. const TCHAR* const c_pszDotBak = TEXT(".bak");
  271. DWORD dwSize = (lstrlen(pszExistingVpnFile) + lstrlen(c_pszDotBak) + 1)*sizeof(TCHAR);
  272. LPTSTR pszBackupFile = (LPTSTR)CmMalloc(dwSize);
  273. if (pszBackupFile)
  274. {
  275. wsprintf(pszBackupFile, TEXT("%s%s"), pszExistingVpnFile, c_pszDotBak);
  276. if (pszBackupFile[0])
  277. {
  278. if (CopyFile(pszExistingVpnFile, pszBackupFile, FALSE)) // FALSE == bFailIfExists
  279. {
  280. //
  281. // Now copy over the new file
  282. //
  283. if (CopyFile(pszNewVpnFile, pszExistingVpnFile, FALSE)) // FALSE == bFailIfExists
  284. {
  285. bReturn = TRUE;
  286. }
  287. else
  288. {
  289. DWORD dwError = GetLastError();
  290. CMTRACE1(TEXT("OverwriteVpnFileWithUpdate -- CopyFile of the new file over the original file failed, GLE %s"), dwError);
  291. CMASSERTMSG(FALSE, TEXT("OverwriteVpnFileWithUpdate -- update of the original file failed, attempting to restore the original from backup."));
  292. //
  293. // We need to restore the backup file
  294. //
  295. if (!CopyFile(pszBackupFile, pszExistingVpnFile, FALSE)) // FALSE == bFailIfExists
  296. {
  297. dwError = GetLastError();
  298. CMTRACE1(TEXT("OverwriteVpnFileWithUpdate -- CopyFile to restore the saved backup file failed, GLE %s"), dwError);
  299. CMASSERTMSG(FALSE, TEXT("OverwriteVpnFileWithUpdate -- restoration of backup failed!"));
  300. }
  301. }
  302. //
  303. // Delete the backup file
  304. //
  305. DeleteFile(pszBackupFile);
  306. }
  307. else
  308. {
  309. DWORD dwError = GetLastError();
  310. CMTRACE1(TEXT("OverwriteVpnFileWithUpdate -- CopyFile of the original file to the backup file failed, GLE %s"), dwError);
  311. }
  312. }
  313. }
  314. CmFree(pszBackupFile);
  315. if (bReturn)
  316. {
  317. CMTRACE(TEXT("OverwriteVpnFileWithUpdate -- VPN file update succeeded!"));
  318. }
  319. else
  320. {
  321. CMTRACE(TEXT("OverwriteVpnFileWithUpdate -- VPN file update failed."));
  322. }
  323. return bReturn;
  324. }
  325. //+----------------------------------------------------------------------------
  326. //
  327. // Function: UpdateVpnFileForProfile
  328. //
  329. // Synopsis: This function is called to download and update a VPN file with a
  330. // newly downloaded VPN update file.
  331. //
  332. // Arguments: LPCTSTR pszCmpPath - full path to the cmp file
  333. //
  334. // Returns: BOOL - TRUE if the download and update were successful.
  335. //
  336. // History: quintinb Created 11/03/00
  337. //
  338. //+----------------------------------------------------------------------------
  339. BOOL UpdateVpnFileForProfile(LPCTSTR pszCmpPath)
  340. {
  341. if ((NULL == pszCmpPath) || (TEXT('\0') == pszCmpPath[0]))
  342. {
  343. CMASSERTMSG(FALSE, TEXT("UpdateVpnFileForProfile in cmdl32.exe -- invalid pszCmpPath parameter."));
  344. return FALSE;
  345. }
  346. BOOL bReturn = FALSE;
  347. //
  348. // Convert the .cmp path into the .cms path
  349. //
  350. LPTSTR pszService = GetPrivateProfileStringWithAlloc(c_pszCmSection, c_pszCmEntryCmsFile, TEXT(""), pszCmpPath);
  351. if (pszService && *pszService)
  352. {
  353. //
  354. // We have the relative path to the cms, build the full path to the file
  355. //
  356. LPTSTR pszCmsPath = CmBuildFullPathFromRelative(pszCmpPath, pszService);
  357. if (pszCmsPath && *pszCmsPath)
  358. {
  359. //
  360. // Next get the VPN phonebook file name from the profile.
  361. //
  362. LPTSTR pszVpnFileName = GetPrivateProfileStringWithAlloc(c_pszCmSection, c_pszCmEntryTunnelFile, TEXT(""), pszCmsPath);
  363. if (pszVpnFileName && *pszVpnFileName)
  364. {
  365. LPTSTR pszVpnFile = CmBuildFullPathFromRelative(pszCmpPath, pszVpnFileName);
  366. if (pszVpnFile && *pszVpnFile)
  367. {
  368. //
  369. // Now get the URL to update the vpn file from
  370. //
  371. LPTSTR pszVpnUpdateUrl = GetPrivateProfileStringWithAlloc(c_pszCmSectionSettings, c_pszCmEntryVpnUpdateUrl, TEXT(""), pszVpnFile);
  372. if (pszVpnUpdateUrl && *pszVpnUpdateUrl)
  373. {
  374. //
  375. // Finally, we have a URL so let's download the updated VPN server list.
  376. //
  377. LPTSTR pszUpdatedVpnFile = NULL;
  378. bReturn = DownloadVpnFileFromUrl(pszVpnUpdateUrl, &pszUpdatedVpnFile);
  379. if (bReturn && pszUpdatedVpnFile && *pszUpdatedVpnFile)
  380. {
  381. bReturn = OverwriteVpnFileWithUpdate(pszVpnFile, pszUpdatedVpnFile);
  382. }
  383. CmFree (pszUpdatedVpnFile);
  384. }
  385. else
  386. {
  387. CMASSERTMSG(FALSE, TEXT("UpdateVpnFileForProfile in cmdl32.exe -- unable to get the URL to update the vpn file from..."));
  388. }
  389. CmFree(pszVpnUpdateUrl);
  390. }
  391. else
  392. {
  393. CMASSERTMSG(FALSE, TEXT("UpdateVpnFileForProfile in cmdl32.exe -- unable to expand the path to the vpn file."));
  394. }
  395. CmFree(pszVpnFile);
  396. }
  397. else
  398. {
  399. CMASSERTMSG(FALSE, TEXT("UpdateVpnFileForProfile in cmdl32.exe -- unable to retrieve the vpn file name."));
  400. }
  401. CmFree(pszVpnFileName);
  402. }
  403. else
  404. {
  405. CMASSERTMSG(FALSE, TEXT("UpdateVpnFileForProfile in cmdl32.exe -- unable to build the cms path from the cmp path."));
  406. }
  407. CmFree(pszCmsPath);
  408. }
  409. else
  410. {
  411. CMASSERTMSG(FALSE, TEXT("UpdateVpnFileForProfile in cmdl32.exe -- unable to get the relative path to the CMS."));
  412. }
  413. CmFree(pszService);
  414. return bReturn;
  415. }