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.

531 lines
15 KiB

  1. /*++
  2. Copyright (c) 2000,2001 Microsoft Corporation
  3. Module Name:
  4. DISKIO.CPP
  5. Abstract:
  6. Disk IO routines for the password reset wizards. These routines
  7. do disk writes as unbuffered writes in order to prevent uncontrolled
  8. copies of the private key blob from being left lying around. For that
  9. reason, utility routines are included to derive a proper size for the
  10. blob write that will be an integer multiple of the sector size of
  11. the medium, a required condition to use an unbuffered write operation.
  12. Assistance is also provided in finding removeable medium drives.
  13. Some state of the disk IO subsystem is preserved in global variables,
  14. prefixed by "g_".
  15. Author:
  16. Environment:
  17. WinXP
  18. --*/
  19. // Dependencies: shellapi.h, shell32.lib for SHGetFileInfo()
  20. // windows.h, kernel32.lib for GetDiskFreeSpace()
  21. // io.h for _waccess()
  22. #include <nt.h>
  23. #include <ntrtl.h>
  24. #include <nturtl.h>
  25. #include <windef.h>
  26. #include <windows.h>
  27. #include <string.h>
  28. #include <io.h>
  29. #include <stdio.h>
  30. //#include <shellapi.h>
  31. #include <shlwapi.h>
  32. //#include <shlobjp.h>
  33. #include "switches.h"
  34. #include "wizres.h"
  35. #include "testaudit.h"
  36. extern HINSTANCE g_hInstance;
  37. #if !defined(SHFMT_OPT_FULL)
  38. #if defined (__cplusplus)
  39. extern "C" {
  40. #endif
  41. DWORD WINAPI SHFormatDrive(HWND,UINT,UINT,UINT);
  42. #define SHFMT_ID_DEFAULT 0xffff
  43. #define SHFMT_OPT_FULL 0x0001
  44. #define SHFMT_OPT_SYSONLY 0x0002
  45. #define SHFMT_ERROR 0xffffffffL
  46. #define SHFMT_CANCEL 0xfffffffeL
  47. #define SHFMT_NOFORMAT 0xffffffdL
  48. #if defined (__cplusplus)
  49. }
  50. #endif
  51. #endif
  52. // Miscellaneous declarations not contain in header files
  53. // These will be miscellaneous items found in other files within this project
  54. int RMessageBox(HWND hw,UINT_PTR uiResIDTitle, UINT_PTR uiResIDText, UINT uiType);
  55. extern HWND c_hDlg;
  56. extern WCHAR pszFileName[];
  57. INT g_iFileSize = 0;
  58. INT g_iBufferSize = 0;
  59. INT g_iSectorSize = 0;
  60. HANDLE g_hFile = NULL;
  61. /**********************************************************************
  62. GetDriveFreeSpace
  63. Get DWORD value of free space on the drive associated with the path, in bytes.
  64. **********************************************************************/
  65. DWORD GetDriveFreeSpace(WCHAR *pszFilePath)
  66. {
  67. WCHAR rgcModel[]={L"A:"};
  68. DWORD dwSpc,dwBps,dwCfc,dwTcc,dwFree;
  69. ASSERT(pszFilePath);
  70. if (NULL == pszFilePath) return 0;
  71. rgcModel[0] = *pszFilePath;
  72. if (!GetDiskFreeSpace(rgcModel,&dwSpc,&dwBps,&dwCfc,&dwTcc))
  73. {
  74. ASSERTMSG("GetDiskFreeSpace failed",0);
  75. return 0;
  76. }
  77. // Free is bytes per sector * sectors per cluster * free clusters
  78. dwFree = dwBps * dwCfc * dwSpc;
  79. return dwFree;
  80. }
  81. /**********************************************************************
  82. GetDriveSectorSize
  83. Return DWORD size in byte of a single sector on the drive associated with the path.
  84. **********************************************************************/
  85. DWORD GetDriveSectorSize(WCHAR *pszFilePath)
  86. {
  87. WCHAR rgcModel[]={L"A:"};
  88. DWORD dwSpc,dwBps,dwCfc,dwTcc;
  89. ASSERT(pszFilePath);
  90. if (NULL == pszFilePath)
  91. {
  92. return 0;
  93. }
  94. rgcModel[0] = *pszFilePath;
  95. if (!GetDiskFreeSpace(rgcModel,&dwSpc,&dwBps,&dwCfc,&dwTcc))
  96. {
  97. ASSERTMSG("GetDiskFreeSpace failed",0);
  98. return 0;
  99. }
  100. return dwBps;
  101. }
  102. /**********************************************************************
  103. CreateFileBuffer
  104. Create a buffer to contain iDataSize bytes that is an integral multiple of iSectorSize
  105. buffers.
  106. **********************************************************************/
  107. LPVOID CreateFileBuffer(INT iDataSize,INT iSectorSize)
  108. {
  109. INT iSize;
  110. LPVOID lpv;
  111. if (iDataSize == iSectorSize)
  112. {
  113. iSize = iDataSize;
  114. }
  115. else
  116. {
  117. iSize = iDataSize/iSectorSize;
  118. iSize += 1;
  119. iSize *= iSectorSize;
  120. }
  121. g_iBufferSize = iSize;
  122. lpv = VirtualAlloc(NULL,iSize,MEM_COMMIT,PAGE_READWRITE | PAGE_NOCACHE);
  123. ASSERTMSG("VirtualAlloc failed to create buffer",lpv);
  124. return lpv;
  125. }
  126. /**********************************************************************
  127. ReleaseFileBuffer()
  128. Release the file buffer created by CreateFileBuffer
  129. **********************************************************************/
  130. void ReleaseFileBuffer(LPVOID lpv)
  131. {
  132. ASSERT(lpv);
  133. if (NULL == lpv) return;
  134. SecureZeroMemory(lpv,g_iBufferSize);
  135. VirtualFree(lpv,0,MEM_RELEASE);
  136. return;
  137. }
  138. /**********************************************************************
  139. FileMediumIsPresent
  140. Test the drive associated with the passed path to see if the medium is present.
  141. Return BOOL TRUE if so.
  142. **********************************************************************/
  143. BOOL FileMediumIsPresent(TCHAR *pszPath)
  144. {
  145. UINT uMode = 0;
  146. BOOL bResult = FALSE;
  147. TCHAR rgcModel[]=TEXT("A:");
  148. DWORD dwError = 0;
  149. ASSERT(pszPath);
  150. if (*pszPath == 0) return FALSE;
  151. rgcModel[0] = *pszPath;
  152. uMode = SetErrorMode(SEM_FAILCRITICALERRORS);
  153. if (0 == _waccess(rgcModel,0))
  154. {
  155. bResult = TRUE;
  156. }
  157. else dwError = GetLastError();
  158. // Correct certain obvious errors with the user's help
  159. if (ERROR_UNRECOGNIZED_MEDIA == dwError)
  160. {
  161. // unformatted disk
  162. WCHAR rgcFmt[200] = {0};
  163. WCHAR rgcMsg[200] = {0};
  164. WCHAR rgcTitle[200] = {0};
  165. CHECKPOINT(70,"Wizard: Save - Unformatted disk in the drive");
  166. #ifdef LOUDLY
  167. OutputDebugString(L"FileMediumIsPresent found an unformatted medium\n");
  168. #endif
  169. INT iCount = LoadString(g_hInstance,IDS_MBTFORMAT,rgcTitle,200 - 1);
  170. iCount = LoadString(g_hInstance,IDS_MBMFORMAT,rgcFmt,200 - 1);
  171. ASSERT(iCount);
  172. if (0 != iCount)
  173. {
  174. swprintf(rgcMsg,rgcFmt,rgcModel);
  175. INT iDrive = PathGetDriveNumber(rgcModel);
  176. int iRet = MessageBox(c_hDlg,rgcMsg,rgcTitle,MB_YESNO);
  177. if (IDYES == iRet)
  178. {
  179. dwError = SHFormatDrive(c_hDlg,iDrive,SHFMT_ID_DEFAULT,0);
  180. if (0 == bResult) bResult = TRUE;
  181. }
  182. }
  183. }
  184. uMode = SetErrorMode(uMode);
  185. return bResult;
  186. }
  187. //
  188. //
  189. /**********************************************************************
  190. GetInputFile
  191. Open input file and return handle to it. Return NULL on file not found.
  192. FileName will be in global buffer pszFileName.
  193. **********************************************************************/
  194. HANDLE GetInputFile(void)
  195. {
  196. HANDLE hFile = INVALID_HANDLE_VALUE;
  197. DWORD dwErr;
  198. WIN32_FILE_ATTRIBUTE_DATA stAttributes = {0};
  199. if (FileMediumIsPresent(pszFileName))
  200. {
  201. CHECKPOINT(72,"Wizard: Restore - disk present");
  202. g_iSectorSize = GetDriveSectorSize(pszFileName);
  203. ASSERT(g_iSectorSize);
  204. if (0 == g_iSectorSize)
  205. {
  206. return NULL;
  207. }
  208. if (GetFileAttributesEx(pszFileName,GetFileExInfoStandard,&stAttributes))
  209. {
  210. // file exists and we have a size for it.
  211. g_iFileSize = stAttributes.nFileSizeLow;
  212. }
  213. else
  214. {
  215. dwErr = GetLastError();
  216. if (dwErr == ERROR_FILE_NOT_FOUND)
  217. {
  218. RMessageBox(c_hDlg,IDS_MBTWRONGDISK ,IDS_MBMWRONGDISK ,MB_ICONEXCLAMATION);
  219. }
  220. else
  221. {
  222. ASSERT(0); // get file attributes failed
  223. RMessageBox(c_hDlg,IDS_MBTDISKERROR ,IDS_MBMDISKERROR ,MB_ICONEXCLAMATION);
  224. }
  225. g_hFile = NULL;
  226. return NULL;
  227. } // end GetFileAttributes
  228. hFile = CreateFileW(pszFileName,
  229. GENERIC_READ,
  230. 0,
  231. NULL,
  232. OPEN_EXISTING,
  233. FILE_FLAG_NO_BUFFERING,
  234. NULL);
  235. if (INVALID_HANDLE_VALUE == hFile) {
  236. dwErr = GetLastError();
  237. if (dwErr == ERROR_FILE_NOT_FOUND)
  238. {
  239. NCHECKPOINT(73,"Wizard: Restore - wrong disk (file not found)");
  240. RMessageBox(c_hDlg,IDS_MBTWRONGDISK ,IDS_MBMWRONGDISK ,MB_ICONEXCLAMATION);
  241. }
  242. else
  243. {
  244. NCHECKPOINT(74,"Wizard: Restore - bad disk");
  245. RMessageBox(c_hDlg,IDS_MBTDISKERROR ,IDS_MBMDISKERROR ,MB_ICONEXCLAMATION);
  246. }
  247. }
  248. }
  249. else
  250. {
  251. CHECKPOINT(71,"Wizard: Restore - no disk");
  252. RMessageBox(c_hDlg,IDS_MBTNODISK ,IDS_MBMNODISK ,MB_ICONEXCLAMATION);
  253. }
  254. if ((NULL == hFile) || (INVALID_HANDLE_VALUE == hFile))
  255. {
  256. g_hFile = NULL;
  257. return NULL;
  258. }
  259. g_hFile = hFile;
  260. return hFile;
  261. }
  262. /**********************************************************************
  263. CloseInputFile
  264. Close the input file and set the global file handle to NULL
  265. **********************************************************************/
  266. void CloseInputFile(void)
  267. {
  268. if (g_hFile)
  269. {
  270. CloseHandle(g_hFile);
  271. g_hFile = NULL;
  272. }
  273. return;
  274. }
  275. /**********************************************************************
  276. GetOutputFile
  277. Open for overwrite or Create the output file to pszFileName. Return handle on
  278. success or NULL on fail. Get user permission to overwrite.
  279. **********************************************************************/
  280. HANDLE GetOutputFile(void)
  281. {
  282. HANDLE hFile = NULL;
  283. DWORD dwErr;
  284. if (FileMediumIsPresent(pszFileName))
  285. {
  286. CHECKPOINT(75,"Wizard: Save - open output file");
  287. g_iSectorSize = GetDriveSectorSize(pszFileName);
  288. ASSERT(g_iSectorSize);
  289. if (0 == g_iSectorSize)
  290. {
  291. return NULL;
  292. }
  293. hFile = CreateFileW(pszFileName,
  294. GENERIC_WRITE,
  295. 0,
  296. NULL,
  297. CREATE_NEW,
  298. FILE_FLAG_NO_BUFFERING,
  299. NULL);
  300. if ((NULL == hFile) || (INVALID_HANDLE_VALUE == hFile))
  301. {
  302. dwErr = GetLastError();
  303. if ((dwErr == ERROR_FILE_EXISTS))
  304. {
  305. CHECKPOINT(76,"Wizard: Save - file already exists");
  306. if (IDYES != RMessageBox(c_hDlg,IDS_MBTOVERWRITE ,IDS_MBMOVERWRITE ,MB_YESNO))
  307. {
  308. // Overwrite abandoned.
  309. g_hFile = NULL;
  310. return NULL;
  311. }
  312. else
  313. {
  314. SetFileAttributes(pszFileName,FILE_ATTRIBUTE_NORMAL);
  315. hFile = CreateFileW(pszFileName,
  316. GENERIC_WRITE,
  317. 0,
  318. NULL,
  319. CREATE_ALWAYS,
  320. FILE_FLAG_NO_BUFFERING,
  321. NULL);
  322. #ifdef LOUDLY
  323. dwErr = GetLastError();
  324. swprintf(rgct,L"File create failed %x\n",dwErr);
  325. OutputDebugString(rgct);
  326. #endif
  327. }
  328. } // end if already exists error
  329. } // end if NULL == hFile
  330. }
  331. else
  332. {
  333. RMessageBox(c_hDlg,IDS_MBTNODISK ,IDS_MBMNODISK ,MB_ICONEXCLAMATION);
  334. }
  335. if (INVALID_HANDLE_VALUE == hFile)
  336. {
  337. g_hFile = NULL;
  338. return NULL;
  339. }
  340. g_hFile = hFile;
  341. return hFile;
  342. }
  343. /**********************************************************************
  344. DWORD ReadPrivateData(PWSTR, LPBYTE *prgb, INT *piCount)
  345. DWORD WritePrivateData(PWSTR, LPBYTE lpData, INT icbData)
  346. These functions read or write a reasonably short block of data to a disk
  347. device, avoiding buffering of the data. This allows the data to be wiped
  348. by the client before the buffers are released. The created buffer is an integral
  349. multiple of the medium sector size as required by the unbuffered disk I/O
  350. routines.
  351. The DWORD return value is that which would return from GetLastError() and
  352. can be handled accordingly.
  353. ReadPrivateData() returns a malloc'd pointer which must be freed by the client. It
  354. also returns the count of bytes read from the medium to the INT *.
  355. WritePrivateData() writes a count of bytes from LPBYTE to the disk. When it returns,
  356. the buffer used to do so has been flushed and the file is closed.
  357. prgb = byte ptr to data returned from the read
  358. piCount = size of active data field within the buffer
  359. Note that even if the read fails (file not found, read error, etc.) the buffer
  360. ptr is still valid (non-NULL)
  361. **********************************************************************/
  362. INT ReadPrivateData(BYTE **prgb,INT *piCount)
  363. {
  364. LPVOID lpv;
  365. DWORD dwBytesRead;
  366. // detect / handle errors
  367. ASSERT(g_hFile);
  368. ASSERT(prgb);
  369. ASSERT(piCount);
  370. if (NULL == prgb) return 0;
  371. if (NULL == piCount) return 0;
  372. if (g_hFile)
  373. {
  374. // set file ptr to beginning in case this is a retry
  375. SetFilePointer(g_hFile,0,0,FILE_BEGIN);
  376. // allocate a buffer for the read data
  377. lpv = CreateFileBuffer(g_iFileSize,g_iSectorSize);
  378. if (NULL == lpv)
  379. {
  380. *prgb = 0; // indicate no need to free this buffer
  381. *piCount = 0;
  382. return 0;
  383. }
  384. // save buffer address and filled size
  385. *prgb = (BYTE *)lpv; // even if no data, gotta free using VirtualFree()
  386. *piCount = 0;
  387. // do the read - return chars read if successful
  388. if (0 == ReadFile(g_hFile,lpv,g_iBufferSize,&dwBytesRead,NULL)) return 0;
  389. *piCount = g_iFileSize;
  390. if (g_iFileSize == 0) SetLastError(NTE_BAD_DATA);
  391. return g_iFileSize;
  392. }
  393. return 0;
  394. }
  395. BOOL WritePrivateData(BYTE *lpData,INT icbData)
  396. {
  397. DWORD dwcb = 0;
  398. LPVOID lpv;
  399. // detect/handle errors
  400. ASSERT(lpData);
  401. ASSERT(g_hFile);
  402. ASSERT(icbData);
  403. if (NULL == g_hFile) return FALSE;
  404. if (NULL == lpData) return FALSE;
  405. if (0 == icbData) return FALSE;
  406. if (g_hFile)
  407. {
  408. g_iFileSize = icbData;
  409. lpv = CreateFileBuffer(g_iFileSize,g_iSectorSize);
  410. if (NULL == lpv)
  411. {
  412. return FALSE;
  413. }
  414. ZeroMemory(lpv,g_iBufferSize);
  415. memcpy(lpv,lpData,icbData);
  416. // I elect to check the result of the write only by checking the byte
  417. // count on the write, as some rather normal conditions can cause a fail. This
  418. // test gets em all. I don't care exactly why.
  419. WriteFile(g_hFile,lpv,g_iBufferSize,&dwcb,NULL);
  420. SecureZeroMemory(lpv,g_iBufferSize);
  421. VirtualFree(lpv,0,MEM_RELEASE);
  422. }
  423. // ret TRUE iff file write succeeds and count of bytes is correct
  424. if ((INT)dwcb != g_iBufferSize) return FALSE;
  425. else return TRUE;
  426. }