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.

4665 lines
124 KiB

  1. /*++
  2. Copyright (c) 1997-1999 Microsoft Corporation
  3. Module Name:
  4. cipher.c
  5. Abstract:
  6. This module implements the encryption utility for encrypted
  7. NTFS files.
  8. Author:
  9. Robert Reichel [RobertRe] 28-Feb-1997
  10. Robert Gu [RobertG] 24-Mar-1998
  11. Revision History:
  12. Code reused from compact.exe, file compression utility
  13. --*/
  14. //
  15. // Include the standard header files.
  16. //
  17. //#define UNICODE
  18. //#define _UNICODE
  19. #include <windows.h>
  20. #include <stdio.h>
  21. #include <winioctl.h>
  22. #include <shellapi.h>
  23. #include <winefs.h>
  24. #include <malloc.h>
  25. #include <rc4.h>
  26. #include <randlib.h> // NewGenRandom() - Win2k and whistler
  27. #include <rpc.h>
  28. #include <wincrypt.h>
  29. #include "support.h"
  30. #include "msg.h"
  31. #define lstrchr wcschr
  32. #define lstricmp _wcsicmp
  33. #define lstrnicmp _wcsnicmp
  34. //
  35. // FIRST_COLUMN_WIDTH - When encrypting files, the width of the output
  36. // column which displays the file name
  37. //
  38. #define FIRST_COLUMN_WIDTH (20)
  39. #define ENUMPATHLENGTH (4096)
  40. #define DosDriveLimitCount (26)
  41. #define PASSWORDLEN 1024
  42. #define UserChooseYes 0
  43. #define UserChooseNo 1
  44. #define ChoiceNotDefined 3
  45. #define KEYPATH TEXT("Software\\Microsoft\\Windows NT\\CurrentVersion\\EFS\\CurrentKeys")
  46. #define KEYPATHROOT HKEY_CURRENT_USER
  47. #define CERT_HASH TEXT("CertificateHash")
  48. #define WIPING_DIR TEXT("EFSTMPWP\\")
  49. #define RANDOM_BYTES(pv, cb) NewGenRandom(NULL, NULL, pv, cb)
  50. #define YEARCOUNT (LONGLONG) 10000000*3600*24*365 // One Year's tick count
  51. //
  52. // Local data structure
  53. //
  54. typedef struct _CIPHER_VOLUME_INFO {
  55. LPWSTR VolumeName[DosDriveLimitCount];
  56. LPWSTR DosDeviceName[DosDriveLimitCount];
  57. } CIPHER_VOLUME_INFO, *PCIPHER_VOLUME_INFO;
  58. //
  59. //
  60. // definitions for initializing and working with random fill data.
  61. //
  62. typedef struct {
  63. RC4_KEYSTRUCT Key;
  64. CRITICAL_SECTION Lock;
  65. BOOL LockValid;
  66. PBYTE pbRandomFill;
  67. DWORD cbRandomFill;
  68. LONG cbFilled;
  69. BOOLEAN fRandomFill; // is fill randomized?
  70. } SECURE_FILL_INFO, *PSECURE_FILL_INFO;
  71. // Local procedure types
  72. //
  73. typedef BOOLEAN (*PACTION_ROUTINE) (
  74. IN PTCHAR DirectorySpec,
  75. IN PTCHAR FileSpec
  76. );
  77. typedef VOID (*PFINAL_ACTION_ROUTINE) (
  78. );
  79. //
  80. // Declare global variables to hold the command line information
  81. //
  82. BOOLEAN DoSubdirectories = FALSE; // recurse
  83. BOOLEAN IgnoreErrors = FALSE; // keep going despite errs
  84. BOOLEAN UserSpecifiedFileSpec = FALSE;
  85. BOOLEAN ForceOperation = FALSE; // encrypt/decrypt even if already so
  86. BOOLEAN Quiet = FALSE; // be less verbose
  87. BOOLEAN DisplayAllFiles = FALSE; // dsply hidden, system?
  88. BOOLEAN DoFiles = FALSE; // operation for files "/a"
  89. BOOLEAN SetUpNewUserKey = FALSE; // Set up new user key
  90. BOOLEAN RefreshUserKeyOnFiles = FALSE; // Refresh User Key on EFS files
  91. BOOLEAN DisplayFilesOnly = FALSE; // Do not refresh $EFS, just display the file names
  92. BOOLEAN FillUnusedSpace = FALSE; // Fill unused disk space with random data
  93. BOOLEAN GenerateDRA = FALSE; // Generate Data Recovery Certificate files
  94. BOOLEAN ExportEfsCert = FALSE; // Export EFS certificate and keys to a PFX file
  95. TCHAR StartingDirectory[MAX_PATH]; // parameter to "/s"
  96. ULONG AttributesNoDisplay = FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN;
  97. BOOLEAN DisplayUseOptionW = FALSE;
  98. //
  99. // Declare global variables to hold encryption statistics
  100. //
  101. LARGE_INTEGER TotalDirectoryCount;
  102. LARGE_INTEGER TotalFileCount;
  103. TCHAR Buf[1024]; // for displaying stuff
  104. SECURE_FILL_INFO GlobalSecureFill;
  105. BOOLEAN GlobalSecureFillInitialized;
  106. #if 0
  107. #define TestOutPut
  108. #endif
  109. //
  110. // Now do the routines to list the encryption state and size of
  111. // a file and/or directory
  112. //
  113. BOOLEAN
  114. DisplayFile (
  115. IN PTCHAR FileSpec,
  116. IN PWIN32_FIND_DATA FindData
  117. )
  118. {
  119. TCHAR PrintState;
  120. //
  121. // Decide if the file is compressed and if so then
  122. // get the compressed file size.
  123. //
  124. if (FindData->dwFileAttributes & FILE_ATTRIBUTE_ENCRYPTED) {
  125. PrintState = 'E';
  126. } else {
  127. PrintState = 'U';
  128. }
  129. //
  130. // Print out the encryption state and file name
  131. // The following swprintf should be safe. Any one component of the file path could not
  132. // be longer than MAX_PATH. That means lstrlen(FindData->cFileName) <= MAX_PATH
  133. // Buf holds 1024 TCHARs.
  134. //
  135. if (!Quiet &&
  136. (DisplayAllFiles ||
  137. (0 == (FindData->dwFileAttributes & AttributesNoDisplay)))) {
  138. swprintf(Buf, TEXT("%c %s"), PrintState, FindData->cFileName);
  139. DisplayMsg(CIPHER_THROW_NL, Buf);
  140. }
  141. TotalFileCount.QuadPart += 1;
  142. return TRUE;
  143. }
  144. BOOLEAN
  145. DoListAction (
  146. IN PTCHAR DirectorySpec,
  147. IN PTCHAR FileSpec
  148. )
  149. {
  150. PTCHAR DirectorySpecEnd;
  151. //
  152. // So that we can keep on appending names to the directory spec
  153. // get a pointer to the end of its string
  154. //
  155. DirectorySpecEnd = DirectorySpec + lstrlen(DirectorySpec);
  156. //
  157. // List the encryption attribute for the directory
  158. //
  159. {
  160. ULONG Attributes;
  161. Attributes = GetFileAttributes( DirectorySpec );
  162. if (0xFFFFFFFF == Attributes) {
  163. if (!Quiet || !IgnoreErrors) {
  164. //
  165. // Refrain from displaying error only when in quiet
  166. // mode *and* we're ignoring errors.
  167. //
  168. DisplayErr(DirectorySpec, GetLastError());
  169. }
  170. if (!IgnoreErrors) {
  171. return FALSE;
  172. }
  173. } else {
  174. if (Attributes & FILE_ATTRIBUTE_ENCRYPTED) {
  175. DisplayMsg(CIPHER_LIST_EDIR, DirectorySpec);
  176. } else {
  177. DisplayMsg(CIPHER_LIST_UDIR, DirectorySpec);
  178. }
  179. }
  180. TotalDirectoryCount.QuadPart += 1;
  181. }
  182. //
  183. // Now for every file in the directory that matches the file spec we will
  184. // will open the file and list its encryption state
  185. //
  186. {
  187. HANDLE FindHandle;
  188. WIN32_FIND_DATA FindData;
  189. //
  190. // setup the template for findfirst/findnext
  191. //
  192. //
  193. // Make sure we don't try any paths that are too long for us
  194. // to deal with.
  195. //
  196. if (((DirectorySpecEnd - DirectorySpec) + lstrlen( FileSpec )) <
  197. MAX_PATH) {
  198. lstrcpy( DirectorySpecEnd, FileSpec );
  199. FindHandle = FindFirstFile( DirectorySpec, &FindData );
  200. if (INVALID_HANDLE_VALUE != FindHandle) {
  201. do {
  202. //
  203. // append the found file to the directory spec and open the
  204. // file
  205. //
  206. if (0 == lstrcmp(FindData.cFileName, TEXT("..")) ||
  207. 0 == lstrcmp(FindData.cFileName, TEXT("."))) {
  208. continue;
  209. }
  210. //
  211. // Make sure we don't try any paths that are too long for us
  212. // to deal with.
  213. //
  214. if ((DirectorySpecEnd - DirectorySpec) +
  215. lstrlen( FindData.cFileName ) >= MAX_PATH ) {
  216. continue;
  217. }
  218. lstrcpy( DirectorySpecEnd, FindData.cFileName );
  219. //
  220. // Now print out the state of the file
  221. //
  222. DisplayFile( DirectorySpec, &FindData );
  223. } while ( FindNextFile( FindHandle, &FindData ));
  224. FindClose( FindHandle );
  225. }
  226. }
  227. }
  228. //
  229. // For if we are to do subdirectores then we will look for every
  230. // subdirectory and recursively call ourselves to list the subdirectory
  231. //
  232. if (DoSubdirectories) {
  233. HANDLE FindHandle;
  234. WIN32_FIND_DATA FindData;
  235. //
  236. // Setup findfirst/findnext to search the entire directory
  237. //
  238. if (((DirectorySpecEnd - DirectorySpec) + lstrlen( TEXT("*") )) <
  239. MAX_PATH) {
  240. lstrcpy( DirectorySpecEnd, TEXT("*") );
  241. FindHandle = FindFirstFile( DirectorySpec, &FindData );
  242. if (INVALID_HANDLE_VALUE != FindHandle) {
  243. do {
  244. //
  245. // Now skip over the . and .. entries otherwise we'll recurse
  246. // like mad
  247. //
  248. if (0 == lstrcmp(&FindData.cFileName[0], TEXT(".")) ||
  249. 0 == lstrcmp(&FindData.cFileName[0], TEXT(".."))) {
  250. continue;
  251. } else {
  252. //
  253. // If the entry is for a directory then we'll tack on the
  254. // subdirectory name to the directory spec and recursively
  255. // call otherselves
  256. //
  257. if (FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
  258. //
  259. // Make sure we don't try any paths that are too long for us
  260. // to deal with.
  261. //
  262. if ((DirectorySpecEnd - DirectorySpec) +
  263. lstrlen( TEXT("\\") ) +
  264. lstrlen( FindData.cFileName ) >= MAX_PATH ) {
  265. continue;
  266. }
  267. lstrcpy( DirectorySpecEnd, FindData.cFileName );
  268. lstrcat( DirectorySpecEnd, TEXT("\\") );
  269. if (!DoListAction( DirectorySpec, FileSpec )) {
  270. FindClose( FindHandle );
  271. return FALSE || IgnoreErrors;
  272. }
  273. }
  274. }
  275. } while ( FindNextFile( FindHandle, &FindData ));
  276. FindClose( FindHandle );
  277. }
  278. }
  279. }
  280. return TRUE;
  281. }
  282. VOID
  283. DoFinalListAction (
  284. )
  285. {
  286. return;
  287. }
  288. BOOLEAN
  289. EncryptAFile (
  290. IN PTCHAR FileSpec,
  291. IN PWIN32_FIND_DATA FindData
  292. )
  293. {
  294. USHORT State = 1;
  295. ULONG i;
  296. BOOL Success;
  297. double f = 1.0;
  298. //
  299. // ForceOperation actually doesn't do anything. EncryptFile() will not encrypt an EFS file.
  300. // A legacy option from compact.
  301. //
  302. if ((FindData->dwFileAttributes & FILE_ATTRIBUTE_ENCRYPTED) &&
  303. !ForceOperation) {
  304. return TRUE;
  305. }
  306. if ( (0 == (FindData->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) && (!DoFiles)) {
  307. //
  308. // Skip the files
  309. //
  310. return TRUE;
  311. }
  312. Success = EncryptFile( FileSpec );
  313. if (!Success) {
  314. if (Quiet && IgnoreErrors) {
  315. return TRUE;
  316. }
  317. swprintf(Buf, TEXT("%s "), FindData->cFileName);
  318. DisplayMsg(CIPHER_THROW, Buf);
  319. for (i = lstrlen(FindData->cFileName) + 1; i < FIRST_COLUMN_WIDTH; ++i) {
  320. swprintf(Buf, TEXT("%c"), ' ');
  321. DisplayMsg(CIPHER_THROW, Buf);
  322. }
  323. DisplayMsg(CIPHER_ERR);
  324. if (!Quiet && !IgnoreErrors) {
  325. if (ERROR_INVALID_FUNCTION == GetLastError()) {
  326. // This error is caused by doing the fsctl on a
  327. // non-encrypting volume.
  328. DisplayMsg(CIPHER_WRONG_FILE_SYSTEM, FindData->cFileName);
  329. } else {
  330. DisplayErr(FindData->cFileName, GetLastError());
  331. }
  332. }
  333. return IgnoreErrors;
  334. }
  335. if (!DisplayUseOptionW && ( 0 == (FindData->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))){
  336. DisplayUseOptionW = TRUE;
  337. }
  338. if (!Quiet &&
  339. (DisplayAllFiles ||
  340. (0 == (FindData->dwFileAttributes & AttributesNoDisplay)))) {
  341. swprintf(Buf, TEXT("%s "), FindData->cFileName);
  342. DisplayMsg(CIPHER_THROW, Buf);
  343. for (i = lstrlen(FindData->cFileName) + 1; i < FIRST_COLUMN_WIDTH; ++i) {
  344. swprintf(Buf, TEXT("%c"), ' ');
  345. DisplayMsg(CIPHER_THROW, Buf);
  346. }
  347. DisplayMsg(CIPHER_OK);
  348. }
  349. TotalFileCount.QuadPart += 1;
  350. return TRUE;
  351. }
  352. BOOLEAN
  353. DoEncryptAction (
  354. IN PTCHAR DirectorySpec,
  355. IN PTCHAR FileSpec
  356. )
  357. {
  358. PTCHAR DirectorySpecEnd;
  359. //
  360. // If the file spec is null then we'll set the encryption bit for the
  361. // the directory spec and get out.
  362. //
  363. if (lstrlen(FileSpec) == 0) {
  364. USHORT State = 1;
  365. ULONG Length;
  366. DisplayMsg(CIPHER_ENCRYPT_DIR, DirectorySpec);
  367. if (!EncryptFile( DirectorySpec )) {
  368. if (!Quiet || !IgnoreErrors) {
  369. DisplayMsg(CIPHER_ERR);
  370. }
  371. if (!Quiet && !IgnoreErrors) {
  372. DisplayErr(DirectorySpec, GetLastError());
  373. }
  374. return IgnoreErrors;
  375. }
  376. if (!Quiet) {
  377. DisplayMsg(CIPHER_OK);
  378. }
  379. TotalDirectoryCount.QuadPart += 1;
  380. TotalFileCount.QuadPart += 1;
  381. return TRUE;
  382. }
  383. //
  384. // So that we can keep on appending names to the directory spec
  385. // get a pointer to the end of its string
  386. //
  387. DirectorySpecEnd = DirectorySpec + lstrlen( DirectorySpec );
  388. //
  389. // List the directory that we will be encrypting within and say what its
  390. // current encryption attribute is.
  391. //
  392. {
  393. ULONG Attributes;
  394. Attributes = GetFileAttributes( DirectorySpec );
  395. //
  396. // DirectorySpec could be passed in from the user. It could be bogus.
  397. //
  398. if (-1 == Attributes) {
  399. DisplayErr(DirectorySpec, GetLastError());
  400. return FALSE;
  401. }
  402. if ( DoFiles ) {
  403. if (Attributes & FILE_ATTRIBUTE_ENCRYPTED) {
  404. DisplayMsg(CIPHER_ENCRYPT_EDIR, DirectorySpec);
  405. } else {
  406. DisplayMsg(CIPHER_ENCRYPT_UDIR, DirectorySpec);
  407. }
  408. } else {
  409. if (Attributes & FILE_ATTRIBUTE_ENCRYPTED) {
  410. DisplayMsg(CIPHER_ENCRYPT_EDIR_NF, DirectorySpec);
  411. } else {
  412. DisplayMsg(CIPHER_ENCRYPT_UDIR_NF, DirectorySpec);
  413. }
  414. }
  415. TotalDirectoryCount.QuadPart += 1;
  416. }
  417. //
  418. // Now for every file in the directory that matches the file spec we will
  419. // will open the file and encrypt it
  420. //
  421. {
  422. HANDLE FindHandle;
  423. HANDLE FileHandle;
  424. WIN32_FIND_DATA FindData;
  425. //
  426. // setup the template for findfirst/findnext
  427. //
  428. if (((DirectorySpecEnd - DirectorySpec) + lstrlen( FileSpec )) <
  429. MAX_PATH) {
  430. lstrcpy( DirectorySpecEnd, FileSpec );
  431. FindHandle = FindFirstFile( DirectorySpec, &FindData );
  432. if (INVALID_HANDLE_VALUE != FindHandle) {
  433. do {
  434. //
  435. // Now skip over the . and .. entries
  436. //
  437. if (0 == lstrcmp(&FindData.cFileName[0], TEXT(".")) ||
  438. 0 == lstrcmp(&FindData.cFileName[0], TEXT(".."))) {
  439. continue;
  440. } else {
  441. //
  442. // Make sure we don't try any paths that are too long for us
  443. // to deal with.
  444. //
  445. if ( (DirectorySpecEnd - DirectorySpec) +
  446. lstrlen( FindData.cFileName ) >= MAX_PATH ) {
  447. continue;
  448. }
  449. //
  450. // append the found file to the directory spec and open
  451. // the file
  452. //
  453. lstrcpy( DirectorySpecEnd, FindData.cFileName );
  454. //
  455. // Hack hack, kludge kludge. Refrain from compressing
  456. // files named "\NTDLR" to help users avoid hosing
  457. // themselves.
  458. //
  459. if (IsNtldr(DirectorySpec)) {
  460. if (!Quiet) {
  461. DisplayMsg(CIPHER_SKIPPING, DirectorySpecEnd);
  462. }
  463. continue;
  464. }
  465. EncryptAFile( DirectorySpec, &FindData );
  466. }
  467. } while ( FindNextFile( FindHandle, &FindData ));
  468. FindClose( FindHandle );
  469. }
  470. }
  471. }
  472. //
  473. // If we are to do subdirectores then we will look for every subdirectory
  474. // and recursively call ourselves to list the subdirectory
  475. //
  476. if (DoSubdirectories) {
  477. HANDLE FindHandle;
  478. WIN32_FIND_DATA FindData;
  479. //
  480. // Setup findfirst/findnext to search the entire directory
  481. //
  482. if (((DirectorySpecEnd - DirectorySpec) + lstrlen( TEXT("*") )) <
  483. MAX_PATH) {
  484. lstrcpy( DirectorySpecEnd, TEXT("*") );
  485. FindHandle = FindFirstFile( DirectorySpec, &FindData );
  486. if (INVALID_HANDLE_VALUE != FindHandle) {
  487. do {
  488. //
  489. // Now skip over the . and .. entries otherwise we'll recurse
  490. // like mad
  491. //
  492. if (0 == lstrcmp(&FindData.cFileName[0], TEXT(".")) ||
  493. 0 == lstrcmp(&FindData.cFileName[0], TEXT(".."))) {
  494. continue;
  495. } else {
  496. //
  497. // If the entry is for a directory then we'll tack on the
  498. // subdirectory name to the directory spec and recursively
  499. // call otherselves
  500. //
  501. if (FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
  502. //
  503. // Make sure we don't try any paths that are too long for us
  504. // to deal with.
  505. //
  506. if ((DirectorySpecEnd - DirectorySpec) +
  507. lstrlen( TEXT("\\") ) +
  508. lstrlen( FindData.cFileName ) >= MAX_PATH ) {
  509. continue;
  510. }
  511. lstrcpy( DirectorySpecEnd, FindData.cFileName );
  512. lstrcat( DirectorySpecEnd, TEXT("\\") );
  513. if (!DoEncryptAction( DirectorySpec, FileSpec )) {
  514. FindClose( FindHandle );
  515. return FALSE || IgnoreErrors;
  516. }
  517. }
  518. }
  519. } while ( FindNextFile( FindHandle, &FindData ));
  520. FindClose( FindHandle );
  521. }
  522. }
  523. }
  524. return TRUE;
  525. }
  526. VOID
  527. DoFinalEncryptAction (
  528. )
  529. {
  530. TCHAR FileCount[32];
  531. TCHAR DirectoryCount[32];
  532. FormatFileSize(&TotalFileCount, 0, FileCount, FALSE);
  533. FormatFileSize(&TotalDirectoryCount, 0, DirectoryCount, FALSE);
  534. if ( DoFiles ) {
  535. DisplayMsg(CIPHER_ENCRYPT_SUMMARY, FileCount, DirectoryCount);
  536. if (DisplayUseOptionW) {
  537. DisplayMsg(CIPHER_USE_W);
  538. }
  539. } else {
  540. DisplayMsg(CIPHER_ENCRYPT_SUMMARY_NF, FileCount, DirectoryCount);
  541. }
  542. return;
  543. }
  544. BOOLEAN
  545. DecryptAFile (
  546. IN PTCHAR FileSpec,
  547. IN PWIN32_FIND_DATA FindData
  548. )
  549. {
  550. USHORT State = 0;
  551. ULONG Length;
  552. if (!(FindData->dwFileAttributes & FILE_ATTRIBUTE_ENCRYPTED) &&
  553. !ForceOperation) {
  554. return TRUE;
  555. }
  556. if ( (0 == (FindData->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) && (!DoFiles)) {
  557. //
  558. // Skip the files
  559. //
  560. return TRUE;
  561. }
  562. if (!DecryptFile(FileSpec, 0L )) {
  563. if (!Quiet || !IgnoreErrors) {
  564. swprintf(Buf, TEXT("%s "), FindData->cFileName);
  565. DisplayMsg(CIPHER_THROW, Buf);
  566. DisplayMsg(CIPHER_ERR);
  567. if (!Quiet && !IgnoreErrors) {
  568. if (ERROR_INVALID_FUNCTION == GetLastError()) {
  569. // This error is caused by doing the fsctl on a
  570. // non-compressing volume.
  571. DisplayMsg(CIPHER_WRONG_FILE_SYSTEM, FindData->cFileName);
  572. } else {
  573. DisplayErr(FindData->cFileName, GetLastError());
  574. }
  575. }
  576. }
  577. return IgnoreErrors;
  578. }
  579. if (!Quiet &&
  580. (DisplayAllFiles ||
  581. (0 == (FindData->dwFileAttributes & AttributesNoDisplay)))) {
  582. swprintf(Buf, TEXT("%s "), FindData->cFileName);
  583. DisplayMsg(CIPHER_THROW, Buf);
  584. DisplayMsg(CIPHER_OK);
  585. }
  586. //
  587. // Increment our running total
  588. //
  589. TotalFileCount.QuadPart += 1;
  590. return TRUE;
  591. }
  592. BOOLEAN
  593. DoDecryptAction (
  594. IN PTCHAR DirectorySpec,
  595. IN PTCHAR FileSpec
  596. )
  597. {
  598. PTCHAR DirectorySpecEnd;
  599. //
  600. // If the file spec is null then we'll clear the encryption bit for the
  601. // the directory spec and get out.
  602. //
  603. if (lstrlen(FileSpec) == 0) {
  604. HANDLE FileHandle;
  605. USHORT State = 0;
  606. ULONG Length;
  607. DisplayMsg(CIPHER_DECRYPT_DIR, DirectorySpec);
  608. if (!DecryptFile( DirectorySpec, 0L )) {
  609. if (!Quiet || !IgnoreErrors) {
  610. DisplayMsg(CIPHER_ERR);
  611. }
  612. if (!Quiet && !IgnoreErrors) {
  613. DisplayErr(DirectorySpec, GetLastError());
  614. }
  615. return IgnoreErrors;
  616. }
  617. if (!Quiet) {
  618. DisplayMsg(CIPHER_OK);
  619. }
  620. TotalDirectoryCount.QuadPart += 1;
  621. TotalFileCount.QuadPart += 1;
  622. return TRUE;
  623. }
  624. //
  625. // So that we can keep on appending names to the directory spec
  626. // get a pointer to the end of its string
  627. //
  628. DirectorySpecEnd = DirectorySpec + lstrlen( DirectorySpec );
  629. //
  630. // List the directory that we will be uncompressing within and say what its
  631. // current compress attribute is
  632. //
  633. {
  634. ULONG Attributes;
  635. Attributes = GetFileAttributes( DirectorySpec );
  636. //
  637. // DirectorySpec could be passed in from the user. It could be bogus.
  638. //
  639. if (-1 == Attributes) {
  640. DisplayErr(DirectorySpec, GetLastError());
  641. return FALSE;
  642. }
  643. if ( DoFiles) {
  644. if (Attributes & FILE_ATTRIBUTE_ENCRYPTED) {
  645. DisplayMsg(CIPHER_DECRYPT_EDIR, DirectorySpec);
  646. } else {
  647. DisplayMsg(CIPHER_DECRYPT_UDIR, DirectorySpec);
  648. }
  649. } else {
  650. if (Attributes & FILE_ATTRIBUTE_ENCRYPTED) {
  651. DisplayMsg(CIPHER_DECRYPT_EDIR_NF, DirectorySpec);
  652. } else {
  653. DisplayMsg(CIPHER_DECRYPT_UDIR_NF, DirectorySpec);
  654. }
  655. }
  656. TotalDirectoryCount.QuadPart += 1;
  657. }
  658. //
  659. // Now for every file in the directory that matches the file spec we will
  660. // will open the file and uncompress it
  661. //
  662. {
  663. HANDLE FindHandle;
  664. WIN32_FIND_DATA FindData;
  665. //
  666. // setup the template for findfirst/findnext
  667. //
  668. if (((DirectorySpecEnd - DirectorySpec) + lstrlen( FileSpec )) <
  669. MAX_PATH) {
  670. lstrcpy( DirectorySpecEnd, FileSpec );
  671. FindHandle = FindFirstFile( DirectorySpec, &FindData );
  672. if (INVALID_HANDLE_VALUE != FindHandle) {
  673. do {
  674. //
  675. // Now skip over the . and .. entries
  676. //
  677. if (0 == lstrcmp(&FindData.cFileName[0], TEXT(".")) ||
  678. 0 == lstrcmp(&FindData.cFileName[0], TEXT(".."))) {
  679. continue;
  680. } else {
  681. //
  682. // Make sure we don't try any paths that are too long for us
  683. // to deal with.
  684. //
  685. if ((DirectorySpecEnd - DirectorySpec) +
  686. lstrlen( FindData.cFileName ) >= MAX_PATH ) {
  687. continue;
  688. }
  689. //
  690. // append the found file to the directory spec and open
  691. // the file
  692. //
  693. lstrcpy( DirectorySpecEnd, FindData.cFileName );
  694. //
  695. // Now decrypt the file
  696. //
  697. DecryptAFile( DirectorySpec, &FindData );
  698. }
  699. } while ( FindNextFile( FindHandle, &FindData ));
  700. FindClose( FindHandle );
  701. }
  702. }
  703. }
  704. //
  705. // If we are to do subdirectores then we will look for every subdirectory
  706. // and recursively call ourselves to list the subdirectory
  707. //
  708. if (DoSubdirectories) {
  709. HANDLE FindHandle;
  710. WIN32_FIND_DATA FindData;
  711. //
  712. // Setup findfirst/findnext to search the entire directory
  713. //
  714. if (((DirectorySpecEnd - DirectorySpec) + lstrlen( TEXT("*") )) <
  715. MAX_PATH) {
  716. lstrcpy( DirectorySpecEnd, TEXT("*") );
  717. FindHandle = FindFirstFile( DirectorySpec, &FindData );
  718. if (INVALID_HANDLE_VALUE != FindHandle) {
  719. do {
  720. //
  721. // Now skip over the . and .. entries otherwise we'll recurse
  722. // like mad
  723. //
  724. if (0 == lstrcmp(&FindData.cFileName[0], TEXT(".")) ||
  725. 0 == lstrcmp(&FindData.cFileName[0], TEXT(".."))) {
  726. continue;
  727. } else {
  728. //
  729. // If the entry is for a directory then we'll tack on the
  730. // subdirectory name to the directory spec and recursively
  731. // call otherselves
  732. //
  733. if (FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
  734. //
  735. // Make sure we don't try any paths that are too long for us
  736. // to deal with.
  737. //
  738. if ((DirectorySpecEnd - DirectorySpec) +
  739. lstrlen( TEXT("\\") ) +
  740. lstrlen( FindData.cFileName ) >= MAX_PATH ) {
  741. continue;
  742. }
  743. lstrcpy( DirectorySpecEnd, FindData.cFileName );
  744. lstrcat( DirectorySpecEnd, TEXT("\\") );
  745. if (!DoDecryptAction( DirectorySpec, FileSpec )) {
  746. FindClose( FindHandle );
  747. return FALSE || IgnoreErrors;
  748. }
  749. }
  750. }
  751. } while ( FindNextFile( FindHandle, &FindData ));
  752. FindClose( FindHandle );
  753. }
  754. }
  755. }
  756. return TRUE;
  757. }
  758. VOID
  759. DoFinalDecryptAction (
  760. )
  761. {
  762. TCHAR FileCount[32];
  763. TCHAR DirectoryCount[32];
  764. FormatFileSize(&TotalFileCount, 0, FileCount, FALSE);
  765. FormatFileSize(&TotalDirectoryCount, 0, DirectoryCount, FALSE);
  766. if (DoFiles) {
  767. DisplayMsg(CIPHER_DECRYPT_SUMMARY, FileCount, DirectoryCount);
  768. } else {
  769. DisplayMsg(CIPHER_DECRYPT_SUMMARY_NF, FileCount, DirectoryCount);
  770. }
  771. return;
  772. }
  773. VOID
  774. CipherConvertHashToStr(
  775. IN PBYTE pHashData,
  776. IN DWORD cbData,
  777. OUT LPWSTR OutHashStr
  778. )
  779. {
  780. DWORD Index = 0;
  781. BOOLEAN NoLastZero = FALSE;
  782. for (; Index < cbData; Index+=2) {
  783. BYTE HashByteLow = pHashData[Index] & 0x0f;
  784. BYTE HashByteHigh = (pHashData[Index] & 0xf0) >> 4;
  785. OutHashStr[Index * 5/2] = HashByteHigh > 9 ? (WCHAR)(HashByteHigh - 9 + 0x40): (WCHAR)(HashByteHigh + 0x30);
  786. OutHashStr[Index * 5/2 + 1] = HashByteLow > 9 ? (WCHAR)(HashByteLow - 9 + 0x40): (WCHAR)(HashByteLow + 0x30);
  787. if (Index + 1 < cbData) {
  788. HashByteLow = pHashData[Index+1] & 0x0f;
  789. HashByteHigh = (pHashData[Index+1] & 0xf0) >> 4;
  790. OutHashStr[Index * 5/2 + 2] = HashByteHigh > 9 ? (WCHAR)(HashByteHigh - 9 + 0x40): (WCHAR)(HashByteHigh + 0x30);
  791. OutHashStr[Index * 5/2 + 3] = HashByteLow > 9 ? (WCHAR)(HashByteLow - 9 + 0x40): (WCHAR)(HashByteLow + 0x30);
  792. OutHashStr[Index * 5/2 + 4] = L' ';
  793. } else {
  794. OutHashStr[Index * 5/2 + 2] = 0;
  795. NoLastZero = TRUE;
  796. }
  797. }
  798. if (!NoLastZero) {
  799. OutHashStr[Index*5/2] = 0;
  800. }
  801. }
  802. VOID
  803. CipherDisplayCrntEfsHash(
  804. )
  805. {
  806. DWORD rc;
  807. HKEY hRegKey = NULL;
  808. PBYTE pbHash;
  809. DWORD cbHash;
  810. DWORD nSize = MAX_COMPUTERNAME_LENGTH + 1;
  811. WCHAR LocalComputerName[MAX_COMPUTERNAME_LENGTH + 1];
  812. if (!GetComputerName ( LocalComputerName, &nSize )){
  813. //
  814. // This is not likely to happen.
  815. //
  816. return;
  817. }
  818. rc = RegOpenKeyEx(
  819. KEYPATHROOT,
  820. KEYPATH,
  821. 0,
  822. GENERIC_READ,
  823. &hRegKey
  824. );
  825. if (rc == ERROR_SUCCESS) {
  826. DWORD Type;
  827. rc = RegQueryValueEx(
  828. hRegKey,
  829. CERT_HASH,
  830. NULL,
  831. &Type,
  832. NULL,
  833. &cbHash
  834. );
  835. if (rc == ERROR_SUCCESS) {
  836. //
  837. // Query out the thumbprint, find the cert, and return the key information.
  838. //
  839. if (pbHash = (PBYTE)malloc( cbHash )) {
  840. rc = RegQueryValueEx(
  841. hRegKey,
  842. CERT_HASH,
  843. NULL,
  844. &Type,
  845. pbHash,
  846. &cbHash
  847. );
  848. if (rc == ERROR_SUCCESS) {
  849. LPWSTR OutHash;
  850. OutHash = (LPWSTR) malloc(((((cbHash + 1)/2) * 5)+1) * sizeof(WCHAR));
  851. if (OutHash) {
  852. CipherConvertHashToStr(pbHash, cbHash, OutHash);
  853. DisplayMsg(CIPHER_CURRENT_CERT, LocalComputerName, OutHash);
  854. free(OutHash);
  855. }
  856. }
  857. free(pbHash);
  858. }
  859. }
  860. RegCloseKey( hRegKey );
  861. }
  862. return;
  863. }
  864. BOOL
  865. CipherConvertToDriveLetter(
  866. IN OUT LPWSTR VolBuffer,
  867. IN PCIPHER_VOLUME_INFO VolumeInfo
  868. )
  869. {
  870. WCHAR DeviceName[MAX_PATH];
  871. WORD DriveIndex = 0;
  872. while (DriveIndex < DosDriveLimitCount) {
  873. if (VolumeInfo->VolumeName[DriveIndex]) {
  874. if (!wcscmp(VolBuffer, VolumeInfo->VolumeName[DriveIndex])) {
  875. lstrcpy(VolBuffer, TEXT("A:\\"));
  876. VolBuffer[0] += DriveIndex;
  877. return TRUE;
  878. }
  879. VolBuffer[48] = 0;
  880. if (VolumeInfo->DosDeviceName[DriveIndex] && QueryDosDevice( &(VolBuffer[4]), DeviceName, MAX_PATH)) {
  881. if (!wcscmp(DeviceName, VolumeInfo->DosDeviceName[DriveIndex])) {
  882. lstrcpy(VolBuffer, TEXT("A:\\"));
  883. VolBuffer[0] += DriveIndex;
  884. return TRUE;
  885. }
  886. }
  887. }
  888. DriveIndex++;
  889. }
  890. return FALSE;
  891. }
  892. VOID
  893. CipherTouchDirFiles(
  894. IN WCHAR *DirPath,
  895. IN PCIPHER_VOLUME_INFO VolumeInfo
  896. )
  897. {
  898. PTCHAR DirectorySpecEnd;
  899. HANDLE FindHandle;
  900. WIN32_FIND_DATA FindData;
  901. HANDLE hFile;
  902. //
  903. // So that we can keep on appending names to the directory spec
  904. // get a pointer to the end of its string
  905. //
  906. DirectorySpecEnd = DirPath + lstrlen( DirPath );
  907. //
  908. // setup the template for findfirst/findnext
  909. //
  910. if ((DirectorySpecEnd - DirPath) < ENUMPATHLENGTH - 2* sizeof(WCHAR)) {
  911. lstrcpy( DirectorySpecEnd, TEXT("*") );
  912. FindHandle = FindFirstFile( DirPath, &FindData );
  913. if (INVALID_HANDLE_VALUE != FindHandle) {
  914. do {
  915. //
  916. // Now skip over the . and .. entries
  917. //
  918. if (0 == lstrcmp(&FindData.cFileName[0], TEXT(".")) ||
  919. 0 == lstrcmp(&FindData.cFileName[0], TEXT(".."))) {
  920. continue;
  921. } else {
  922. //
  923. // Make sure we don't try any paths that are too long for us
  924. // to deal with.
  925. //
  926. if ((DirectorySpecEnd - DirPath) +
  927. lstrlen( FindData.cFileName ) >= ENUMPATHLENGTH ) {
  928. continue;
  929. }
  930. if ( !(FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) &&
  931. (FindData.dwFileAttributes & FILE_ATTRIBUTE_ENCRYPTED)) {
  932. //
  933. // append the found file to the directory spec and open
  934. // the file
  935. //
  936. lstrcpy( DirectorySpecEnd, FindData.cFileName );
  937. //
  938. // Now touch the file
  939. //
  940. if (DisplayFilesOnly) {
  941. DisplayMsg(CIPHER_THROW_NL, DirPath);
  942. } else {
  943. hFile = CreateFileW(
  944. DirPath,
  945. GENERIC_READ,
  946. FILE_SHARE_READ | FILE_SHARE_WRITE,
  947. NULL,
  948. OPEN_EXISTING,
  949. 0,
  950. NULL
  951. );
  952. if ( INVALID_HANDLE_VALUE != hFile ){
  953. DisplayMsg(CIPHER_TOUCH_OK, DirPath);
  954. CloseHandle(hFile);
  955. } else {
  956. DisplayErr(DirPath, GetLastError());
  957. }
  958. }
  959. }
  960. }
  961. } while ( FindNextFile( FindHandle, &FindData ));
  962. FindClose( FindHandle );
  963. }
  964. }
  965. //
  966. // Setup findfirst/findnext to search the sub directory
  967. //
  968. if ((DirectorySpecEnd - DirPath) < ENUMPATHLENGTH - 2* sizeof(WCHAR)) {
  969. lstrcpy( DirectorySpecEnd, TEXT("*") );
  970. FindHandle = FindFirstFile( DirPath, &FindData );
  971. if (INVALID_HANDLE_VALUE != FindHandle) {
  972. do {
  973. //
  974. // Now skip over the . and .. entries otherwise we'll recurse
  975. // like mad
  976. //
  977. if (0 == lstrcmp(&FindData.cFileName[0], TEXT(".")) ||
  978. 0 == lstrcmp(&FindData.cFileName[0], TEXT(".."))) {
  979. continue;
  980. } else {
  981. //
  982. // If the entry is for a directory then we'll tack on the
  983. // subdirectory name to the directory spec and recursively
  984. // call otherselves
  985. //
  986. if (FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
  987. BOOL b;
  988. WCHAR MountVolName[MAX_PATH];
  989. //
  990. // Make sure we don't try any paths that are too long for us
  991. // to deal with.
  992. //
  993. if ((DirectorySpecEnd - DirPath) +
  994. lstrlen( TEXT("\\") ) +
  995. lstrlen( FindData.cFileName ) >= ENUMPATHLENGTH ) {
  996. continue;
  997. }
  998. lstrcpy( DirectorySpecEnd, FindData.cFileName );
  999. lstrcat( DirectorySpecEnd, TEXT("\\") );
  1000. //
  1001. // Check if this DIR point to another volume
  1002. //
  1003. b = GetVolumeNameForVolumeMountPoint(DirPath, MountVolName, MAX_PATH);
  1004. if (b) {
  1005. if (CipherConvertToDriveLetter(MountVolName, VolumeInfo)){
  1006. continue;
  1007. }
  1008. }
  1009. CipherTouchDirFiles(DirPath, VolumeInfo);
  1010. }
  1011. }
  1012. } while ( FindNextFile( FindHandle, &FindData ));
  1013. FindClose( FindHandle );
  1014. }
  1015. }
  1016. }
  1017. DWORD
  1018. CipherTouchEncryptedFiles(
  1019. )
  1020. {
  1021. WCHAR VolBuffer[MAX_PATH];
  1022. WCHAR *SearchPath = NULL;
  1023. HANDLE SearchHandle;
  1024. BOOL SearchNext = TRUE;
  1025. CIPHER_VOLUME_INFO VolumeInfo;
  1026. LPWSTR VolumeNames;
  1027. LPWSTR VolumeNamesCrnt;
  1028. LPWSTR DosDeviceNames;
  1029. LPWSTR DosDeviceNamesCrnt;
  1030. DWORD DriveIndex = 0;
  1031. WCHAR TmpChar;
  1032. BOOL b;
  1033. VolumeNames = (LPWSTR) malloc ( DosDriveLimitCount * MAX_PATH * sizeof(WCHAR) );
  1034. DosDeviceNames = (LPWSTR) malloc ( DosDriveLimitCount * MAX_PATH * sizeof(WCHAR) );
  1035. if ( !VolumeNames || !DosDeviceNames) {
  1036. if (VolumeNames) {
  1037. free(VolumeNames);
  1038. }
  1039. if (DosDeviceNames) {
  1040. free(DosDeviceNames);
  1041. }
  1042. return ERROR_NOT_ENOUGH_MEMORY;
  1043. }
  1044. //
  1045. // Don't popup when query floopy and etc.
  1046. //
  1047. SetErrorMode(SEM_FAILCRITICALERRORS);
  1048. lstrcpy(VolBuffer, TEXT("A:\\"));
  1049. VolumeNamesCrnt = VolumeNames;
  1050. DosDeviceNamesCrnt = DosDeviceNames;
  1051. //
  1052. // Get all the volume and device names which has a drive letter assigned
  1053. //
  1054. while (DriveIndex < DosDriveLimitCount) {
  1055. b = GetVolumeNameForVolumeMountPoint( VolBuffer,
  1056. VolumeNamesCrnt,
  1057. (DWORD)(VolumeNames + DosDriveLimitCount * MAX_PATH - VolumeNamesCrnt));
  1058. if (!b) {
  1059. VolumeInfo.VolumeName[DriveIndex] = NULL;
  1060. VolumeInfo.DosDeviceName[DriveIndex++] = NULL;
  1061. VolBuffer[0]++;
  1062. continue;
  1063. }
  1064. VolumeInfo.VolumeName[DriveIndex] = VolumeNamesCrnt;
  1065. VolumeNamesCrnt += lstrlen(VolumeNamesCrnt) + 1;
  1066. //
  1067. // The number 48 is copied from utils\mountvol\mountvol.c
  1068. //
  1069. TmpChar = VolumeInfo.VolumeName[DriveIndex][48];
  1070. VolumeInfo.VolumeName[DriveIndex][48] = 0;
  1071. if (QueryDosDevice( &(VolumeInfo.VolumeName[DriveIndex][4]),
  1072. DosDeviceNamesCrnt,
  1073. (DWORD)(DosDeviceNames + DosDriveLimitCount * MAX_PATH - DosDeviceNamesCrnt))) {
  1074. VolumeInfo.DosDeviceName[DriveIndex] = DosDeviceNamesCrnt;
  1075. DosDeviceNamesCrnt += lstrlen(DosDeviceNamesCrnt) + 1;
  1076. } else {
  1077. VolumeInfo.DosDeviceName[DriveIndex] = NULL;
  1078. }
  1079. VolumeInfo.VolumeName[DriveIndex][48] = TmpChar;
  1080. VolBuffer[0]++;
  1081. DriveIndex++;
  1082. }
  1083. SearchPath = (WCHAR *) malloc( ENUMPATHLENGTH * sizeof(WCHAR) );
  1084. if (!SearchPath) {
  1085. return ERROR_NOT_ENOUGH_MEMORY;
  1086. }
  1087. SearchHandle = FindFirstVolume(VolBuffer, MAX_PATH);
  1088. if ( INVALID_HANDLE_VALUE != SearchHandle ) {
  1089. if (DisplayFilesOnly) {
  1090. DisplayMsg(CIPHER_ENCRYPTED_FILES, NULL);
  1091. }
  1092. while ( SearchNext ) {
  1093. if (CipherConvertToDriveLetter(VolBuffer, &VolumeInfo)){
  1094. //
  1095. // Check if this volume is a NTFS volume
  1096. //
  1097. if(GetVolumeInformation(
  1098. VolBuffer, // Current root directory.
  1099. NULL, // Volume name.
  1100. 0, // Volume name length.
  1101. NULL, // Serial number.
  1102. NULL, // Maximum length.
  1103. NULL,
  1104. SearchPath, // File system type.
  1105. MAX_PATH
  1106. )){
  1107. if(!wcscmp(SearchPath, TEXT("NTFS"))){
  1108. lstrcpy( SearchPath, VolBuffer );
  1109. CipherTouchDirFiles(SearchPath, &VolumeInfo);
  1110. }
  1111. }
  1112. }
  1113. SearchNext = FindNextVolume(SearchHandle, VolBuffer, MAX_PATH);
  1114. }
  1115. FindVolumeClose(SearchHandle);
  1116. }
  1117. free(SearchPath);
  1118. free(VolumeNames);
  1119. free(DosDeviceNames);
  1120. return ERROR_SUCCESS;
  1121. }
  1122. BOOL
  1123. EncodeAndAlloc(
  1124. DWORD dwEncodingType,
  1125. LPCSTR lpszStructType,
  1126. const void * pvStructInfo,
  1127. PBYTE * pbEncoded,
  1128. PDWORD pcbEncoded
  1129. )
  1130. {
  1131. BOOL b = FALSE;
  1132. if (CryptEncodeObject(
  1133. dwEncodingType,
  1134. lpszStructType,
  1135. pvStructInfo,
  1136. NULL,
  1137. pcbEncoded )) {
  1138. *pbEncoded = (PBYTE)malloc( *pcbEncoded );
  1139. if (*pbEncoded) {
  1140. if (CryptEncodeObject(
  1141. dwEncodingType,
  1142. lpszStructType,
  1143. pvStructInfo,
  1144. *pbEncoded,
  1145. pcbEncoded )) {
  1146. b = TRUE;
  1147. } else {
  1148. free( *pbEncoded );
  1149. *pbEncoded = NULL;
  1150. }
  1151. } else {
  1152. SetLastError( ERROR_NOT_ENOUGH_MEMORY );
  1153. }
  1154. }
  1155. return( b );
  1156. }
  1157. BOOLEAN
  1158. CreateSelfSignedRecoveryCertificate(
  1159. OUT PCCERT_CONTEXT * pCertContext,
  1160. OUT LPWSTR *lpContainerName,
  1161. OUT LPWSTR *lpProviderName
  1162. )
  1163. /*++
  1164. Routine Description:
  1165. This routine sets up and creates a self-signed certificate.
  1166. Arguments:
  1167. Return Value:
  1168. TRUE on success, FALSE on failure. Call GetLastError() for more details.
  1169. --*/
  1170. {
  1171. BOOLEAN fReturn = FALSE;
  1172. DWORD rc = ERROR_SUCCESS;
  1173. PBYTE pbHash = NULL;
  1174. LPWSTR lpDisplayInfo = NULL;
  1175. HCRYPTKEY hKey = 0;
  1176. HCRYPTPROV hProv = 0;
  1177. GUID guidContainerName;
  1178. LPWSTR TmpContainerName;
  1179. RPC_STATUS RpcStatus = ERROR_SUCCESS;
  1180. *pCertContext = NULL;
  1181. *lpContainerName = NULL;
  1182. *lpProviderName = NULL;
  1183. //
  1184. // Create a key pair
  1185. //
  1186. //
  1187. // Container name
  1188. //
  1189. RpcStatus = UuidCreate(&guidContainerName);
  1190. if ( (ERROR_SUCCESS != RpcStatus) && (RPC_S_UUID_LOCAL_ONLY != RpcStatus) ) {
  1191. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  1192. return(fReturn);
  1193. }
  1194. if (ERROR_SUCCESS == UuidToStringW(&guidContainerName, (unsigned short **)lpContainerName )) {
  1195. //
  1196. // Copy the container name into LSA heap memory
  1197. //
  1198. *lpProviderName = MS_DEF_PROV;
  1199. //
  1200. // Create the key container
  1201. //
  1202. if (CryptAcquireContext(&hProv, *lpContainerName, MS_DEF_PROV, PROV_RSA_FULL, CRYPT_NEWKEYSET )) {
  1203. if (CryptGenKey(hProv, AT_KEYEXCHANGE, RSA1024BIT_KEY | CRYPT_EXPORTABLE, &hKey)) {
  1204. DWORD NameLength = 64;
  1205. LPWSTR AgentName = NULL;
  1206. //
  1207. // Construct the subject name information
  1208. //
  1209. AgentName = (LPWSTR)malloc(NameLength * sizeof(WCHAR));
  1210. if (AgentName){
  1211. if (!GetUserName(AgentName, &NameLength)){
  1212. free(AgentName);
  1213. AgentName = (LPWSTR)malloc(NameLength * sizeof(WCHAR));
  1214. //
  1215. // Try again with big buffer
  1216. //
  1217. if ( AgentName ){
  1218. if (!GetUserName(AgentName, &NameLength)){
  1219. rc = GetLastError();
  1220. free(AgentName);
  1221. AgentName = NULL;
  1222. }
  1223. } else {
  1224. rc = ERROR_NOT_ENOUGH_MEMORY;
  1225. }
  1226. }
  1227. } else {
  1228. rc = ERROR_NOT_ENOUGH_MEMORY;
  1229. }
  1230. if (AgentName) {
  1231. LPCWSTR DNNameTemplate = L"CN=%ws,L=EFS,OU=EFS File Encryption Certificate";
  1232. DWORD cbDNName = 0;
  1233. cbDNName = (wcslen( DNNameTemplate ) + 1) * sizeof( WCHAR ) + (wcslen( AgentName ) + 1) * sizeof( WCHAR );
  1234. lpDisplayInfo = (LPWSTR)malloc( cbDNName );
  1235. if (lpDisplayInfo) {
  1236. swprintf( lpDisplayInfo, DNNameTemplate, AgentName );
  1237. } else {
  1238. rc = ERROR_NOT_ENOUGH_MEMORY;
  1239. }
  1240. free(AgentName);
  1241. AgentName = NULL;
  1242. }
  1243. if (lpDisplayInfo) {
  1244. //
  1245. // Use this piece of code to create the PCERT_NAME_BLOB going into CertCreateSelfSignCertificate()
  1246. //
  1247. CERT_NAME_BLOB SubjectName;
  1248. SubjectName.cbData = 0;
  1249. if(CertStrToNameW(
  1250. CRYPT_ASN_ENCODING,
  1251. lpDisplayInfo,
  1252. 0,
  1253. NULL,
  1254. NULL,
  1255. &SubjectName.cbData,
  1256. NULL)) {
  1257. SubjectName.pbData = (BYTE *) malloc(SubjectName.cbData);
  1258. if (SubjectName.pbData) {
  1259. if (CertStrToNameW(
  1260. CRYPT_ASN_ENCODING,
  1261. lpDisplayInfo,
  1262. 0,
  1263. NULL,
  1264. SubjectName.pbData,
  1265. &SubjectName.cbData,
  1266. NULL) ) {
  1267. //
  1268. // Make the enhanced key usage
  1269. //
  1270. CERT_ENHKEY_USAGE certEnhKeyUsage;
  1271. LPSTR lpstr;
  1272. CERT_EXTENSION certExt;
  1273. lpstr = szOID_EFS_RECOVERY;
  1274. certEnhKeyUsage.cUsageIdentifier = 1;
  1275. certEnhKeyUsage.rgpszUsageIdentifier = &lpstr;
  1276. // now call CryptEncodeObject to encode the enhanced key usage into the extension struct
  1277. certExt.Value.cbData = 0;
  1278. certExt.Value.pbData = NULL;
  1279. certExt.fCritical = FALSE;
  1280. certExt.pszObjId = szOID_ENHANCED_KEY_USAGE;
  1281. //
  1282. // Encode it
  1283. //
  1284. if (EncodeAndAlloc(
  1285. CRYPT_ASN_ENCODING,
  1286. X509_ENHANCED_KEY_USAGE,
  1287. &certEnhKeyUsage,
  1288. &certExt.Value.pbData,
  1289. &certExt.Value.cbData
  1290. )) {
  1291. //
  1292. // finally, set up the array of extensions in the certInfo struct
  1293. // any further extensions need to be added to this array.
  1294. //
  1295. CERT_EXTENSIONS certExts;
  1296. CRYPT_KEY_PROV_INFO KeyProvInfo;
  1297. SYSTEMTIME StartTime;
  1298. FILETIME FileTime;
  1299. LARGE_INTEGER TimeData;
  1300. SYSTEMTIME EndTime;
  1301. certExts.cExtension = 1;
  1302. certExts.rgExtension = &certExt;
  1303. memset( &KeyProvInfo, 0, sizeof( CRYPT_KEY_PROV_INFO ));
  1304. KeyProvInfo.pwszContainerName = *lpContainerName;
  1305. KeyProvInfo.pwszProvName = *lpProviderName;
  1306. KeyProvInfo.dwProvType = PROV_RSA_FULL;
  1307. KeyProvInfo.dwKeySpec = AT_KEYEXCHANGE;
  1308. GetSystemTime(&StartTime);
  1309. SystemTimeToFileTime(&StartTime, &FileTime);
  1310. TimeData.LowPart = FileTime.dwLowDateTime;
  1311. TimeData.HighPart = (LONG) FileTime.dwHighDateTime;
  1312. TimeData.QuadPart += YEARCOUNT * 100;
  1313. FileTime.dwLowDateTime = TimeData.LowPart;
  1314. FileTime.dwHighDateTime = (DWORD) TimeData.HighPart;
  1315. FileTimeToSystemTime(&FileTime, &EndTime);
  1316. *pCertContext = CertCreateSelfSignCertificate(
  1317. hProv,
  1318. &SubjectName,
  1319. 0,
  1320. &KeyProvInfo,
  1321. NULL,
  1322. &StartTime,
  1323. &EndTime,
  1324. &certExts
  1325. );
  1326. if (*pCertContext) {
  1327. fReturn = TRUE;
  1328. } else {
  1329. rc = GetLastError();
  1330. }
  1331. free( certExt.Value.pbData );
  1332. } else {
  1333. rc = GetLastError();
  1334. }
  1335. } else {
  1336. rc = GetLastError();
  1337. }
  1338. free( SubjectName.pbData );
  1339. } else {
  1340. rc = ERROR_NOT_ENOUGH_MEMORY;
  1341. }
  1342. } else {
  1343. rc = GetLastError();
  1344. }
  1345. free( lpDisplayInfo );
  1346. } else {
  1347. rc = ERROR_NOT_ENOUGH_MEMORY;
  1348. }
  1349. CryptDestroyKey( hKey );
  1350. } else {
  1351. rc = GetLastError();
  1352. }
  1353. CryptReleaseContext( hProv, 0 );
  1354. hProv = 0;
  1355. if (ERROR_SUCCESS != rc) {
  1356. //
  1357. // Creating cert failed. Let's delete the key container.
  1358. //
  1359. CryptAcquireContext(&hProv, *lpContainerName, MS_DEF_PROV, PROV_RSA_FULL, CRYPT_DELETEKEYSET | CRYPT_SILENT );
  1360. }
  1361. } else {
  1362. rc = GetLastError();
  1363. }
  1364. if (ERROR_SUCCESS != rc) {
  1365. RpcStringFree( (unsigned short **)lpContainerName );
  1366. *lpContainerName = NULL;
  1367. }
  1368. } else {
  1369. rc = ERROR_NOT_ENOUGH_MEMORY;
  1370. }
  1371. if (!fReturn) {
  1372. if (*pCertContext) {
  1373. CertFreeCertificateContext( *pCertContext );
  1374. *pCertContext = NULL;
  1375. }
  1376. }
  1377. SetLastError( rc );
  1378. return( fReturn );
  1379. }
  1380. BOOLEAN
  1381. GetPassword(
  1382. OUT LPWSTR *PasswordStr
  1383. )
  1384. /*++
  1385. Routine Description:
  1386. Input a string from stdin in the Console code page.
  1387. We can't use fgetws since it uses the wrong code page.
  1388. Arguments:
  1389. Buffer - Buffer to put the read string into.
  1390. The Buffer will be zero terminated and will have any traing CR/LF removed
  1391. Return Values:
  1392. None.
  1393. --*/
  1394. {
  1395. int size;
  1396. LPSTR MbcsBuffer = NULL;
  1397. LPSTR Result;
  1398. DWORD Mode;
  1399. DWORD MbcsSize;
  1400. DWORD MbcsLength;
  1401. //
  1402. // Allocate a local buffer to read the string into
  1403. // Include room for the trimmed CR/LF
  1404. //
  1405. MbcsSize = (PASSWORDLEN+2) * sizeof(WCHAR);
  1406. MbcsBuffer = (LPSTR) malloc((PASSWORDLEN+2) * sizeof(WCHAR));
  1407. *PasswordStr = (LPWSTR) malloc((PASSWORDLEN+1) * sizeof(WCHAR));
  1408. if ( (MbcsBuffer == NULL) || (*PasswordStr == NULL) ) {
  1409. if (MbcsBuffer) {
  1410. free (MbcsBuffer);
  1411. }
  1412. if (*PasswordStr) {
  1413. free (*PasswordStr);
  1414. }
  1415. DisplayMsg(CIPHER_NO_MEMORY);
  1416. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  1417. return FALSE;
  1418. }
  1419. DisplayMsg(CIPHER_PROMPT_PASSWORD);
  1420. // turn off echo
  1421. GetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), &Mode);
  1422. SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE),
  1423. (~(ENABLE_ECHO_INPUT)) & Mode);
  1424. Result = fgets( MbcsBuffer, MbcsSize, stdin );
  1425. if ( Result == NULL ) {
  1426. SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), Mode);
  1427. free(MbcsBuffer);
  1428. free (*PasswordStr);
  1429. *PasswordStr = NULL;
  1430. return TRUE;
  1431. }
  1432. DisplayMsg(CIPHER_CONFIRM_PASSWORD);
  1433. Result = fgets( (LPSTR)*PasswordStr, (PASSWORDLEN+1) * sizeof(WCHAR), stdin );
  1434. // turn echo back on
  1435. SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), Mode);
  1436. _putws ( L"\n" );
  1437. if (strcmp( (LPSTR) *PasswordStr, MbcsBuffer)){
  1438. //
  1439. // Password not match.
  1440. //
  1441. DisplayMsg(CIPHER_PASSWORD_NOMATCH);
  1442. free(MbcsBuffer);
  1443. free (*PasswordStr);
  1444. SetLastError(ERROR_INVALID_PASSWORD);
  1445. *PasswordStr = NULL;
  1446. return FALSE;
  1447. }
  1448. if ( Result == NULL ) {
  1449. free(MbcsBuffer);
  1450. free (*PasswordStr);
  1451. *PasswordStr = NULL;
  1452. return TRUE;
  1453. }
  1454. //
  1455. // Trim any trailing CR or LF char from the string
  1456. //
  1457. MbcsLength = lstrlenA( MbcsBuffer );
  1458. if ( MbcsLength == 0 ) {
  1459. free(MbcsBuffer);
  1460. free (*PasswordStr);
  1461. *PasswordStr = NULL;
  1462. return TRUE;
  1463. }
  1464. if ( MbcsBuffer[MbcsLength-1] == '\n' || MbcsBuffer[MbcsLength-1] == '\r' ) {
  1465. MbcsBuffer[MbcsLength-1] = '\0';
  1466. MbcsLength --;
  1467. }
  1468. //
  1469. // Convert the string to UNICODE
  1470. //
  1471. size = MultiByteToWideChar( GetConsoleOutputCP(),
  1472. 0,
  1473. MbcsBuffer,
  1474. MbcsLength+1, // Include trailing zero
  1475. *PasswordStr,
  1476. PASSWORDLEN );
  1477. free(MbcsBuffer);
  1478. if ( size == 0 ) {
  1479. DisplayErr(NULL, GetLastError());
  1480. free (*PasswordStr);
  1481. *PasswordStr = NULL;
  1482. return FALSE;
  1483. }
  1484. return TRUE;
  1485. }
  1486. DWORD
  1487. PromtUserYesNo(
  1488. IN LPWSTR FileName,
  1489. OUT DWORD *UserChoice
  1490. )
  1491. {
  1492. BOOLEAN Continue = TRUE;
  1493. LPWSTR Result;
  1494. LPWSTR Yesnotext;
  1495. DWORD TextLen;
  1496. //
  1497. // File exists
  1498. //
  1499. *UserChoice = ChoiceNotDefined;
  1500. MySetThreadUILanguage(0);
  1501. TextLen = FormatMessage(FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_ALLOCATE_BUFFER,
  1502. NULL, CIPHER_YESNOANSWER, 0, (LPVOID)&Yesnotext, 0, NULL);
  1503. if (TextLen && Yesnotext) {
  1504. while (TRUE) {
  1505. WCHAR FirstChar;
  1506. DisplayMsg(CIPHER_FILE_EXISTS, FileName);
  1507. Result = fgetws((LPWSTR)Buf, sizeof(Buf)/sizeof (WCHAR), stdin);
  1508. if (!Result) {
  1509. //
  1510. // Error or end of file. Just return.
  1511. //
  1512. LocalFree(Yesnotext);
  1513. return GetLastError();
  1514. }
  1515. //
  1516. // Trim any trailing CR or LF char from the string
  1517. //
  1518. FirstChar = towupper(Buf[0]);
  1519. if (Yesnotext[0] == FirstChar) {
  1520. *UserChoice = UserChooseYes;
  1521. break;
  1522. } else if (Yesnotext[1] == FirstChar) {
  1523. *UserChoice = UserChooseNo;
  1524. break;
  1525. }
  1526. }
  1527. LocalFree(Yesnotext);
  1528. } else {
  1529. return GetLastError();
  1530. }
  1531. return ERROR_SUCCESS;
  1532. }
  1533. DWORD
  1534. GenerateCertFiles(
  1535. IN LPWSTR StartingDirectory
  1536. )
  1537. {
  1538. HCERTSTORE memStore;
  1539. DWORD dwLastError = ERROR_SUCCESS;
  1540. PCCERT_CONTEXT pCertContext;
  1541. LPWSTR ContainerName;
  1542. LPWSTR ProviderName;
  1543. LPWSTR CertFileName;
  1544. LPWSTR PfxPassword;
  1545. if (!GetPassword( &PfxPassword )){
  1546. return GetLastError();
  1547. }
  1548. memStore = CertOpenStore(
  1549. CERT_STORE_PROV_MEMORY,
  1550. 0,
  1551. 0,
  1552. CERT_STORE_MAXIMUM_ALLOWED_FLAG,
  1553. NULL
  1554. );
  1555. //
  1556. // 5 -- .PFX or .CER plus NULL
  1557. //
  1558. CertFileName = (LPWSTR)malloc((wcslen(StartingDirectory)+5) * sizeof(WCHAR));
  1559. if (memStore && CertFileName) {
  1560. //
  1561. // Let's check if the files exist or not
  1562. //
  1563. wcscpy(CertFileName, StartingDirectory);
  1564. wcscat(CertFileName, L".PFX");
  1565. if (GetFileAttributes(CertFileName) != -1) {
  1566. DWORD UserChoice;
  1567. if (((dwLastError = PromtUserYesNo(CertFileName, &UserChoice)) != ERROR_SUCCESS) ||
  1568. (UserChoice != UserChooseYes)) {
  1569. free(CertFileName);
  1570. CertCloseStore( memStore, 0 );
  1571. return dwLastError;
  1572. }
  1573. }
  1574. wcscpy(CertFileName, StartingDirectory);
  1575. wcscat(CertFileName, L".CER");
  1576. if (GetFileAttributes(CertFileName) != -1) {
  1577. DWORD UserChoice;
  1578. if (((dwLastError = PromtUserYesNo(CertFileName, &UserChoice)) != ERROR_SUCCESS) ||
  1579. (UserChoice != UserChooseYes)) {
  1580. free(CertFileName);
  1581. CertCloseStore( memStore, 0 );
  1582. return dwLastError;
  1583. }
  1584. }
  1585. //
  1586. // Generate the cert first
  1587. //
  1588. if (CreateSelfSignedRecoveryCertificate(&pCertContext, &ContainerName, &ProviderName)){
  1589. HANDLE hFile;
  1590. HCRYPTPROV hProv = 0;
  1591. DWORD BytesWritten = 0;
  1592. //
  1593. // We got the certificate. Let's generate the CER file first
  1594. //
  1595. hFile = CreateFileW(
  1596. CertFileName,
  1597. GENERIC_WRITE,
  1598. 0,
  1599. NULL,
  1600. CREATE_ALWAYS,
  1601. FILE_ATTRIBUTE_NORMAL,
  1602. NULL
  1603. );
  1604. if ( INVALID_HANDLE_VALUE != hFile) {
  1605. //
  1606. // Let's write out the CER file
  1607. //
  1608. if(!WriteFile(
  1609. hFile,
  1610. pCertContext->pbCertEncoded,
  1611. pCertContext->cbCertEncoded,
  1612. &BytesWritten,
  1613. NULL
  1614. )){
  1615. dwLastError = GetLastError();
  1616. } else {
  1617. DisplayMsg(CIPHER_CER_CREATED);
  1618. }
  1619. CloseHandle(hFile);
  1620. } else {
  1621. dwLastError = GetLastError();
  1622. }
  1623. if (CertAddCertificateContextToStore(memStore, pCertContext, CERT_STORE_ADD_ALWAYS, NULL)){
  1624. CRYPT_DATA_BLOB PFX;
  1625. memset( &PFX, 0, sizeof( CRYPT_DATA_BLOB ));
  1626. //
  1627. // Asking password
  1628. //
  1629. if (PFXExportCertStoreEx(
  1630. memStore,
  1631. &PFX,
  1632. PfxPassword,
  1633. NULL,
  1634. EXPORT_PRIVATE_KEYS | REPORT_NOT_ABLE_TO_EXPORT_PRIVATE_KEY | REPORT_NO_PRIVATE_KEY)){
  1635. PFX.pbData = (BYTE *) malloc(PFX.cbData);
  1636. if (PFX.pbData) {
  1637. if (PFXExportCertStoreEx(
  1638. memStore,
  1639. &PFX,
  1640. PfxPassword,
  1641. NULL,
  1642. EXPORT_PRIVATE_KEYS | REPORT_NOT_ABLE_TO_EXPORT_PRIVATE_KEY | REPORT_NO_PRIVATE_KEY)){
  1643. //
  1644. // Write out the PFX file
  1645. //
  1646. wcscpy(CertFileName, StartingDirectory);
  1647. wcscat(CertFileName, L".PFX");
  1648. hFile = CreateFileW(
  1649. CertFileName,
  1650. GENERIC_WRITE,
  1651. 0,
  1652. NULL,
  1653. CREATE_ALWAYS,
  1654. FILE_ATTRIBUTE_NORMAL,
  1655. NULL
  1656. );
  1657. if ( INVALID_HANDLE_VALUE != hFile) {
  1658. //
  1659. // Let's write out the CER file
  1660. //
  1661. if(!WriteFile(
  1662. hFile,
  1663. PFX.pbData,
  1664. PFX.cbData,
  1665. &BytesWritten,
  1666. NULL
  1667. )){
  1668. dwLastError = GetLastError();
  1669. } else {
  1670. DisplayMsg(CIPHER_PFX_CREATED);
  1671. }
  1672. CloseHandle(hFile);
  1673. } else {
  1674. dwLastError = GetLastError();
  1675. }
  1676. } else {
  1677. dwLastError = GetLastError();
  1678. }
  1679. free( PFX.pbData );
  1680. } else {
  1681. dwLastError = ERROR_NOT_ENOUGH_MEMORY;
  1682. }
  1683. } else {
  1684. dwLastError = GetLastError();
  1685. }
  1686. }
  1687. //
  1688. // Let's delete the key
  1689. //
  1690. CertFreeCertificateContext(pCertContext);
  1691. RpcStringFree( (unsigned short **)&ContainerName );
  1692. CryptAcquireContext(&hProv, ContainerName, ProviderName, PROV_RSA_FULL, CRYPT_DELETEKEYSET | CRYPT_SILENT );
  1693. } else {
  1694. dwLastError = GetLastError();
  1695. }
  1696. //
  1697. // Close Store and free the
  1698. //
  1699. free(CertFileName);
  1700. CertCloseStore( memStore, 0 );
  1701. } else {
  1702. dwLastError = ERROR_NOT_ENOUGH_MEMORY;
  1703. }
  1704. if (PfxPassword){
  1705. free(PfxPassword);
  1706. }
  1707. if (ERROR_SUCCESS != dwLastError) {
  1708. DisplayErr(NULL, dwLastError);
  1709. }
  1710. return dwLastError;
  1711. }
  1712. DWORD
  1713. SecureInitializeRandomFill(
  1714. IN OUT PSECURE_FILL_INFO pSecureFill,
  1715. IN ULONG FillSize,
  1716. IN PBYTE FillValue OPTIONAL
  1717. )
  1718. /*++
  1719. FillValue = NULL
  1720. Use Random fill and random mixing logic.
  1721. FillValue = valid pointer to fill byte
  1722. Fill region with specified value, with no random mixing.
  1723. --*/
  1724. {
  1725. DWORD dwLastError;
  1726. __try {
  1727. //
  1728. // allocate the critical section.
  1729. //
  1730. InitializeCriticalSection( &pSecureFill->Lock );
  1731. } __except (EXCEPTION_EXECUTE_HANDLER )
  1732. {
  1733. return ERROR_NOT_ENOUGH_MEMORY;
  1734. }
  1735. pSecureFill->LockValid = TRUE;
  1736. pSecureFill->cbRandomFill = FillSize;
  1737. pSecureFill->pbRandomFill = VirtualAlloc(
  1738. NULL,
  1739. FillSize,
  1740. MEM_COMMIT,
  1741. PAGE_READWRITE
  1742. );
  1743. if( pSecureFill->pbRandomFill != NULL )
  1744. {
  1745. BYTE RandomFill[256];
  1746. if( FillValue != NULL )
  1747. {
  1748. memset( pSecureFill->pbRandomFill, *FillValue, pSecureFill->cbRandomFill );
  1749. pSecureFill->fRandomFill = FALSE;
  1750. return ERROR_SUCCESS;
  1751. }
  1752. //
  1753. // initialize the region with initial random pad.
  1754. //
  1755. pSecureFill->fRandomFill = TRUE;
  1756. RANDOM_BYTES( RandomFill, sizeof(RandomFill) );
  1757. rc4_key( &pSecureFill->Key, sizeof(RandomFill), RandomFill );
  1758. rc4( &pSecureFill->Key, pSecureFill->cbRandomFill, pSecureFill->pbRandomFill );
  1759. //
  1760. // initialize the key.
  1761. //
  1762. RANDOM_BYTES( RandomFill, sizeof(RandomFill) );
  1763. rc4_key( &pSecureFill->Key, sizeof(RandomFill), RandomFill );
  1764. ZeroMemory( RandomFill, sizeof(RandomFill) );
  1765. return ERROR_SUCCESS;
  1766. }
  1767. dwLastError = GetLastError();
  1768. DeleteCriticalSection( &pSecureFill->Lock );
  1769. pSecureFill->LockValid = FALSE;
  1770. return dwLastError;
  1771. }
  1772. VOID
  1773. SecureMixRandomFill(
  1774. IN OUT PSECURE_FILL_INFO pSecureFill,
  1775. IN ULONG cbBytesThisFill
  1776. )
  1777. {
  1778. LONG Result;
  1779. LONG Compare;
  1780. if( !pSecureFill->fRandomFill )
  1781. {
  1782. return;
  1783. }
  1784. //
  1785. // update the fill once it has been used 8 times.
  1786. //
  1787. Compare = (LONG)(8 * pSecureFill->cbRandomFill);
  1788. Result = InterlockedExchangeAdd(
  1789. &pSecureFill->cbFilled,
  1790. cbBytesThisFill
  1791. );
  1792. if( (Result+Compare) > Compare )
  1793. {
  1794. Result = 0;
  1795. //
  1796. // if there was a race condition, only one thread will update the random fill.
  1797. //
  1798. if( TryEnterCriticalSection( &pSecureFill->Lock ) )
  1799. {
  1800. rc4( &pSecureFill->Key, pSecureFill->cbRandomFill, pSecureFill->pbRandomFill );
  1801. LeaveCriticalSection( &pSecureFill->Lock );
  1802. }
  1803. }
  1804. }
  1805. DWORD
  1806. SecureDeleteRandomFill(
  1807. IN PSECURE_FILL_INFO pSecureFill
  1808. )
  1809. {
  1810. if( pSecureFill->pbRandomFill != NULL )
  1811. {
  1812. VirtualFree( pSecureFill->pbRandomFill, pSecureFill->cbRandomFill, MEM_RELEASE );
  1813. }
  1814. if( pSecureFill->LockValid )
  1815. {
  1816. DeleteCriticalSection( &pSecureFill->Lock );
  1817. }
  1818. ZeroMemory( pSecureFill, sizeof(*pSecureFill) );
  1819. return ERROR_SUCCESS;
  1820. }
  1821. #define MaxFileNum 100000000
  1822. #define MaxDigit 9
  1823. HANDLE
  1824. CreateMyTempFile(
  1825. LPWSTR TempPath
  1826. )
  1827. {
  1828. static DWORD TempIndex = 0;
  1829. WCHAR TempFileName[MAX_PATH];
  1830. WCHAR TempIndexString[MaxDigit+2];
  1831. DWORD TempPathLength;
  1832. HANDLE TempHandle;
  1833. BOOLEAN ContinueSearch = TRUE;
  1834. DWORD RetCode;
  1835. if (wcslen(TempPath) >= (MAX_PATH - 3 - MaxDigit)) {
  1836. //
  1837. // Path too long. This should not happen as the TempPath should be the root of the volume
  1838. //
  1839. SetLastError(ERROR_LABEL_TOO_LONG);
  1840. return INVALID_HANDLE_VALUE;
  1841. }
  1842. wcscpy(TempFileName, TempPath);
  1843. TempPathLength = wcslen(TempPath);
  1844. while ( (TempIndex <= MaxFileNum) && ContinueSearch ) {
  1845. wsprintf(TempIndexString, L"%ld", TempIndex);
  1846. wcscat(TempFileName, TempIndexString);
  1847. wcscat(TempFileName, L".E");
  1848. TempHandle = CreateFileW(
  1849. TempFileName,
  1850. GENERIC_WRITE,
  1851. 0,
  1852. NULL,
  1853. CREATE_NEW,
  1854. FILE_ATTRIBUTE_NORMAL |
  1855. FILE_FLAG_DELETE_ON_CLOSE,
  1856. NULL
  1857. );
  1858. if (TempHandle != INVALID_HANDLE_VALUE) {
  1859. return TempHandle;
  1860. }
  1861. RetCode = GetLastError();
  1862. switch (RetCode) {
  1863. case ERROR_INVALID_PARAMETER :
  1864. case ERROR_WRITE_PROTECT :
  1865. case ERROR_FILE_NOT_FOUND :
  1866. case ERROR_BAD_PATHNAME :
  1867. case ERROR_INVALID_NAME :
  1868. case ERROR_PATH_NOT_FOUND :
  1869. case ERROR_NETWORK_ACCESS_DENIED :
  1870. case ERROR_DISK_CORRUPT :
  1871. case ERROR_FILE_CORRUPT :
  1872. case ERROR_DISK_FULL :
  1873. ContinueSearch = FALSE;
  1874. break;
  1875. default:
  1876. TempFileName[TempPathLength] = 0;
  1877. break;
  1878. }
  1879. TempIndex++;
  1880. }
  1881. //
  1882. // We got the filename.
  1883. //
  1884. return TempHandle;
  1885. }
  1886. DWORD
  1887. SecureProcessMft(
  1888. IN LPWSTR DriveLetter,
  1889. IN HANDLE hTempFile
  1890. )
  1891. {
  1892. NTFS_VOLUME_DATA_BUFFER VolumeData;
  1893. DWORD cbOutput;
  1894. __int64 TotalMftEntries;
  1895. PHANDLE pHandleArray = NULL;
  1896. DWORD FreeMftEntries;
  1897. DWORD i;
  1898. DWORD dwLastError = ERROR_SUCCESS;
  1899. //
  1900. // get the count of MFT records. This will fail if not NTFS, so bail in that case.
  1901. //
  1902. if(!DeviceIoControl(
  1903. hTempFile,
  1904. FSCTL_GET_NTFS_VOLUME_DATA, // dwIoControlCode
  1905. NULL,
  1906. 0,
  1907. &VolumeData,
  1908. sizeof(VolumeData),
  1909. &cbOutput,
  1910. NULL
  1911. ))
  1912. {
  1913. return GetLastError();
  1914. }
  1915. TotalMftEntries = VolumeData.MftValidDataLength.QuadPart / VolumeData.BytesPerFileRecordSegment;
  1916. if( TotalMftEntries > (0xFFFFFFFF/sizeof(HANDLE)) )
  1917. {
  1918. return ERROR_INVALID_PARAMETER;
  1919. }
  1920. FreeMftEntries = (DWORD)TotalMftEntries;
  1921. pHandleArray = HeapAlloc(GetProcessHeap(), 0 , FreeMftEntries*sizeof(HANDLE));
  1922. if( pHandleArray == NULL )
  1923. {
  1924. return ERROR_NOT_ENOUGH_MEMORY;
  1925. }
  1926. ZeroMemory( pHandleArray, FreeMftEntries * sizeof(HANDLE) );
  1927. for( i=0;i< FreeMftEntries ; i++ )
  1928. {
  1929. WCHAR szTempPath[ MAX_PATH + 1 ];
  1930. DWORD FillIndex;
  1931. pHandleArray[i] = CreateMyTempFile(DriveLetter);
  1932. if( pHandleArray[i] == INVALID_HANDLE_VALUE )
  1933. {
  1934. dwLastError = GetLastError();
  1935. break;
  1936. }
  1937. //
  1938. // for each file created, write at most BytesPerFileRecordSegment data to it.
  1939. //
  1940. for( FillIndex = 0 ; FillIndex < (VolumeData.BytesPerFileRecordSegment/8) ; FillIndex++ )
  1941. {
  1942. DWORD dwBytesWritten;
  1943. if(!WriteFile(
  1944. pHandleArray[i],
  1945. GlobalSecureFill.pbRandomFill,
  1946. 8,
  1947. &dwBytesWritten,
  1948. NULL
  1949. ))
  1950. {
  1951. break;
  1952. }
  1953. }
  1954. if (i && !(i % 200)) {
  1955. //
  1956. // Keep users informed for every 50 files we created.
  1957. //
  1958. printf(".");
  1959. }
  1960. }
  1961. if( dwLastError == ERROR_DISK_FULL )
  1962. {
  1963. dwLastError = ERROR_SUCCESS;
  1964. }
  1965. #ifdef TestOutPut
  1966. printf("\nmft error=%lu entries created=%lu total = %I64u\n", dwLastError, i, TotalMftEntries);
  1967. #endif
  1968. for (i=0;i < FreeMftEntries;i++) {
  1969. if( pHandleArray[i] != INVALID_HANDLE_VALUE &&
  1970. pHandleArray[i] != NULL
  1971. )
  1972. {
  1973. CloseHandle( pHandleArray[i] );
  1974. }
  1975. }
  1976. if( pHandleArray != NULL )
  1977. {
  1978. HeapFree(GetProcessHeap(), 0, pHandleArray );
  1979. }
  1980. return dwLastError;
  1981. }
  1982. DWORD
  1983. SecureProcessFreeClusters(
  1984. IN LPWSTR DrivePath,
  1985. IN HANDLE hTempFile
  1986. )
  1987. {
  1988. HANDLE hVolume = INVALID_HANDLE_VALUE;
  1989. WCHAR VolumeName[100]; // 50 should be enough. 100 is more than enough.
  1990. NTFS_VOLUME_DATA_BUFFER VolumeData;
  1991. STARTING_LCN_INPUT_BUFFER LcnInput;
  1992. VOLUME_BITMAP_BUFFER *pBitmap = NULL;
  1993. MOVE_FILE_DATA MoveFile;
  1994. __int64 cbBitmap;
  1995. DWORD cbOutput;
  1996. unsigned __int64 ClusterLocation;
  1997. unsigned __int64 Lcn;
  1998. BYTE Mask;
  1999. unsigned __int64 Free = 0;
  2000. DWORD Fail = 0;
  2001. #ifdef TestOutPut
  2002. DWORD dwStart, dwStop;
  2003. #endif
  2004. __int64 ClusterIndex;
  2005. DWORD dwLastError = ERROR_SUCCESS;
  2006. //
  2007. // first, find out if there are free or reserved clusters.
  2008. // this will fail if the volume is not NTFS.
  2009. //
  2010. if (!GetVolumeNameForVolumeMountPoint(
  2011. DrivePath,
  2012. VolumeName,
  2013. sizeof(VolumeName)/sizeof(WCHAR) )){
  2014. return GetLastError();
  2015. }
  2016. VolumeName[wcslen(VolumeName)-1] = 0; // Truncate the trailing slash
  2017. if(!DeviceIoControl(
  2018. hTempFile,
  2019. FSCTL_GET_NTFS_VOLUME_DATA, // dwIoControlCode
  2020. NULL,
  2021. 0,
  2022. &VolumeData,
  2023. sizeof(VolumeData),
  2024. &cbOutput,
  2025. NULL
  2026. ))
  2027. {
  2028. dwLastError = GetLastError();
  2029. goto Cleanup;
  2030. }
  2031. if( VolumeData.FreeClusters.QuadPart == 0 &&
  2032. VolumeData.TotalReserved.QuadPart == 0 )
  2033. {
  2034. return ERROR_SUCCESS;
  2035. }
  2036. hVolume = CreateFileW( VolumeName,
  2037. FILE_READ_ATTRIBUTES | GENERIC_WRITE,
  2038. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  2039. NULL,
  2040. OPEN_EXISTING,
  2041. FILE_FLAG_NO_BUFFERING, // no buffering
  2042. NULL
  2043. );
  2044. if( hVolume == INVALID_HANDLE_VALUE )
  2045. {
  2046. dwLastError = GetLastError();
  2047. goto Cleanup;
  2048. }
  2049. //
  2050. // allocate space for the volume bitmap.
  2051. //
  2052. cbBitmap = sizeof(VOLUME_BITMAP_BUFFER) + (VolumeData.TotalClusters.QuadPart / 8);
  2053. if( cbBitmap > 0xFFFFFFFF )
  2054. {
  2055. dwLastError = ERROR_INVALID_PARAMETER;
  2056. goto Cleanup;
  2057. }
  2058. pBitmap = HeapAlloc(GetProcessHeap(), 0, (DWORD)cbBitmap);
  2059. if( pBitmap == NULL )
  2060. {
  2061. dwLastError = ERROR_NOT_ENOUGH_MEMORY;
  2062. goto Cleanup;
  2063. }
  2064. //
  2065. // grab the volume bitmap.
  2066. //
  2067. LcnInput.StartingLcn.QuadPart = 0;
  2068. ZeroMemory( &MoveFile, sizeof(MoveFile) );
  2069. MoveFile.FileHandle = hTempFile;
  2070. MoveFile.StartingVcn.QuadPart = 0;
  2071. MoveFile.ClusterCount = 1;
  2072. #ifdef TestOutPut
  2073. dwStart = GetTickCount();
  2074. #endif
  2075. if(!DeviceIoControl(
  2076. hVolume,
  2077. FSCTL_GET_VOLUME_BITMAP,
  2078. &LcnInput,
  2079. sizeof(LcnInput),
  2080. pBitmap,
  2081. (DWORD)cbBitmap,
  2082. &cbOutput,
  2083. NULL
  2084. ))
  2085. {
  2086. dwLastError = GetLastError();
  2087. goto Cleanup;
  2088. }
  2089. //
  2090. // insure file is only bytes per cluster in length.
  2091. // this will shrink the file if necessary. We waited until after we fetched the
  2092. // volume bitmap to insure we only process the free clusters that existed prior to
  2093. // the shrink operation.
  2094. //
  2095. if(SetFilePointer(
  2096. hTempFile,
  2097. (LONG)VolumeData.BytesPerCluster,
  2098. NULL,
  2099. FILE_BEGIN
  2100. ) == INVALID_SET_FILE_POINTER)
  2101. {
  2102. dwLastError = GetLastError();
  2103. goto Cleanup;
  2104. }
  2105. if(!SetEndOfFile( hTempFile ))
  2106. {
  2107. dwLastError = GetLastError();
  2108. goto Cleanup;
  2109. }
  2110. Mask = 1;
  2111. Lcn = pBitmap->StartingLcn.QuadPart;
  2112. for(ClusterIndex = 0 ; ClusterIndex < VolumeData.TotalClusters.QuadPart ; ClusterIndex++)
  2113. {
  2114. if( (pBitmap->Buffer[ClusterIndex/8] & Mask) == 0 )
  2115. {
  2116. DWORD dwMoveError = ERROR_SUCCESS;
  2117. //
  2118. // move a single cluster from the temp file to the free cluster.
  2119. //
  2120. MoveFile.StartingLcn.QuadPart = Lcn;
  2121. if(!DeviceIoControl(
  2122. hVolume,
  2123. FSCTL_MOVE_FILE, // dwIoControlCode
  2124. &MoveFile,
  2125. sizeof(MoveFile),
  2126. NULL,
  2127. 0,
  2128. &cbOutput,
  2129. NULL
  2130. ))
  2131. {
  2132. dwMoveError = GetLastError();
  2133. }
  2134. //
  2135. // if it succeeded, or the cluster was in use, mark it used in the bitmap.
  2136. //
  2137. if( dwMoveError == ERROR_SUCCESS || dwMoveError == ERROR_ACCESS_DENIED )
  2138. {
  2139. pBitmap->Buffer[ClusterIndex/8] |= Mask;
  2140. } else {
  2141. Fail++;
  2142. }
  2143. Free++;
  2144. if ( !(Free % 200) ) {
  2145. //
  2146. // Keep users informed for every 50 files we created.
  2147. //
  2148. printf(".");
  2149. }
  2150. }
  2151. Lcn ++;
  2152. Mask <<= 1;
  2153. if(Mask == 0)
  2154. {
  2155. Mask = 1;
  2156. }
  2157. }
  2158. #ifdef TestOutPut
  2159. dwStop = GetTickCount();
  2160. printf("\nFreeCount = %I64x fail = %lu elapsed = %lu\n", Free, Fail, dwStop-dwStart);
  2161. #endif
  2162. Cleanup:
  2163. if( pBitmap != NULL )
  2164. {
  2165. HeapFree( GetProcessHeap(), 0, pBitmap );
  2166. }
  2167. if( hVolume != INVALID_HANDLE_VALUE )
  2168. {
  2169. CloseHandle( hVolume );
  2170. }
  2171. return dwLastError;
  2172. }
  2173. DWORD
  2174. SecureDeleteFreeSpace(
  2175. IN LPWSTR Directory
  2176. )
  2177. /*++
  2178. This routine fills the disk specified by the input Directory parameter with random fill.
  2179. Input is of the form "C:\", for instance.
  2180. Notes on approaches not employed here:
  2181. Alternate method would use defrag API to move random fill around the
  2182. free cluster map. Requires admin priviliges to the volume. Slower than filling volume with
  2183. a new file.
  2184. Variant on alternate method: fill volume 80% with file, grab free cluster map,
  2185. delete file associated with 80% fill, then use defrag API to fill the free cluster map
  2186. mentioned previously.
  2187. Does not fill cluster slack space for each file on the system. Could do this by
  2188. enumerating all files, and then extending+fill to slack boundry+restore original
  2189. EOF.
  2190. Does not fill $LOG. Queried file system folks on whether this is possible by creating
  2191. many small temporary files containing random fill.
  2192. --*/
  2193. {
  2194. UINT DriveType;
  2195. DWORD DirNameLength;
  2196. DWORD BufferLength;
  2197. LPWSTR PathName = NULL;
  2198. LPWSTR TempDirName = NULL;
  2199. BOOL b;
  2200. BOOL DirCreated = FALSE;
  2201. DWORD Attributes;
  2202. DWORD SectorsPerCluster;
  2203. DWORD BytesPerSector;
  2204. WCHAR TempFileName[ MAX_PATH + 1 ];
  2205. HANDLE hTempFile = INVALID_HANDLE_VALUE;
  2206. DWORD dwWriteBytes;
  2207. unsigned __int64 TotalBytesWritten;
  2208. unsigned __int64 NotifyBytesWritten;
  2209. unsigned __int64 NotifyInterval;
  2210. ULARGE_INTEGER TotalFreeBytes;
  2211. PBYTE pbFillBuffer = NULL;
  2212. ULONG cbFillBuffer;
  2213. NTFS_VOLUME_DATA_BUFFER VolumeData;
  2214. __int64 MftEntries = 0;
  2215. BOOLEAN ClustersRemaining = FALSE;
  2216. DWORD cbOutput;
  2217. DWORD dwLastError = ERROR_SUCCESS;
  2218. DWORD dwTestError;
  2219. #ifdef TestOutPut
  2220. ULARGE_INTEGER StartTime;
  2221. ULARGE_INTEGER StopTime;
  2222. #endif
  2223. //
  2224. // collect information about the disk in question.
  2225. //
  2226. DirNameLength = wcslen(Directory);
  2227. BufferLength = (DirNameLength + 1) <= MAX_PATH ?
  2228. (MAX_PATH + 1) * sizeof(WCHAR) : (DirNameLength + 1) * sizeof (WCHAR);
  2229. PathName = (LPWSTR) malloc(BufferLength);
  2230. if ( !PathName ) {
  2231. return ERROR_NOT_ENOUGH_MEMORY;
  2232. }
  2233. TempDirName = (LPWSTR) malloc(BufferLength + wcslen(WIPING_DIR) * sizeof (WCHAR));
  2234. if ( !TempDirName ) {
  2235. free(PathName);
  2236. return ERROR_NOT_ENOUGH_MEMORY;
  2237. }
  2238. b = GetVolumePathNameW(
  2239. Directory,
  2240. PathName,
  2241. BufferLength
  2242. );
  2243. if (!b) {
  2244. dwLastError = GetLastError();
  2245. goto Cleanup;
  2246. }
  2247. DriveType = GetDriveTypeW( PathName );
  2248. if( DriveType == DRIVE_REMOTE ||
  2249. DriveType == DRIVE_CDROM )
  2250. {
  2251. dwLastError = ERROR_NOT_SUPPORTED;
  2252. goto Cleanup;
  2253. }
  2254. if(!GetDiskFreeSpaceW(
  2255. PathName,
  2256. &SectorsPerCluster,
  2257. &BytesPerSector,
  2258. NULL,
  2259. NULL
  2260. ))
  2261. {
  2262. dwLastError = GetLastError();
  2263. goto Cleanup;
  2264. }
  2265. //
  2266. // allocate memory chunk to accomodate cluster size data
  2267. //
  2268. cbFillBuffer = GlobalSecureFill.cbRandomFill;
  2269. pbFillBuffer = GlobalSecureFill.pbRandomFill;
  2270. //
  2271. // determine how many bytes free space on the disk to enable notification of
  2272. // overall progress.
  2273. //
  2274. if(!GetDiskFreeSpaceExW(
  2275. PathName,
  2276. NULL,
  2277. NULL,
  2278. &TotalFreeBytes
  2279. ))
  2280. {
  2281. dwLastError = GetLastError();
  2282. goto Cleanup;
  2283. }
  2284. //
  2285. // Let's Create the temp directory
  2286. //
  2287. wcscpy(TempDirName, PathName);
  2288. wcscat(TempDirName, WIPING_DIR);
  2289. if (!CreateDirectory(TempDirName, NULL)){
  2290. //
  2291. // Could not create our temp directory. Quit.
  2292. //
  2293. if ((dwLastError = GetLastError()) != ERROR_ALREADY_EXISTS){
  2294. goto Cleanup;
  2295. }
  2296. }
  2297. DirCreated = TRUE;
  2298. //
  2299. // generate temporary file.
  2300. //
  2301. if( GetTempFileNameW(
  2302. TempDirName,
  2303. L"fil",
  2304. 0,
  2305. TempFileName
  2306. ) == 0 )
  2307. {
  2308. dwLastError = GetLastError();
  2309. goto Cleanup;
  2310. }
  2311. Attributes = GetFileAttributes(TempFileName);
  2312. if (0xFFFFFFFF == Attributes) {
  2313. dwLastError = GetLastError();
  2314. goto Cleanup;
  2315. }
  2316. if (Attributes & FILE_ATTRIBUTE_ENCRYPTED) {
  2317. if (!DecryptFile(TempFileName, 0)){
  2318. dwLastError = GetLastError();
  2319. goto Cleanup;
  2320. }
  2321. }
  2322. hTempFile = CreateFileW(
  2323. TempFileName,
  2324. GENERIC_WRITE,
  2325. 0, // exclusive access
  2326. NULL,
  2327. OPEN_EXISTING,
  2328. FILE_ATTRIBUTE_NORMAL |
  2329. FILE_FLAG_NO_BUFFERING | // no buffering
  2330. FILE_FLAG_DELETE_ON_CLOSE, // delete file when it closes.
  2331. NULL
  2332. );
  2333. if( hTempFile == INVALID_HANDLE_VALUE )
  2334. {
  2335. dwLastError = GetLastError();
  2336. goto Cleanup;
  2337. }
  2338. if (Attributes & FILE_ATTRIBUTE_COMPRESSED) {
  2339. USHORT State = COMPRESSION_FORMAT_NONE;
  2340. //
  2341. // Uncompress the directory first
  2342. //
  2343. b = DeviceIoControl(hTempFile,
  2344. FSCTL_SET_COMPRESSION,
  2345. &State,
  2346. sizeof(USHORT),
  2347. NULL,
  2348. 0,
  2349. &BufferLength,
  2350. FALSE
  2351. );
  2352. if ( !b ){
  2353. dwLastError = GetLastError();
  2354. goto Cleanup;
  2355. }
  2356. }
  2357. TotalBytesWritten = 0;
  2358. //
  2359. // tell the user something happened for each 1% processed.
  2360. //
  2361. NotifyInterval = (TotalFreeBytes.QuadPart / 100);
  2362. NotifyBytesWritten = NotifyInterval;
  2363. dwWriteBytes = cbFillBuffer;
  2364. #ifdef TestOutPut
  2365. GetSystemTimeAsFileTime( (FILETIME*)&StartTime );
  2366. #endif
  2367. while( TRUE )
  2368. {
  2369. DWORD BytesWritten;
  2370. if( TotalBytesWritten >= NotifyBytesWritten )
  2371. {
  2372. printf(".");
  2373. NotifyBytesWritten += NotifyInterval;
  2374. }
  2375. //
  2376. // mix random fill.
  2377. //
  2378. SecureMixRandomFill( &GlobalSecureFill, dwWriteBytes );
  2379. if(!WriteFile(
  2380. hTempFile,
  2381. pbFillBuffer,
  2382. dwWriteBytes,
  2383. &BytesWritten,
  2384. NULL
  2385. ))
  2386. {
  2387. if( GetLastError() == ERROR_DISK_FULL )
  2388. {
  2389. dwLastError = ERROR_SUCCESS;
  2390. //
  2391. // if the attempted write failed, enter a retry mode with downgraded
  2392. // buffersize to catch the last bits of slop.
  2393. //
  2394. if( dwWriteBytes > BytesPerSector )
  2395. {
  2396. dwWriteBytes = BytesPerSector;
  2397. continue;
  2398. }
  2399. } else {
  2400. dwLastError = GetLastError();
  2401. }
  2402. break;
  2403. }
  2404. TotalBytesWritten += BytesWritten;
  2405. }
  2406. #ifdef TestOutPut
  2407. GetSystemTimeAsFileTime( (FILETIME*)&StopTime );
  2408. {
  2409. ULARGE_INTEGER ElapsedTime;
  2410. SYSTEMTIME st;
  2411. ElapsedTime.QuadPart = (StopTime.QuadPart - StartTime.QuadPart);
  2412. FileTimeToSystemTime( (FILETIME*)&ElapsedTime, &st );
  2413. printf("\nTotalWritten = %I64u time = %02u:%02u:%02u.%02u\n",
  2414. TotalBytesWritten,
  2415. st.wHour,
  2416. st.wMinute,
  2417. st.wSecond,
  2418. st.wMilliseconds
  2419. );
  2420. }
  2421. #endif
  2422. //
  2423. // at this point, the disk should be full.
  2424. // If the disk is NTFS:
  2425. // 1. Fill the MFT.
  2426. // 2. Fill any free/reserved clusters.
  2427. //
  2428. dwTestError = SecureProcessMft( TempDirName, hTempFile );
  2429. // dwTestError = SecureProcessMft( PathName, hTempFile );
  2430. #ifdef TestOutPut
  2431. if (ERROR_SUCCESS != dwTestError) {
  2432. printf("\nWriting NTFS MFT & LOG. Error:");
  2433. DisplayErr(NULL, dwTestError);
  2434. }
  2435. #endif
  2436. dwTestError = SecureProcessFreeClusters( PathName, hTempFile );
  2437. #ifdef TestOutPut
  2438. if (ERROR_SUCCESS != dwTestError) {
  2439. printf("\nWriting NTFS reserved clusters. Error:");
  2440. DisplayErr(NULL, dwTestError);
  2441. }
  2442. #endif
  2443. Cleanup:
  2444. if (hTempFile != INVALID_HANDLE_VALUE) {
  2445. //
  2446. // flush the buffers. Likely has no effect if we used FILE_FLAG_NO_BUFFERING
  2447. //
  2448. //Sleep(INFINITE);
  2449. FlushFileBuffers( hTempFile );
  2450. CloseHandle( hTempFile );
  2451. }
  2452. if (DirCreated && TempDirName) {
  2453. RemoveDirectory(TempDirName);
  2454. }
  2455. if( PathName != NULL ){
  2456. free(PathName);
  2457. }
  2458. if ( TempDirName != NULL ) {
  2459. free(TempDirName);
  2460. }
  2461. return dwLastError;
  2462. }
  2463. BOOL CheckMinVersion ()
  2464. {
  2465. OSVERSIONINFOEX osvi;
  2466. DWORDLONG dwlConditionMask = 0;
  2467. BOOL GoodVersion;
  2468. // Initialize the OSVERSIONINFOEX structure.
  2469. ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX));
  2470. osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
  2471. osvi.dwMajorVersion = 5;
  2472. osvi.dwMinorVersion = 0;
  2473. osvi.wServicePackMajor = 3;
  2474. // Initialize the condition mask.
  2475. VER_SET_CONDITION( dwlConditionMask, VER_MAJORVERSION,
  2476. VER_GREATER_EQUAL );
  2477. VER_SET_CONDITION( dwlConditionMask, VER_MINORVERSION,
  2478. VER_GREATER_EQUAL );
  2479. VER_SET_CONDITION( dwlConditionMask, VER_SERVICEPACKMAJOR,
  2480. VER_GREATER_EQUAL );
  2481. // Perform the test.
  2482. GoodVersion = VerifyVersionInfo(
  2483. &osvi,
  2484. VER_MAJORVERSION | VER_MINORVERSION | VER_SERVICEPACKMAJOR,
  2485. dwlConditionMask
  2486. );
  2487. return GoodVersion;
  2488. }
  2489. PCRYPT_KEY_PROV_INFO
  2490. GetKeyProvInfo(
  2491. PCCERT_CONTEXT pCertContext
  2492. )
  2493. {
  2494. DWORD cbData = 0;
  2495. BOOL b;
  2496. PCRYPT_KEY_PROV_INFO pCryptKeyProvInfo = NULL;
  2497. b = CertGetCertificateContextProperty(
  2498. pCertContext,
  2499. CERT_KEY_PROV_INFO_PROP_ID,
  2500. NULL,
  2501. &cbData
  2502. );
  2503. if (b) {
  2504. pCryptKeyProvInfo = (PCRYPT_KEY_PROV_INFO)malloc( cbData );
  2505. if (pCryptKeyProvInfo != NULL) {
  2506. b = CertGetCertificateContextProperty(
  2507. pCertContext,
  2508. CERT_KEY_PROV_INFO_PROP_ID,
  2509. pCryptKeyProvInfo,
  2510. &cbData
  2511. );
  2512. if (!b) {
  2513. free( pCryptKeyProvInfo );
  2514. pCryptKeyProvInfo = NULL;
  2515. }
  2516. } else {
  2517. SetLastError( ERROR_NOT_ENOUGH_MEMORY );
  2518. }
  2519. }
  2520. return ( pCryptKeyProvInfo );
  2521. }
  2522. DWORD
  2523. GetUserInput(
  2524. IN DWORD MsgNum,
  2525. IN OUT LPWSTR StrBuf,
  2526. IN DWORD SizeInChars
  2527. )
  2528. {
  2529. int ii;
  2530. DisplayMsg(MsgNum);
  2531. if (!fgetws((LPWSTR)StrBuf, SizeInChars, stdin)) {
  2532. //
  2533. // Error or end of file. Just return.
  2534. //
  2535. return GetLastError();
  2536. }
  2537. //
  2538. // Strip off CR and LN
  2539. //
  2540. ii = wcslen(StrBuf) - 1;
  2541. while (ii >=0 ) {
  2542. if ((StrBuf[ii] == 0x0a) || (StrBuf[ii] == 0x0d)) {
  2543. StrBuf[ii] = 0;
  2544. ii--;
  2545. } else {
  2546. break;
  2547. }
  2548. }
  2549. return ERROR_SUCCESS;
  2550. }
  2551. DWORD
  2552. BackEfsCert(
  2553. IN LPWSTR EfsFileName,
  2554. IN LPWSTR PfxFileName
  2555. )
  2556. /*++
  2557. Routine Description:
  2558. Export EFS certificate and keys to a PFX file
  2559. Arguments:
  2560. EfsFileName - EFS file
  2561. PfxFileName - PfxFileName
  2562. Return Values:
  2563. Win32 Error code
  2564. --*/
  2565. {
  2566. BOOLEAN EFSFileExist = FALSE;
  2567. HCERTSTORE memStore = 0;
  2568. HCERTSTORE myStore = 0;
  2569. PCCERT_CONTEXT pCertContext = NULL;
  2570. LPWSTR ContainerName = NULL;
  2571. LPWSTR ProviderName = NULL;
  2572. LPWSTR PfxPassword = NULL;
  2573. PCRYPT_KEY_PROV_INFO pCryptKeyProvInfo = NULL;
  2574. HCRYPTKEY hLocalKey = 0;
  2575. HCRYPTPROV hLocalProv = 0;
  2576. DWORD Attributes;
  2577. DWORD RetCode = ERROR_SUCCESS;
  2578. BOOLEAN ValidCertFound = FALSE;
  2579. HKEY hRegKey = NULL;
  2580. CRYPT_HASH_BLOB HashBlob;
  2581. HANDLE hFile;
  2582. if ((NULL == EfsFileName) || (NULL == PfxFileName)) {
  2583. //
  2584. // EfsFileName & PfxFileName have MAX_PATH available
  2585. //
  2586. return ERROR_INVALID_PARAMETER;
  2587. }
  2588. if (EfsFileName[0] != 0) {
  2589. Attributes = GetFileAttributes( EfsFileName );
  2590. if (0xFFFFFFFF == Attributes) {
  2591. //
  2592. // Failed
  2593. //
  2594. return GetLastError();
  2595. }
  2596. if (0 == (Attributes & FILE_ATTRIBUTE_ENCRYPTED)) {
  2597. return ERROR_FILE_NOT_ENCRYPTED;
  2598. }
  2599. EFSFileExist = TRUE;
  2600. }
  2601. if (EFSFileExist) {
  2602. //
  2603. // Export the certs existing on the file
  2604. //
  2605. PENCRYPTION_CERTIFICATE_HASH_LIST pUsers = NULL;
  2606. RetCode = QueryUsersOnEncryptedFile(
  2607. EfsFileName,
  2608. &pUsers
  2609. );
  2610. if ( ERROR_SUCCESS == RetCode) {
  2611. //
  2612. // Create a memory cert store
  2613. //
  2614. DWORD nCerts = 0;
  2615. memStore = CertOpenStore(
  2616. CERT_STORE_PROV_MEMORY,
  2617. 0,
  2618. 0,
  2619. CERT_STORE_MAXIMUM_ALLOWED_FLAG,
  2620. NULL
  2621. );
  2622. if (memStore) {
  2623. myStore = CertOpenStore(
  2624. CERT_STORE_PROV_SYSTEM_REGISTRY_W,
  2625. 0, // dwEncodingType
  2626. 0, // hCryptProv,
  2627. CERT_SYSTEM_STORE_CURRENT_USER,
  2628. L"My"
  2629. );
  2630. if (myStore) {
  2631. //
  2632. // Let's find the cert
  2633. //
  2634. nCerts = pUsers->nCert_Hash;
  2635. while(nCerts){
  2636. //
  2637. // We will export all the certs in MY store. Usually only one.
  2638. //
  2639. pCertContext = CertFindCertificateInStore( myStore,
  2640. CRYPT_ASN_ENCODING,
  2641. 0,
  2642. CERT_FIND_HASH,
  2643. (CRYPT_HASH_BLOB*) pUsers->pUsers[nCerts-1]->pHash,
  2644. NULL
  2645. );
  2646. if (pCertContext != NULL) {
  2647. //
  2648. // Let's try to see if keys are available
  2649. //
  2650. pCryptKeyProvInfo = GetKeyProvInfo( pCertContext );
  2651. if (pCryptKeyProvInfo) {
  2652. if (CryptAcquireContext( &hLocalProv, pCryptKeyProvInfo->pwszContainerName, pCryptKeyProvInfo->pwszProvName, PROV_RSA_FULL, CRYPT_SILENT)) {
  2653. if (CryptGetUserKey(hLocalProv, AT_KEYEXCHANGE, &hLocalKey)) {
  2654. //
  2655. // We found the key. Let's add the cert to Memory store
  2656. //
  2657. if (CertAddCertificateContextToStore(memStore, pCertContext, CERT_STORE_ADD_ALWAYS, NULL)){
  2658. //
  2659. // Cert added.
  2660. //
  2661. ValidCertFound = TRUE;
  2662. }
  2663. CryptDestroyKey( hLocalKey );
  2664. }
  2665. CryptReleaseContext( hLocalProv, 0 );
  2666. }
  2667. free (pCryptKeyProvInfo);
  2668. }
  2669. CertFreeCertificateContext( pCertContext );
  2670. }
  2671. nCerts--;
  2672. }
  2673. if (!ValidCertFound) {
  2674. //
  2675. // We didn't get good certs. Warn the user.
  2676. //
  2677. DisplayMsg(CIPHER_NO_LOCAL_CERT);
  2678. }
  2679. CertCloseStore(myStore, 0);
  2680. myStore = 0;
  2681. } else {
  2682. CertCloseStore( memStore, 0 );
  2683. memStore = 0;
  2684. RetCode = GetLastError();
  2685. }
  2686. }
  2687. if (pUsers) {
  2688. FreeEncryptionCertificateHashList(pUsers);
  2689. pUsers = NULL;
  2690. }
  2691. } else {
  2692. return RetCode;
  2693. }
  2694. } else {
  2695. //
  2696. // EFS file not provided, try to export the current EFS cert
  2697. //
  2698. RetCode = RegOpenKeyEx(
  2699. KEYPATHROOT,
  2700. KEYPATH,
  2701. 0,
  2702. GENERIC_READ,
  2703. &hRegKey
  2704. );
  2705. if (RetCode == ERROR_SUCCESS) {
  2706. DWORD Type;
  2707. RetCode = RegQueryValueEx(
  2708. hRegKey,
  2709. CERT_HASH,
  2710. NULL,
  2711. &Type,
  2712. NULL,
  2713. &(HashBlob.cbData)
  2714. );
  2715. if (RetCode == ERROR_SUCCESS) {
  2716. //
  2717. // Query out the thumbprint, find the cert, and return the key information.
  2718. //
  2719. if (HashBlob.pbData = (PBYTE)malloc( HashBlob.cbData )) {
  2720. RetCode = RegQueryValueEx(
  2721. hRegKey,
  2722. CERT_HASH,
  2723. NULL,
  2724. &Type,
  2725. HashBlob.pbData,
  2726. &(HashBlob.cbData)
  2727. );
  2728. if (RetCode == ERROR_SUCCESS) {
  2729. //
  2730. // We get the cert hash. Get the cert from MY to MemStore
  2731. //
  2732. memStore = CertOpenStore(
  2733. CERT_STORE_PROV_MEMORY,
  2734. 0,
  2735. 0,
  2736. CERT_STORE_MAXIMUM_ALLOWED_FLAG,
  2737. NULL
  2738. );
  2739. if (memStore) {
  2740. myStore = CertOpenStore(
  2741. CERT_STORE_PROV_SYSTEM_REGISTRY_W,
  2742. 0, // dwEncodingType
  2743. 0, // hCryptProv,
  2744. CERT_SYSTEM_STORE_CURRENT_USER,
  2745. L"My"
  2746. );
  2747. if (myStore) {
  2748. pCertContext = CertFindCertificateInStore( myStore,
  2749. CRYPT_ASN_ENCODING,
  2750. 0,
  2751. CERT_FIND_HASH,
  2752. (CRYPT_HASH_BLOB*) &HashBlob,
  2753. NULL
  2754. );
  2755. if (pCertContext != NULL) {
  2756. //
  2757. // Let's try to see if keys are available
  2758. //
  2759. pCryptKeyProvInfo = GetKeyProvInfo( pCertContext );
  2760. if (pCryptKeyProvInfo) {
  2761. if (CryptAcquireContext( &hLocalProv, pCryptKeyProvInfo->pwszContainerName, pCryptKeyProvInfo->pwszProvName, PROV_RSA_FULL, CRYPT_SILENT)) {
  2762. if (CryptGetUserKey(hLocalProv, AT_KEYEXCHANGE, &hLocalKey)) {
  2763. //
  2764. // We found the key. Let's add the cert to Memory store
  2765. //
  2766. if (CertAddCertificateContextToStore(memStore, pCertContext, CERT_STORE_ADD_ALWAYS, NULL)){
  2767. //
  2768. // Cert added.
  2769. //
  2770. ValidCertFound = TRUE;
  2771. }
  2772. CryptDestroyKey( hLocalKey );
  2773. }
  2774. CryptReleaseContext( hLocalProv, 0 );
  2775. }
  2776. free (pCryptKeyProvInfo);
  2777. }
  2778. CertFreeCertificateContext( pCertContext );
  2779. }
  2780. CertCloseStore(myStore, 0);
  2781. myStore = 0;
  2782. }
  2783. }
  2784. }
  2785. free(HashBlob.pbData);
  2786. }
  2787. }
  2788. RegCloseKey( hRegKey );
  2789. }
  2790. }
  2791. if (ValidCertFound && memStore && (RetCode == ERROR_SUCCESS)) {
  2792. //
  2793. // We got the cert ready to export. Warn the user with message box.
  2794. //
  2795. LPWSTR WarnText = NULL;
  2796. LPWSTR WarnTitle= NULL;
  2797. CRYPT_DATA_BLOB PFX;
  2798. DWORD TextLen = 0;
  2799. int ButtonID = 0;
  2800. RetCode = GetResourceString(&WarnText, CIPHER_BACKUP_OK);
  2801. if (ERROR_SUCCESS == RetCode) {
  2802. RetCode = GetResourceString(&WarnTitle, CIPHER_BACKUP_WRN);
  2803. }
  2804. if (ERROR_SUCCESS == RetCode) {
  2805. ButtonID = MessageBox(NULL, WarnText, WarnTitle, MB_OKCANCEL | MB_TOPMOST);
  2806. LocalFree( WarnText );
  2807. LocalFree( WarnTitle );
  2808. } else {
  2809. if (WarnText) {
  2810. LocalFree( WarnText );
  2811. }
  2812. if (WarnTitle) {
  2813. LocalFree( WarnTitle );
  2814. }
  2815. }
  2816. if (ButtonID == IDOK) {
  2817. if (PfxFileName[0] == 0 ) {
  2818. //
  2819. // Let's try to get the PFX file name
  2820. //
  2821. RetCode = GetUserInput(
  2822. CIPHER_PFX_FILENAME_NEEDED,
  2823. PfxFileName,
  2824. MAX_PATH
  2825. );
  2826. if (ERROR_SUCCESS != RetCode) {
  2827. PfxFileName[0] = 0;
  2828. }
  2829. }
  2830. //
  2831. // Adding the .PFX if the file extension not provided
  2832. //
  2833. TextLen = wcslen(PfxFileName);
  2834. if ((PfxFileName[0] != 0) && TextLen > 4) {
  2835. if (lstricmp(&PfxFileName[ TextLen - 4], L".PFX")){
  2836. if (TextLen <= MAX_PATH - 5) {
  2837. wcscpy(&PfxFileName[TextLen], L".PFX");
  2838. } else {
  2839. RetCode = ERROR_BUFFER_OVERFLOW;
  2840. PfxFileName[0] = 0;
  2841. }
  2842. }
  2843. } else if (PfxFileName[0] != 0) {
  2844. wcscpy(&PfxFileName[TextLen], L".PFX");
  2845. }
  2846. if (PfxFileName[0]) {
  2847. if (GetPassword( &PfxPassword )) {
  2848. memset( &PFX, 0, sizeof( CRYPT_DATA_BLOB ));
  2849. //
  2850. // Asking password
  2851. //
  2852. if (PFXExportCertStoreEx(
  2853. memStore,
  2854. &PFX,
  2855. PfxPassword,
  2856. NULL,
  2857. EXPORT_PRIVATE_KEYS | REPORT_NOT_ABLE_TO_EXPORT_PRIVATE_KEY | REPORT_NO_PRIVATE_KEY)){
  2858. PFX.pbData = (BYTE *) malloc(PFX.cbData);
  2859. if (PFX.pbData) {
  2860. if (PFXExportCertStoreEx(
  2861. memStore,
  2862. &PFX,
  2863. PfxPassword,
  2864. NULL,
  2865. EXPORT_PRIVATE_KEYS | REPORT_NOT_ABLE_TO_EXPORT_PRIVATE_KEY | REPORT_NO_PRIVATE_KEY)){
  2866. //
  2867. // Write out the PFX file
  2868. //
  2869. hFile = CreateFileW(
  2870. PfxFileName,
  2871. GENERIC_WRITE,
  2872. 0,
  2873. NULL,
  2874. CREATE_ALWAYS,
  2875. FILE_ATTRIBUTE_NORMAL,
  2876. NULL
  2877. );
  2878. if ( INVALID_HANDLE_VALUE != hFile) {
  2879. //
  2880. // Let's write out the CER file
  2881. //
  2882. if(!WriteFile(
  2883. hFile,
  2884. PFX.pbData,
  2885. PFX.cbData,
  2886. &TextLen,
  2887. NULL
  2888. )){
  2889. RetCode = GetLastError();
  2890. DisplayMsg(CIPHER_CERTS_BACKUP_FAILED);
  2891. } else {
  2892. DisplayMsg(CIPHER_CERTS_BACKED);
  2893. RetCode = ERROR_SUCCESS;
  2894. }
  2895. CloseHandle(hFile);
  2896. } else {
  2897. RetCode = GetLastError();
  2898. DisplayMsg(CIPHER_CERTS_BACKUP_FAILED);
  2899. }
  2900. } else {
  2901. RetCode = GetLastError();
  2902. DisplayMsg(CIPHER_CERTS_BACKUP_FAILED);
  2903. }
  2904. free( PFX.pbData );
  2905. } else {
  2906. RetCode = ERROR_NOT_ENOUGH_MEMORY;
  2907. DisplayMsg(CIPHER_CERTS_BACKUP_FAILED);
  2908. }
  2909. }
  2910. if (PfxPassword) {
  2911. free(PfxPassword);
  2912. PfxPassword = 0;
  2913. }
  2914. } else {
  2915. RetCode = GetLastError();
  2916. }
  2917. } else {
  2918. RetCode = ERROR_INVALID_PARAMETER;
  2919. DisplayMsg(CIPHER_CERTS_BACKUP_FAILED);
  2920. }
  2921. }
  2922. }
  2923. if (memStore) {
  2924. CertCloseStore(memStore, 0);
  2925. }
  2926. return RetCode;
  2927. }
  2928. VOID
  2929. __cdecl
  2930. main()
  2931. {
  2932. PTCHAR *argv;
  2933. ULONG argc;
  2934. ULONG i;
  2935. PACTION_ROUTINE ActionRoutine = NULL;
  2936. PFINAL_ACTION_ROUTINE FinalActionRoutine = NULL;
  2937. TCHAR DirectorySpec[MAX_PATH];
  2938. TCHAR FileSpec[MAX_PATH];
  2939. PTCHAR p;
  2940. BOOL b;
  2941. InitializeIoStreams();
  2942. argv = CommandLineToArgvW(GetCommandLine(), &argc);
  2943. if (NULL == argv) {
  2944. DisplayErr(NULL, GetLastError());
  2945. return;
  2946. }
  2947. //
  2948. // Scan through the arguments looking for switches
  2949. //
  2950. for (i = 1; i < argc; i += 1) {
  2951. if (argv[i][0] == '/') {
  2952. if (0 == lstricmp(argv[i], TEXT("/e"))) {
  2953. if (ActionRoutine != NULL && ActionRoutine != DoEncryptAction) {
  2954. DisplayMsg(CIPHER_USAGE, NULL);
  2955. return;
  2956. }
  2957. ActionRoutine = DoEncryptAction;
  2958. FinalActionRoutine = DoFinalEncryptAction;
  2959. } else if (0 == lstricmp(argv[i], TEXT("/d"))) {
  2960. if (ActionRoutine != NULL && ActionRoutine != DoListAction) {
  2961. DisplayMsg(CIPHER_USAGE, NULL);
  2962. return;
  2963. }
  2964. ActionRoutine = DoDecryptAction;
  2965. FinalActionRoutine = DoFinalDecryptAction;
  2966. } else if (0 == lstricmp(argv[i], TEXT("/a"))){
  2967. DoFiles = TRUE;
  2968. } else if (0 == lstricmp(argv[i], TEXT("/q"))) {
  2969. Quiet = TRUE;
  2970. } else if (0 == lstricmp(argv[i], TEXT("/k"))){
  2971. SetUpNewUserKey = TRUE;
  2972. } else if (0 == lstricmp(argv[i], TEXT("/u"))){
  2973. RefreshUserKeyOnFiles = TRUE;
  2974. } else if (0 == lstricmp(argv[i], TEXT("/n"))){
  2975. DisplayFilesOnly = TRUE;
  2976. } else if (0 == lstricmp(argv[i], TEXT("/h"))){
  2977. DisplayAllFiles = TRUE;
  2978. } else if (0 == lstrnicmp(argv[i], TEXT("/s"), 2)) {
  2979. PTCHAR pch;
  2980. DoSubdirectories = TRUE;
  2981. pch = lstrchr(argv[i], ':');
  2982. if (NULL != pch) {
  2983. //
  2984. // We need space for \ * and NULL. That is where 3 comes from.
  2985. //
  2986. if (wcslen(pch+1) > ((sizeof(StartingDirectory) / sizeof (TCHAR)) - 3)){
  2987. //
  2988. // The dir is too long for us
  2989. //
  2990. DisplayErr(NULL, ERROR_BUFFER_OVERFLOW);
  2991. return;
  2992. } else {
  2993. lstrcpy(StartingDirectory, pch + 1);
  2994. }
  2995. } else {
  2996. //
  2997. // We require an explicit directory to be passed.
  2998. //
  2999. DisplayMsg(CIPHER_USAGE, NULL);
  3000. return;
  3001. }
  3002. } else if (0 == lstricmp(argv[i], TEXT("/i"))) {
  3003. IgnoreErrors = TRUE;
  3004. } else if (0 == lstricmp(argv[i], TEXT("/f"))) {
  3005. ForceOperation = TRUE;
  3006. } else if (0 == lstrnicmp(argv[i], TEXT("/x"), 2)){
  3007. DWORD dLen;
  3008. ExportEfsCert = TRUE;
  3009. //
  3010. // Using FileSpec for the source encrypted file.
  3011. // Using DirectorySpec for the destination PFX file.
  3012. // CIPHER /X[:EFSFILE] [PFXFILE]
  3013. //
  3014. DirectorySpec[0] = 0;
  3015. FileSpec[0] = 0;
  3016. dLen = wcslen(argv[i]);
  3017. if ((dLen > 3) && argv[i][2] == ':') {
  3018. //
  3019. // Try to get the EFSFILE
  3020. //
  3021. if ( (dLen -3) >= MAX_PATH) {
  3022. //
  3023. // 3 is for /X:
  3024. //
  3025. DisplayMsg(CIPHER_INVALID_PATH, &(argv[i][3]));
  3026. return;
  3027. } else {
  3028. lstrcpy( FileSpec, &(argv[i][3]));
  3029. }
  3030. }
  3031. if ((i+1) < argc) {
  3032. //
  3033. // Try to get the target PFX file name
  3034. //
  3035. if (wcslen(argv[i+1]) >= MAX_PATH) {
  3036. DisplayMsg(CIPHER_INVALID_PATH, argv[i+1]);
  3037. return;
  3038. } else {
  3039. lstrcpy( DirectorySpec, argv[i+1]);
  3040. }
  3041. }
  3042. break;
  3043. } else if (0 == lstrnicmp(argv[i], TEXT("/r"), 2)){
  3044. PTCHAR pch;
  3045. GenerateDRA = TRUE;
  3046. pch = lstrchr(argv[i], ':');
  3047. if (NULL != pch) {
  3048. //
  3049. // We will append .CER (PFX) to the path. Plus the NULL. Extra 5 TCHARs are needed.
  3050. //
  3051. if (wcslen(pch+1) > ((sizeof(StartingDirectory) / sizeof (TCHAR)) - 5)){
  3052. //
  3053. // The path is too long for us
  3054. //
  3055. DisplayErr(NULL, ERROR_BUFFER_OVERFLOW);
  3056. return;
  3057. }else {
  3058. lstrcpy(StartingDirectory, pch + 1);
  3059. }
  3060. } else {
  3061. //
  3062. // We require an explicit file to be passed.
  3063. //
  3064. DisplayMsg(CIPHER_USAGE, NULL);
  3065. return;
  3066. }
  3067. } else if (0 == lstrnicmp(argv[i], TEXT("/w"), 2)){
  3068. PTCHAR pch;
  3069. FillUnusedSpace = TRUE;
  3070. pch = lstrchr(argv[i], ':');
  3071. if (NULL != pch) {
  3072. if (wcslen(pch+1) > ((sizeof(StartingDirectory) / sizeof (TCHAR)) - 1)){
  3073. //
  3074. // The path is too long for us
  3075. //
  3076. DisplayErr(NULL, ERROR_BUFFER_OVERFLOW);
  3077. return;
  3078. }else {
  3079. lstrcpy(StartingDirectory, pch + 1);
  3080. }
  3081. } else {
  3082. //
  3083. // We require an explicit directory to be passed.
  3084. //
  3085. DisplayMsg(CIPHER_USAGE, NULL);
  3086. return;
  3087. }
  3088. } else {
  3089. DisplayMsg(CIPHER_USAGE, NULL);
  3090. return;
  3091. }
  3092. } else {
  3093. UserSpecifiedFileSpec = TRUE;
  3094. }
  3095. }
  3096. if (SetUpNewUserKey) {
  3097. DWORD RetCode;
  3098. //
  3099. // Set up new user key here
  3100. //
  3101. RetCode = SetUserFileEncryptionKey(NULL);
  3102. if ( ERROR_SUCCESS != RetCode ) {
  3103. //
  3104. // Display error info.
  3105. //
  3106. DisplayErr(NULL, GetLastError());
  3107. } else {
  3108. //
  3109. // Get the new hash and display it.
  3110. //
  3111. CipherDisplayCrntEfsHash();
  3112. }
  3113. //
  3114. // Create user key should not be used with other options.
  3115. // We will ignore other options if user do.
  3116. //
  3117. return;
  3118. }
  3119. if (RefreshUserKeyOnFiles) {
  3120. DWORD RetCode;
  3121. RetCode = CipherTouchEncryptedFiles();
  3122. if (RetCode != ERROR_SUCCESS) {
  3123. DisplayErr(NULL, RetCode);
  3124. }
  3125. return;
  3126. }
  3127. if (GenerateDRA) {
  3128. DWORD RetCode;
  3129. RetCode = GenerateCertFiles(StartingDirectory);
  3130. return;
  3131. }
  3132. if (ExportEfsCert) {
  3133. DWORD RetCode;
  3134. RetCode = BackEfsCert(FileSpec, DirectorySpec);
  3135. if (RetCode != ERROR_SUCCESS) {
  3136. DisplayErr(NULL, RetCode);
  3137. }
  3138. return;
  3139. }
  3140. if (FillUnusedSpace) {
  3141. BYTE FillByte[2] = { 0x00, 0xFF };
  3142. DWORD WriteValue[3] = {CIPHER_WRITE_ZERO, CIPHER_WRITE_FF, CIPHER_WRITE_RANDOM};
  3143. PBYTE pFillByte[3] = {&FillByte[0], &FillByte[1], NULL};
  3144. LPWSTR WriteChars;
  3145. DWORD RetCode;
  3146. if (!CheckMinVersion()) {
  3147. DisplayErr(NULL, ERROR_OLD_WIN_VERSION);
  3148. return;
  3149. }
  3150. //
  3151. // We are going to erase the disks
  3152. //
  3153. DisplayMsg(CIPHER_WIPE_WARNING, NULL);
  3154. for (i = 0; i < 3; i++) {
  3155. RetCode = SecureInitializeRandomFill( &GlobalSecureFill, 4096 * 128, pFillByte[i] );
  3156. if (RetCode != ERROR_SUCCESS) {
  3157. SecureDeleteRandomFill(&GlobalSecureFill);
  3158. break;
  3159. }
  3160. if ( ERROR_SUCCESS == GetResourceString(&WriteChars, WriteValue[i])){
  3161. DisplayMsg(CIPHER_WIPE_PROGRESS, WriteChars);
  3162. LocalFree(WriteChars);
  3163. }
  3164. RetCode = SecureDeleteFreeSpace(StartingDirectory);
  3165. printf("\n");
  3166. SecureDeleteRandomFill( &GlobalSecureFill );
  3167. if (RetCode != ERROR_SUCCESS) {
  3168. break;
  3169. }
  3170. }
  3171. if (RetCode != ERROR_SUCCESS) {
  3172. DisplayErr(NULL, RetCode);
  3173. }
  3174. return;
  3175. }
  3176. //
  3177. // If the use didn't specify an action then set the default to do a listing
  3178. //
  3179. if (ActionRoutine == NULL) {
  3180. ActionRoutine = DoListAction;
  3181. FinalActionRoutine = DoFinalListAction;
  3182. }
  3183. //
  3184. // If the user didn't specify a file spec then we'll do just "*"
  3185. //
  3186. if (!UserSpecifiedFileSpec) {
  3187. DWORD PathLen;
  3188. //
  3189. // Get our current directory because the action routines might move us
  3190. // around
  3191. //
  3192. if (DoSubdirectories) {
  3193. if (ActionRoutine != DoListAction) {
  3194. (VOID)(ActionRoutine)( StartingDirectory, TEXT("") );
  3195. }
  3196. if (!SetCurrentDirectory( StartingDirectory )) {
  3197. DisplayErr(StartingDirectory, GetLastError());
  3198. return;
  3199. }
  3200. } else {
  3201. PathLen = GetCurrentDirectory( MAX_PATH, StartingDirectory );
  3202. if (0 == PathLen) {
  3203. DisplayErr(NULL, GetLastError());
  3204. return;
  3205. } else if (PathLen >= MAX_PATH) {
  3206. DisplayErr(NULL, ERROR_BUFFER_OVERFLOW);
  3207. return;
  3208. }
  3209. }
  3210. PathLen = GetFullPathName( TEXT("*"), MAX_PATH, DirectorySpec, &p );
  3211. if (0 == PathLen) {
  3212. DisplayErr(NULL, GetLastError());
  3213. return;
  3214. }
  3215. if (PathLen >= MAX_PATH) {
  3216. DisplayErr(NULL, ERROR_BUFFER_OVERFLOW);
  3217. return;
  3218. }
  3219. //
  3220. // If PathLen < MAX_PATH, than wcslen(P) < MAX_PATH
  3221. //
  3222. lstrcpy( FileSpec, p ); *p = '\0';
  3223. (VOID)(ActionRoutine)( DirectorySpec, FileSpec );
  3224. } else {
  3225. //
  3226. // Get our current directory because the action routines might move us
  3227. // around
  3228. //
  3229. DWORD PathLen;
  3230. if (!DoSubdirectories) {
  3231. PathLen = GetCurrentDirectory( MAX_PATH, StartingDirectory );
  3232. if (0 == PathLen) {
  3233. DisplayErr(NULL, GetLastError());
  3234. return;
  3235. } else if (PathLen >= MAX_PATH) {
  3236. DisplayErr(NULL, ERROR_BUFFER_OVERFLOW);
  3237. return;
  3238. }
  3239. } else if (!SetCurrentDirectory( StartingDirectory )) {
  3240. DisplayErr(StartingDirectory, GetLastError());
  3241. return;
  3242. }
  3243. //
  3244. // Now scan the arguments again looking for non-switches
  3245. // and this time do the action, but before calling reset
  3246. // the current directory so that things work again
  3247. //
  3248. for (i = 1; i < argc; i += 1) {
  3249. if (argv[i][0] != '/') {
  3250. SetCurrentDirectory( StartingDirectory );
  3251. //
  3252. // Handle a command with "." as the file argument specially,
  3253. // since it doesn't make good sense and the results without
  3254. // this code are surprising.
  3255. //
  3256. if ('.' == argv[i][0] && '\0' == argv[i][1]) {
  3257. argv[i] = TEXT("*");
  3258. GetFullPathName(argv[i], MAX_PATH, DirectorySpec, &p);
  3259. *p = '\0';
  3260. p = NULL;
  3261. } else {
  3262. PWCHAR pwch;
  3263. //
  3264. // We need to deal with path longer than MAX_PATH later.
  3265. // This code is based on Compact. They have the same problem
  3266. // as we do. So far, we have not heard any one complaining about this.
  3267. // Let's track this in the RAID.
  3268. //
  3269. PathLen = GetFullPathName(argv[i], MAX_PATH, DirectorySpec, &p);
  3270. if ( (0 == PathLen) || ( PathLen > (MAX_PATH - 1)) ){
  3271. DisplayMsg(CIPHER_INVALID_PARAMETER, argv[i]);
  3272. break;
  3273. }
  3274. //
  3275. // We want to treat "foobie:xxx" as an invalid drive name,
  3276. // rather than as a name identifying a stream. If there's
  3277. // a colon, there should be only a single character before
  3278. // it.
  3279. //
  3280. pwch = wcschr(argv[i], ':');
  3281. if (NULL != pwch && pwch - argv[i] != 1) {
  3282. DisplayMsg(CIPHER_INVALID_PATH, argv[i]);
  3283. break;
  3284. }
  3285. //
  3286. // GetFullPathName strips trailing dots, but we want
  3287. // to save them so that "*." will work correctly.
  3288. //
  3289. if ('.' == argv[i][lstrlen(argv[i]) - 1]) {
  3290. if (PathLen >= MAX_PATH - 2 ) {
  3291. DisplayMsg(CIPHER_INVALID_PATH, argv[i]);
  3292. break;
  3293. } else {
  3294. lstrcat(DirectorySpec, TEXT("."));
  3295. }
  3296. }
  3297. }
  3298. if (p != NULL) {
  3299. if (wcslen(p) >= (sizeof(FileSpec) / sizeof (TCHAR))) {
  3300. DisplayMsg(CIPHER_INVALID_PATH, argv[i]);
  3301. break;
  3302. } else {
  3303. lstrcpy( FileSpec, p ); *p = '\0';
  3304. }
  3305. } else {
  3306. FileSpec[0] = '\0';
  3307. }
  3308. if (!(ActionRoutine)( DirectorySpec, FileSpec ) &&
  3309. !IgnoreErrors) {
  3310. break;
  3311. }
  3312. }
  3313. }
  3314. }
  3315. //
  3316. // Reset our current directory back
  3317. //
  3318. SetCurrentDirectory( StartingDirectory );
  3319. //
  3320. // And do the final action routine that will print out the final
  3321. // statistics of what we've done
  3322. //
  3323. (FinalActionRoutine)();
  3324. }