Leaked source code of windows server 2003
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.

525 lines
19 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: DWORD - ERROR_SUCCESS if download was successful, error code otherwise
  34. //
  35. // History: quintinb Created 11/05/00
  36. //
  37. //+----------------------------------------------------------------------------
  38. DWORD DownloadVpnFileFromUrl(LPCTSTR pszVpnUpdateUrl, LPTSTR* ppszVpnUpdateFile)
  39. {
  40. DWORD dwError = ERROR_NOT_ENOUGH_MEMORY;
  41. BOOL bDeleteFileOnFailure = FALSE;
  42. HANDLE hFile = NULL;
  43. HINTERNET hInternet = NULL;
  44. HINTERNET hPage = NULL;
  45. DWORD dwSize = MAX_PATH;
  46. LPTSTR pszBuffer = NULL;
  47. BOOL bExitLoop = FALSE;
  48. if ((NULL == pszVpnUpdateUrl) || (TEXT('\0') == pszVpnUpdateUrl[0]))
  49. {
  50. dwError = ERROR_INVALID_PARAMETER;
  51. goto Cleanup;
  52. }
  53. CMTRACE1("DownloadVpnFileFromUrl: URL is %s", pszVpnUpdateUrl);
  54. //
  55. // First, let's create the file that we are going to download the updated file
  56. // too. This requires us to figure out what the temporary directory path is
  57. // and then create a uniquely named file in it.
  58. //
  59. do
  60. {
  61. CmFree(pszBuffer);
  62. pszBuffer = (LPTSTR)CmMalloc((dwSize + 1)*sizeof(TCHAR));
  63. if (pszBuffer)
  64. {
  65. DWORD dwReturnedSize = GetTempPath (dwSize, pszBuffer);
  66. if (0 == dwReturnedSize)
  67. {
  68. //
  69. // An error occurred, lets report it and bail.
  70. //
  71. dwError = GetLastError();
  72. CMASSERTMSG(FALSE, TEXT("DownloadVpnFileFromUrl -- GetTempPath returned an error."));
  73. CMTRACE1(TEXT("DownloadVpnFileFromUrl -- GetTempPath failed, GLE = %d"), dwError);
  74. goto Cleanup;
  75. }
  76. else if (dwReturnedSize > dwSize)
  77. {
  78. //
  79. // Not big enough we will have to loop again.
  80. //
  81. dwSize = dwReturnedSize;
  82. if (1024*1024 < dwReturnedSize)
  83. {
  84. CMASSERTMSG(FALSE, TEXT("DownloadVpnFileFromUrl -- GetTempPath asked for more than 1MB of memory. Something is wrong, bailing."));
  85. goto Cleanup;
  86. }
  87. }
  88. else
  89. {
  90. //
  91. // We got what we wanted, it's time to leave the loop
  92. //
  93. bExitLoop = TRUE;
  94. }
  95. }
  96. else
  97. {
  98. CMASSERTMSG(FALSE, TEXT("DownloadVpnFileFromUrl -- CmMalloc failed for pszBuffer."));
  99. goto Cleanup;
  100. }
  101. } while(!bExitLoop);
  102. //
  103. // Okay, now we have the temp file path. Next let's get a temp file name in that directory.
  104. //
  105. *ppszVpnUpdateFile = (LPTSTR)CmMalloc((dwSize + 24)*sizeof(TCHAR)); // GetTempFileName doesn't provide sizing info, lame
  106. if (*ppszVpnUpdateFile)
  107. {
  108. dwSize = GetTempFileName(pszBuffer, TEXT("VPN"), 0, *ppszVpnUpdateFile);
  109. if ((0 == dwSize) || (TEXT('\0') == (*ppszVpnUpdateFile)[0]))
  110. {
  111. dwError = GetLastError();
  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. // Supress auto-dial calls to CM from WININET now that we have a handle
  144. //
  145. SuppressInetAutoDial(hInternet);
  146. //
  147. // Make sure that WinInet isn't in offline mode
  148. //
  149. (VOID)SetInetStateConnected(hInternet);
  150. //
  151. // Open the URL
  152. //
  153. hPage = InternetOpenUrl(hInternet, pszVpnUpdateUrl, NULL, 0, 0, 0);
  154. if (hPage)
  155. {
  156. const DWORD c_dwBufferSize = 1024; // REVIEW: why did the original use 4096 on the stack, seems awfully large to me?
  157. pszBuffer = (LPTSTR)CmMalloc(c_dwBufferSize);
  158. if (pszBuffer)
  159. {
  160. bExitLoop = FALSE;
  161. do
  162. {
  163. if (InternetReadFile(hPage, pszBuffer, c_dwBufferSize, &dwSize))
  164. {
  165. //
  166. // We got data, write it to the temp file
  167. //
  168. if (0 == dwSize)
  169. {
  170. //
  171. // We succeeded with a zero read size. That means we hit
  172. // end of file and are done.
  173. //
  174. dwError = ERROR_SUCCESS;
  175. bExitLoop = TRUE;
  176. }
  177. if (FALSE == WriteFile(hFile, pszBuffer, dwSize, &dwSize, NULL))
  178. {
  179. dwError = GetLastError();
  180. CMASSERTMSG(FALSE, TEXT("DownloadVpnFileFromUrl -- WriteFile failed."));
  181. goto Cleanup;
  182. }
  183. }
  184. else
  185. {
  186. dwError = GetLastError();
  187. goto Cleanup;
  188. }
  189. } while (!bExitLoop);
  190. //
  191. // now let's see if we have a valid file, or an "error" HTML page
  192. //
  193. if (0 == GetPrivateProfileSection(c_pszCmSectionVpnServers,
  194. pszBuffer,
  195. c_dwBufferSize,
  196. *ppszVpnUpdateFile))
  197. {
  198. dwError = ERROR_INVALID_DATA;
  199. CMTRACE(TEXT("DownloadVpnFileFromUrl -- downloaded file does not seem to contain a VPN list."));
  200. goto Cleanup;
  201. }
  202. }
  203. else
  204. {
  205. CMASSERTMSG(FALSE, TEXT("DownloadVpnFileFromUrl -- unable to allocate the file buffer"));
  206. goto Cleanup;
  207. }
  208. }
  209. else
  210. {
  211. dwError = GetLastError();
  212. CMTRACE1(TEXT("DownloadVpnFileFromUrl -- InternetOpenUrl failed, GLE %d"), dwError);
  213. }
  214. }
  215. else
  216. {
  217. dwError = GetLastError();
  218. CMTRACE1(TEXT("DownloadVpnFileFromUrl -- InternetOpen failed, GLE %d"), dwError);
  219. }
  220. }
  221. Cleanup:
  222. //
  223. // Close our handles
  224. //
  225. if (hPage)
  226. {
  227. InternetCloseHandle(hPage);
  228. }
  229. if (hInternet)
  230. {
  231. InternetCloseHandle(hInternet);
  232. }
  233. if (hFile)
  234. {
  235. CloseHandle(hFile);
  236. }
  237. //
  238. // Free up the buffer we alloc-ed
  239. //
  240. CmFree(pszBuffer);
  241. //
  242. // Finally cleanup the temp file and temp file name if we failed
  243. //
  244. if (ERROR_SUCCESS != dwError)
  245. {
  246. if (bDeleteFileOnFailure && *ppszVpnUpdateFile)
  247. {
  248. DeleteFile(*ppszVpnUpdateFile);
  249. }
  250. CmFree(*ppszVpnUpdateFile);
  251. *ppszVpnUpdateFile = NULL;
  252. CMTRACE(TEXT("DownloadVpnFileFromUrl -- VPN file download failed!"));
  253. }
  254. else
  255. {
  256. CMTRACE(TEXT("DownloadVpnFileFromUrl -- VPN file download succeeded!"));
  257. }
  258. return dwError;
  259. }
  260. //+----------------------------------------------------------------------------
  261. //
  262. // Function: OverwriteVpnFileWithUpdate
  263. //
  264. // Synopsis: This function is responsible for copying the given new vpn file
  265. // over the given existing vpn file. The code first makes a backup
  266. // copy of the existing file just in case something goes wrong with the
  267. // data overwrite. If a problem exists then it copies the original back
  268. // over to ensure nothing got corrupted in the failed copy.
  269. //
  270. // Arguments: LPCTSTR pszExistingVpnFile - full path to the existing VPN file
  271. // LPCTSTR pszNewVpnFile - full path to the temp VPN file to overwrite
  272. // the existing file with.
  273. //
  274. // Returns: DWORD - ERROR_SUCCESS if update was successful, error code otherwise
  275. //
  276. // History: quintinb Created 11/03/00
  277. //
  278. //+----------------------------------------------------------------------------
  279. DWORD OverwriteVpnFileWithUpdate(LPCTSTR pszExistingVpnFile, LPCTSTR pszNewVpnFile)
  280. {
  281. if ((NULL == pszExistingVpnFile) || (NULL == pszNewVpnFile) ||
  282. (TEXT('\0') == pszExistingVpnFile[0]) || (TEXT('\0') == pszNewVpnFile[0]))
  283. {
  284. CMASSERTMSG(FALSE, TEXT("OverwriteVpnFileWithUpdate -- invalid parameter passed."));
  285. return FALSE;
  286. }
  287. DWORD dwError = ERROR_NOT_ENOUGH_MEMORY;
  288. //
  289. // We first want to make a backup copy of the original file
  290. //
  291. const TCHAR* const c_pszDotBak = TEXT(".bak");
  292. DWORD dwSize = (lstrlen(pszExistingVpnFile) + lstrlen(c_pszDotBak) + 1)*sizeof(TCHAR);
  293. LPTSTR pszBackupFile = (LPTSTR)CmMalloc(dwSize);
  294. if (pszBackupFile)
  295. {
  296. wsprintf(pszBackupFile, TEXT("%s%s"), pszExistingVpnFile, c_pszDotBak);
  297. CMASSERTMSG(pszBackupFile[0], TEXT("OverwriteVpnFileWithUpdate -- wsprintf failed!"));
  298. if (CopyFile(pszExistingVpnFile, pszBackupFile, FALSE)) // FALSE == bFailIfExists
  299. {
  300. //
  301. // Now copy over the new file
  302. //
  303. if (CopyFile(pszNewVpnFile, pszExistingVpnFile, FALSE)) // FALSE == bFailIfExists
  304. {
  305. dwError = ERROR_SUCCESS;
  306. }
  307. else
  308. {
  309. dwError = GetLastError();
  310. CMTRACE1(TEXT("OverwriteVpnFileWithUpdate -- CopyFile of the new file over the original file failed, GLE %s"), dwError);
  311. CMASSERTMSG(FALSE, TEXT("OverwriteVpnFileWithUpdate -- update of the original file failed, attempting to restore the original from backup."));
  312. //
  313. // We need to restore the backup file
  314. //
  315. if (!CopyFile(pszBackupFile, pszExistingVpnFile, FALSE)) // FALSE == bFailIfExists
  316. {
  317. // NOTE we don't use dwError here, we want the original error to be logged
  318. CMTRACE1(TEXT("OverwriteVpnFileWithUpdate -- CopyFile to restore the saved backup file failed, GLE %s"), GetLastError());
  319. CMASSERTMSG(FALSE, TEXT("OverwriteVpnFileWithUpdate -- restoration of backup failed!"));
  320. }
  321. }
  322. //
  323. // Delete the backup file
  324. //
  325. DeleteFile(pszBackupFile);
  326. }
  327. else
  328. {
  329. dwError = GetLastError();
  330. CMTRACE1(TEXT("OverwriteVpnFileWithUpdate -- CopyFile of the original file to the backup file failed, GLE %s"), dwError);
  331. }
  332. }
  333. CmFree(pszBackupFile);
  334. if (ERROR_SUCCESS == dwError)
  335. {
  336. CMTRACE(TEXT("OverwriteVpnFileWithUpdate -- VPN file update succeeded!"));
  337. }
  338. else
  339. {
  340. CMTRACE(TEXT("OverwriteVpnFileWithUpdate -- VPN file update failed."));
  341. }
  342. return dwError;
  343. }
  344. //+----------------------------------------------------------------------------
  345. //
  346. // Function: UpdateVpnFileForProfile
  347. //
  348. // Synopsis: This function is called to download and update a VPN file with a
  349. // newly downloaded VPN update file.
  350. //
  351. // Arguments: LPCTSTR pszCmpPath - full path to the cmp file
  352. // CmLogFile * pLog - object to use for logging
  353. //
  354. // Returns: BOOL - TRUE if the download and update were successful.
  355. //
  356. // History: quintinb Created 11/03/00
  357. //
  358. //+----------------------------------------------------------------------------
  359. BOOL UpdateVpnFileForProfile(LPCTSTR pszCmpPath, LPCTSTR pszCmsPath, CmLogFile * pLog, BOOL bCheckConnection)
  360. {
  361. if ((NULL == pszCmpPath) || (TEXT('\0') == pszCmpPath[0]))
  362. {
  363. CMASSERTMSG(FALSE, TEXT("UpdateVpnFileForProfile in cmdl32.exe -- invalid pszCmpPath parameter."));
  364. return FALSE;
  365. }
  366. BOOL bLogAtEnd = TRUE;
  367. BOOL bReturn = FALSE;
  368. DWORD dwError = ERROR_INVALID_PARAMETER;
  369. if (pszCmsPath && *pszCmsPath)
  370. {
  371. //
  372. // Let's check to see if we are connected unless the caller told us to skip the check
  373. //
  374. if (bCheckConnection)
  375. {
  376. LPTSTR pszConnectionName = GetPrivateProfileStringWithAlloc(c_pszCmSection, c_pszCmEntryServiceName, TEXT(""), pszCmsPath);
  377. if (pszConnectionName && *pszConnectionName)
  378. {
  379. if (FALSE == IsConnectionAlive(pszConnectionName))
  380. {
  381. CMTRACE(TEXT("UpdateVpnFileForProfile -- not connected ... aborting."));
  382. pLog->Log(VPN_DOWNLOAD_FAILURE, ERROR_NOT_CONNECTED, TEXT(""), TEXT(""));
  383. CmFree(pszConnectionName);
  384. return FALSE;
  385. }
  386. }
  387. CmFree(pszConnectionName);
  388. }
  389. //
  390. // Next get the VPN phonebook file name from the profile.
  391. //
  392. LPTSTR pszVpnFileName = GetPrivateProfileStringWithAlloc(c_pszCmSection, c_pszCmEntryTunnelFile, TEXT(""), pszCmsPath);
  393. if (pszVpnFileName && *pszVpnFileName)
  394. {
  395. LPTSTR pszVpnFile = CmBuildFullPathFromRelative(pszCmpPath, pszVpnFileName);
  396. if (pszVpnFile && *pszVpnFile)
  397. {
  398. //
  399. // Now get the URL to update the vpn file from
  400. //
  401. LPTSTR pszVpnUpdateUrl = GetPrivateProfileStringWithAlloc(c_pszCmSectionSettings, c_pszCmEntryVpnUpdateUrl, TEXT(""), pszVpnFile);
  402. if (pszVpnUpdateUrl && *pszVpnUpdateUrl)
  403. {
  404. //
  405. // Finally, we have a URL so let's download the updated VPN server list.
  406. //
  407. LPTSTR pszUpdatedVpnFile = NULL;
  408. dwError = DownloadVpnFileFromUrl(pszVpnUpdateUrl, &pszUpdatedVpnFile);
  409. bReturn = (ERROR_SUCCESS == dwError);
  410. bLogAtEnd = FALSE; // we're going to start logging items right now
  411. if (bReturn)
  412. {
  413. pLog->Log(VPN_DOWNLOAD_SUCCESS, pszVpnFile, pszVpnUpdateUrl);
  414. }
  415. else
  416. {
  417. pLog->Log(VPN_DOWNLOAD_FAILURE, dwError, pszVpnFile, pszVpnUpdateUrl);
  418. }
  419. if (bReturn && pszUpdatedVpnFile && *pszUpdatedVpnFile)
  420. {
  421. dwError = OverwriteVpnFileWithUpdate(pszVpnFile, pszUpdatedVpnFile);
  422. bReturn = (ERROR_SUCCESS == dwError);
  423. if (bReturn)
  424. {
  425. pLog->Log(VPN_UPDATE_SUCCESS, pszVpnFile);
  426. }
  427. else
  428. {
  429. pLog->Log(VPN_UPDATE_FAILURE, dwError, pszVpnFile);
  430. }
  431. }
  432. CmFree (pszUpdatedVpnFile);
  433. }
  434. else
  435. {
  436. dwError = GetLastError();
  437. CMASSERTMSG(FALSE, TEXT("UpdateVpnFileForProfile in cmdl32.exe -- unable to get the URL to update the vpn file from..."));
  438. }
  439. CmFree(pszVpnUpdateUrl);
  440. }
  441. else
  442. {
  443. dwError = GetLastError();
  444. CMASSERTMSG(FALSE, TEXT("UpdateVpnFileForProfile in cmdl32.exe -- unable to expand the path to the vpn file."));
  445. }
  446. CmFree(pszVpnFile);
  447. }
  448. else
  449. {
  450. dwError = GetLastError();
  451. CMASSERTMSG(FALSE, TEXT("UpdateVpnFileForProfile in cmdl32.exe -- unable to retrieve the vpn file name."));
  452. }
  453. CmFree(pszVpnFileName);
  454. }
  455. if (bLogAtEnd)
  456. {
  457. pLog->Log(VPN_DOWNLOAD_FAILURE, dwError, TEXT("?"), TEXT("?"));
  458. }
  459. return bReturn;
  460. }