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

10040 lines
288 KiB

  1. /*++
  2. Copyright (c) 1997-1999 Microsoft Corporation
  3. Module Name:
  4. efsapi.cxx
  5. Abstract:
  6. EFS (Encrypting File System) API Interfaces
  7. Author:
  8. Robert Reichel (RobertRe)
  9. Robert Gu (RobertG)
  10. Environment:
  11. Revision History:
  12. --*/
  13. #include <lsapch.hxx>
  14. //
  15. // Fodder
  16. extern "C" {
  17. #include <nt.h>
  18. #include <ntdef.h>
  19. #include <ntrtl.h>
  20. #include <nturtl.h>
  21. #include <windows.h>
  22. #include <stdio.h>
  23. #include <wincrypt.h>
  24. #include <efsstruc.h>
  25. #include "lsasrvp.h"
  26. #include "debug.h"
  27. #include "efssrv.hxx"
  28. #include "userkey.h"
  29. #include "lsapmsgs.h"
  30. }
  31. //Constant -- This buffer length should be enough for EFS temp file name
  32. #define TEMPFILELEN 26
  33. //
  34. // Initial memory allocation block size for $EFS
  35. //
  36. #define INIT_EFS_BLOCK_SIZE 4096
  37. #define INITBUFFERSIZE 4096
  38. #define ENCRYPT 1
  39. #define EfsErrPrint //
  40. #define BASIC_KEY_INFO 1
  41. //
  42. // Global Variables
  43. //
  44. DESTable DesTable;
  45. UCHAR DriverSessionKey[DES_BLOCKLEN];
  46. HANDLE LsaPid = NULL;
  47. //
  48. // Prototypes
  49. //
  50. ULONG
  51. StringInfoCmp(
  52. IN PFILE_STREAM_INFORMATION StreamInfoBase,
  53. IN PFILE_STREAM_INFORMATION LaterStreamInfoBase,
  54. IN ULONG StreamInfoSize
  55. );
  56. BOOLEAN
  57. EncryptFSCTLData(
  58. IN ULONG Fsctl,
  59. IN ULONG Psc,
  60. IN ULONG Csc,
  61. IN PVOID EfsData,
  62. IN ULONG EfsDataLength,
  63. IN OUT PUCHAR Buffer,
  64. IN OUT PULONG BufferLength
  65. );
  66. BOOLEAN
  67. SendHandle(
  68. IN HANDLE Handle,
  69. IN OUT PUCHAR EfsData,
  70. IN OUT PULONG EfsDataLength
  71. );
  72. BOOLEAN
  73. SendEfs(
  74. IN PEFS_KEY Fek,
  75. IN PEFS_DATA_STREAM_HEADER Efs,
  76. OUT PUCHAR EfsData,
  77. OUT PULONG EfsDataLength
  78. );
  79. BOOLEAN
  80. SendHandleAndEfs(
  81. IN HANDLE Handle,
  82. IN PEFS_DATA_STREAM_HEADER Efs,
  83. IN OUT PUCHAR EfsData,
  84. IN OUT PULONG EfsDataLength
  85. );
  86. NTSTATUS
  87. SendSkFsctl(
  88. IN ULONG PSC,
  89. IN ULONG CSC,
  90. IN ULONG EfsCode,
  91. IN PUCHAR InputData,
  92. IN ULONG InputDataSize,
  93. IN HANDLE Handle,
  94. IN ULONG FsCode,
  95. OUT IO_STATUS_BLOCK *IoStatusBlock
  96. );
  97. NTSTATUS
  98. EndErrorEncryptFile(
  99. IN HANDLE FileHandle,
  100. IN PUCHAR InputData,
  101. IN ULONG InputDataSize,
  102. OUT IO_STATUS_BLOCK *IoStatusBlock
  103. );
  104. NTSTATUS
  105. GetRootHandle(
  106. IN HANDLE FileHandle,
  107. PHANDLE RootDirectoryHandle
  108. );
  109. NTSTATUS
  110. GetParentEfsStream(
  111. IN HANDLE CurrentFileHandle,
  112. IN PUNICODE_STRING CurrentFileName,
  113. OUT PEFS_DATA_STREAM_HEADER *ParentEfsStream
  114. );
  115. DWORD
  116. MyCopyFile(
  117. HANDLE SourceFile,
  118. PUNICODE_STRING StreamNames,
  119. PHANDLE StreamHandles,
  120. PEFS_STREAM_SIZE StreamSizes,
  121. ULONG StreamCount,
  122. HANDLE hTargetFile,
  123. PHANDLE * TargetStreamHandles
  124. );
  125. VOID
  126. CleanupOpenFileStreams(
  127. IN PHANDLE Handles OPTIONAL,
  128. IN PUNICODE_STRING StreamNames OPTIONAL,
  129. IN PEFS_STREAM_SIZE Sizes OPTIONAL,
  130. IN PFILE_STREAM_INFORMATION StreamInfoBase OPTIONAL,
  131. IN HANDLE HSourceFile OPTIONAL,
  132. IN ULONG StreamCount
  133. );
  134. NTSTATUS
  135. GetBackupFileName(
  136. LPCWSTR SourceFile,
  137. LPWSTR * BackupName
  138. );
  139. DWORD
  140. CopyStream(
  141. HANDLE Target,
  142. HANDLE Source,
  143. PEFS_STREAM_SIZE StreamSize
  144. );
  145. DWORD
  146. CheckVolumeSpace(
  147. PFILE_FS_SIZE_INFORMATION VolInfo,
  148. PEFS_STREAM_SIZE StreamSizes,
  149. PHANDLE StreamHandles,
  150. ULONG StreamCount
  151. );
  152. DWORD
  153. CompressStreams(
  154. PEFS_STREAM_SIZE StreamSizes,
  155. PHANDLE StreamHandles,
  156. ULONG State,
  157. ULONG StreamCount
  158. );
  159. DWORD
  160. CheckOpenSection(
  161. PEFS_STREAM_SIZE StreamSizes,
  162. PHANDLE StreamHandles,
  163. ULONG StreamCount
  164. );
  165. DWORD
  166. CopyStreamSection(
  167. HANDLE Target,
  168. HANDLE SrcMapping,
  169. PLARGE_INTEGER Offset,
  170. PLARGE_INTEGER DataLength,
  171. PLARGE_INTEGER AllocationGranularity
  172. );
  173. BOOL
  174. EfspSetEfsOnFile(
  175. IN HANDLE hFile,
  176. PEFS_DATA_STREAM_HEADER pEfsStream,
  177. IN PEFS_KEY pNewFek
  178. );
  179. NTSTATUS
  180. GetFileEfsStream(
  181. IN HANDLE hFile,
  182. OUT PEFS_DATA_STREAM_HEADER * pEfsStream
  183. );
  184. DWORD
  185. EncryptFileSrv(
  186. IN PEFS_USER_INFO pEfsUserInfo,
  187. IN PUNICODE_STRING SourceFileNameU,
  188. IN HANDLE LogFileH
  189. )
  190. /*++
  191. Routine Description:
  192. This routine is the top level routine of the EncryptFile API. It
  193. opens the passed source file and copies all of its data streams to
  194. a backup file in a known location. It then marks all of the streams
  195. of the source as encrypted, and copies them back.
  196. Arguments:
  197. SourceFileName - Supplies a Unicode string with the name of
  198. the file to be encrypted.
  199. LogFileH - Log file handle. Log file is zero size when passed in.
  200. Return Value:
  201. ERROR_SUCCESS on success, other on failure.
  202. --*/
  203. {
  204. BOOL b = TRUE;
  205. BOOLEAN CleanupSuccessful = TRUE;
  206. BOOLEAN KeepLogFile = FALSE;
  207. ULONG StatusInfoOffset = 0 ;
  208. DWORD hResult = ERROR_SUCCESS;
  209. DWORD FileAttributes;
  210. HANDLE FileHandle;
  211. HANDLE hSourceFile;
  212. HANDLE hBackupFile = 0;
  213. PHANDLE StreamHandles = NULL;
  214. LPWSTR SourceFileName;
  215. LPWSTR BackupFileName;
  216. FILE_FS_SIZE_INFORMATION VolInfo;
  217. FILE_INTERNAL_INFORMATION SourceID;
  218. FILE_INTERNAL_INFORMATION BackupID;
  219. NTSTATUS Status;
  220. OBJECT_ATTRIBUTES Obja;
  221. PFILE_STREAM_INFORMATION LaterStreamInfoBase = NULL;
  222. PFILE_STREAM_INFORMATION StreamInfoBase = NULL;
  223. PEFS_STREAM_SIZE StreamSizes = NULL;
  224. PUNICODE_STRING StreamNames = NULL;
  225. UINT TmpResult;
  226. ULONG LaterStreamInfoSize = 0;
  227. ULONG StreamCount = 0;
  228. ULONG StreamInfoSize = 0;
  229. ULONG i;
  230. DWORD tmpDW;
  231. PEFS_DATA_STREAM_HEADER ParentEfsStream = NULL;
  232. PEFS_DATA_STREAM_HEADER CurrentEfsStream = NULL;
  233. IO_STATUS_BLOCK IoStatusBlock;
  234. ULONG InputDataSize;
  235. ULONG EfsDataLength;
  236. PUCHAR InputData;
  237. WORD WebDavPath = 0;
  238. //
  239. // Convert the source file name into an LPWSTR
  240. //
  241. if (!LogFileH) {
  242. //
  243. // No LogFile means WEBDAVPATH
  244. //
  245. WebDavPath = WEBDAVPATH;
  246. }
  247. SourceFileName = (LPWSTR)LsapAllocateLsaHeap( SourceFileNameU->Length + sizeof( UNICODE_NULL ));
  248. if (SourceFileName == NULL) {
  249. MarkFileForDelete( LogFileH );
  250. EfsErrPrint("Out of memory allocating SourceFileName");
  251. return( ERROR_NOT_ENOUGH_MEMORY );
  252. }
  253. SourceFileName[SourceFileNameU->Length/sizeof(WCHAR)] = UNICODE_NULL;
  254. RtlCopyMemory( SourceFileName, SourceFileNameU->Buffer, SourceFileNameU->Length );
  255. DebugLog((DEB_TRACE_EFS, "Encrypting file %ws \n", SourceFileName));
  256. FileAttributes = GetFileAttributes( SourceFileName );
  257. if (FileAttributes == -1) {
  258. if (LogFileH) {
  259. MarkFileForDelete( LogFileH );
  260. }
  261. LsapFreeLsaHeap( SourceFileName );
  262. EfsErrPrint("GetFileAttributes failed with -1");
  263. return GetLastError();
  264. }
  265. //
  266. // Open the target file
  267. //
  268. if ( FileAttributes & FILE_ATTRIBUTE_DIRECTORY ){
  269. tmpDW = FILE_FLAG_BACKUP_SEMANTICS;
  270. } else {
  271. tmpDW = FILE_FLAG_OPEN_REPARSE_POINT;
  272. }
  273. //
  274. // CreateFile will add FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES | SYNCHRONIZE
  275. //
  276. hSourceFile = CreateFile(
  277. SourceFileName,
  278. FILE_READ_DATA | FILE_WRITE_DATA | FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES,
  279. 0,
  280. NULL,
  281. OPEN_EXISTING,
  282. tmpDW,
  283. NULL
  284. );
  285. if (hSourceFile != INVALID_HANDLE_VALUE) {
  286. NTSTATUS Status1;
  287. if ( FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) {
  288. //
  289. // Fail the call if the file is HSM or SIS file
  290. //
  291. FILE_ATTRIBUTE_TAG_INFORMATION TagInfo;
  292. Status = NtQueryInformationFile(
  293. hSourceFile,
  294. &IoStatusBlock,
  295. &TagInfo,
  296. sizeof ( FILE_ATTRIBUTE_TAG_INFORMATION ),
  297. FileAttributeTagInformation
  298. );
  299. if ( NT_SUCCESS( Status ) && ( (IO_REPARSE_TAG_HSM == TagInfo.ReparseTag) || (IO_REPARSE_TAG_SIS == TagInfo.ReparseTag))) {
  300. //
  301. // Log the error saying we do not support HSM and SIS
  302. //
  303. EfsLogEntry(
  304. EVENTLOG_ERROR_TYPE,
  305. 0,
  306. EFS_REPARSE_FILE_ERROR,
  307. 1,
  308. sizeof(ULONG),
  309. (LPCWSTR *)&SourceFileName,
  310. &TagInfo.ReparseTag
  311. );
  312. if (LogFileH) {
  313. MarkFileForDelete( LogFileH );
  314. }
  315. LsapFreeLsaHeap( SourceFileName );
  316. CloseHandle( hSourceFile );
  317. EfsErrPrint("This is a SIS or HSM file.\n");
  318. return ERROR_ACCESS_DENIED;
  319. }
  320. }
  321. Status = NtQueryVolumeInformationFile(
  322. hSourceFile,
  323. &IoStatusBlock,
  324. &VolInfo,
  325. sizeof ( FILE_FS_SIZE_INFORMATION ),
  326. FileFsSizeInformation
  327. );
  328. if (WebDavPath != WEBDAVPATH) {
  329. Status1 = NtQueryInformationFile(
  330. hSourceFile,
  331. &IoStatusBlock,
  332. &SourceID,
  333. sizeof ( FILE_INTERNAL_INFORMATION ),
  334. FileInternalInformation
  335. );
  336. } else {
  337. //
  338. // SourceID not needed for WEB DAV file
  339. //
  340. Status1 = STATUS_SUCCESS;
  341. }
  342. if ( NT_SUCCESS( Status ) && NT_SUCCESS( Status1 ) ) {
  343. /*
  344. //
  345. // Get parent directory $EFS
  346. // We will visit this in Blackcomb
  347. //
  348. RpcRevertToSelf();
  349. Status = GetParentEfsStream(
  350. hSourceFile,
  351. SourceFileNameU,
  352. &ParentEfsStream
  353. );
  354. */
  355. if (NT_SUCCESS( Status ) ) {
  356. if ( FileAttributes & FILE_ATTRIBUTE_DIRECTORY ) {
  357. if ( FileAttributes & FILE_ATTRIBUTE_COMPRESSED ){
  358. USHORT State = COMPRESSION_FORMAT_NONE;
  359. ULONG Length;
  360. //
  361. // Uncompress the directory first
  362. //
  363. b = DeviceIoControl(hSourceFile,
  364. FSCTL_SET_COMPRESSION,
  365. &State,
  366. sizeof(USHORT),
  367. NULL,
  368. 0,
  369. &Length,
  370. FALSE
  371. );
  372. if ( !b ){
  373. hResult = GetLastError();
  374. DebugLog((DEB_WARN, "DeviceIoControl failed, setting hResult = %d\n", hResult ));
  375. EfsErrPrint("Uncompress the directory failed. Win Error=%d\n",hResult);
  376. }
  377. }
  378. if (hResult == ERROR_SUCCESS) {
  379. //
  380. // Set_Encrypt on directory
  381. //
  382. //
  383. // We do not check the operation of the LOG.
  384. // Should we fail the normal operation just because the LOG operations
  385. // failed? The answer is probably not. The chance to use the LOG file is very
  386. // slim. We will use TxF when it is ready and we have time to deal with this.
  387. //
  388. if (LogFileH) {
  389. CreateLogHeader(
  390. LogFileH,
  391. VolInfo.BytesPerSector,
  392. &(SourceID.IndexNumber),
  393. NULL,
  394. SourceFileName,
  395. NULL,
  396. Encrypting,
  397. BeginEncryptDir,
  398. NULL
  399. );
  400. }
  401. PEFS_KEY Fek ;
  402. b = GenerateFEK( &Fek );
  403. if (b) {
  404. if (ConstructDirectoryEFS( pEfsUserInfo, Fek, &CurrentEfsStream )) {
  405. //
  406. // Prepare an Input data buffer in the form of
  407. // PSC, [EFS_FC, CSC, SK, H, H, [SK, H, H]sk, $EFS]sk
  408. //
  409. InputDataSize = 2 * sizeof(DriverSessionKey) + 7 * sizeof(ULONG)
  410. + CurrentEfsStream->Length;
  411. InputData = (PUCHAR)LsapAllocateLsaHeap( InputDataSize );
  412. if ( NULL != InputData ) {
  413. EfsDataLength = InputDataSize - 3 * sizeof(ULONG);
  414. ( VOID ) SendHandleAndEfs(
  415. hSourceFile,
  416. CurrentEfsStream,
  417. InputData + 3 * sizeof(ULONG),
  418. &EfsDataLength
  419. );
  420. ( VOID ) EncryptFSCTLData(
  421. EFS_SET_ENCRYPT,
  422. EFS_ENCRYPT_STREAM,
  423. EFS_ENCRYPT_DIRSTR,
  424. InputData + 3*sizeof(ULONG),
  425. EfsDataLength,
  426. InputData,
  427. &InputDataSize
  428. );
  429. Status = NtFsControlFile(
  430. hSourceFile,
  431. 0,
  432. NULL,
  433. NULL,
  434. &IoStatusBlock,
  435. FSCTL_SET_ENCRYPTION,
  436. InputData,
  437. InputDataSize,
  438. NULL,
  439. 0
  440. );
  441. if (NT_SUCCESS( Status )) {
  442. hResult = ERROR_SUCCESS;
  443. } else {
  444. DebugLog((DEB_ERROR, "EncryptFileSrv: NtFsControlFile failed, status = (%x)\n" ,Status ));
  445. hResult = RtlNtStatusToDosError( Status );
  446. //
  447. // Make sure the error was mapped
  448. //
  449. if (hResult == ERROR_MR_MID_NOT_FOUND) {
  450. DebugLog((DEB_WARN, "Unable to map NT Error (%x) to Win32 error, returning ERROR_ENCRYPTION_FAILED\n" , Status ));
  451. hResult = ERROR_ENCRYPTION_FAILED;
  452. }
  453. EfsErrPrint("Encrypt directory FSCTL failed. Win Error=%d\n",hResult);
  454. }
  455. LsapFreeLsaHeap( InputData );
  456. } else {
  457. hResult = ERROR_NOT_ENOUGH_MEMORY;
  458. EfsErrPrint("FSCTL input data memory allocation failed.\n");
  459. }
  460. LsapFreeLsaHeap( CurrentEfsStream );
  461. } else {
  462. hResult = GetLastError();
  463. ASSERT( hResult != ERROR_SUCCESS );
  464. DebugLog((DEB_WARN, "ConstructDirectoryEFS returned %x to hResult\n" ,hResult ));
  465. EfsErrPrint("ConstructDirectoryEFS failed. Win Error=%d\n",hResult);
  466. }
  467. LsapFreeLsaHeap( Fek );
  468. Fek = NULL;
  469. } else {
  470. hResult = GetLastError();
  471. ASSERT( hResult != ERROR_SUCCESS );
  472. EfsErrPrint("Generate directory FEK failed. Win Error=%d\n",hResult);
  473. }
  474. if ((hResult != ERROR_SUCCESS) && ( FileAttributes & FILE_ATTRIBUTE_COMPRESSED )) {
  475. //
  476. // Restore the compression state
  477. //
  478. USHORT State = COMPRESSION_FORMAT_DEFAULT;
  479. ULONG Length;
  480. (VOID) DeviceIoControl(hSourceFile,
  481. FSCTL_SET_COMPRESSION,
  482. &State,
  483. sizeof(USHORT),
  484. NULL,
  485. 0,
  486. &Length,
  487. FALSE
  488. );
  489. }
  490. //
  491. // if ConstructDirectoryEFS fail, error will be returned in the end.
  492. //
  493. }
  494. } else {
  495. //
  496. // It's a file, not a directory.
  497. //
  498. //
  499. // Enumerate all the streams on the file
  500. //
  501. Status = GetStreamInformation(
  502. hSourceFile,
  503. &StreamInfoBase, // Free this
  504. &StreamInfoSize
  505. );
  506. if (NT_SUCCESS( Status )) {
  507. hResult = OpenFileStreams(
  508. hSourceFile,
  509. 0,
  510. OPEN_FOR_ENC,
  511. StreamInfoBase,
  512. FILE_READ_DATA | FILE_WRITE_DATA | FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES | SYNCHRONIZE,
  513. FILE_OPEN,
  514. FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_REPARSE_POINT,
  515. &VolInfo,
  516. &StreamNames, // Free this but not the contents!
  517. &StreamHandles, // Free this
  518. &StreamSizes, // Free this
  519. &StreamCount
  520. );
  521. if (hResult == ERROR_SUCCESS) {
  522. //
  523. // We have handles to all of the streams of the file
  524. //
  525. //
  526. // Prepare an Input data buffer in the form of
  527. // PSC, [EFS_FC, CSC, Fek, [Fek]sk, $EFS]sk
  528. //
  529. PEFS_KEY Fek ;
  530. b = GenerateFEK( &Fek );
  531. if (b) {
  532. b = ConstructEFS(
  533. pEfsUserInfo,
  534. Fek,
  535. ParentEfsStream,
  536. &CurrentEfsStream
  537. );
  538. if (b) {
  539. InputDataSize = 2 * EFS_KEY_SIZE( Fek ) + 3 * sizeof(ULONG)
  540. + CurrentEfsStream->Length;
  541. InputData = (PUCHAR)LsapAllocateLsaHeap( InputDataSize );
  542. if ( NULL != InputData ){
  543. //
  544. // This routine creates the backup file.
  545. //
  546. Status = CreateBackupFile(
  547. SourceFileNameU,
  548. &hBackupFile,
  549. &BackupID,
  550. &BackupFileName
  551. );
  552. //
  553. // If power down happens right here before
  554. // the log file header is written, we will have a zero size
  555. // temp file left on the disk. This is very unlikely and not
  556. // a big deal we have a zero size file left on the disk.
  557. // After we use TxF, this will not even be an issue.
  558. //
  559. if ( NT_SUCCESS(Status) ){
  560. if (LogFileH) {
  561. Status = CreateLogHeader(
  562. LogFileH,
  563. VolInfo.BytesPerSector,
  564. &(SourceID.IndexNumber),
  565. &(BackupID.IndexNumber),
  566. SourceFileName,
  567. BackupFileName,
  568. Encrypting,
  569. BeginEncryptFile,
  570. &StatusInfoOffset
  571. );
  572. }
  573. LsapFreeLsaHeap( BackupFileName );
  574. if ( NT_SUCCESS(Status) ){
  575. if (LogFileH){
  576. Status = WriteLogFile(
  577. LogFileH,
  578. VolInfo.BytesPerSector,
  579. StatusInfoOffset,
  580. BeginEncryptFile
  581. );
  582. if ( !NT_SUCCESS(Status) ){
  583. //
  584. // Delete the backup file
  585. //
  586. MarkFileForDelete( hBackupFile );
  587. CloseHandle( hBackupFile );
  588. hBackupFile = 0;
  589. EfsErrPrint("Failed to write the log file.\n");
  590. }
  591. }
  592. } else {
  593. MarkFileForDelete( hBackupFile );
  594. CloseHandle( hBackupFile );
  595. hBackupFile = 0;
  596. EfsErrPrint("Failed to create the Log header.\n");
  597. }
  598. } else {
  599. //
  600. // Fail to create the backup file
  601. // Log it.
  602. //
  603. EfsLogEntry(
  604. EVENTLOG_ERROR_TYPE,
  605. 0,
  606. EFS_TMP_FILE_ERROR,
  607. 1,
  608. sizeof(NTSTATUS),
  609. (LPCWSTR *)&SourceFileName,
  610. &Status
  611. );
  612. EfsErrPrint("Failed to create the backup file.");
  613. }
  614. if ( NT_SUCCESS(Status) ){
  615. EfsDataLength = InputDataSize - 3 * sizeof(ULONG);
  616. //
  617. // Prepare the FSCTL input data
  618. //
  619. ( VOID ) SendEfs(
  620. Fek,
  621. CurrentEfsStream,
  622. InputData + 3 * sizeof(ULONG),
  623. &EfsDataLength
  624. );
  625. ( VOID ) EncryptFSCTLData(
  626. EFS_SET_ENCRYPT,
  627. EFS_ENCRYPT_FILE,
  628. EFS_ENCRYPT_FILE,
  629. InputData + 3*sizeof(ULONG),
  630. EfsDataLength,
  631. InputData,
  632. &InputDataSize
  633. );
  634. //
  635. // Write the $EFS and turn on the bits
  636. //
  637. Status = NtFsControlFile(
  638. hSourceFile,
  639. 0,
  640. NULL,
  641. NULL,
  642. &IoStatusBlock,
  643. FSCTL_SET_ENCRYPTION,
  644. InputData,
  645. InputDataSize,
  646. NULL,
  647. 0
  648. );
  649. if ( NT_SUCCESS( Status ) ){
  650. //
  651. // All failures from here on out need to be closed
  652. // with another FSCTL call.
  653. //
  654. //
  655. // Enumerate the streams again, and make sure nothing
  656. // has changed
  657. //
  658. Status = GetStreamInformation(
  659. hSourceFile,
  660. &LaterStreamInfoBase, // Free this
  661. &LaterStreamInfoSize
  662. );
  663. if (NT_SUCCESS( Status )) {
  664. if (StreamInfoSize == LaterStreamInfoSize) {
  665. //
  666. // Compare the original stream info structure with the one we just got,
  667. // and make sure they're identical. If not, punt.
  668. //
  669. ULONG rc = StringInfoCmp(StreamInfoBase, LaterStreamInfoBase, StreamInfoSize);
  670. if (rc == 0) {
  671. //
  672. // Copy the file to the backup file. Success if target exists
  673. // (because the make temporary file command creates it).
  674. //
  675. PHANDLE TargetHandles;
  676. //
  677. // Revert to self to be able to open the multiple streams on the backup file
  678. //
  679. RpcRevertToSelf();
  680. hResult = MyCopyFile(
  681. hSourceFile, // handle to the file we're copying from (source file)
  682. StreamNames, // names of the streams of the source file
  683. StreamHandles, // handles to the streams of the source file
  684. StreamSizes, // sizes of the streams of the source file
  685. StreamCount, // number of streams we're copying, including unnamed data stream
  686. hBackupFile, // Backup file handle
  687. &TargetHandles // new handles of corresponding streams on backup file
  688. );
  689. //
  690. // Even the impersonation failed, it is OK. We already got all the handles we need.
  691. //
  692. ( VOID ) RpcImpersonateClient( NULL );
  693. if (hResult == ERROR_SUCCESS) {
  694. //
  695. // The backup file now exists and has data in it.
  696. // We do not check the error code of WriteLogFile for the following reasons,
  697. // 1. We are overwriting the sectors, out of disk space is not possible. The sectors have
  698. // just been written, defective sector is very unlikely.
  699. // 2. In case, the sector becomes defective between the two writes. More than 99.99%
  700. // we can still finish the job without any problem.
  701. // 3. In real life, it is very unlikely that power down or crash happens here and the sectors
  702. // just become defective right after last write.
  703. //
  704. // When TxF is used later, this will not be an issue.
  705. //
  706. if (LogFileH){
  707. ( VOID )WriteLogFile(
  708. LogFileH,
  709. VolInfo.BytesPerSector,
  710. StatusInfoOffset,
  711. EncryptTmpFileWritten
  712. );
  713. }
  714. hResult = CheckOpenSection(
  715. StreamSizes,
  716. StreamHandles,
  717. StreamCount
  718. );
  719. if ( ERROR_SUCCESS == hResult ){
  720. hResult = CompressStreams(
  721. StreamSizes,
  722. StreamHandles,
  723. COMPRESSION_FORMAT_NONE,
  724. StreamCount
  725. );
  726. if (ERROR_SUCCESS != hResult) {
  727. EfsErrPrint("CompressStreams Failed. Win Error=%d\n",hResult);
  728. }
  729. } else {
  730. DebugLog((DEB_ERROR, "CompressStreams returned %d\n" ,hResult ));
  731. EfsErrPrint("Failed to check the open section. Win Error=%d\n",hResult);
  732. }
  733. if ( ERROR_SUCCESS == hResult ){
  734. //
  735. // Reuse the input data buffer for each stream
  736. // FSCTL call.
  737. //
  738. ( VOID )SendEfs(
  739. Fek,
  740. CurrentEfsStream,
  741. InputData + 3 * sizeof(ULONG),
  742. &EfsDataLength
  743. );
  744. ( VOID ) EncryptFSCTLData(
  745. EFS_SET_ENCRYPT,
  746. EFS_ENCRYPT_STREAM,
  747. EFS_ENCRYPT_STREAM,
  748. InputData + 3*sizeof(ULONG),
  749. EfsDataLength,
  750. InputData,
  751. &InputDataSize
  752. );
  753. //
  754. // Copy each stream from the backup to the original.
  755. // CopyFileStreams attempts to undo things in case of problems,
  756. // so we just have to report success or failure.
  757. //
  758. hResult = CopyFileStreams(
  759. TargetHandles, // handles to streams on the backup file
  760. StreamHandles, // handles to streams on the source file
  761. StreamCount, // number of streams
  762. StreamSizes, // sizes of streams
  763. Encrypting, // mark StreamHandles as Encrypted before copy
  764. InputData, // FSCTL input data
  765. InputDataSize, // FSCTL input data size
  766. &CleanupSuccessful
  767. );
  768. if (hResult != ERROR_SUCCESS) {
  769. EfsErrPrint("CopyFileStreams Failed. Win Error=%d\n",hResult);
  770. DebugLog((DEB_ERROR, "CopyFileStreams returned %d\n" ,hResult ));
  771. }
  772. }
  773. LsapFreeLsaHeap( Fek );
  774. Fek = NULL;
  775. if (hResult == ERROR_SUCCESS || CleanupSuccessful) {
  776. if (hResult == ERROR_SUCCESS) {
  777. //
  778. // Encryption is almost done. The file is still in a transit status
  779. // No error checking for writing the log file for the same reason
  780. // mentioned above.
  781. //
  782. if (LogFileH){
  783. ( VOID )WriteLogFile(
  784. LogFileH,
  785. VolInfo.BytesPerSector,
  786. StatusInfoOffset,
  787. EncryptionDone
  788. );
  789. }
  790. //
  791. // Reuse the InputData buffer.
  792. // FSCTL Mark encryption success
  793. //
  794. Status = SendSkFsctl(
  795. 0,
  796. 0,
  797. EFS_ENCRYPT_DONE,
  798. InputData,
  799. InputDataSize,
  800. hSourceFile,
  801. FSCTL_ENCRYPTION_FSCTL_IO,
  802. &IoStatusBlock
  803. );
  804. } else {
  805. //
  806. // FSCTL Fail Encrypting. We can reuse the InputData.
  807. // No stream has been encrypted yet.
  808. // Decrypt File will do the trick to restore the file status.
  809. //
  810. if (LogFileH){
  811. ( VOID )WriteLogFile(
  812. LogFileH,
  813. VolInfo.BytesPerSector,
  814. StatusInfoOffset,
  815. EncryptionBackout
  816. );
  817. }
  818. ( VOID ) EndErrorEncryptFile(
  819. hSourceFile,
  820. InputData,
  821. InputDataSize,
  822. &IoStatusBlock
  823. );
  824. }
  825. if (LogFileH){
  826. ( VOID )WriteLogFile(
  827. LogFileH,
  828. VolInfo.BytesPerSector,
  829. StatusInfoOffset,
  830. EncryptionSrcDone
  831. );
  832. }
  833. //
  834. // Either the operation worked, or it failed but we managed to clean
  835. // up after ourselves. In either case, we no longer need the backup
  836. // file or the log file.
  837. //
  838. // Delete the backup file first.
  839. //
  840. LONG j;
  841. // Do we need delete each stream?
  842. for (j=StreamCount - 1 ; j >= 0 ; j--) {
  843. MarkFileForDelete( TargetHandles[j] );
  844. }
  845. } else {
  846. //
  847. // The operation failed and we couldn't clean up. Keep the
  848. // log file and the backup file around so we can retry on
  849. // reboot.
  850. //
  851. if (LogFileH){
  852. KeepLogFile = TRUE;
  853. ( VOID )WriteLogFile(
  854. LogFileH,
  855. VolInfo.BytesPerSector,
  856. StatusInfoOffset,
  857. EncryptionMessup
  858. );
  859. }
  860. }
  861. //
  862. // Regardless of what happened, we don't need these any more.
  863. //
  864. LONG j;
  865. for ( j = StreamCount -1 ; j >=0; j--) {
  866. CloseHandle( TargetHandles[j] );
  867. }
  868. hBackupFile = 0;
  869. LsapFreeLsaHeap( TargetHandles );
  870. } else {
  871. //
  872. // We couldn't copy everything to the backup file.
  873. // No need to record error log information after this point.
  874. // Tell the driver that the operation has failed.
  875. //
  876. // MyCopyFile has already taken care of cleaning up the
  877. // backup file.
  878. //
  879. hBackupFile = 0;
  880. DebugLog((DEB_ERROR, "MyCopyFile failed, error = %d\n" ,hResult ));
  881. LsapFreeLsaHeap( Fek );
  882. Fek = NULL;
  883. //
  884. // FSCTL Fail Encrypting. We can reuse the InputData.
  885. // No stream has been encrypted yet.
  886. // Decrypt File will do the trick to restore the file status.
  887. //
  888. //
  889. // We ignore the return status from FSCTL call,
  890. // If it is failed, the only way to restore the status
  891. // is by rebooting the system.
  892. //
  893. // Robert Reichel, you need think about what happened if
  894. // the following call failed, although it is very unlikely.
  895. // If the call fails and the log file gets removed, the file
  896. // will be unaccessible. Convert the return code to hResult is
  897. // obviously not correct.
  898. //
  899. ( VOID ) EndErrorEncryptFile(
  900. hSourceFile,
  901. InputData,
  902. InputDataSize,
  903. &IoStatusBlock
  904. );
  905. EfsErrPrint("Failed to make a copy of the file. Win Error=%d\n",hResult);
  906. }
  907. } else {
  908. //
  909. // Somebody added/removed stream(s).
  910. // FSCTL Fail Encrypting. We can reuse the InputData.
  911. // No stream has been encrypted yet.
  912. // Decrypt File will do the trick to restore the file status.
  913. //
  914. MarkFileForDelete( hBackupFile );
  915. LsapFreeLsaHeap( Fek );
  916. Fek = NULL;
  917. ( VOID ) EndErrorEncryptFile(
  918. hSourceFile,
  919. InputData,
  920. InputDataSize,
  921. &IoStatusBlock
  922. );
  923. hResult = ERROR_ENCRYPTION_FAILED;
  924. EfsErrPrint("Streams changed while doing encryption, StringInfoCmp(). Win Error=%d\n",hResult);
  925. }
  926. } else {
  927. //
  928. // Stream info size changed
  929. // FSCTL Fail Encrypting. We can reuse the InputData.
  930. // No stream has been encrypted yet.
  931. // Decrypt File will do the trick to restore the file status.
  932. //
  933. MarkFileForDelete( hBackupFile );
  934. LsapFreeLsaHeap( Fek );
  935. Fek = NULL;
  936. //
  937. // We ignore the return status from FSCTL call,
  938. // If it is failed, the only way to restore the status
  939. // is by rebooting the system.
  940. //
  941. // Robert Reichel, you need think about what happened if
  942. // the following call failed, although it is very unlikely.
  943. // If the call fails and the log file gets removed, the file
  944. // will be unaccessible. Convert the return code to hResult is
  945. // obviously not correct.
  946. //
  947. ( VOID ) EndErrorEncryptFile(
  948. hSourceFile,
  949. InputData,
  950. InputDataSize,
  951. &IoStatusBlock
  952. );
  953. hResult = ERROR_ENCRYPTION_FAILED;
  954. EfsErrPrint("Streams changed while doing encryption, Size not eaqual. Win Error=%d\n",hResult);
  955. }
  956. LsapFreeLsaHeap( LaterStreamInfoBase );
  957. } else {
  958. //
  959. // GetStreamInformation() Failed
  960. // FSCTL Fail Encrypting. We can reuse the InputData.
  961. // No stream has been encrypted yet.
  962. // Decrypt File will do the trick to restore the file status.
  963. //
  964. MarkFileForDelete( hBackupFile );
  965. ( VOID ) EndErrorEncryptFile(
  966. hSourceFile,
  967. InputData,
  968. InputDataSize,
  969. &IoStatusBlock
  970. );
  971. LsapFreeLsaHeap( Fek );
  972. Fek = NULL;
  973. hResult = RtlNtStatusToDosError( Status );
  974. DebugLog((DEB_ERROR, "GetStreamInformation failed, error = %d\n" ,hResult ));
  975. EfsErrPrint("Cannot get the Streams for verification. Win Error=%d\n",hResult);
  976. }
  977. } else {
  978. //
  979. // Set encryption failed. No bits are turned on.
  980. // Only the unnamed data stream is created in temp file
  981. //
  982. MarkFileForDelete( hBackupFile );
  983. LsapFreeLsaHeap( Fek );
  984. Fek = NULL;
  985. DebugLog((DEB_ERROR, "EncryptFileSrv: NtFsControlFile failed, status = (%x)\n" ,Status ));
  986. hResult = RtlNtStatusToDosError( Status );
  987. //
  988. // Make sure the error was mapped
  989. //
  990. if (hResult == ERROR_MR_MID_NOT_FOUND) {
  991. DebugLog((DEB_WARN, "Unable to map NT Error (%x) to Win32 error, returning ERROR_ENCRYPTION_FAILED\n" , Status ));
  992. hResult = ERROR_ENCRYPTION_FAILED;
  993. }
  994. EfsErrPrint("Failed to write the $EFS or turn on the bit. Win Error=%d\n",hResult);
  995. }
  996. } else {
  997. //
  998. // Create Backup File failed or write log file failed
  999. // Temp file is already deleted.
  1000. //
  1001. LsapFreeLsaHeap( Fek );
  1002. Fek = NULL;
  1003. DebugLog((DEB_ERROR, "EncryptFileSrv: CreateBackupFile or CreateLogHeader failed, status = (%x)\n" ,Status ));
  1004. hResult = RtlNtStatusToDosError( Status );
  1005. //
  1006. // Make sure the error was mapped
  1007. //
  1008. if (hResult == ERROR_MR_MID_NOT_FOUND) {
  1009. DebugLog((DEB_WARN, "Unable to map NT Error (%x) to Win32 error, returning ERROR_ENCRYPTION_FAILED\n" , Status ));
  1010. hResult = ERROR_ENCRYPTION_FAILED;
  1011. }
  1012. }
  1013. if ( hBackupFile ){
  1014. CloseHandle( hBackupFile );
  1015. hBackupFile = 0;
  1016. }
  1017. if ( InputData ){
  1018. LsapFreeLsaHeap( InputData );
  1019. }
  1020. } else {
  1021. LsapFreeLsaHeap( Fek );
  1022. Fek = NULL;
  1023. hResult = ERROR_NOT_ENOUGH_MEMORY;
  1024. EfsErrPrint("Out of memory.\n");
  1025. }
  1026. LsapFreeLsaHeap( CurrentEfsStream );
  1027. } else {
  1028. hResult = GetLastError();
  1029. DebugLog((DEB_ERROR, "ConstructEFS returned %x\n" ,hResult ));
  1030. LsapFreeLsaHeap( Fek );
  1031. Fek = NULL;
  1032. EfsErrPrint("Failed to generate the FEK. Win Error=%d\n",hResult);
  1033. }
  1034. } else {
  1035. hResult = GetLastError();
  1036. EfsErrPrint("Failed to generate the FEK. Win Error=%d\n",hResult);
  1037. }
  1038. CleanupOpenFileStreams(
  1039. StreamHandles,
  1040. StreamNames,
  1041. StreamSizes,
  1042. NULL,
  1043. hSourceFile,
  1044. StreamCount
  1045. );
  1046. StreamHandles = NULL;
  1047. StreamNames = NULL;
  1048. hSourceFile = NULL;
  1049. } else {
  1050. DebugLog((DEB_ERROR, "OpenFileStreams returned %d\n" ,hResult ));
  1051. EfsErrPrint("Failed to open all the streams. Win Error=%d\n",hResult);
  1052. }
  1053. LsapFreeLsaHeap( StreamInfoBase );
  1054. StreamInfoBase = NULL;
  1055. } else {
  1056. //
  1057. // Unable to get stream information
  1058. //
  1059. DebugLog((DEB_ERROR, "Unable to obtain stream information, status = %x\n" ,Status ));
  1060. hResult = RtlNtStatusToDosError( Status );
  1061. //
  1062. // Make sure the error was mapped
  1063. //
  1064. if (hResult == ERROR_MR_MID_NOT_FOUND) {
  1065. DebugLog((DEB_WARN, "Unable to map NT Error (%x) to Win32 error, returning ERROR_ENCRYPTION_FAILED\n" , Status ));
  1066. hResult = ERROR_ENCRYPTION_FAILED;
  1067. }
  1068. EfsErrPrint("Failed to get all streams. Win Error=%d\n",hResult);
  1069. }
  1070. }
  1071. //
  1072. // Free ParentEfsStream
  1073. //
  1074. if ( ParentEfsStream ){
  1075. LsapFreeLsaHeap( ParentEfsStream );
  1076. }
  1077. } else {
  1078. //
  1079. // GetParentEfsStream failed
  1080. //
  1081. hResult = RtlNtStatusToDosError( Status );
  1082. //
  1083. // Make sure the error was mapped
  1084. //
  1085. if (hResult == ERROR_MR_MID_NOT_FOUND) {
  1086. DebugLog((DEB_WARN, "Unable to map NT Error (%x) to Win32 error, returning ERROR_ENCRYPTION_FAILED\n" , Status ));
  1087. hResult = ERROR_ENCRYPTION_FAILED;
  1088. }
  1089. EfsErrPrint("GetParentEfsStream failed. Win Error=%d\n",hResult);
  1090. }
  1091. } else {
  1092. //
  1093. // Either get volume info failed or get target file ID failed
  1094. //
  1095. if ( !NT_SUCCESS(Status1) ){
  1096. Status = Status1;
  1097. }
  1098. hResult = RtlNtStatusToDosError( Status );
  1099. //
  1100. // Make sure the error was mapped
  1101. //
  1102. if (hResult == ERROR_MR_MID_NOT_FOUND) {
  1103. DebugLog((DEB_WARN, "Unable to map NT Error (%x) to Win32 error, returning ERROR_ENCRYPTION_FAILED\n" , Status ));
  1104. hResult = ERROR_ENCRYPTION_FAILED;
  1105. }
  1106. EfsErrPrint("Either get volume info failed or get target file ID failed. Win Error=%d\n",hResult);
  1107. }
  1108. if ( hSourceFile ){
  1109. CloseHandle( hSourceFile );
  1110. }
  1111. } else {
  1112. //
  1113. // Open source file failed
  1114. //
  1115. hResult = GetLastError();
  1116. EfsErrPrint("EFS Open source file failed. Win Error=%d FileName=%ws\n", hResult, SourceFileName);
  1117. }
  1118. if (!KeepLogFile && LogFileH) {
  1119. //
  1120. // Delete the Log File
  1121. //
  1122. MarkFileForDelete( LogFileH );
  1123. }
  1124. LsapFreeLsaHeap( SourceFileName );
  1125. if (hResult != ERROR_SUCCESS) {
  1126. DebugLog((DEB_WARN, "EncryptFileSrv returning %x\n", hResult ));
  1127. }
  1128. return( hResult );
  1129. }
  1130. DWORD
  1131. DecryptFileSrv(
  1132. IN PUNICODE_STRING SourceFileNameU,
  1133. IN HANDLE LogFileH,
  1134. IN ULONG Recovery
  1135. )
  1136. /*++
  1137. Routine Description:
  1138. This routine is the top level routine of the EncryptFile API. It
  1139. opens the passed source file and copies all of its data streams to
  1140. a backup file in a known location. It then marks all of the streams
  1141. of the source as encrypted, and copies them back.
  1142. Arguments:
  1143. SourceFileName - Supplies a Unicode string with the name of
  1144. the file to be encrypted.
  1145. LogFileH - Log file handle. Log file is zero size when passed in.
  1146. Recovery - If the decryption is for recovery or not
  1147. Return Value:
  1148. ERROR_SUCCESS on success, other on failure.
  1149. --*/
  1150. {
  1151. BOOL b = TRUE;
  1152. BOOLEAN CleanupSuccessful = FALSE;
  1153. BOOLEAN KeepLogFile = FALSE;
  1154. ULONG StatusInfoOffset = 0 ;
  1155. DWORD hResult = ERROR_SUCCESS;
  1156. DWORD FileAttributes;
  1157. HANDLE FileHandle;
  1158. HANDLE hSourceFile = NULL ;
  1159. HANDLE hBackupFile = 0;
  1160. PHANDLE StreamHandles = NULL;
  1161. LPWSTR SourceFileName;
  1162. LPWSTR BackupFileName;
  1163. FILE_FS_SIZE_INFORMATION VolInfo;
  1164. FILE_INTERNAL_INFORMATION SourceID;
  1165. FILE_INTERNAL_INFORMATION BackupID;
  1166. NTSTATUS Status = STATUS_SUCCESS;
  1167. OBJECT_ATTRIBUTES Obja;
  1168. PFILE_STREAM_INFORMATION LaterStreamInfoBase = NULL;
  1169. PFILE_STREAM_INFORMATION StreamInfoBase = NULL;
  1170. PEFS_STREAM_SIZE StreamSizes = NULL;
  1171. PUNICODE_STRING StreamNames = NULL;
  1172. UINT TmpResult;
  1173. ULONG LaterStreamInfoSize = 0;
  1174. ULONG StreamCount = 0;
  1175. ULONG StreamInfoSize = 0;
  1176. ULONG i;
  1177. DWORD tmpDW;
  1178. IO_STATUS_BLOCK IoStatusBlock;
  1179. ULONG InputDataSize;
  1180. ULONG EfsDataLength;
  1181. PUCHAR InputData;
  1182. ULONG CreateOption = FILE_SYNCHRONOUS_IO_NONALERT;
  1183. UNICODE_STRING SrcNtName;
  1184. WORD WebDavPath = 0;
  1185. if (!LogFileH) {
  1186. //
  1187. // No LogFile means WEBDAVPATH
  1188. //
  1189. WebDavPath = WEBDAVPATH;
  1190. }
  1191. //
  1192. // Convert the source file name into an LPWSTR
  1193. //
  1194. SourceFileName = (LPWSTR)LsapAllocateLsaHeap( SourceFileNameU->Length + sizeof( UNICODE_NULL ));
  1195. if (SourceFileName == NULL) {
  1196. if (LogFileH) {
  1197. MarkFileForDelete( LogFileH );
  1198. }
  1199. return( ERROR_NOT_ENOUGH_MEMORY );
  1200. }
  1201. InputDataSize = 7 * sizeof ( ULONG ) + 2 * sizeof ( DriverSessionKey );
  1202. InputData = (PUCHAR)LsapAllocateLsaHeap( InputDataSize );
  1203. if ( InputData == NULL ) {
  1204. if (LogFileH) {
  1205. MarkFileForDelete( LogFileH );
  1206. }
  1207. LsapFreeLsaHeap( SourceFileName );
  1208. return( ERROR_NOT_ENOUGH_MEMORY );
  1209. }
  1210. EfsDataLength = InputDataSize - 3 * sizeof ( ULONG );
  1211. SourceFileName[SourceFileNameU->Length/sizeof(WCHAR)] = UNICODE_NULL;
  1212. RtlCopyMemory( SourceFileName, SourceFileNameU->Buffer, SourceFileNameU->Length );
  1213. DebugLog((DEB_TRACE_EFS, "Decrypting file %ws \n", SourceFileName));
  1214. FileAttributes = GetFileAttributes( SourceFileName );
  1215. if (FileAttributes == -1) {
  1216. if (LogFileH) {
  1217. MarkFileForDelete( LogFileH );
  1218. }
  1219. LsapFreeLsaHeap( SourceFileName );
  1220. LsapFreeLsaHeap( InputData );
  1221. return GetLastError();
  1222. }
  1223. if (!(FileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
  1224. CreateOption |= FILE_OPEN_REPARSE_POINT;
  1225. }
  1226. b = RtlDosPathNameToNtPathName_U(
  1227. SourceFileName,
  1228. &SrcNtName,
  1229. NULL,
  1230. NULL
  1231. );
  1232. if ( b ){
  1233. InitializeObjectAttributes(
  1234. &Obja,
  1235. &SrcNtName,
  1236. OBJ_CASE_INSENSITIVE,
  1237. 0,
  1238. NULL
  1239. );
  1240. Status = NtCreateFile(
  1241. &hSourceFile,
  1242. FILE_READ_DATA | FILE_WRITE_DATA | FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES | SYNCHRONIZE,
  1243. &Obja,
  1244. &IoStatusBlock,
  1245. NULL,
  1246. 0,
  1247. 0,
  1248. FILE_OPEN,
  1249. CreateOption,
  1250. NULL,
  1251. 0
  1252. );
  1253. //
  1254. // Free the NT name
  1255. //
  1256. RtlFreeHeap(
  1257. RtlProcessHeap(),
  1258. 0,
  1259. SrcNtName.Buffer
  1260. );
  1261. } else {
  1262. //
  1263. // The error code here is not quite accurate here. It is very unlikely
  1264. // getting here. Possibly out of memory
  1265. //
  1266. Status = STATUS_ENCRYPTION_FAILED;
  1267. hResult = GetLastError();
  1268. }
  1269. if ( NT_SUCCESS( Status ) ) {
  1270. //
  1271. // Determine if this path is to a directory or a file. If it's a directory,
  1272. // we have very little to do.
  1273. //
  1274. Status = NtQueryVolumeInformationFile(
  1275. hSourceFile,
  1276. &IoStatusBlock,
  1277. &VolInfo,
  1278. sizeof ( FILE_FS_SIZE_INFORMATION ),
  1279. FileFsSizeInformation
  1280. );
  1281. if ( NT_SUCCESS( Status ) && (WebDavPath != WEBDAVPATH) ){
  1282. Status = NtQueryInformationFile(
  1283. hSourceFile,
  1284. &IoStatusBlock,
  1285. &SourceID,
  1286. sizeof ( FILE_INTERNAL_INFORMATION ),
  1287. FileInternalInformation
  1288. );
  1289. }
  1290. if ( !NT_SUCCESS( Status ) ) {
  1291. CloseHandle( hSourceFile );
  1292. if (LogFileH) {
  1293. MarkFileForDelete( LogFileH );
  1294. }
  1295. LsapFreeLsaHeap( SourceFileName );
  1296. LsapFreeLsaHeap( InputData );
  1297. hResult = RtlNtStatusToDosError( Status );
  1298. //
  1299. // Make sure the error was mapped
  1300. //
  1301. if (hResult == ERROR_MR_MID_NOT_FOUND) {
  1302. DebugLog((DEB_WARN, "Unable to map NT Error (%x) to Win32 error, returning ERROR_ENCRYPTION_FAILED\n" , Status ));
  1303. hResult = ERROR_DECRYPTION_FAILED;
  1304. }
  1305. return hResult;
  1306. }
  1307. if (FileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
  1308. //
  1309. // We do not check the operation of the LOG.
  1310. // Should we fail the normal operation just because the LOG operations
  1311. // failed? The answer is probably not. The chance to use the LOG file is very
  1312. // slim. We will use TxF when it is ready and we have time to deal with this.
  1313. //
  1314. if (LogFileH) {
  1315. CreateLogHeader(
  1316. LogFileH,
  1317. VolInfo.BytesPerSector,
  1318. &(SourceID.IndexNumber),
  1319. NULL,
  1320. SourceFileName,
  1321. NULL,
  1322. Decrypting,
  1323. BeginDecryptDir,
  1324. NULL
  1325. );
  1326. }
  1327. //
  1328. // FSCTL Do Directory stuff
  1329. //
  1330. Status = SendSkFsctl(
  1331. EFS_DECRYPT_STREAM,
  1332. EFS_DECRYPT_DIRSTR,
  1333. EFS_SET_ENCRYPT,
  1334. InputData,
  1335. InputDataSize,
  1336. hSourceFile,
  1337. FSCTL_SET_ENCRYPTION,
  1338. &IoStatusBlock
  1339. );
  1340. if ( NT_SUCCESS( Status ) && IoStatusBlock.Information ){
  1341. //
  1342. // IoStatusBlock.Information != 0 means there is no more encrypted
  1343. // streams in the file (or dir).
  1344. // If the following call failed, we could hardly restore the dir to the
  1345. // perfect condition. It is very unlikely to fail here while we
  1346. // succeed above.
  1347. //
  1348. Status = SendSkFsctl(
  1349. EFS_DECRYPT_FILE,
  1350. EFS_DECRYPT_DIRFILE,
  1351. EFS_SET_ENCRYPT,
  1352. InputData,
  1353. InputDataSize,
  1354. hSourceFile,
  1355. FSCTL_SET_ENCRYPTION,
  1356. &IoStatusBlock
  1357. );
  1358. } else if ( NT_SUCCESS( Status ) && (IoStatusBlock.Information == 0)) {
  1359. //
  1360. // More than 1 streams on the directory were encrypted. Log it.
  1361. //
  1362. EfsLogEntry(
  1363. EVENTLOG_ERROR_TYPE,
  1364. 0,
  1365. EFS_DIR_MULTISTR_ERROR,
  1366. 1,
  1367. 0,
  1368. (LPCWSTR *)&SourceFileName,
  1369. NULL
  1370. );
  1371. }
  1372. CloseHandle( hSourceFile );
  1373. if (LogFileH) {
  1374. MarkFileForDelete( LogFileH );
  1375. }
  1376. LsapFreeLsaHeap( SourceFileName );
  1377. LsapFreeLsaHeap( InputData );
  1378. if ( NT_SUCCESS( Status ) ){
  1379. return( ERROR_SUCCESS );
  1380. } else {
  1381. return(ERROR_DECRYPTION_FAILED);
  1382. }
  1383. }
  1384. //
  1385. // Enumerate all the streams on the file
  1386. //
  1387. Status = GetStreamInformation(
  1388. hSourceFile,
  1389. &StreamInfoBase, // Free this
  1390. &StreamInfoSize
  1391. );
  1392. if (NT_SUCCESS( Status )) {
  1393. hResult = OpenFileStreams(
  1394. hSourceFile,
  1395. 0,
  1396. OPEN_FOR_DEC,
  1397. StreamInfoBase,
  1398. FILE_READ_DATA | FILE_WRITE_DATA | FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES | SYNCHRONIZE,
  1399. FILE_OPEN,
  1400. FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_REPARSE_POINT,
  1401. &VolInfo,
  1402. &StreamNames, // Don't free this!
  1403. &StreamHandles, // Free this
  1404. &StreamSizes, // Free this
  1405. &StreamCount
  1406. );
  1407. if (hResult == ERROR_SUCCESS) {
  1408. //
  1409. // This routine creates the backup file.
  1410. //
  1411. Status = CreateBackupFile(
  1412. SourceFileNameU,
  1413. &hBackupFile,
  1414. &BackupID,
  1415. &BackupFileName
  1416. );
  1417. //
  1418. // If power down happens right here before
  1419. // the log file header is written, we will have a zero size
  1420. // temp file left on the disk. This is very unlikely and not
  1421. // a big deal we have a zero size file left on the disk.
  1422. //
  1423. if ( NT_SUCCESS(Status) ){
  1424. if (LogFileH) {
  1425. Status = CreateLogHeader(
  1426. LogFileH,
  1427. VolInfo.BytesPerSector,
  1428. &(SourceID.IndexNumber),
  1429. &(BackupID.IndexNumber),
  1430. SourceFileName,
  1431. BackupFileName,
  1432. Decrypting,
  1433. BeginDecryptFile,
  1434. &StatusInfoOffset
  1435. );
  1436. }
  1437. //
  1438. // BackupFile name not needed any more.
  1439. //
  1440. LsapFreeLsaHeap( BackupFileName );
  1441. if ( NT_SUCCESS(Status) ){
  1442. if (LogFileH) {
  1443. Status = WriteLogFile(
  1444. LogFileH,
  1445. VolInfo.BytesPerSector,
  1446. StatusInfoOffset,
  1447. BeginDecryptFile
  1448. );
  1449. }
  1450. if ( !NT_SUCCESS(Status) ){
  1451. //
  1452. // Delete the backup file
  1453. //
  1454. MarkFileForDelete( hBackupFile );
  1455. CloseHandle( hBackupFile );
  1456. hBackupFile = 0;
  1457. }
  1458. } else {
  1459. MarkFileForDelete( hBackupFile );
  1460. CloseHandle( hBackupFile );
  1461. hBackupFile = 0;
  1462. }
  1463. } else {
  1464. //
  1465. // Fail to create the backup file
  1466. // Log it.
  1467. //
  1468. EfsLogEntry(
  1469. EVENTLOG_ERROR_TYPE,
  1470. 0,
  1471. EFS_TMP_FILE_ERROR,
  1472. 1,
  1473. sizeof(NTSTATUS),
  1474. (LPCWSTR *)&SourceFileName,
  1475. &Status
  1476. );
  1477. }
  1478. if ( NT_SUCCESS(Status) ){
  1479. //
  1480. // We have handles to all of the streams of the file
  1481. //
  1482. // Enter "Decrypting" state here. FSCTL call.
  1483. //
  1484. // All failures from here on out need to be closed
  1485. // with another FSCTL call.
  1486. //
  1487. Status = SendSkFsctl(
  1488. 0,
  1489. 0,
  1490. EFS_DECRYPT_BEGIN,
  1491. InputData,
  1492. InputDataSize,
  1493. hSourceFile,
  1494. FSCTL_ENCRYPTION_FSCTL_IO,
  1495. &IoStatusBlock
  1496. );
  1497. }
  1498. if ( !NT_SUCCESS( Status ) ){
  1499. //
  1500. // Nothing has been done to the file.
  1501. //
  1502. CleanupOpenFileStreams(
  1503. StreamHandles,
  1504. StreamNames,
  1505. StreamSizes,
  1506. StreamInfoBase,
  1507. hSourceFile,
  1508. StreamCount
  1509. );
  1510. StreamHandles = NULL;
  1511. StreamNames = NULL;
  1512. StreamInfoBase = NULL;
  1513. if (LogFileH) {
  1514. MarkFileForDelete( LogFileH );
  1515. }
  1516. if ( hBackupFile ) {
  1517. MarkFileForDelete( hBackupFile );
  1518. CloseHandle( hBackupFile );
  1519. }
  1520. LsapFreeLsaHeap( SourceFileName );
  1521. LsapFreeLsaHeap( InputData );
  1522. hResult = RtlNtStatusToDosError( Status );
  1523. //
  1524. // Make sure the error was mapped
  1525. //
  1526. if (hResult == ERROR_MR_MID_NOT_FOUND) {
  1527. DebugLog((DEB_WARN, "Unable to map NT Error (%x) to Win32 error, returning ERROR_ENCRYPTION_FAILED\n" , Status ));
  1528. hResult = ERROR_DECRYPTION_FAILED;
  1529. }
  1530. return hResult;
  1531. }
  1532. //
  1533. // Enumerate the streams again, and make sure nothing
  1534. // has changed. From this point on, the file is in TRANSITION
  1535. // status. Any failure should not delete the logfile, unless the FSCTL
  1536. // EFS_ENCRYPT_DONE is called
  1537. //
  1538. Status = GetStreamInformation(
  1539. hSourceFile,
  1540. &LaterStreamInfoBase, // Free this
  1541. &LaterStreamInfoSize
  1542. );
  1543. if (NT_SUCCESS( Status )) {
  1544. if (StreamInfoSize == LaterStreamInfoSize) {
  1545. //
  1546. // Compare the original stream info structure with the one we just got,
  1547. // and make sure they're identical. If not, punt.
  1548. //
  1549. ULONG rc = StringInfoCmp(StreamInfoBase, LaterStreamInfoBase, StreamInfoSize);
  1550. if (rc == 0) {
  1551. //
  1552. // Copy the file to the backup file. Success if target exists
  1553. // (because the make temporary file command creates it).
  1554. //
  1555. PHANDLE TargetHandles = NULL;
  1556. //
  1557. // Revert to self to open multiple streams on the backup file
  1558. //
  1559. RpcRevertToSelf();
  1560. hResult = MyCopyFile(
  1561. hSourceFile, // handle to the file we're copying from (source file)
  1562. StreamNames, // names of the streams of the source file
  1563. StreamHandles, // handles to the streams of the source file
  1564. StreamSizes, // sizes of the streams of the source file
  1565. StreamCount, // number of streams we're copying, including unnamed data stream
  1566. hBackupFile, // Backup file handle
  1567. &TargetHandles // new handles of corresponding streams on backup file
  1568. );
  1569. //
  1570. // Even the impersonation failed, it is OK. We already got all the handles we need.
  1571. //
  1572. ( VOID ) RpcImpersonateClient( NULL );
  1573. if (hResult == ERROR_SUCCESS) {
  1574. //
  1575. // The backup file now exists and has data in it.
  1576. // We do not check the error code of WriteLogFile for the following reasons,
  1577. // 1. We are overwriting the sectors, out of disk space is not possible. The sectors have
  1578. // just been written, defective sector is very unlikely.
  1579. // 2. In case, the sector becomes defective between the two writes. More than 99.99%
  1580. // we can still finish the job without any problem.
  1581. // 3. In real life, it is very unlikely that power down or crash happens here and the sectors
  1582. // just become defective right after last write.
  1583. //
  1584. // When later TxF is used, we will not manage the log file.
  1585. //
  1586. if (LogFileH) {
  1587. ( VOID )WriteLogFile(
  1588. LogFileH,
  1589. VolInfo.BytesPerSector,
  1590. StatusInfoOffset,
  1591. DecryptTmpFileWritten
  1592. );
  1593. }
  1594. hResult = CheckOpenSection(
  1595. StreamSizes,
  1596. StreamHandles,
  1597. StreamCount
  1598. );
  1599. if ( ERROR_SUCCESS == hResult ){
  1600. //
  1601. // Reuse the input data buffer for each stream
  1602. // FSCTL call.
  1603. //
  1604. ( VOID )SendHandle(
  1605. hSourceFile,
  1606. InputData + 3 * sizeof( ULONG ),
  1607. &EfsDataLength
  1608. );
  1609. ( VOID ) EncryptFSCTLData(
  1610. EFS_SET_ENCRYPT,
  1611. EFS_DECRYPT_STREAM,
  1612. EFS_DECRYPT_STREAM,
  1613. InputData + 3 * sizeof(ULONG),
  1614. EfsDataLength,
  1615. InputData,
  1616. &InputDataSize
  1617. );
  1618. //
  1619. // Copy each stream from the backup to the original.
  1620. // CopyFileStreams attempts to undo things in case of problems,
  1621. // so we just have to report success or failure.
  1622. //
  1623. hResult = CopyFileStreams(
  1624. TargetHandles, // handles to streams on the backup file
  1625. StreamHandles, // handles to streams on the source file
  1626. StreamCount, // number of streams
  1627. StreamSizes, // sizes of streams
  1628. Decrypting, // mark StreamHandles as Encrypted before copy
  1629. InputData, // FSCTL input data
  1630. InputDataSize, // FSCTL input data size
  1631. &CleanupSuccessful
  1632. );
  1633. }
  1634. if (hResult == ERROR_SUCCESS ) {
  1635. //
  1636. // Encryption is almost done. The file is still in a transit status
  1637. // No error checking for writing the log file for the same reason
  1638. // mentioned above.
  1639. //
  1640. if (LogFileH) {
  1641. ( VOID )WriteLogFile(
  1642. LogFileH,
  1643. VolInfo.BytesPerSector,
  1644. StatusInfoOffset,
  1645. DecryptionDone
  1646. );
  1647. }
  1648. //
  1649. // FSCTL Mark Decryption success
  1650. //
  1651. ( VOID ) SendSkFsctl(
  1652. EFS_DECRYPT_FILE,
  1653. EFS_DECRYPT_FILE,
  1654. EFS_SET_ENCRYPT,
  1655. InputData,
  1656. InputDataSize,
  1657. hSourceFile,
  1658. FSCTL_SET_ENCRYPTION,
  1659. &IoStatusBlock
  1660. );
  1661. //
  1662. // Delete the backup file first.
  1663. //
  1664. LONG j;
  1665. for (j = StreamCount - 1 ; j >= 0 ; j--) {
  1666. MarkFileForDelete( TargetHandles[j] );
  1667. }
  1668. } else {
  1669. if ( CleanupSuccessful ){
  1670. //
  1671. // The operation failed, but we could back out cleanly.
  1672. // Delete the backup file first.
  1673. //
  1674. LONG j;
  1675. for (j = StreamCount - 1 ; j >= 0 ; j--) {
  1676. MarkFileForDelete( TargetHandles[j] );
  1677. }
  1678. } else {
  1679. //
  1680. // The operation failed and we couldn't clean up. Keep the
  1681. // log file and the backup file around so we can retry on
  1682. // reboot.
  1683. //
  1684. KeepLogFile = TRUE;
  1685. }
  1686. }
  1687. //
  1688. // Regardless of what happened, we don't need these any more.
  1689. //
  1690. LONG j;
  1691. for (j=StreamCount - 1 ; j >= 0 ; j--) {
  1692. CloseHandle( TargetHandles[j] );
  1693. }
  1694. LsapFreeLsaHeap( TargetHandles );
  1695. } else {
  1696. //
  1697. // We couldn't copy everything to the backup file.
  1698. //
  1699. // Tell the driver that the operation has failed.
  1700. //
  1701. // MyCopyFile has already taken care of cleaning up the
  1702. // backup file.
  1703. //
  1704. DebugLog((DEB_ERROR, "MyCopyFile failed, error = %d\n" ,hResult ));
  1705. //
  1706. // FSCTL Fail Decrypting
  1707. // EFS_ENCRYPT_DONE will do the trick.
  1708. //
  1709. ( VOID ) SendSkFsctl(
  1710. 0,
  1711. 0,
  1712. EFS_ENCRYPT_DONE,
  1713. InputData,
  1714. InputDataSize,
  1715. hSourceFile,
  1716. FSCTL_ENCRYPTION_FSCTL_IO,
  1717. &IoStatusBlock
  1718. );
  1719. if ( hBackupFile ) {
  1720. //
  1721. // MyCopyFile has deleted the backup file
  1722. //
  1723. hBackupFile = 0;
  1724. }
  1725. }
  1726. } else {
  1727. //
  1728. // FSCTL Fail Decrypting
  1729. // EFS_ENCRYPT_DONE will do the trick.
  1730. //
  1731. ( VOID ) SendSkFsctl(
  1732. 0,
  1733. 0,
  1734. EFS_ENCRYPT_DONE,
  1735. InputData,
  1736. InputDataSize,
  1737. hSourceFile,
  1738. FSCTL_ENCRYPTION_FSCTL_IO,
  1739. &IoStatusBlock
  1740. );
  1741. if ( hBackupFile ) {
  1742. MarkFileForDelete( hBackupFile );
  1743. CloseHandle( hBackupFile );
  1744. hBackupFile = 0;
  1745. }
  1746. hResult = ERROR_DECRYPTION_FAILED;
  1747. }
  1748. } else {
  1749. //
  1750. // FSCTL Fail Decrypting
  1751. // EFS_ENCRYPT_DONE will do the trick.
  1752. //
  1753. ( VOID ) SendSkFsctl(
  1754. 0,
  1755. 0,
  1756. EFS_ENCRYPT_DONE,
  1757. InputData,
  1758. InputDataSize,
  1759. hSourceFile,
  1760. FSCTL_ENCRYPTION_FSCTL_IO,
  1761. &IoStatusBlock
  1762. );
  1763. if ( hBackupFile ) {
  1764. MarkFileForDelete( hBackupFile );
  1765. CloseHandle( hBackupFile );
  1766. hBackupFile = 0;
  1767. }
  1768. hResult = ERROR_DECRYPTION_FAILED;
  1769. }
  1770. LsapFreeLsaHeap( LaterStreamInfoBase );
  1771. } else {
  1772. //
  1773. // FSCTL Fail Decrypting
  1774. // EFS_ENCRYPT_DONE will do the trick.
  1775. //
  1776. ( VOID ) SendSkFsctl(
  1777. 0,
  1778. 0,
  1779. EFS_ENCRYPT_DONE,
  1780. InputData,
  1781. InputDataSize,
  1782. hSourceFile,
  1783. FSCTL_ENCRYPTION_FSCTL_IO,
  1784. &IoStatusBlock
  1785. );
  1786. if ( hBackupFile ) {
  1787. MarkFileForDelete( hBackupFile );
  1788. CloseHandle( hBackupFile );
  1789. hBackupFile = 0;
  1790. }
  1791. hResult = RtlNtStatusToDosError( Status );
  1792. //
  1793. // Make sure the error was mapped
  1794. //
  1795. if (hResult == ERROR_MR_MID_NOT_FOUND) {
  1796. DebugLog((DEB_WARN, "Unable to map NT Error (%x) to Win32 error, returning ERROR_ENCRYPTION_FAILED\n" , Status ));
  1797. hResult = ERROR_DECRYPTION_FAILED;
  1798. }
  1799. }
  1800. CleanupOpenFileStreams(
  1801. StreamHandles,
  1802. StreamNames,
  1803. StreamSizes,
  1804. NULL,
  1805. hSourceFile,
  1806. StreamCount
  1807. );
  1808. StreamHandles = NULL;
  1809. StreamNames = NULL;
  1810. hSourceFile = NULL;
  1811. }
  1812. LsapFreeLsaHeap( StreamInfoBase );
  1813. } else {
  1814. hResult = RtlNtStatusToDosError( Status );
  1815. //
  1816. // Make sure the error was mapped
  1817. //
  1818. if (hResult == ERROR_MR_MID_NOT_FOUND) {
  1819. DebugLog((DEB_WARN, "Unable to map NT Error (%x) to Win32 error, returning ERROR_ENCRYPTION_FAILED\n" , Status ));
  1820. hResult = ERROR_DECRYPTION_FAILED;
  1821. }
  1822. }
  1823. if ( hSourceFile ){
  1824. CloseHandle( hSourceFile );
  1825. }
  1826. } else {
  1827. if ( Status != STATUS_ENCRYPTION_FAILED ){
  1828. //
  1829. // NtCreateFile failed
  1830. //
  1831. if (FileAttributes & FILE_ATTRIBUTE_READONLY) {
  1832. hResult = ERROR_FILE_READ_ONLY;
  1833. } else {
  1834. hResult = RtlNtStatusToDosError( Status );
  1835. //
  1836. // Make sure the error was mapped
  1837. //
  1838. if (hResult == ERROR_MR_MID_NOT_FOUND) {
  1839. DebugLog((DEB_WARN, "Unable to map NT Error (%x) to Win32 error, returning ERROR_ENCRYPTION_FAILED\n" , Status ));
  1840. hResult = ERROR_DECRYPTION_FAILED;
  1841. }
  1842. }
  1843. }
  1844. // else Convert Dos name failed
  1845. }
  1846. if (!KeepLogFile && LogFileH) {
  1847. MarkFileForDelete( LogFileH );
  1848. }
  1849. //
  1850. // Free memory
  1851. //
  1852. LsapFreeLsaHeap( SourceFileName );
  1853. LsapFreeLsaHeap( InputData );
  1854. return( hResult );
  1855. }
  1856. DWORD
  1857. MyCopyFile(
  1858. HANDLE hSourceFile,
  1859. PUNICODE_STRING StreamNames,
  1860. PHANDLE StreamHandles,
  1861. PEFS_STREAM_SIZE StreamSizes,
  1862. ULONG StreamCount,
  1863. HANDLE hTargetFile,
  1864. PHANDLE * TargetStreamHandles
  1865. )
  1866. {
  1867. ULONG i;
  1868. NTSTATUS Status;
  1869. PHANDLE TargetHandles;
  1870. DWORD hResult = 0;
  1871. IO_STATUS_BLOCK IoStatusBlock;
  1872. TargetHandles = (PHANDLE)LsapAllocateLsaHeap( StreamCount * sizeof( HANDLE ));
  1873. if (TargetHandles == NULL) {
  1874. return( ERROR_NOT_ENOUGH_MEMORY );
  1875. }
  1876. RtlZeroMemory( TargetHandles, StreamCount * sizeof( HANDLE ));
  1877. for (i=0 ; i<StreamCount ; i++) {
  1878. //
  1879. // For each stream on the source, create a stream with the same name on the target
  1880. //
  1881. if ( (DEF_STR_LEN == StreamNames[i].Length) &&
  1882. !memcmp( StreamNames[i].Buffer,
  1883. DEFAULT_STREAM,
  1884. StreamNames[i].Length
  1885. )){
  1886. //
  1887. // Default stream
  1888. //
  1889. TargetHandles[i] = hTargetFile;
  1890. if ( !(StreamSizes[i].StreamFlag & FILE_ATTRIBUTE_SPARSE_FILE) ){
  1891. //
  1892. // Reserve space for non sparse stream
  1893. //
  1894. FILE_END_OF_FILE_INFORMATION FileSize;
  1895. FileSize.EndOfFile = StreamSizes[i].EOFSize;
  1896. Status = NtSetInformationFile(
  1897. TargetHandles[i],
  1898. &IoStatusBlock,
  1899. &FileSize,
  1900. sizeof(FileSize),
  1901. FileEndOfFileInformation
  1902. );
  1903. } else {
  1904. Status = STATUS_SUCCESS;
  1905. }
  1906. } else {
  1907. OBJECT_ATTRIBUTES Obja;
  1908. PLARGE_INTEGER AllocSize;
  1909. if ( !(StreamSizes[i].StreamFlag & FILE_ATTRIBUTE_SPARSE_FILE) ){
  1910. //
  1911. // Reserve space for non sparse stream
  1912. //
  1913. AllocSize = &(StreamSizes[i].EOFSize);
  1914. } else {
  1915. AllocSize = NULL;
  1916. }
  1917. InitializeObjectAttributes(
  1918. &Obja,
  1919. &StreamNames[i],
  1920. 0,
  1921. hTargetFile,
  1922. NULL
  1923. );
  1924. Status = NtCreateFile(
  1925. &TargetHandles[i],
  1926. #ifdef EFSDBG
  1927. GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE,
  1928. #else
  1929. GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE | DELETE,
  1930. #endif
  1931. &Obja,
  1932. &IoStatusBlock,
  1933. AllocSize,
  1934. 0,
  1935. #ifdef EFSDBG
  1936. FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, // have to share with delete-ers, since the main stream is open for delete
  1937. #else
  1938. FILE_SHARE_DELETE, // have to share with delete-ers, since the main stream is open for delete
  1939. #endif
  1940. FILE_CREATE,
  1941. FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_REPARSE_POINT,
  1942. NULL,
  1943. 0
  1944. );
  1945. if (!NT_SUCCESS( Status )){
  1946. //
  1947. // Just make sure it is zero
  1948. //
  1949. TargetHandles[i] = 0;
  1950. }
  1951. }
  1952. if (NT_SUCCESS( Status )) {
  1953. USHORT State = COMPRESSION_FORMAT_NONE;
  1954. ULONG Length;
  1955. if ( StreamSizes[i].StreamFlag & FILE_ATTRIBUTE_COMPRESSED ){
  1956. State = COMPRESSION_FORMAT_DEFAULT;
  1957. }
  1958. //
  1959. // Return code is not checked. Failing to compress or decompress the
  1960. // the temp file should not prevent the encryption operation.
  1961. //
  1962. (VOID) DeviceIoControl(
  1963. TargetHandles[i],
  1964. FSCTL_SET_COMPRESSION,
  1965. &State,
  1966. sizeof(USHORT),
  1967. NULL,
  1968. 0,
  1969. &Length,
  1970. FALSE
  1971. );
  1972. hResult = CopyStream( TargetHandles[i], StreamHandles[i], &StreamSizes[i] );
  1973. }
  1974. if (!NT_SUCCESS( Status ) || hResult != ERROR_SUCCESS) {
  1975. //
  1976. // We either failed in creating a new stream on the target,
  1977. // or in copying it from the source to the target. Regardless,
  1978. // for each stream we created in the target, delete it.
  1979. //
  1980. ULONG StreamsCreated;
  1981. if (NT_SUCCESS( Status ) || TargetHandles[i]) {
  1982. StreamsCreated = i;
  1983. } else {
  1984. StreamsCreated = i-1;
  1985. }
  1986. ULONG j;
  1987. //
  1988. // Default stream handle is in TargetHandles[0]
  1989. //
  1990. for ( j = 0 ; j <=StreamsCreated ; j++) {
  1991. //
  1992. // Paranoia: check if the handle is valid.
  1993. //
  1994. if (TargetHandles[j]){
  1995. MarkFileForDelete( TargetHandles[j] );
  1996. CloseHandle( TargetHandles[j] );
  1997. }
  1998. }
  1999. LsapFreeLsaHeap( TargetHandles );
  2000. //
  2001. // Just to be safe
  2002. //
  2003. TargetHandles = NULL;
  2004. if (!NT_SUCCESS( Status )) {
  2005. hResult = RtlNtStatusToDosError( Status );
  2006. }
  2007. break;
  2008. }
  2009. }
  2010. *TargetStreamHandles = TargetHandles;
  2011. return( hResult );
  2012. }
  2013. DWORD
  2014. OpenFileStreams(
  2015. IN HANDLE hSourceFile,
  2016. IN ULONG ShareMode,
  2017. IN ULONG Flag,
  2018. IN PFILE_STREAM_INFORMATION StreamInfoBase,
  2019. IN ULONG FileAccess,
  2020. IN ULONG CreateDisposition,
  2021. IN ULONG CreateOption,
  2022. IN PFILE_FS_SIZE_INFORMATION VolInfo,
  2023. OUT PUNICODE_STRING * StreamNames,
  2024. OUT PHANDLE * StreamHandles,
  2025. OUT PEFS_STREAM_SIZE * StreamSizes,
  2026. OUT PULONG StreamCount
  2027. )
  2028. /*++
  2029. Routine Description:
  2030. This routine opens the streams of file hSourceFile.
  2031. Arguments:
  2032. hSourceFile - Supplies an opened handle to the file being worked.
  2033. ShareMode - The share mode to open the streams.
  2034. Flags - The reason for open the streams.
  2035. StreamInfoBase - Information about the streams;
  2036. StreamNames - The names of the streams.
  2037. StreamHandles - The handles of the streams.
  2038. StreamCount - Number strteams in the file.
  2039. FileAccess - Desired access to the streams.
  2040. CreateDisposition - Create disposition of the streams.
  2041. CreateOption - Create options of the streams.
  2042. StreamSizes - the sizes and attributes of the streams.
  2043. Return Value:
  2044. Result of the operation.
  2045. --*/
  2046. {
  2047. NTSTATUS Status;
  2048. PUNICODE_STRING Names = NULL;
  2049. PHANDLE Handles = NULL;
  2050. PEFS_STREAM_SIZE Sizes = NULL;
  2051. DWORD rc = ERROR_SUCCESS;
  2052. PFILE_STREAM_INFORMATION StreamInfo = StreamInfoBase;
  2053. BOOL b;
  2054. //
  2055. // First, count the number of streams
  2056. //
  2057. if (StreamInfoBase == NULL) {
  2058. //
  2059. // No stream to open. TRUE for most DIR.
  2060. //
  2061. *StreamCount = 0;
  2062. return ERROR_SUCCESS;
  2063. }
  2064. *StreamCount = 0;
  2065. while ( StreamInfo ) {
  2066. (*StreamCount)++;
  2067. if (StreamInfo->NextEntryOffset){
  2068. StreamInfo = (PFILE_STREAM_INFORMATION)((PCHAR) StreamInfo + StreamInfo->NextEntryOffset);
  2069. } else {
  2070. StreamInfo = NULL;
  2071. }
  2072. }
  2073. DebugLog((DEB_TRACE_EFS, "Found %d streams\n",*StreamCount));
  2074. //
  2075. // Allocate enough room for pointers and handles to the streams and their names
  2076. //
  2077. Handles = (PHANDLE) LsapAllocateLsaHeap( *StreamCount * sizeof( HANDLE ));
  2078. Names = (PUNICODE_STRING) LsapAllocateLsaHeap( *StreamCount * sizeof( UNICODE_STRING ));
  2079. if ( StreamSizes ){
  2080. Sizes = (PEFS_STREAM_SIZE) LsapAllocateLsaHeap( *StreamCount * sizeof( EFS_STREAM_SIZE ));
  2081. }
  2082. if (Names == NULL || Handles == NULL || (StreamSizes && (Sizes == NULL))) {
  2083. if (Handles != NULL) {
  2084. LsapFreeLsaHeap( Handles );
  2085. }
  2086. if (Names != NULL) {
  2087. LsapFreeLsaHeap( Names );
  2088. }
  2089. if (Sizes != NULL) {
  2090. LsapFreeLsaHeap( Sizes );
  2091. }
  2092. DebugLog((DEB_ERROR, "Out of heap in OpenFileStreams\n"));
  2093. return( ERROR_NOT_ENOUGH_MEMORY );
  2094. }
  2095. //
  2096. // Zero out the handle array to simplify cleanup later
  2097. //
  2098. RtlZeroMemory( Handles, *StreamCount * sizeof( HANDLE ));
  2099. //
  2100. // Open a handle to each stream for exclusive access
  2101. //
  2102. StreamInfo = StreamInfoBase;
  2103. ULONG i = 0;
  2104. while ( StreamInfo ) {
  2105. IO_STATUS_BLOCK IoStatusBlock;
  2106. //
  2107. // Build a string descriptor for the name of the stream.
  2108. //
  2109. Names[i].Buffer = &StreamInfo->StreamName[0];
  2110. Names[i].MaximumLength = Names[i].Length = (USHORT) StreamInfo->StreamNameLength;
  2111. if (Sizes != NULL) {
  2112. Sizes[i].EOFSize = StreamInfo->StreamSize;
  2113. Sizes[i].AllocSize = StreamInfo->StreamAllocationSize;
  2114. }
  2115. DebugLog((DEB_TRACE_EFS, "Opening stream %wZ\n",&Names[i]));
  2116. if ( StreamInfo->NextEntryOffset ){
  2117. StreamInfo = (PFILE_STREAM_INFORMATION)((PCHAR) StreamInfo + StreamInfo->NextEntryOffset);
  2118. } else {
  2119. StreamInfo = NULL;
  2120. }
  2121. //
  2122. // To avoid sharing violation, we do not open the default stream again.
  2123. // This also improves the performance
  2124. //
  2125. if ( (DEF_STR_LEN == Names[i].Length) &&
  2126. !memcmp( Names[i].Buffer,
  2127. DEFAULT_STREAM,
  2128. DEF_STR_LEN
  2129. )
  2130. ){
  2131. Handles[i] = hSourceFile;
  2132. Status = STATUS_SUCCESS;
  2133. } else {
  2134. //
  2135. // Open the source stream.
  2136. //
  2137. OBJECT_ATTRIBUTES Obja;
  2138. InitializeObjectAttributes(
  2139. &Obja,
  2140. &Names[i],
  2141. 0,
  2142. hSourceFile,
  2143. NULL
  2144. );
  2145. Status = NtCreateFile(
  2146. &Handles[i],
  2147. FileAccess,
  2148. &Obja,
  2149. &IoStatusBlock,
  2150. NULL,
  2151. 0,
  2152. ShareMode,
  2153. FILE_OPEN,
  2154. CreateOption,
  2155. NULL,
  2156. 0
  2157. );
  2158. }
  2159. if ( NT_SUCCESS(Status) && ( Flag != OPEN_FOR_EXP ) ){
  2160. //
  2161. // Flush the streams. This is not allowed in export because of the permission.
  2162. //
  2163. Status = NtFlushBuffersFile(
  2164. Handles[i],
  2165. &IoStatusBlock
  2166. );
  2167. }
  2168. if ( (Sizes != NULL) && NT_SUCCESS(Status) ) {
  2169. FILE_BASIC_INFORMATION StreamBasicInfo;
  2170. IO_STATUS_BLOCK IoStatusBlock;
  2171. //
  2172. // Get File Attributes
  2173. //
  2174. Status = NtQueryInformationFile(
  2175. Handles[i],
  2176. &IoStatusBlock,
  2177. &StreamBasicInfo,
  2178. sizeof ( FILE_BASIC_INFORMATION ),
  2179. FileBasicInformation
  2180. );
  2181. if (NT_SUCCESS(Status)){
  2182. Sizes[i].StreamFlag = StreamBasicInfo.FileAttributes;
  2183. }
  2184. }
  2185. if ( !NT_SUCCESS(Status) ) {
  2186. DebugLog((DEB_ERROR, "Unable to open stream %wZ, status = (%x)\n", &Names[i], Status ));
  2187. rc = RtlNtStatusToDosError( Status );
  2188. //
  2189. // In case the error isn't mapped, make sure we return something intelligent
  2190. //
  2191. if (rc == ERROR_MR_MID_NOT_FOUND) {
  2192. DebugLog((DEB_TRACE_EFS, "OpenFileStreams returning ERROR_ENCRYPTION_FAILED\n" ));
  2193. rc = ERROR_ENCRYPTION_FAILED;
  2194. }
  2195. break;
  2196. }
  2197. i++;
  2198. }
  2199. //
  2200. // Estimate the space for Encrypt or Decrypt operation
  2201. //
  2202. if ( (rc == ERROR_SUCCESS) &&
  2203. ((Flag == OPEN_FOR_ENC) || (Flag == OPEN_FOR_DEC))){
  2204. rc = CheckVolumeSpace( VolInfo, Sizes, Handles, *StreamCount);
  2205. }
  2206. if ( rc != ERROR_SUCCESS ) {
  2207. ULONG j;
  2208. for (j=0 ; j<i ; j++) {
  2209. if ( hSourceFile != Handles[j] ){
  2210. NtClose( Handles[j] );
  2211. }
  2212. }
  2213. }
  2214. if ( rc == ERROR_SUCCESS ) {
  2215. *StreamNames = Names;
  2216. *StreamHandles = Handles;
  2217. if (StreamSizes){
  2218. *StreamSizes = Sizes;
  2219. }
  2220. } else {
  2221. LsapFreeLsaHeap( Names);
  2222. LsapFreeLsaHeap( Handles);
  2223. if ( Sizes ){
  2224. LsapFreeLsaHeap( Sizes);
  2225. }
  2226. }
  2227. return( rc );
  2228. }
  2229. NTSTATUS
  2230. GetStreamInformation(
  2231. IN HANDLE SourceFile,
  2232. OUT PFILE_STREAM_INFORMATION * StreamInfoBase,
  2233. OUT PULONG StreamInfoSize
  2234. )
  2235. /*++
  2236. Routine Description:
  2237. This routine queries the stream information from the passed source file.
  2238. Arguments:
  2239. SourceFile - Supplies an opened handle to the file being queried.
  2240. StreamInfoBase - Returns a pointer to the stream information as returned
  2241. by NtQueryInformationFile().
  2242. StreamInfoSize - Returns the size of the information returned in the
  2243. StreamInfoBase parameter.
  2244. Return Value:
  2245. STATUS_SUCCESS on success, else failure, either from RtlAllocateHeap()
  2246. or NtQueryInformationFile();
  2247. --*/
  2248. {
  2249. NTSTATUS Status;
  2250. IO_STATUS_BLOCK IoStatusBlock;
  2251. *StreamInfoSize = 4096;
  2252. //
  2253. // Stolen from CreateDirectoryExW (base\client\dir.c)
  2254. //
  2255. do {
  2256. *StreamInfoBase = (PFILE_STREAM_INFORMATION)LsapAllocateLsaHeap( *StreamInfoSize);
  2257. if ( NULL == *StreamInfoBase ) {
  2258. return( STATUS_NO_MEMORY );
  2259. }
  2260. RtlZeroMemory(*StreamInfoBase, *StreamInfoSize);
  2261. Status = NtQueryInformationFile(
  2262. SourceFile,
  2263. &IoStatusBlock,
  2264. (PVOID) *StreamInfoBase,
  2265. *StreamInfoSize,
  2266. FileStreamInformation
  2267. );
  2268. if ( !NT_SUCCESS(Status) ) {
  2269. LsapFreeLsaHeap( *StreamInfoBase);
  2270. *StreamInfoBase = NULL;
  2271. *StreamInfoSize *= 2;
  2272. } else {
  2273. if (IoStatusBlock.Information == 0) {
  2274. //
  2275. // No data stream were found. True for most DIR.
  2276. //
  2277. LsapFreeLsaHeap( *StreamInfoBase);
  2278. *StreamInfoBase = NULL;
  2279. *StreamInfoSize = 0;
  2280. }
  2281. }
  2282. } while ( Status == STATUS_BUFFER_OVERFLOW ||
  2283. Status == STATUS_BUFFER_TOO_SMALL );
  2284. return( Status );
  2285. }
  2286. DWORD
  2287. CopyFileStreams(
  2288. PHANDLE SourceStreams,
  2289. PHANDLE StreamHandles,
  2290. ULONG StreamCount,
  2291. PEFS_STREAM_SIZE StreamSizes,
  2292. EFSP_OPERATION Operation,
  2293. PUCHAR FsInputData,
  2294. ULONG FsInputDataSize,
  2295. PBOOLEAN CleanupSuccessful
  2296. )
  2297. /*++
  2298. Routine Description:
  2299. This routine takes an array of source handles and target handles
  2300. and attempts to copy the sources to the targets, in the order
  2301. that the handles appear in the arrays.
  2302. If there is an error part of the way through, this routine will
  2303. try to clean up as well as it can, and return to the user whether
  2304. or not to consider the target file corrupted.
  2305. Arguments:
  2306. SourceStreams - Supplies an array of handles to streams to be copied.
  2307. StreamHandles - Supplies an array of handles of target streams to be
  2308. copied into.
  2309. StreamCount - Supplies the number of elemets in the first two arrays.
  2310. StreamSizes - Supplies an array of sizes of the streams being copied.
  2311. Operation - Whether the streams are being encrypted or decrypted.
  2312. FsInputData - Supplies the input data for the FSCTL_SET_ENCRYPTION call.
  2313. FsInputDataSize - The length of FsInputData.
  2314. CleanupSuccessful - If there is a failure, this parameter will return
  2315. whether or not one or more of the streams on the file has been
  2316. corrupted.
  2317. Return Value:
  2318. ERROR_SUCCESS on success, failure otherwise. In case of failure,
  2319. callers should examine the CleanupSuccessful flag to determine the
  2320. state of the target file.
  2321. --*/
  2322. {
  2323. ULONG StreamIndex;
  2324. DWORD hResult = 0;
  2325. NTSTATUS Status = STATUS_SUCCESS;
  2326. BOOL b = TRUE;
  2327. ULONG i;
  2328. DWORD rc = ERROR_SUCCESS;
  2329. IO_STATUS_BLOCK IoStatusBlock;
  2330. FILE_BASIC_INFORMATION StreamBasicInfo = { 0 };
  2331. *CleanupSuccessful = TRUE;
  2332. for (StreamIndex = 0; StreamIndex < StreamCount ; StreamIndex++) {
  2333. if ( Operation == EncryptRecovering ) {
  2334. //
  2335. // Called for recovering an unsuccessful encrypt. Get the attributes first.
  2336. //
  2337. Status = NtQueryInformationFile(
  2338. StreamHandles[StreamIndex],
  2339. &IoStatusBlock,
  2340. &StreamBasicInfo,
  2341. sizeof ( FILE_BASIC_INFORMATION ),
  2342. FileBasicInformation
  2343. );
  2344. if ( !NT_SUCCESS( Status )) {
  2345. b = FALSE;
  2346. break;
  2347. }
  2348. }
  2349. if ( ( Operation != EncryptRecovering ) ||
  2350. (StreamBasicInfo.FileAttributes & FILE_ATTRIBUTE_ENCRYPTED) ){
  2351. //
  2352. // Mark target stream encrypted or decrypted.
  2353. // Encrypt or decrypt information is in the input data
  2354. //
  2355. Status = NtFsControlFile(
  2356. StreamHandles[StreamIndex],
  2357. 0,
  2358. NULL,
  2359. NULL,
  2360. &IoStatusBlock,
  2361. FSCTL_SET_ENCRYPTION,
  2362. FsInputData,
  2363. FsInputDataSize,
  2364. NULL,
  2365. 0
  2366. );
  2367. }
  2368. if (NT_SUCCESS( Status )) {
  2369. if ( Operation == EncryptRecovering ) {
  2370. //
  2371. // Check if we need to re-compress the file
  2372. //
  2373. if ( StreamSizes[StreamIndex].StreamFlag & FILE_ATTRIBUTE_COMPRESSED ){
  2374. //
  2375. // Compress the target stream
  2376. //
  2377. USHORT State = COMPRESSION_FORMAT_DEFAULT;
  2378. ULONG Length;
  2379. //
  2380. // Return code is not checked. Failing to compress or decompress the
  2381. // the original file should not prevent the recovery.
  2382. //
  2383. (VOID) DeviceIoControl(
  2384. StreamHandles[StreamIndex],
  2385. FSCTL_SET_COMPRESSION,
  2386. &State,
  2387. sizeof(USHORT),
  2388. NULL,
  2389. 0,
  2390. &Length,
  2391. FALSE
  2392. );
  2393. }
  2394. }
  2395. hResult = CopyStream( StreamHandles[StreamIndex], SourceStreams[StreamIndex], &StreamSizes[StreamIndex] );
  2396. } else {
  2397. //
  2398. // Not successful, but if we haven't modified the file at all, we can
  2399. // still back out cleanly.
  2400. //
  2401. if (StreamIndex == 0) {
  2402. return( RtlNtStatusToDosError( Status ) );
  2403. }
  2404. }
  2405. if (!NT_SUCCESS( Status ) || hResult != ERROR_SUCCESS) {
  2406. b = FALSE;
  2407. break;
  2408. }
  2409. }
  2410. if (!b) {
  2411. if (!NT_SUCCESS( Status )) {
  2412. //
  2413. // Save the reason why we failed so we can return it.
  2414. //
  2415. rc = RtlNtStatusToDosError( Status );
  2416. } else {
  2417. rc = hResult;
  2418. }
  2419. //
  2420. // Something failed, back up and clean up. StreamIndex has the
  2421. // index of the last stream we were operating on.
  2422. //
  2423. if (Operation == Encrypting) {
  2424. //
  2425. // If we were encrypting, then we need to go back and mark each
  2426. // stream decrypted, and attempt to restore it from the backup.
  2427. // If either of those fail, we're hosed.
  2428. //
  2429. for (i=0; i<StreamIndex ; i++) {
  2430. //
  2431. // Mark stream decrypted. We can reuse the input data buffer
  2432. // here.
  2433. //
  2434. ( VOID )GetDecryptFsInput(
  2435. StreamHandles[StreamIndex],
  2436. FsInputData,
  2437. &FsInputDataSize
  2438. );
  2439. Status = NtFsControlFile(
  2440. StreamHandles[StreamIndex],
  2441. 0,
  2442. NULL,
  2443. NULL,
  2444. &IoStatusBlock,
  2445. FSCTL_SET_ENCRYPTION,
  2446. FsInputData,
  2447. FsInputDataSize,
  2448. NULL,
  2449. 0
  2450. );
  2451. //
  2452. // Attempt to copy the stream from backup
  2453. //
  2454. hResult = CopyStream( StreamHandles[StreamIndex], SourceStreams[StreamIndex], &StreamSizes[StreamIndex] );
  2455. if (!NT_SUCCESS( Status ) || hResult != ERROR_SUCCESS) {
  2456. *CleanupSuccessful = FALSE;
  2457. //
  2458. // Give up
  2459. //
  2460. break;
  2461. }
  2462. }
  2463. } else {
  2464. //
  2465. // Decrypting. Not a whole lot we can do here, because
  2466. // we can't put the file back the way it was.
  2467. //
  2468. *CleanupSuccessful = FALSE;
  2469. }
  2470. }
  2471. return( rc );
  2472. }
  2473. DWORD
  2474. CopyStream(
  2475. HANDLE Target,
  2476. HANDLE Source,
  2477. PEFS_STREAM_SIZE StreamSize
  2478. )
  2479. /*++
  2480. Routine Description:
  2481. This routine copies a file stream from a source stream to a target
  2482. stream. It assumes that the streams have been opened for appropriate
  2483. access.
  2484. Arguments:
  2485. Target - Supplies a handle to the stream to be written to. This handle
  2486. must be open for WRITE access.
  2487. Source - Supplies a stream handle to copy from. This handle must be open
  2488. for READ access.
  2489. StreamSize - Supplies the size of the stream in bytes.
  2490. Return Value:
  2491. ERROR_SUCCESS on success, failure otherwise.
  2492. --*/
  2493. {
  2494. SYSTEM_INFO SystemInfo;
  2495. LARGE_INTEGER StreamOffset;
  2496. LARGE_INTEGER AllocationGranularity;
  2497. HANDLE hStreamMapping;
  2498. DWORD rc = NO_ERROR;
  2499. IO_STATUS_BLOCK IoStatusBlock;
  2500. NTSTATUS Status;
  2501. if ( 0 == (StreamSize->EOFSize).QuadPart ){
  2502. return ERROR_SUCCESS;
  2503. }
  2504. GetSystemInfo( &SystemInfo );
  2505. SetFilePointer( Target, 0, NULL, FILE_BEGIN);
  2506. AllocationGranularity.HighPart = 0;
  2507. AllocationGranularity.LowPart = SystemInfo.dwAllocationGranularity;
  2508. hStreamMapping = CreateFileMapping( Source, NULL, PAGE_READONLY, 0, 0, NULL );
  2509. if (hStreamMapping == NULL) {
  2510. return( GetLastError() );
  2511. }
  2512. if ( StreamSize->StreamFlag & FILE_ATTRIBUTE_SPARSE_FILE ){
  2513. //
  2514. // Sparsed stream. Query the ranges first.
  2515. //
  2516. FILE_ALLOCATED_RANGE_BUFFER InputData;
  2517. PFILE_ALLOCATED_RANGE_BUFFER Ranges;
  2518. ULONG OutDataBufferSize;
  2519. ULONG RangeCount;
  2520. //
  2521. // Set the target as a sparse file
  2522. //
  2523. Status = NtFsControlFile(
  2524. Target,
  2525. 0,
  2526. NULL,
  2527. NULL,
  2528. &IoStatusBlock,
  2529. FSCTL_SET_SPARSE,
  2530. NULL,
  2531. 0,
  2532. NULL,
  2533. 0
  2534. );
  2535. if ( NT_SUCCESS(Status) ){
  2536. //
  2537. // Set the EOF of the target
  2538. //
  2539. FILE_END_OF_FILE_INFORMATION FileSize;
  2540. FileSize.EndOfFile = StreamSize->EOFSize;
  2541. Status = NtSetInformationFile(
  2542. Target,
  2543. &IoStatusBlock,
  2544. &FileSize,
  2545. sizeof(FileSize),
  2546. FileEndOfFileInformation
  2547. );
  2548. }
  2549. if ( !NT_SUCCESS(Status) ){
  2550. CloseHandle( hStreamMapping );
  2551. return RtlNtStatusToDosError( Status );
  2552. }
  2553. InputData.FileOffset.QuadPart = 0;
  2554. InputData.Length.QuadPart = 0x7fffffffffffffff;
  2555. OutDataBufferSize = INITBUFFERSIZE;
  2556. do {
  2557. Ranges = (PFILE_ALLOCATED_RANGE_BUFFER)LsapAllocateLsaHeap( OutDataBufferSize );
  2558. if ( NULL == Ranges ){
  2559. CloseHandle( hStreamMapping );
  2560. return ERROR_NOT_ENOUGH_MEMORY;
  2561. }
  2562. Status = NtFsControlFile(
  2563. Source,
  2564. 0,
  2565. NULL,
  2566. NULL,
  2567. &IoStatusBlock,
  2568. FSCTL_QUERY_ALLOCATED_RANGES,
  2569. &InputData,
  2570. sizeof( FILE_ALLOCATED_RANGE_BUFFER ),
  2571. Ranges,
  2572. OutDataBufferSize
  2573. );
  2574. if (Status == STATUS_PENDING){
  2575. ASSERT(TRUE);
  2576. WaitForSingleObject(
  2577. Source,
  2578. INFINITE
  2579. );
  2580. Status = IoStatusBlock.Status;
  2581. }
  2582. if ( !NT_SUCCESS(Status) ) {
  2583. LsapFreeLsaHeap( Ranges );
  2584. Ranges = NULL;
  2585. OutDataBufferSize += INITBUFFERSIZE;
  2586. }
  2587. } while ( Status == STATUS_BUFFER_OVERFLOW );
  2588. if ( NT_SUCCESS(Status) ){
  2589. //
  2590. // We got the ranges
  2591. //
  2592. RangeCount = (ULONG)IoStatusBlock.Information / sizeof (FILE_ALLOCATED_RANGE_BUFFER);
  2593. for ( ULONG ii = 0; ii < RangeCount; ii++ ){
  2594. DWORD LowMoved;
  2595. //
  2596. // Move the target file pointer first
  2597. //
  2598. StreamOffset = Ranges[ii].FileOffset;
  2599. LowMoved = SetFilePointer(
  2600. Target,
  2601. StreamOffset.LowPart,
  2602. &StreamOffset.HighPart,
  2603. FILE_BEGIN
  2604. );
  2605. if ( ( LowMoved != 0xFFFFFFFF ) || ( NO_ERROR != (rc = GetLastError()))){
  2606. rc = CopyStreamSection(
  2607. Target,
  2608. hStreamMapping,
  2609. &StreamOffset,
  2610. &(Ranges[ii].Length),
  2611. &AllocationGranularity
  2612. );
  2613. }
  2614. if ( NO_ERROR != rc ) {
  2615. break;
  2616. }
  2617. }
  2618. LsapFreeLsaHeap( Ranges );
  2619. Ranges = NULL;
  2620. } else {
  2621. rc = RtlNtStatusToDosError( Status );
  2622. if ( Ranges ) {
  2623. LsapFreeLsaHeap( Ranges );
  2624. Ranges = NULL;
  2625. }
  2626. }
  2627. } else {
  2628. //
  2629. // Non sparsed stream
  2630. //
  2631. StreamOffset.HighPart = 0;
  2632. StreamOffset.LowPart = 0;
  2633. rc = CopyStreamSection(
  2634. Target,
  2635. hStreamMapping,
  2636. &StreamOffset,
  2637. &(StreamSize->EOFSize),
  2638. &AllocationGranularity
  2639. );
  2640. }
  2641. CloseHandle( hStreamMapping );
  2642. if ( rc == NO_ERROR ) {
  2643. //
  2644. // Flush the stream
  2645. //
  2646. Status = NtFlushBuffersFile(
  2647. Target,
  2648. &IoStatusBlock
  2649. );
  2650. if ( !NT_SUCCESS(Status) ) {
  2651. rc = RtlNtStatusToDosError( Status );
  2652. }
  2653. }
  2654. return( rc );
  2655. }
  2656. VOID
  2657. CleanupOpenFileStreams(
  2658. IN PHANDLE Handles OPTIONAL,
  2659. IN PUNICODE_STRING StreamNames OPTIONAL,
  2660. IN PEFS_STREAM_SIZE Sizes OPTIONAL,
  2661. IN PFILE_STREAM_INFORMATION StreamInfoBase OPTIONAL,
  2662. IN HANDLE HSourceFile OPTIONAL,
  2663. IN ULONG StreamCount
  2664. )
  2665. /*++
  2666. Routine Description:
  2667. This routine cleans up after a call to OpenFileStreams.
  2668. Arguments:
  2669. Handles - Supplies the array of handles returned from OpenFileStreams.
  2670. Sizes - Supplies the array of stream sizes returned from OpenFileStreams.
  2671. StreamCount - Supplies the number of streams returned from OpenFileStreams.
  2672. Return Value:
  2673. None. This is no recovery operation should this routine fail.
  2674. --*/
  2675. {
  2676. ULONG i;
  2677. if ( Handles ){
  2678. for (ULONG i = 0; i<StreamCount ; i++) {
  2679. if (HSourceFile == Handles[i]) {
  2680. HSourceFile = 0;
  2681. }
  2682. NtClose( Handles[i] );
  2683. }
  2684. LsapFreeLsaHeap( Handles);
  2685. if (HSourceFile) {
  2686. //
  2687. // Dir with data streams will get here
  2688. //
  2689. NtClose( HSourceFile );
  2690. }
  2691. } else if ( HSourceFile ){
  2692. //
  2693. // HSourceFile is among one of Handles[]
  2694. //
  2695. NtClose( HSourceFile );
  2696. }
  2697. if ( StreamNames ){
  2698. LsapFreeLsaHeap( StreamNames);
  2699. }
  2700. if ( Sizes ){
  2701. LsapFreeLsaHeap( Sizes);
  2702. }
  2703. if ( StreamInfoBase ){
  2704. LsapFreeLsaHeap( StreamInfoBase );
  2705. }
  2706. return;
  2707. }
  2708. VOID
  2709. MarkFileForDelete(
  2710. HANDLE FileHandle
  2711. )
  2712. /*++
  2713. Routine Description:
  2714. This function marks the passed file for delete, so that it
  2715. will be deleted by the system when its last handle is closed.
  2716. Arguments:
  2717. FileHandle - A handle to a file that has been opened for DELETE
  2718. access (see comments in the procedure body about this).
  2719. Return Value:
  2720. None.
  2721. --*/
  2722. {
  2723. FILE_DISPOSITION_INFORMATION Disposition;
  2724. IO_STATUS_BLOCK IoStatusBlock;
  2725. NTSTATUS Status;
  2726. #ifdef EFSDBG
  2727. //
  2728. // If we're in debugging mode, the file has not been opened
  2729. // for delete access, since that would prohibit any other
  2730. // process from accessing the file (which we want to do during
  2731. // the debugging phase).
  2732. //
  2733. // Open the file again, for delete access this time, and
  2734. // mark it for delete. In the normal case, we don't have
  2735. // to do this.
  2736. //
  2737. OBJECT_ATTRIBUTES Obja;
  2738. UNICODE_STRING Unicode;
  2739. RtlInitUnicodeString( &Unicode, NULL );
  2740. InitializeObjectAttributes(
  2741. &Obja,
  2742. &Unicode,
  2743. 0,
  2744. FileHandle,
  2745. NULL
  2746. );
  2747. Status = NtCreateFile(
  2748. &FileHandle, // yes, overwrite the parameter
  2749. DELETE | SYNCHRONIZE,
  2750. &Obja,
  2751. &IoStatusBlock,
  2752. NULL,
  2753. 0,
  2754. FILE_SHARE_READ | FILE_SHARE_WRITE,
  2755. FILE_OPEN,
  2756. FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
  2757. NULL,
  2758. 0
  2759. );
  2760. if (!NT_SUCCESS( Status )) {
  2761. DbgPrint("NtCreateFile in MarkFileForDelete failed, status = %x\n",Status);
  2762. }
  2763. #endif
  2764. //
  2765. // "DeleteFile is defined to be DeleteFileW, so undef it here...
  2766. //
  2767. #undef DeleteFile
  2768. Disposition.DeleteFile = TRUE;
  2769. Status = NtSetInformationFile(
  2770. FileHandle,
  2771. &IoStatusBlock,
  2772. &Disposition,
  2773. sizeof(Disposition),
  2774. FileDispositionInformation
  2775. );
  2776. if (!NT_SUCCESS( Status )) {
  2777. WCHAR ErrorCode[16];
  2778. LPWSTR pErrorCode;
  2779. _ltow( Status, ErrorCode, 16 );
  2780. pErrorCode = &ErrorCode[0];
  2781. EfsLogEntry(
  2782. EVENTLOG_WARNING_TYPE,
  2783. 0,
  2784. EFS_DEL_LOGFILE_ERROR,
  2785. 1,
  2786. 0,
  2787. (LPCWSTR *)&pErrorCode,
  2788. NULL
  2789. );
  2790. }
  2791. #ifdef EFSDBG
  2792. CloseHandle( FileHandle );
  2793. #endif
  2794. }
  2795. BOOLEAN
  2796. SendHandle(
  2797. IN HANDLE Handle,
  2798. IN OUT PUCHAR EfsData,
  2799. IN OUT PULONG EfsDataLength
  2800. )
  2801. /*++
  2802. Routine Description:
  2803. Constructs an EFS Data section of the form (Handle will be truncated to ULONG for SunDown)
  2804. SK, Handle, Handle, [SK, Handle, Handle]sk
  2805. Arguments:
  2806. Handle - Supplies the handle value to be encoded
  2807. EfsData - Supplies a buffer large enough to contain the
  2808. output data.
  2809. EfsDataLength - Supplies the length of the EfsData, and
  2810. returns either the length required or the length
  2811. used.
  2812. Return Value:
  2813. TRUE on success, FALSE otherwise.
  2814. --*/
  2815. {
  2816. //
  2817. // Compute the total size required
  2818. //
  2819. ULONG TotalSize = 4 * sizeof( ULONG ) + 2 * sizeof( DriverSessionKey );
  2820. if (*EfsDataLength < TotalSize) {
  2821. *EfsDataLength = TotalSize;
  2822. return( FALSE );
  2823. }
  2824. *EfsDataLength = TotalSize;
  2825. //
  2826. // Copy everything in, and encrypt what needs to be encrypted.
  2827. //
  2828. PUCHAR Where = EfsData;
  2829. RtlCopyMemory( Where, DriverSessionKey, sizeof( DriverSessionKey ) );
  2830. Where += sizeof( DriverSessionKey );
  2831. PULONG pUlong = (PULONG)Where;
  2832. *pUlong = PtrToUlong(Handle);
  2833. Where += sizeof( ULONG );
  2834. pUlong = (PULONG)Where;
  2835. *pUlong = PtrToUlong(Handle);
  2836. Where += sizeof( ULONG );
  2837. PUCHAR CryptData = Where;
  2838. RtlCopyMemory( CryptData, EfsData, TotalSize/2 );
  2839. //
  2840. // Now encrypt the data starting at CryptData
  2841. //
  2842. LONG bytesToBeEnc = (LONG)(TotalSize/2);
  2843. ASSERT( (bytesToBeEnc % DES_BLOCKLEN) == 0 );
  2844. while ( bytesToBeEnc > 0 ) {
  2845. //
  2846. // Encrypt data with DES
  2847. //
  2848. des( CryptData,
  2849. CryptData,
  2850. &DesTable,
  2851. ENCRYPT
  2852. );
  2853. CryptData += DES_BLOCKLEN;
  2854. bytesToBeEnc -= DES_BLOCKLEN;
  2855. }
  2856. return( TRUE );
  2857. }
  2858. BOOLEAN
  2859. SendEfs(
  2860. IN PEFS_KEY Fek,
  2861. IN PEFS_DATA_STREAM_HEADER Efs,
  2862. OUT PUCHAR EfsData,
  2863. OUT PULONG EfsDataLength
  2864. )
  2865. /*++
  2866. Routine Description:
  2867. Constructs an EFS Data section of the form
  2868. FEK, [FEK]sk, $EFS
  2869. Arguments:
  2870. Fek - Supplies the FEK to be encoded
  2871. Efs - Supplies the EFS to be encoded
  2872. EfsData - Supplies a buffer large enough for the returned
  2873. data.
  2874. EfsDataLength - Supplies the length of the EfsData, and
  2875. returns either the length required or the length
  2876. used.
  2877. Return Value:
  2878. TRUE on success, FALSE otherwise.
  2879. --*/
  2880. {
  2881. //
  2882. // Compute the total size required
  2883. //
  2884. ULONG TotalSize = 2 * EFS_KEY_SIZE( Fek ) + Efs->Length;
  2885. if (*EfsDataLength < TotalSize) {
  2886. *EfsDataLength = TotalSize;
  2887. return( FALSE );
  2888. }
  2889. *EfsDataLength = TotalSize;
  2890. //
  2891. // Copy in the FEK twice, followed by the EFS stream
  2892. //
  2893. PUCHAR Where = EfsData;
  2894. RtlCopyMemory( Where, Fek, EFS_KEY_SIZE( Fek ) );
  2895. Where += EFS_KEY_SIZE( Fek );
  2896. //
  2897. // Save the location that we're going to encrypt
  2898. //
  2899. PUCHAR CryptData = Where;
  2900. RtlCopyMemory( Where, Fek, EFS_KEY_SIZE( Fek ) );
  2901. Where += EFS_KEY_SIZE( Fek );
  2902. if ( Where != (PUCHAR) Efs ){
  2903. RtlCopyMemory( Where, Efs, Efs->Length );
  2904. }
  2905. //
  2906. // Encrypt the second FEK
  2907. //
  2908. LONG bytesToBeEnc = (LONG)(EFS_KEY_SIZE( Fek ));
  2909. ASSERT( (bytesToBeEnc % DES_BLOCKLEN) == 0 );
  2910. while ( bytesToBeEnc > 0 ) {
  2911. //
  2912. // Encrypt data with DES
  2913. //
  2914. des( CryptData,
  2915. CryptData,
  2916. &DesTable,
  2917. ENCRYPT
  2918. );
  2919. CryptData += DES_BLOCKLEN;
  2920. bytesToBeEnc -= DES_BLOCKLEN;
  2921. }
  2922. return( TRUE );
  2923. }
  2924. BOOLEAN
  2925. SendHandleAndEfs(
  2926. IN HANDLE Handle,
  2927. IN PEFS_DATA_STREAM_HEADER Efs,
  2928. IN OUT PUCHAR EfsData,
  2929. IN OUT PULONG EfsDataLength
  2930. )
  2931. /*++
  2932. Routine Description:
  2933. Constructs an EFS Data section of the form (Handle will be truncated to ULONG for SunDown)
  2934. SK, Handle, Handle, [SK, Handle, Handle]sk $EFS
  2935. Arguments:
  2936. Fek - Supplies the FEK to be encoded
  2937. Efs - Supplies the EFS to be encoded
  2938. EfsData - Returns a buffer containing the EFS data
  2939. EfsDataLength - Returns the length of the EFS data.
  2940. Return Value:
  2941. TRUE on success, FALSE otherwise.
  2942. --*/
  2943. {
  2944. ULONG TotalSize = 4 * sizeof( ULONG ) + 2 * sizeof( DriverSessionKey ) + Efs->Length;
  2945. if (*EfsDataLength < TotalSize) {
  2946. *EfsDataLength = TotalSize;
  2947. return( FALSE );
  2948. }
  2949. if ( SendHandle( Handle, EfsData, EfsDataLength ) ) {
  2950. //
  2951. // Tack the EFS onto the end of the buffer
  2952. //
  2953. RtlCopyMemory( EfsData + (*EfsDataLength), Efs, Efs->Length );
  2954. *EfsDataLength += Efs->Length;
  2955. return( TRUE );
  2956. } else {
  2957. return( FALSE );
  2958. }
  2959. }
  2960. BOOLEAN
  2961. EncryptFSCTLData(
  2962. IN ULONG Fsctl,
  2963. IN ULONG Psc,
  2964. IN ULONG Csc,
  2965. IN PVOID EfsData,
  2966. IN ULONG EfsDataLength,
  2967. IN OUT PUCHAR Buffer,
  2968. IN OUT PULONG BufferLength
  2969. )
  2970. /*++
  2971. Routine Description:
  2972. Constructs the input to the various FSCTL routines based
  2973. on the passed parameters. The general form is:
  2974. PSC, [EFS_FC, CSC, [EFS Data]]sk
  2975. Arguments:
  2976. Return Value:
  2977. TRUE on success, FALSE otherwise.
  2978. --*/
  2979. {
  2980. ULONG TotalSize = 3 * sizeof( ULONG ) + EfsDataLength;
  2981. if (*BufferLength < TotalSize) {
  2982. *BufferLength = TotalSize;
  2983. return( FALSE );
  2984. }
  2985. *BufferLength = TotalSize;
  2986. //
  2987. // Copy all the data in, and encrypt what needs to be encrypted
  2988. //
  2989. PULONG pUlong = (PULONG)Buffer;
  2990. *pUlong++ = Psc;
  2991. *pUlong++ = Fsctl;
  2992. *pUlong++ = Csc;
  2993. //
  2994. // EfsData might point to inside Buffer and the data already in place
  2995. //
  2996. if ( (PVOID)pUlong != (PVOID)EfsData )
  2997. RtlCopyMemory( (PUCHAR)pUlong, EfsData, EfsDataLength );
  2998. LONG bytesToBeEnc = (LONG)(2 * sizeof(ULONG) + EfsDataLength);
  2999. ASSERT( (bytesToBeEnc % DES_BLOCKLEN) == 0 );
  3000. PUCHAR CryptData = Buffer + sizeof( ULONG );
  3001. while ( bytesToBeEnc > 0 ) {
  3002. //
  3003. // Encrypt data with DES
  3004. //
  3005. des( CryptData,
  3006. CryptData,
  3007. &DesTable,
  3008. ENCRYPT
  3009. );
  3010. CryptData += DES_BLOCKLEN;
  3011. bytesToBeEnc -= DES_BLOCKLEN;
  3012. }
  3013. return( TRUE );
  3014. }
  3015. NTSTATUS
  3016. GetParentEfsStream(
  3017. IN HANDLE CurrentFileHandle,
  3018. IN PUNICODE_STRING CurrentFileName,
  3019. OUT PEFS_DATA_STREAM_HEADER *ParentEfsStream
  3020. )
  3021. /*++
  3022. Routine Description:
  3023. Get the $EFS from the parent directory
  3024. Arguments:
  3025. SourceFileName -- Current file or directory name.
  3026. ParentEfsStream
  3027. Return Value:
  3028. Status of operation.
  3029. --*/
  3030. {
  3031. ULONG Index;
  3032. HANDLE ParentDir;
  3033. PUCHAR InputData;
  3034. ULONG InputDataSize;
  3035. ULONG OutputDataSize;
  3036. ULONG EfsDataLength;
  3037. NTSTATUS Status;
  3038. IO_STATUS_BLOCK IoStatusBlock;
  3039. //
  3040. // Get the parent name
  3041. //
  3042. *ParentEfsStream = NULL;
  3043. Index = (CurrentFileName->Length)/sizeof( WCHAR ) - 1;
  3044. while ( (Index > 0) && ( CurrentFileName->Buffer[Index] != L'\\') )
  3045. Index--;
  3046. if ( Index <= 0 )
  3047. return STATUS_OBJECT_PATH_NOT_FOUND;
  3048. LPWSTR ParentDirName;
  3049. /*
  3050. if ( CurrentFileName->Buffer[Index-1] == L':' ){
  3051. //
  3052. // Parent is a root directory
  3053. //
  3054. Status = GetRootHandle( CurrentFileHandle, &ParentDir );
  3055. if (!NT_SUCCESS( Status )){
  3056. *ParentEfsStream = NULL;
  3057. return STATUS_OBJECT_PATH_NOT_FOUND;
  3058. }
  3059. } else {
  3060. */
  3061. //
  3062. // A normal directory. We can use WIN 32 API to open it.
  3063. //
  3064. ParentDirName = (LPWSTR) LsapAllocateLsaHeap( ( Index + 1 ) * sizeof(WCHAR) );
  3065. if ( ParentDirName == NULL ) {
  3066. *ParentEfsStream = NULL;
  3067. return STATUS_INSUFFICIENT_RESOURCES;
  3068. }
  3069. RtlCopyMemory( ParentDirName, &CurrentFileName->Buffer[0], Index * sizeof(WCHAR));
  3070. ParentDirName[Index] = UNICODE_NULL;
  3071. //
  3072. // FILE_FLAG_BACKUP_SEMANTICS is required to open a directory.
  3073. // How about if a user does not have the backup privilege?
  3074. //
  3075. ParentDir = CreateFile(
  3076. ParentDirName,
  3077. FILE_READ_ATTRIBUTES,
  3078. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  3079. NULL,
  3080. OPEN_EXISTING,
  3081. FILE_FLAG_BACKUP_SEMANTICS,
  3082. NULL
  3083. );
  3084. //
  3085. // There is no need for us to hold ParentDirName any more
  3086. //
  3087. LsapFreeLsaHeap( ParentDirName );
  3088. if ( ParentDir == INVALID_HANDLE_VALUE ){
  3089. return STATUS_OBJECT_PATH_NOT_FOUND;
  3090. }
  3091. /*
  3092. }
  3093. */
  3094. //
  3095. // Now we got a handle to the parent directory in ParentDir.
  3096. // Allocate input and output data buffer
  3097. //
  3098. OutputDataSize = INIT_EFS_BLOCK_SIZE;
  3099. *ParentEfsStream = (PEFS_DATA_STREAM_HEADER) LsapAllocateLsaHeap( OutputDataSize );
  3100. if ( *ParentEfsStream == NULL ){
  3101. CloseHandle( ParentDir );
  3102. return STATUS_INSUFFICIENT_RESOURCES;
  3103. }
  3104. //
  3105. // PSC, [EFS_FC, CSC , SK, H, H, [SK, H, H]sk]sk
  3106. // PSC, CSC are ignored in this FSCTL call
  3107. //
  3108. InputDataSize = 2 * sizeof(DriverSessionKey) + 7 * sizeof(ULONG);
  3109. InputData = (PUCHAR)LsapAllocateLsaHeap( InputDataSize );
  3110. if ( InputData == NULL ){
  3111. LsapFreeLsaHeap( *ParentEfsStream );
  3112. *ParentEfsStream = NULL;
  3113. CloseHandle( ParentDir );
  3114. return STATUS_INSUFFICIENT_RESOURCES;
  3115. }
  3116. //
  3117. // Prepare an input data for making a FSCTL call to get the $EFS
  3118. //
  3119. EfsDataLength = 2 * sizeof(DriverSessionKey) + 4 * sizeof(ULONG);
  3120. SendHandle( ParentDir, InputData + 3*sizeof(ULONG), &EfsDataLength );
  3121. (VOID) EncryptFSCTLData(
  3122. EFS_GET_ATTRIBUTE,
  3123. 0,
  3124. 0,
  3125. InputData + 3*sizeof(ULONG),
  3126. EfsDataLength,
  3127. InputData,
  3128. &InputDataSize
  3129. );
  3130. Status = NtFsControlFile(
  3131. ParentDir,
  3132. 0,
  3133. NULL,
  3134. NULL,
  3135. &IoStatusBlock,
  3136. FSCTL_ENCRYPTION_FSCTL_IO,
  3137. InputData,
  3138. InputDataSize,
  3139. *ParentEfsStream,
  3140. OutputDataSize
  3141. );
  3142. if (!NT_SUCCESS( Status )) {
  3143. //
  3144. // Check if the output data buffer too small
  3145. // Try again if it is.
  3146. //
  3147. if ( Status == STATUS_BUFFER_TOO_SMALL ){
  3148. OutputDataSize = *(ULONG*)(*ParentEfsStream);
  3149. if (OutputDataSize > INIT_EFS_BLOCK_SIZE){
  3150. LsapFreeLsaHeap( *ParentEfsStream );
  3151. *ParentEfsStream = (PEFS_DATA_STREAM_HEADER)LsapAllocateLsaHeap( OutputDataSize );
  3152. if ( *ParentEfsStream ) {
  3153. Status = NtFsControlFile(
  3154. ParentDir,
  3155. 0,
  3156. NULL,
  3157. NULL,
  3158. &IoStatusBlock,
  3159. FSCTL_ENCRYPTION_FSCTL_IO,
  3160. InputData,
  3161. InputDataSize,
  3162. *ParentEfsStream,
  3163. OutputDataSize
  3164. );
  3165. }
  3166. }
  3167. }
  3168. if ( !NT_SUCCESS( Status ) ){
  3169. if ( *ParentEfsStream ){
  3170. LsapFreeLsaHeap( *ParentEfsStream );
  3171. *ParentEfsStream = NULL;
  3172. }
  3173. Status = STATUS_SUCCESS;
  3174. }
  3175. }
  3176. LsapFreeLsaHeap( InputData );
  3177. CloseHandle( ParentDir );
  3178. return Status;
  3179. }
  3180. NTSTATUS
  3181. GetRootHandle(
  3182. IN HANDLE FileHandle,
  3183. PHANDLE RootDirectoryHandle
  3184. )
  3185. /*++
  3186. Routine Description:
  3187. Get the handle to the root directory
  3188. Arguments:
  3189. FileHandle -- Current file or directory handle.
  3190. RootDirectoryHandle -- Parent directory
  3191. Return Value:
  3192. Status of operation.
  3193. --*/
  3194. {
  3195. NTSTATUS Status;
  3196. OBJECT_ATTRIBUTES Obja;
  3197. UNICODE_STRING FileId;
  3198. IO_STATUS_BLOCK IoStatusBlock;
  3199. //
  3200. // This is magic. It opens the root directory of a volume by ID,
  3201. // relative to the passed file name.
  3202. //
  3203. ULONG FileIdBuffer[2];
  3204. FileIdBuffer[0] = 0x00000005;
  3205. FileIdBuffer[1] = 0x00050000;
  3206. FileId.Length = FileId.MaximumLength = 8;
  3207. FileId.Buffer = (PWSTR)FileIdBuffer;
  3208. InitializeObjectAttributes(
  3209. &Obja,
  3210. &FileId,
  3211. 0,
  3212. FileHandle,
  3213. NULL
  3214. );
  3215. Status = NtCreateFile(
  3216. RootDirectoryHandle,
  3217. FILE_READ_ATTRIBUTES,
  3218. &Obja,
  3219. &IoStatusBlock,
  3220. NULL,
  3221. 0,
  3222. FILE_SHARE_DELETE | FILE_SHARE_WRITE | FILE_SHARE_READ,
  3223. FILE_OPEN,
  3224. FILE_OPEN_BY_FILE_ID,
  3225. NULL,
  3226. 0
  3227. );
  3228. return( Status );
  3229. }
  3230. BOOLEAN
  3231. GetDecryptFsInput(
  3232. IN HANDLE Handle,
  3233. OUT PUCHAR InputData,
  3234. OUT PULONG InputDataSize
  3235. )
  3236. /*++
  3237. Routine Description:
  3238. Get the handle to the root directory
  3239. Arguments:
  3240. Handle -- Current file or directory handle.
  3241. InputData -- Data buffer for the decrypt FSCTL input data.
  3242. PSC, [EFS_FC, CSC, SK, H, H, [SK, H, H]sk]sk
  3243. InputDataSize -- FSCTL input data length.
  3244. Return Value:
  3245. TRUE IF SUCCESSFUL.
  3246. --*/
  3247. {
  3248. ULONG RequiredSize;
  3249. ULONG EfsDataSize;
  3250. RequiredSize = 7 * sizeof( ULONG ) + 2 * sizeof(DriverSessionKey);
  3251. if ( *InputDataSize < RequiredSize ){
  3252. *InputDataSize = RequiredSize;
  3253. return FALSE;
  3254. }
  3255. *InputDataSize = RequiredSize;
  3256. EfsDataSize = RequiredSize - 3 * sizeof( ULONG );
  3257. ( VOID )SendHandle(
  3258. Handle,
  3259. InputData + 3 * sizeof( ULONG ),
  3260. &EfsDataSize
  3261. );
  3262. ( VOID ) EncryptFSCTLData(
  3263. EFS_SET_ENCRYPT,
  3264. EFS_DECRYPT_STREAM,
  3265. EFS_DECRYPT_STREAM,
  3266. InputData + 3 * sizeof(ULONG),
  3267. EfsDataSize,
  3268. InputData,
  3269. InputDataSize
  3270. );
  3271. return TRUE;
  3272. }
  3273. NTSTATUS
  3274. EndErrorEncryptFile(
  3275. IN HANDLE FileHandle,
  3276. IN PUCHAR InputData,
  3277. IN ULONG InputDataSize,
  3278. OUT IO_STATUS_BLOCK *IoStatusBlock
  3279. )
  3280. /*++
  3281. Routine Description:
  3282. Removed the $EFS and clear the encrypt bit for the file.
  3283. Arguments:
  3284. FileHandle -- Current file handle.
  3285. InputData -- Data buffer for the decrypt FSCTL input data.
  3286. PSC, [EFS_FC, CSC, SK, H, H, [SK, H, H]sk]sk
  3287. InputDataSize -- FSCTL input data length.
  3288. IoStatusBlock -- Status information from FSCTL call.
  3289. Return Value:
  3290. The status of operation.
  3291. --*/
  3292. {
  3293. return (SendSkFsctl(
  3294. EFS_DECRYPT_FILE,
  3295. EFS_DECRYPT_FILE,
  3296. EFS_SET_ENCRYPT,
  3297. InputData,
  3298. InputDataSize,
  3299. FileHandle,
  3300. FSCTL_SET_ENCRYPTION,
  3301. IoStatusBlock
  3302. )
  3303. );
  3304. }
  3305. NTSTATUS
  3306. SendSkFsctl(
  3307. IN ULONG Psc,
  3308. IN ULONG Csc,
  3309. IN ULONG EfsCode,
  3310. IN PUCHAR InputData,
  3311. IN ULONG InputDataSize,
  3312. IN HANDLE Handle,
  3313. IN ULONG FsCode,
  3314. OUT IO_STATUS_BLOCK *IoStatusBlock
  3315. )
  3316. /*++
  3317. Routine Description:
  3318. Send FSCTL call with general EFS Data format. See comments
  3319. for InputData
  3320. Arguments:
  3321. Psc -- Plain subcode.
  3322. Csc -- Cipher subcode
  3323. EfsCode -- EFS function code.
  3324. InputData -- Data buffer for the decrypt FSCTL input data.
  3325. PSC, [EFS_FC, CSC, SK, H, H, [SK, H, H]sk]sk
  3326. InputDataSize -- FSCTL input data length.
  3327. Handle -- Current stream handle.
  3328. FsCode -- FSCTL control code.
  3329. IoStatusBlock -- Status information from FSCTL call.
  3330. Return Value:
  3331. The status of operation.
  3332. --*/
  3333. {
  3334. ULONG EfsDataLength = InputDataSize - 3 * sizeof (ULONG);
  3335. ULONG RequiredSize = 7 * sizeof( ULONG ) + 2 * sizeof(DriverSessionKey);
  3336. BOOLEAN DummyOutput = FALSE;
  3337. ULONG OutPutLen = 0;
  3338. VOID *OutPutData = NULL;
  3339. if ( InputDataSize < RequiredSize ){
  3340. return STATUS_BUFFER_TOO_SMALL;
  3341. }
  3342. ( VOID )SendHandle(
  3343. Handle,
  3344. InputData + 3 * sizeof( ULONG ),
  3345. &EfsDataLength
  3346. );
  3347. ( VOID ) EncryptFSCTLData(
  3348. EfsCode,
  3349. Psc,
  3350. Csc,
  3351. InputData + 3 * sizeof(ULONG),
  3352. EfsDataLength,
  3353. InputData,
  3354. &InputDataSize
  3355. );
  3356. if (EFS_DECRYPT_STREAM == Psc) {
  3357. OutPutData = (VOID *)&DummyOutput;
  3358. OutPutLen = sizeof(BOOLEAN);
  3359. }
  3360. return ( NtFsControlFile(
  3361. Handle,
  3362. 0,
  3363. NULL,
  3364. NULL,
  3365. IoStatusBlock,
  3366. FsCode,
  3367. InputData,
  3368. InputDataSize,
  3369. OutPutData,
  3370. OutPutLen
  3371. )
  3372. );
  3373. }
  3374. DWORD
  3375. GetVolumeRoot(
  3376. IN PUNICODE_STRING SrcFileName,
  3377. OUT PUNICODE_STRING RootPath
  3378. )
  3379. /*++
  3380. Routine Description:
  3381. Get the root path name from the target file name
  3382. Arguments:
  3383. SrcFileName -- Target file name.
  3384. RootPathInfo -- Root path information
  3385. Return Value:
  3386. The status of operation.
  3387. --*/
  3388. {
  3389. ULONG BufferLength;
  3390. WCHAR *PathName;
  3391. BOOL GotRoot;
  3392. DWORD RetCode = ERROR_SUCCESS;
  3393. BufferLength = (ULONG)((SrcFileName->Length + sizeof(WCHAR)) <= MAX_PATH * sizeof(WCHAR)?
  3394. (MAX_PATH + 1) * sizeof(WCHAR) : (SrcFileName->Length + sizeof (WCHAR)));
  3395. PathName = (WCHAR *) LsapAllocateLsaHeap(BufferLength);
  3396. if ( !PathName ) {
  3397. return STATUS_INSUFFICIENT_RESOURCES;
  3398. }
  3399. RootPath->MaximumLength = (USHORT) BufferLength;
  3400. GotRoot = GetVolumePathName(
  3401. SrcFileName->Buffer,
  3402. PathName,
  3403. BufferLength
  3404. );
  3405. if (GotRoot){
  3406. RootPath->Buffer = PathName;
  3407. RootPath->Length = (USHORT) wcslen(PathName) * sizeof (WCHAR);
  3408. } else {
  3409. RetCode = GetLastError();
  3410. RootPath->Buffer = NULL;
  3411. RootPath->Length = 0;
  3412. RootPath->MaximumLength = 0;
  3413. LsapFreeLsaHeap( PathName );
  3414. }
  3415. return RetCode;
  3416. }
  3417. NTSTATUS
  3418. GetLogFile(
  3419. IN PUNICODE_STRING RootPath,
  3420. OUT HANDLE *LogFile
  3421. )
  3422. /*++
  3423. Routine Description:
  3424. Create the log file.
  3425. Arguments:
  3426. RootPath -- Volume root name.
  3427. LogFile -- Log file handle
  3428. Return Value:
  3429. The status of operation.
  3430. --*/
  3431. {
  3432. NTSTATUS Status = STATUS_SUCCESS;
  3433. HANDLE FileHdl;
  3434. OBJECT_ATTRIBUTES Obja;
  3435. IO_STATUS_BLOCK IoStatusBlock;
  3436. UNICODE_STRING FileName;
  3437. UNICODE_STRING RootNtName;
  3438. UNICODE_STRING LogFileName;
  3439. DWORD FileAttributes;
  3440. PSECURITY_DESCRIPTOR SD;
  3441. BOOLEAN b;
  3442. b = RtlDosPathNameToNtPathName_U(
  3443. RootPath->Buffer,
  3444. &RootNtName,
  3445. NULL,
  3446. NULL
  3447. );
  3448. if ( b ) {
  3449. //
  3450. // Allocate space for the temp log file name
  3451. //
  3452. FileName.Buffer = (WCHAR *) LsapAllocateLsaHeap(
  3453. RootNtName.Length +
  3454. EFSDIRLEN +
  3455. TEMPFILELEN);
  3456. if ( !FileName.Buffer ){
  3457. //
  3458. // Free the NT name
  3459. //
  3460. RtlFreeHeap(
  3461. RtlProcessHeap(),
  3462. 0,
  3463. RootNtName.Buffer
  3464. );
  3465. return STATUS_INSUFFICIENT_RESOURCES;
  3466. }
  3467. //
  3468. // Make the EFS directory name of the volume
  3469. //
  3470. RtlCopyMemory(FileName.Buffer, RootNtName.Buffer, RootNtName.Length - sizeof(WCHAR));
  3471. RtlCopyMemory(
  3472. FileName.Buffer + (RootNtName.Length / sizeof(WCHAR)) - 1,
  3473. EFSDIR,
  3474. EFSDIRLEN
  3475. );
  3476. FileName.Length = RootNtName.Length + EFSDIRLEN - sizeof(WCHAR);
  3477. FileName.MaximumLength = RootNtName.Length + EFSDIRLEN + TEMPFILELEN;
  3478. FileName.Buffer[FileName.Length / sizeof (WCHAR)] = 0;
  3479. //
  3480. // Free the NT name
  3481. //
  3482. RtlFreeHeap(
  3483. RtlProcessHeap(),
  3484. 0,
  3485. RootNtName.Buffer
  3486. );
  3487. //
  3488. // Create the LOG directory and file Security Descriptor
  3489. //
  3490. Status = MakeSystemFullControlSD( &SD );
  3491. if ( NT_SUCCESS(Status) ){
  3492. InitializeObjectAttributes(
  3493. &Obja,
  3494. &FileName,
  3495. OBJ_CASE_INSENSITIVE,
  3496. 0,
  3497. SD
  3498. );
  3499. //
  3500. // Open the EFS Log directory or Create if not exist
  3501. //
  3502. Status = NtCreateFile(
  3503. &FileHdl,
  3504. MAXIMUM_ALLOWED,
  3505. &Obja,
  3506. &IoStatusBlock,
  3507. NULL,
  3508. FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM,
  3509. FILE_SHARE_VALID_FLAGS,
  3510. FILE_OPEN_IF,
  3511. FILE_DIRECTORY_FILE ,
  3512. NULL,
  3513. 0
  3514. );
  3515. if (NT_SUCCESS(Status)){
  3516. //
  3517. // The cache directory is created hidden and system access only. This will be
  3518. // created before any real encryption is done. So there is no need for us to check
  3519. // the encryption status of this directory.
  3520. //
  3521. CloseHandle(FileHdl);
  3522. //
  3523. // Now trying to get the logfile name and create it
  3524. //
  3525. Status = CreateLogFile( &FileName, SD, LogFile );
  3526. } else {
  3527. //
  3528. // Cannot open the EFSCACHE dir
  3529. //
  3530. EfsLogEntry(
  3531. EVENTLOG_ERROR_TYPE,
  3532. 0,
  3533. EFS_OPEN_CACHE_ERROR,
  3534. 0,
  3535. sizeof(NTSTATUS),
  3536. NULL,
  3537. &Status
  3538. );
  3539. }
  3540. {
  3541. //
  3542. // Delete SD
  3543. //
  3544. NTSTATUS TmpStatus;
  3545. BOOLEAN Present;
  3546. BOOLEAN b;
  3547. PACL pAcl;
  3548. TmpStatus = RtlGetDaclSecurityDescriptor(SD, &Present, &pAcl, &b);
  3549. if ( NT_SUCCESS(TmpStatus) && Present ){
  3550. LsapFreeLsaHeap(pAcl);
  3551. }
  3552. LsapFreeLsaHeap(SD);
  3553. }
  3554. }
  3555. LsapFreeLsaHeap( FileName.Buffer );
  3556. } else {
  3557. Status = STATUS_OBJECT_NAME_NOT_FOUND;
  3558. }
  3559. return Status;
  3560. }
  3561. NTSTATUS
  3562. MakeSystemFullControlSD(
  3563. OUT PSECURITY_DESCRIPTOR *ppSD
  3564. )
  3565. /*++
  3566. Routine Description:
  3567. Create a system full control Security Descriptor.
  3568. Arguments:
  3569. ppSD -- System full control security descriptor
  3570. Return Value:
  3571. The status of operation.
  3572. --*/
  3573. {
  3574. NTSTATUS NtStatus = STATUS_SUCCESS;
  3575. PSID SystemSid =NULL;
  3576. SID_IDENTIFIER_AUTHORITY IdentifierAuthority=SECURITY_NT_AUTHORITY;
  3577. PACL pAcl =NULL;
  3578. DWORD cAclSize, cSDSize=0;
  3579. //
  3580. // build system sid
  3581. //
  3582. SystemSid = (PSID) LsapAllocateLsaHeap(RtlLengthRequiredSid(1));
  3583. if ( NULL == SystemSid )
  3584. return(STATUS_INSUFFICIENT_RESOURCES);
  3585. NtStatus = RtlInitializeSid(SystemSid, &IdentifierAuthority, (UCHAR)1);
  3586. if ( !NT_SUCCESS(NtStatus) ){
  3587. LsapFreeLsaHeap( SystemSid );
  3588. return NtStatus;
  3589. }
  3590. *(RtlSubAuthoritySid(SystemSid, 0)) = SECURITY_LOCAL_SYSTEM_RID;
  3591. //
  3592. // build a DACL for system full control
  3593. //
  3594. cAclSize = sizeof(ACL) + sizeof(ACCESS_ALLOWED_OBJECT_ACE) +
  3595. RtlLengthSid(SystemSid);
  3596. pAcl = (PACL)LsapAllocateLsaHeap(cAclSize);
  3597. *ppSD = (PSECURITY_DESCRIPTOR) LsapAllocateLsaHeap(SECURITY_DESCRIPTOR_MIN_LENGTH);
  3598. if ( ( NULL == pAcl ) || ( NULL == *ppSD ) ){
  3599. if ( pAcl ) {
  3600. LsapFreeLsaHeap( pAcl );
  3601. }
  3602. if ( *ppSD ) {
  3603. LsapFreeLsaHeap( *ppSD );
  3604. *ppSD = NULL;
  3605. }
  3606. LsapFreeLsaHeap( SystemSid );
  3607. return STATUS_INSUFFICIENT_RESOURCES;
  3608. }
  3609. RtlZeroMemory(pAcl, cAclSize);
  3610. pAcl->AclRevision = ACL_REVISION_DS;
  3611. pAcl->Sbz1 = (BYTE)0;
  3612. pAcl->AclSize = (USHORT)cAclSize;
  3613. pAcl->AceCount = 0;
  3614. //
  3615. // add a ace to the acl for System full control for file objects
  3616. // the access type is ACCESS_ALLOWED_ACE
  3617. // inheritance flag is CIOI
  3618. //
  3619. NtStatus = RtlAddAccessAllowedAceEx (
  3620. pAcl,
  3621. ACL_REVISION_DS,
  3622. OBJECT_INHERIT_ACE |
  3623. CONTAINER_INHERIT_ACE,
  3624. GENERIC_ALL,
  3625. SystemSid
  3626. );
  3627. if ( NT_SUCCESS(NtStatus) ){
  3628. NtStatus = RtlCreateSecurityDescriptor( *ppSD,
  3629. SECURITY_DESCRIPTOR_REVISION );
  3630. if ( NT_SUCCESS(NtStatus) ){
  3631. //
  3632. // Then set DACL (permission) to the security descriptor
  3633. //
  3634. NtStatus = RtlSetDaclSecurityDescriptor (
  3635. *ppSD,
  3636. TRUE,
  3637. pAcl,
  3638. FALSE
  3639. );
  3640. if ( NT_SUCCESS(NtStatus) ){
  3641. ((SECURITY_DESCRIPTOR *) *ppSD)->Control |= SE_DACL_PROTECTED;
  3642. }
  3643. }
  3644. }
  3645. //
  3646. // free memory for SystemSid
  3647. //
  3648. LsapFreeLsaHeap( SystemSid );
  3649. if (!NT_SUCCESS(NtStatus)){
  3650. LsapFreeLsaHeap( pAcl );
  3651. LsapFreeLsaHeap( *ppSD );
  3652. *ppSD = NULL;
  3653. }
  3654. return (NtStatus);
  3655. }
  3656. NTSTATUS
  3657. CreateLogFile(
  3658. IN PUNICODE_STRING FileName,
  3659. IN PSECURITY_DESCRIPTOR SD,
  3660. OUT HANDLE *LogFile
  3661. )
  3662. /*++
  3663. Routine Description:
  3664. Create a temp log file. We could not use the API GetTempFile to get the temp log file.
  3665. We need our special Security Descriptor.
  3666. Arguments:
  3667. FileName -- Directory to create the temp log file. Has enough space to add temporary
  3668. file name.
  3669. SD -- Security Descriptor.
  3670. LogFile -- File handle.
  3671. Return Value:
  3672. The status of operation.
  3673. --*/
  3674. {
  3675. NTSTATUS Status = STATUS_SUCCESS;
  3676. ULONG Index = 0;
  3677. PWCHAR TempLogFileName;
  3678. int TempFileNameLen;
  3679. USHORT OldLength;
  3680. OBJECT_ATTRIBUTES Obja;
  3681. IO_STATUS_BLOCK IoStatusBlock;
  3682. BOOLEAN StopLoop = FALSE;
  3683. OldLength = FileName->Length + sizeof (WCHAR);
  3684. FileName->Buffer[ FileName->Length/sizeof(WCHAR) ] = L'\\';
  3685. TempLogFileName = FileName->Buffer + OldLength/sizeof (WCHAR) ;
  3686. for (; Index < 10000; Index++){
  3687. TempFileNameLen = swprintf( TempLogFileName, L"EFS%d.LOG", Index);
  3688. FileName->Length = OldLength + (USHORT) TempFileNameLen * sizeof (WCHAR);
  3689. InitializeObjectAttributes(
  3690. &Obja,
  3691. FileName,
  3692. OBJ_CASE_INSENSITIVE,
  3693. 0,
  3694. SD
  3695. );
  3696. Status = NtCreateFile(
  3697. LogFile,
  3698. FILE_READ_DATA | FILE_WRITE_DATA | DELETE | SYNCHRONIZE,
  3699. &Obja,
  3700. &IoStatusBlock,
  3701. NULL,
  3702. FILE_ATTRIBUTE_HIDDEN,
  3703. 0,
  3704. FILE_CREATE,
  3705. FILE_NO_INTERMEDIATE_BUFFERING | FILE_SYNCHRONOUS_IO_NONALERT ,
  3706. NULL,
  3707. 0
  3708. );
  3709. switch (Status) {
  3710. case STATUS_SUCCESS:
  3711. case STATUS_NO_SUCH_FILE:
  3712. case STATUS_OBJECT_PATH_INVALID:
  3713. case STATUS_OBJECT_PATH_SYNTAX_BAD:
  3714. case STATUS_DIRECTORY_IS_A_REPARSE_POINT:
  3715. case STATUS_OBJECT_PATH_NOT_FOUND:
  3716. case STATUS_ACCESS_DENIED:
  3717. case STATUS_DISK_CORRUPT_ERROR:
  3718. case STATUS_FILE_CORRUPT_ERROR:
  3719. case STATUS_DISK_FULL:
  3720. StopLoop = TRUE;
  3721. break;
  3722. default:
  3723. break;
  3724. }
  3725. if (StopLoop) {
  3726. break;
  3727. }
  3728. }
  3729. return Status;
  3730. }
  3731. NTSTATUS
  3732. CreateLogHeader(
  3733. IN HANDLE LogFile,
  3734. IN ULONG SectorSize,
  3735. IN PLARGE_INTEGER TragetID,
  3736. IN PLARGE_INTEGER BackupID OPTIONAL,
  3737. IN LPCWSTR SrcFileName,
  3738. IN LPCWSTR BackupFileName OPTIONAL,
  3739. IN EFSP_OPERATION Operation,
  3740. IN EFS_ACTION_STATUS Action,
  3741. OUT ULONG *LogInfoOffset OPTIONAL
  3742. )
  3743. /*++
  3744. Routine Description:
  3745. Create a log file header.
  3746. Arguments:
  3747. LogFile -- A handle to the log file
  3748. SectorSize -- Sector size of the volume which the log file is in.
  3749. TragetID -- Target file ID.
  3750. BackupID -- Backup file ID.
  3751. SrcFileName -- Target file path
  3752. BackupFileName -- Backup file path
  3753. Operation -- Encrypting or Decrypting
  3754. Action -- The status of the operation.
  3755. LogInfoOffset -- Starting offset of status info copy
  3756. Return Value:
  3757. The status of operation.
  3758. --*/
  3759. {
  3760. BYTE *WorkBuffer;
  3761. PULONG tmpULong;
  3762. PLARGE_INTEGER tmpLL;
  3763. ULONG WorkOffset;
  3764. NTSTATUS Status;
  3765. IO_STATUS_BLOCK IoStatusBlock;
  3766. LARGE_INTEGER ByteOffset;
  3767. ULONG BufferSize;
  3768. ULONG HeadDataSize;
  3769. ULONG SrcFileNameLen; // File path name length in bytes
  3770. ULONG BackupFileNameLen;
  3771. SrcFileNameLen = (wcslen ( SrcFileName ) + 1 ) * sizeof (WCHAR);
  3772. if ( BackupFileName ) {
  3773. BackupFileNameLen = (wcslen ( BackupFileName ) + 1) * sizeof (WCHAR);
  3774. } else {
  3775. BackupFileNameLen = 0;
  3776. }
  3777. HeadDataSize = sizeof ( LOGHEADER ) + SrcFileNameLen + BackupFileNameLen;
  3778. BufferSize = HeadDataSize + sizeof (ULONG); // Data + CheckSum
  3779. if ( BufferSize <= SectorSize ){
  3780. BufferSize = SectorSize;
  3781. } else {
  3782. BufferSize = ((ULONG)((BufferSize - 1) / SectorSize ) + 1) * SectorSize;
  3783. }
  3784. //
  3785. // The memory used here must be aligned with sector boundary.
  3786. // We cannot use LsapAllocateLsaHeap() here
  3787. //
  3788. WorkBuffer = (BYTE *) VirtualAlloc(
  3789. NULL,
  3790. BufferSize,
  3791. MEM_COMMIT,
  3792. PAGE_READWRITE
  3793. );
  3794. if ( NULL == WorkBuffer ){
  3795. return STATUS_INSUFFICIENT_RESOURCES;
  3796. }
  3797. //
  3798. // Prepare common log header
  3799. //
  3800. RtlCopyMemory( ((PLOGHEADER)WorkBuffer)->SIGNATURE, LOGSIG, sizeof(WCHAR) * LOGSIGLEN );
  3801. ((PLOGHEADER)WorkBuffer)->VerID = LOGVERID;
  3802. ((PLOGHEADER)WorkBuffer)->SectorSize = SectorSize;
  3803. if ( Decrypting == Operation ) {
  3804. ((PLOGHEADER)WorkBuffer)->Flag = LOG_DECRYPTION;
  3805. } else {
  3806. ((PLOGHEADER)WorkBuffer)->Flag = 0;
  3807. }
  3808. ((PLOGHEADER)WorkBuffer)->HeaderSize = HeadDataSize;
  3809. ((PLOGHEADER)WorkBuffer)->HeaderBlockSize = BufferSize;
  3810. ((PLOGHEADER)WorkBuffer)->TargetFilePathOffset = sizeof( LOGHEADER );
  3811. ((PLOGHEADER)WorkBuffer)->TargetFilePathLength = SrcFileNameLen;
  3812. RtlCopyMemory(
  3813. WorkBuffer + ((PLOGHEADER)WorkBuffer)->TargetFilePathOffset,
  3814. SrcFileName,
  3815. SrcFileNameLen
  3816. );
  3817. if ( BackupFileName ){
  3818. ((PLOGHEADER)WorkBuffer)->TempFilePathOffset = sizeof( LOGHEADER ) + SrcFileNameLen;
  3819. ((PLOGHEADER)WorkBuffer)->TempFilePathLength = BackupFileNameLen;
  3820. ((PLOGHEADER)WorkBuffer)->TempFileInternalName.QuadPart = BackupID->QuadPart;
  3821. RtlCopyMemory(
  3822. WorkBuffer + ((PLOGHEADER)WorkBuffer)->TempFilePathOffset,
  3823. BackupFileName,
  3824. BackupFileNameLen
  3825. );
  3826. } else {
  3827. ((PLOGHEADER)WorkBuffer)->TempFilePathOffset = 0;
  3828. ((PLOGHEADER)WorkBuffer)->TempFilePathLength = 0;
  3829. ((PLOGHEADER)WorkBuffer)->TempFileInternalName.QuadPart = (LONGLONG) 0;
  3830. }
  3831. ((PLOGHEADER)WorkBuffer)->LengthOfTargetFileInternalName = sizeof (LARGE_INTEGER);
  3832. ((PLOGHEADER)WorkBuffer)->TargetFileInternalName.QuadPart = TragetID->QuadPart;
  3833. ((PLOGHEADER)WorkBuffer)->LengthOfTempFileInternalName = sizeof (LARGE_INTEGER);
  3834. switch (Action){
  3835. case BeginEncryptDir:
  3836. case BeginDecryptDir:
  3837. //
  3838. // No status information required for directory operation
  3839. // If crash happens before the completion, we always switch the status
  3840. // to decrypted status.
  3841. //
  3842. ((PLOGHEADER)WorkBuffer)->OffsetStatus1 = 0;
  3843. ((PLOGHEADER)WorkBuffer)->OffsetStatus2 =0;
  3844. ((PLOGHEADER)WorkBuffer)->Flag |= LOG_DIRECTORY;
  3845. break;
  3846. case BeginEncryptFile:
  3847. case BeginDecryptFile:
  3848. //
  3849. // To guarantee the atomic operation, status info copy begins
  3850. // at sector boundary.
  3851. //
  3852. ((PLOGHEADER)WorkBuffer)->OffsetStatus1 = BufferSize;
  3853. ((PLOGHEADER)WorkBuffer)->OffsetStatus2 = BufferSize + SectorSize;
  3854. if ( LogInfoOffset ){
  3855. *LogInfoOffset = BufferSize;
  3856. }
  3857. break;
  3858. default:
  3859. break;
  3860. }
  3861. CreateBlockSum(WorkBuffer, HeadDataSize, BufferSize );
  3862. //
  3863. // Write out the header sector
  3864. //
  3865. ByteOffset.QuadPart = (LONGLONG) 0;
  3866. Status = NtWriteFile(
  3867. LogFile,
  3868. 0,
  3869. NULL,
  3870. NULL,
  3871. &IoStatusBlock,
  3872. WorkBuffer,
  3873. BufferSize,
  3874. &ByteOffset,
  3875. NULL
  3876. );
  3877. VirtualFree(
  3878. WorkBuffer,
  3879. 0,
  3880. MEM_RELEASE
  3881. );
  3882. return Status;
  3883. }
  3884. NTSTATUS
  3885. WriteLogFile(
  3886. IN HANDLE LogFile,
  3887. IN ULONG SectorSize,
  3888. IN ULONG StartOffset,
  3889. IN EFS_ACTION_STATUS Action
  3890. )
  3891. /*++
  3892. Routine Description:
  3893. Write Log Information.
  3894. Arguments:
  3895. LogFile -- A handle to the log file
  3896. SectorSize -- Sector size of the volume which the log file is in.
  3897. Action -- The status of the operation.
  3898. Return Value:
  3899. The status of operation.
  3900. --*/
  3901. {
  3902. BYTE *WorkBuffer;
  3903. NTSTATUS Status;
  3904. IO_STATUS_BLOCK IoStatusBlock;
  3905. LARGE_INTEGER ByteOffset;
  3906. PULONG tmpULong;
  3907. //
  3908. // The memory used here must be aligned with sector boundary.
  3909. // We cannot use LsapAllocateLsaHeap() here
  3910. //
  3911. WorkBuffer = (BYTE *) VirtualAlloc(
  3912. NULL,
  3913. SectorSize,
  3914. MEM_COMMIT,
  3915. PAGE_READWRITE
  3916. );
  3917. if ( NULL == WorkBuffer ){
  3918. return STATUS_INSUFFICIENT_RESOURCES;
  3919. }
  3920. tmpULong = (PULONG) WorkBuffer;
  3921. *tmpULong = 2 * sizeof ( ULONG );
  3922. * (tmpULong + 1) = Action;
  3923. CreateBlockSum(WorkBuffer, *tmpULong, SectorSize );
  3924. //
  3925. // Write out the header sector
  3926. //
  3927. ByteOffset.QuadPart = (LONGLONG) StartOffset;
  3928. Status = NtWriteFile(
  3929. LogFile,
  3930. 0,
  3931. NULL,
  3932. NULL,
  3933. &IoStatusBlock,
  3934. WorkBuffer,
  3935. SectorSize,
  3936. &ByteOffset,
  3937. NULL
  3938. );
  3939. if ( NT_SUCCESS(Status) ) {
  3940. ByteOffset.QuadPart = (LONGLONG) (StartOffset + SectorSize);
  3941. Status = NtWriteFile(
  3942. LogFile,
  3943. 0,
  3944. NULL,
  3945. NULL,
  3946. &IoStatusBlock,
  3947. WorkBuffer,
  3948. SectorSize,
  3949. &ByteOffset,
  3950. NULL
  3951. );
  3952. }
  3953. VirtualFree(
  3954. WorkBuffer,
  3955. 0,
  3956. MEM_RELEASE
  3957. );
  3958. return Status;
  3959. }
  3960. ULONG
  3961. GetCheckSum(
  3962. IN BYTE *WorkBuffer,
  3963. IN ULONG Length
  3964. )
  3965. /*++
  3966. Routine Description:
  3967. Get the checksum of the written info. A simple checksum
  3968. algorithm is used.
  3969. Arguments:
  3970. WorkBuffer -- Starting point
  3971. Length -- Length of the data to be checksumed.
  3972. Return Value:
  3973. None.
  3974. --*/
  3975. {
  3976. ULONG CheckSum = 0;
  3977. ULONG *WorkData;
  3978. WorkData = (ULONG*)WorkBuffer;
  3979. while ( WorkData < (ULONG *)(WorkBuffer + Length) ){
  3980. //
  3981. // It is OK to add more bytes beyond WorkBuffer + Length if
  3982. // Length is not a multiple of sizeof (ULONG)
  3983. //
  3984. CheckSum += *WorkData++;
  3985. }
  3986. return CheckSum;
  3987. }
  3988. VOID
  3989. CreateBlockSum(
  3990. IN BYTE *WorkBuffer,
  3991. IN ULONG Length,
  3992. IN ULONG BlockSize
  3993. )
  3994. /*++
  3995. Routine Description:
  3996. Create a simple checksum for the sector. The checksum is not security
  3997. sensitive. Only for the purpose of detecting disk write error. A simple checksum
  3998. algorithm is used.
  3999. Arguments:
  4000. WorkBuffer -- Starting point
  4001. Length -- Length of the data to be checksumed.
  4002. SectorSize -- Sector size of the volume which the log file is in.
  4003. Return Value:
  4004. None.
  4005. --*/
  4006. {
  4007. ULONG CheckSum = 0;
  4008. ULONG *WorkData;
  4009. ASSERT ( Length <= BlockSize - sizeof (ULONG));
  4010. CheckSum = GetCheckSum( WorkBuffer, Length );
  4011. //
  4012. // Put the checksum at the end of sector
  4013. //
  4014. WorkData = (ULONG*) (WorkBuffer + BlockSize - sizeof(ULONG));
  4015. *WorkData = CheckSum;
  4016. return;
  4017. }
  4018. NTSTATUS
  4019. CreateBackupFile(
  4020. IN PUNICODE_STRING SourceFileNameU,
  4021. OUT HANDLE *BackupFileHdl,
  4022. OUT FILE_INTERNAL_INFORMATION *BackupID,
  4023. OUT LPWSTR *BackupFileName
  4024. )
  4025. /*++
  4026. Routine Description:
  4027. Create a backup file
  4028. Arguments:
  4029. SourceFileName -- Source file name
  4030. BackupFileHdl -- Backup file handle pointer
  4031. BackupID -- Backup file ID information.
  4032. Return Value:
  4033. The status of operation.
  4034. --*/
  4035. {
  4036. LONG Index;
  4037. int TempFileNameLen;
  4038. LPWSTR BackupPureName;
  4039. UNICODE_STRING BackupFile;
  4040. OBJECT_ATTRIBUTES Obja;
  4041. IO_STATUS_BLOCK IoStatusBlock;
  4042. PSECURITY_DESCRIPTOR SD;
  4043. NTSTATUS Status;
  4044. //
  4045. // Assume source file name in the format XXX...XXX\XXX or XXX
  4046. // No format of X:XXX. (Must be X:\XXX)
  4047. // The name was converted by APIs. The above assumption should be correct.
  4048. //
  4049. Index = SourceFileNameU->Length/sizeof(WCHAR) - 1;
  4050. while ( Index >= 0 ){
  4051. //
  4052. // Find the last '\'
  4053. //
  4054. if ( SourceFileNameU->Buffer[Index--] == L'\\'){
  4055. break;
  4056. }
  4057. }
  4058. Index++;
  4059. //
  4060. // Adjust the Index to point to the end of the directory not including '\'
  4061. //
  4062. if ( SourceFileNameU->Buffer[Index] == L'\\'){
  4063. Index++;
  4064. }
  4065. //
  4066. // Allocate space for the backup file name
  4067. //
  4068. *BackupFileName = (LPWSTR) LsapAllocateLsaHeap( (Index + 20) * sizeof( WCHAR ));
  4069. if ( NULL == *BackupFileName ){
  4070. return STATUS_INSUFFICIENT_RESOURCES;
  4071. }
  4072. RtlCopyMemory( *BackupFileName, SourceFileNameU->Buffer, Index * sizeof(WCHAR));
  4073. BackupPureName = *BackupFileName + Index;
  4074. //
  4075. // Create file Security Descriptor
  4076. //
  4077. Status = MakeSystemFullControlSD( &SD );
  4078. if ( NT_SUCCESS(Status) ){
  4079. BOOLEAN StopLoop = FALSE;
  4080. for (ULONG ii = 0; ii < 100000; ii++){
  4081. BOOLEAN b;
  4082. TempFileNameLen = swprintf(BackupPureName, L"EFS%d.TMP", ii);
  4083. b = RtlDosPathNameToNtPathName_U(
  4084. *BackupFileName,
  4085. &BackupFile,
  4086. NULL,
  4087. NULL
  4088. );
  4089. if ( b ){
  4090. InitializeObjectAttributes(
  4091. &Obja,
  4092. &BackupFile,
  4093. OBJ_CASE_INSENSITIVE,
  4094. 0,
  4095. SD
  4096. );
  4097. //
  4098. // Create the EFS Temp file
  4099. // Does not hurt using FILE_OPEN_REPARSE_POINT
  4100. //
  4101. Status = NtCreateFile(
  4102. BackupFileHdl,
  4103. GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE | DELETE,
  4104. &Obja,
  4105. &IoStatusBlock,
  4106. NULL,
  4107. FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM,
  4108. 0,
  4109. FILE_CREATE,
  4110. FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_REPARSE_POINT,
  4111. NULL,
  4112. 0
  4113. );
  4114. if ( STATUS_ACCESS_DENIED == Status ) {
  4115. //
  4116. // Let's try to open it in the Local_System
  4117. //
  4118. RpcRevertToSelf();
  4119. Status = NtCreateFile(
  4120. BackupFileHdl,
  4121. GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE | DELETE,
  4122. &Obja,
  4123. &IoStatusBlock,
  4124. NULL,
  4125. FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM,
  4126. 0,
  4127. FILE_CREATE,
  4128. FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_REPARSE_POINT,
  4129. NULL,
  4130. 0
  4131. );
  4132. if (RPC_S_OK != RpcImpersonateClient( NULL )){
  4133. //
  4134. // This is very unlikely. We have did this before and it all succeeded.
  4135. // If this happens, let's quit as if we get STATUS_ACCESS_DENIED.
  4136. //
  4137. if (NT_SUCCESS(Status)) {
  4138. MarkFileForDelete(*BackupFileHdl);
  4139. CloseHandle( *BackupFileHdl );
  4140. *BackupFileHdl = 0;
  4141. }
  4142. Status = STATUS_ACCESS_DENIED;
  4143. }
  4144. }
  4145. RtlFreeHeap(
  4146. RtlProcessHeap(),
  4147. 0,
  4148. BackupFile.Buffer
  4149. );
  4150. switch (Status) {
  4151. case STATUS_SUCCESS:
  4152. case STATUS_NO_SUCH_FILE:
  4153. case STATUS_OBJECT_PATH_INVALID:
  4154. case STATUS_OBJECT_PATH_SYNTAX_BAD:
  4155. case STATUS_DIRECTORY_IS_A_REPARSE_POINT:
  4156. case STATUS_OBJECT_PATH_NOT_FOUND:
  4157. case STATUS_ACCESS_DENIED:
  4158. case STATUS_DISK_CORRUPT_ERROR:
  4159. case STATUS_FILE_CORRUPT_ERROR:
  4160. case STATUS_DISK_FULL:
  4161. StopLoop = TRUE;
  4162. break;
  4163. default:
  4164. break;
  4165. }
  4166. if (StopLoop) {
  4167. break;
  4168. }
  4169. }
  4170. }
  4171. if ( NT_SUCCESS(Status) ){
  4172. if ( NT_SUCCESS(Status) ){
  4173. //
  4174. // Get FileID
  4175. //
  4176. Status = NtQueryInformationFile(
  4177. *BackupFileHdl,
  4178. &IoStatusBlock,
  4179. BackupID,
  4180. sizeof ( FILE_INTERNAL_INFORMATION ),
  4181. FileInternalInformation
  4182. );
  4183. if ( !NT_SUCCESS(Status) ){
  4184. MarkFileForDelete(*BackupFileHdl);
  4185. CloseHandle( *BackupFileHdl );
  4186. *BackupFileHdl = 0;
  4187. }
  4188. } else {
  4189. MarkFileForDelete(*BackupFileHdl);
  4190. CloseHandle( *BackupFileHdl );
  4191. *BackupFileHdl = 0;
  4192. }
  4193. }
  4194. {
  4195. //
  4196. // Delete SD
  4197. //
  4198. NTSTATUS TmpStatus;
  4199. BOOLEAN Present;
  4200. BOOLEAN b;
  4201. PACL pAcl;
  4202. TmpStatus = RtlGetDaclSecurityDescriptor(SD, &Present, &pAcl, &b);
  4203. if ( NT_SUCCESS(TmpStatus) && Present ){
  4204. LsapFreeLsaHeap(pAcl);
  4205. }
  4206. LsapFreeLsaHeap(SD);
  4207. }
  4208. }
  4209. if ( !NT_SUCCESS(Status) ){
  4210. LsapFreeLsaHeap( *BackupFileName );
  4211. *BackupFileName = NULL;
  4212. }
  4213. return Status;
  4214. }
  4215. NTSTATUS
  4216. SendGenFsctl(
  4217. IN HANDLE Target,
  4218. IN ULONG Psc,
  4219. IN ULONG Csc,
  4220. IN ULONG EfsCode,
  4221. IN ULONG FsCode
  4222. )
  4223. /*++
  4224. Routine Description:
  4225. Set the encrypted file status to normal.
  4226. Arguments:
  4227. Target -- A handle to the target file or directory.
  4228. Psc -- Plain sub code
  4229. Csc -- Cipher sub code
  4230. EfsCode -- Efs function code
  4231. FsCode -- FSCTL code
  4232. Return Value:
  4233. The status of operation.
  4234. --*/
  4235. {
  4236. NTSTATUS Status = STATUS_SUCCESS;
  4237. ULONG InputDataSize;
  4238. PUCHAR InputData;
  4239. IO_STATUS_BLOCK IoStatusBlock;
  4240. InputDataSize = 7 * sizeof ( ULONG ) + 2 * sizeof ( DriverSessionKey );
  4241. InputData = (PUCHAR)LsapAllocateLsaHeap( InputDataSize );
  4242. if ( InputData == NULL ) {
  4243. //
  4244. // This is unlikely to happen during the boot time.
  4245. //
  4246. return( STATUS_INSUFFICIENT_RESOURCES );
  4247. }
  4248. //
  4249. // Sync FSCTL assumed
  4250. //
  4251. Status = SendSkFsctl(
  4252. Psc,
  4253. Csc,
  4254. EfsCode,
  4255. InputData,
  4256. InputDataSize,
  4257. Target,
  4258. FsCode,
  4259. &IoStatusBlock
  4260. );
  4261. LsapFreeLsaHeap( InputData );
  4262. return Status;
  4263. }
  4264. DWORD
  4265. EfsOpenFileRaw(
  4266. IN LPCWSTR FileName,
  4267. IN LPCWSTR LocalFileName,
  4268. IN BOOL NetSession,
  4269. IN ULONG Flags,
  4270. OUT PVOID * Context
  4271. )
  4272. /*++
  4273. Routine Description:
  4274. This routine is used to open an encrypted file. It opens the file and
  4275. prepares the necessary context to be used in ReadRaw data and WriteRaw
  4276. data.
  4277. Arguments:
  4278. FileName -- Remote File name of the file to be exported. Used to check the share.
  4279. LocalFileName -- Local file name for real jobs.
  4280. NetSession -- Indicates network session.
  4281. Flags -- Indicating if open for export or import; for directory or file.
  4282. Context - Export context to be used by READ operation later. Caller should
  4283. pass this back in ReadRaw().
  4284. Return Value:
  4285. Result of the operation.
  4286. --*/
  4287. {
  4288. ULONG FileAttributes = FILE_ATTRIBUTE_NORMAL;
  4289. ACCESS_MASK FileAccess = 0 ;
  4290. BOOL Privilege = FALSE; // FALSE - not a backup operator
  4291. ULONG CreateDist = 0;
  4292. ULONG CreateOptions = 0;
  4293. ULONG ShareMode = 0;
  4294. HANDLE HSourceFile;
  4295. NTSTATUS NtStatus;
  4296. DWORD HResult;
  4297. OBJECT_ATTRIBUTES ObjectAttributes;
  4298. OBJECT_ATTRIBUTES NetObjectAttributes;
  4299. IO_STATUS_BLOCK IoStatus;
  4300. UNICODE_STRING UniFileName;
  4301. UNICODE_STRING UniNetFileName={0,0,NULL};
  4302. BOOLEAN TranslationStatus;
  4303. PFILE_STREAM_INFORMATION StreamInfoBase = NULL;
  4304. ULONG StreamInfoSize = 0;
  4305. PUNICODE_STRING StreamNames = NULL;
  4306. PHANDLE StreamHandles = NULL;
  4307. ULONG StreamCount = 0;
  4308. TOKEN_PRIVILEGES Privs;
  4309. PTOKEN_PRIVILEGES OldPrivs;
  4310. BOOL b;
  4311. HANDLE TokenHandle = 0;
  4312. DWORD ReturnLength;
  4313. //
  4314. // Convert file name to UNICODE_STRING and UNC format
  4315. // Create an OBJECT_ATTRIBUTES
  4316. //
  4317. TranslationStatus = RtlDosPathNameToNtPathName_U(
  4318. LocalFileName,
  4319. &UniFileName,
  4320. NULL,
  4321. NULL
  4322. );
  4323. if ( !TranslationStatus ) {
  4324. return ERROR_PATH_NOT_FOUND;
  4325. }
  4326. if (NetSession) {
  4327. TranslationStatus = RtlDosPathNameToNtPathName_U(
  4328. FileName,
  4329. &UniNetFileName,
  4330. NULL,
  4331. NULL
  4332. );
  4333. if ( !TranslationStatus ) {
  4334. RtlFreeHeap(
  4335. RtlProcessHeap(),
  4336. 0,
  4337. UniFileName.Buffer
  4338. );
  4339. return ERROR_PATH_NOT_FOUND;
  4340. }
  4341. InitializeObjectAttributes(
  4342. &NetObjectAttributes,
  4343. &UniNetFileName,
  4344. OBJ_CASE_INSENSITIVE,
  4345. NULL,
  4346. NULL
  4347. );
  4348. }
  4349. InitializeObjectAttributes(
  4350. &ObjectAttributes,
  4351. &UniFileName,
  4352. OBJ_CASE_INSENSITIVE,
  4353. NULL,
  4354. NULL
  4355. );
  4356. if ( Flags & CREATE_FOR_IMPORT ){
  4357. //
  4358. // Prepare parameters for create of import
  4359. //
  4360. FileAccess = FILE_WRITE_ATTRIBUTES;
  4361. if ( Flags & CREATE_FOR_DIR ){
  4362. //
  4363. // Import a directory
  4364. //
  4365. FileAccess |= FILE_WRITE_DATA | FILE_READ_DATA | FILE_READ_ATTRIBUTES | SYNCHRONIZE;
  4366. CreateDist = FILE_OPEN_IF;
  4367. CreateOptions |= FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT | FILE_NO_COMPRESSION;
  4368. FileAttributes |= FILE_ATTRIBUTE_DIRECTORY;
  4369. } else {
  4370. //
  4371. // Import file
  4372. // Should we use FILE_SUPERSEDE here?
  4373. //
  4374. FileAccess |= SYNCHRONIZE;
  4375. CreateDist = FILE_OVERWRITE_IF;
  4376. CreateOptions |= FILE_OPEN_REPARSE_POINT | FILE_SYNCHRONOUS_IO_NONALERT | FILE_NO_COMPRESSION;
  4377. if (Flags & OVERWRITE_HIDDEN) {
  4378. FileAttributes |= FILE_ATTRIBUTE_HIDDEN;
  4379. }
  4380. }
  4381. } else {
  4382. //
  4383. // If export is requested and the file is not encrypted,
  4384. // Fail the call.
  4385. //
  4386. FileAccess = FILE_READ_ATTRIBUTES;
  4387. //
  4388. // Prepare parameters for create of export
  4389. //
  4390. CreateDist = FILE_OPEN;
  4391. if ( Flags & CREATE_FOR_DIR ){
  4392. //
  4393. // Export a directory
  4394. //
  4395. FileAccess |= FILE_READ_DATA;
  4396. CreateOptions |= FILE_DIRECTORY_FILE;
  4397. } else {
  4398. FileAccess |= SYNCHRONIZE;
  4399. CreateOptions |= FILE_OPEN_REPARSE_POINT | FILE_SYNCHRONOUS_IO_NONALERT;
  4400. }
  4401. }
  4402. OldPrivs = ( TOKEN_PRIVILEGES *) LsapAllocateLsaHeap(sizeof( TOKEN_PRIVILEGES ));
  4403. if ( OldPrivs == NULL ){
  4404. RtlFreeHeap(
  4405. RtlProcessHeap(),
  4406. 0,
  4407. UniFileName.Buffer
  4408. );
  4409. if (NetSession) {
  4410. RtlFreeHeap(
  4411. RtlProcessHeap(),
  4412. 0,
  4413. UniNetFileName.Buffer
  4414. );
  4415. }
  4416. return ERROR_NOT_ENOUGH_MEMORY;
  4417. }
  4418. //
  4419. // We're impersonating, use the thread token.
  4420. //
  4421. b = OpenThreadToken(
  4422. GetCurrentThread(),
  4423. TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
  4424. FALSE,
  4425. &TokenHandle
  4426. );
  4427. if ( b ) {
  4428. //
  4429. // We've got a token handle
  4430. //
  4431. //
  4432. // If we're doing a create for import, enable restore privilege,
  4433. // otherwise enable backup privilege.
  4434. //
  4435. Privs.PrivilegeCount = 1;
  4436. Privs.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
  4437. if ( !(Flags & CREATE_FOR_IMPORT) ){
  4438. Privs.Privileges[0].Luid = RtlConvertLongToLuid(SE_BACKUP_PRIVILEGE);
  4439. } else {
  4440. Privs.Privileges[0].Luid = RtlConvertLongToLuid(SE_RESTORE_PRIVILEGE);
  4441. }
  4442. ReturnLength = sizeof( TOKEN_PRIVILEGES );
  4443. (VOID) AdjustTokenPrivileges (
  4444. TokenHandle,
  4445. FALSE,
  4446. &Privs,
  4447. sizeof( TOKEN_PRIVILEGES ),
  4448. OldPrivs,
  4449. &ReturnLength
  4450. );
  4451. if ( ERROR_SUCCESS == GetLastError() ) {
  4452. Privilege = TRUE;
  4453. } else {
  4454. //
  4455. // Privilege adjust failed
  4456. //
  4457. CloseHandle( TokenHandle );
  4458. TokenHandle = 0;
  4459. }
  4460. } else {
  4461. //
  4462. // We did not get the handle.
  4463. //
  4464. TokenHandle = 0;
  4465. }
  4466. //
  4467. // Caller will call RpcRevertToSelf().
  4468. // OldPrivs is not needed any more.
  4469. //
  4470. LsapFreeLsaHeap( OldPrivs );
  4471. OldPrivs = NULL;
  4472. if ( !Privilege ){
  4473. //
  4474. // Not a backup operator
  4475. //
  4476. if ( !(Flags & CREATE_FOR_IMPORT) ){
  4477. FileAccess |= FILE_READ_DATA;
  4478. } else {
  4479. FileAccess |= FILE_WRITE_DATA;
  4480. }
  4481. } else {
  4482. //
  4483. // A backup operator or the user with the privilege
  4484. //
  4485. CreateOptions |= FILE_OPEN_FOR_BACKUP_INTENT;
  4486. if ( !(Flags & CREATE_FOR_DIR) ){
  4487. FileAccess |= DELETE;
  4488. }
  4489. }
  4490. if (NetSession) {
  4491. //
  4492. // This create is for checking share access only. The handle from this is not good for
  4493. // FSCTL with data buffer larger than 64K.
  4494. //
  4495. NtStatus = NtCreateFile(
  4496. &HSourceFile,
  4497. FileAccess,
  4498. &NetObjectAttributes,
  4499. &IoStatus,
  4500. (PLARGE_INTEGER) NULL,
  4501. FileAttributes,
  4502. ShareMode,
  4503. CreateDist,
  4504. CreateOptions,
  4505. (PVOID) NULL,
  4506. 0L
  4507. );
  4508. RtlFreeHeap(
  4509. RtlProcessHeap(),
  4510. 0,
  4511. UniNetFileName.Buffer
  4512. );
  4513. if (NT_SUCCESS(NtStatus)) {
  4514. CloseHandle( HSourceFile );
  4515. } else {
  4516. RtlFreeHeap(
  4517. RtlProcessHeap(),
  4518. 0,
  4519. UniFileName.Buffer
  4520. );
  4521. if ( TokenHandle ){
  4522. CloseHandle( TokenHandle );
  4523. }
  4524. return RtlNtStatusToDosError( NtStatus );
  4525. }
  4526. }
  4527. NtStatus = NtCreateFile(
  4528. &HSourceFile,
  4529. FileAccess,
  4530. &ObjectAttributes,
  4531. &IoStatus,
  4532. (PLARGE_INTEGER) NULL,
  4533. FileAttributes,
  4534. ShareMode,
  4535. CreateDist,
  4536. CreateOptions,
  4537. (PVOID) NULL,
  4538. 0L
  4539. );
  4540. RtlFreeHeap(
  4541. RtlProcessHeap(),
  4542. 0,
  4543. UniFileName.Buffer
  4544. );
  4545. //
  4546. // No need for FILE_DIRECTORY_FILE any more
  4547. //
  4548. CreateOptions &= ~FILE_DIRECTORY_FILE;
  4549. FileAttributes &= ~FILE_ATTRIBUTE_DIRECTORY;
  4550. if (NT_SUCCESS(NtStatus)){
  4551. if ( Flags & CREATE_FOR_IMPORT ){
  4552. if (Flags & CREATE_FOR_DIR) {
  4553. //
  4554. // If the dir existed and compressed, we need extra steps to uncompressed it
  4555. //
  4556. FILE_BASIC_INFORMATION StreamBasicInfo;
  4557. //
  4558. // Get File Attributes
  4559. //
  4560. NtStatus = NtQueryInformationFile(
  4561. HSourceFile,
  4562. &IoStatus,
  4563. &StreamBasicInfo,
  4564. sizeof ( FILE_BASIC_INFORMATION ),
  4565. FileBasicInformation
  4566. );
  4567. if (NT_SUCCESS(NtStatus)){
  4568. if (StreamBasicInfo.FileAttributes & FILE_ATTRIBUTE_COMPRESSED){
  4569. USHORT State = COMPRESSION_FORMAT_NONE;
  4570. ULONG Length;
  4571. //
  4572. // Attempt to uncompress the directory
  4573. //
  4574. b = DeviceIoControl(
  4575. HSourceFile,
  4576. FSCTL_SET_COMPRESSION,
  4577. &State,
  4578. sizeof(USHORT),
  4579. NULL,
  4580. 0,
  4581. &Length,
  4582. FALSE
  4583. );
  4584. if (!b) {
  4585. HResult = GetLastError();
  4586. CloseHandle( HSourceFile );
  4587. if ( TokenHandle ){
  4588. CloseHandle( TokenHandle );
  4589. }
  4590. return HResult;
  4591. }
  4592. }
  4593. } else {
  4594. CloseHandle( HSourceFile );
  4595. if ( TokenHandle ){
  4596. CloseHandle( TokenHandle );
  4597. }
  4598. return RtlNtStatusToDosError( NtStatus );
  4599. }
  4600. }
  4601. //
  4602. // Prepare import context
  4603. //
  4604. *Context = LsapAllocateLsaHeap(sizeof( IMPORT_CONTEXT ));
  4605. if ( *Context ){
  4606. (( PIMPORT_CONTEXT ) *Context)->Flag = CONTEXT_FOR_IMPORT;
  4607. if (Flags & CREATE_FOR_DIR) {
  4608. (( PIMPORT_CONTEXT ) *Context)->Flag |= CONTEXT_OPEN_FOR_DIR;
  4609. }
  4610. (( PIMPORT_CONTEXT ) *Context)->Handle = HSourceFile;
  4611. (( PIMPORT_CONTEXT ) *Context)->ContextID = EFS_CONTEXT_ID;
  4612. (( PIMPORT_CONTEXT ) *Context)->Attribute = FileAttributes;
  4613. (( PIMPORT_CONTEXT ) *Context)->CreateDisposition = CreateDist;
  4614. (( PIMPORT_CONTEXT ) *Context)->CreateOptions = CreateOptions;
  4615. (( PIMPORT_CONTEXT ) *Context)->DesiredAccess = FileAccess;
  4616. } else {
  4617. CloseHandle( HSourceFile );
  4618. HSourceFile = 0;
  4619. NtStatus = STATUS_INSUFFICIENT_RESOURCES;
  4620. }
  4621. } else {
  4622. FILE_BASIC_INFORMATION StreamBasicInfo;
  4623. IO_STATUS_BLOCK IoStatusBlock;
  4624. //
  4625. // Get File Attributes
  4626. //
  4627. NtStatus = NtQueryInformationFile(
  4628. HSourceFile,
  4629. &IoStatusBlock,
  4630. &StreamBasicInfo,
  4631. sizeof ( FILE_BASIC_INFORMATION ),
  4632. FileBasicInformation
  4633. );
  4634. if ( NT_SUCCESS(NtStatus)) {
  4635. if ( !(StreamBasicInfo.FileAttributes & FILE_ATTRIBUTE_ENCRYPTED) ){
  4636. NtStatus = STATUS_ACCESS_DENIED;
  4637. }
  4638. }
  4639. if (!NT_SUCCESS(NtStatus)) {
  4640. CloseHandle( HSourceFile );
  4641. HSourceFile = 0;
  4642. if ( TokenHandle ){
  4643. CloseHandle( TokenHandle );
  4644. }
  4645. return RtlNtStatusToDosError( NtStatus );
  4646. }
  4647. //
  4648. // Prepare export context
  4649. //
  4650. NtStatus = GetStreamInformation(
  4651. HSourceFile,
  4652. &StreamInfoBase,
  4653. &StreamInfoSize
  4654. );
  4655. if (NT_SUCCESS(NtStatus)){
  4656. if (FileAccess & DELETE) {
  4657. ShareMode |= FILE_SHARE_DELETE;
  4658. }
  4659. HResult = OpenFileStreams(
  4660. HSourceFile,
  4661. ShareMode,
  4662. OPEN_FOR_EXP,
  4663. StreamInfoBase,
  4664. FileAccess,
  4665. CreateDist,
  4666. CreateOptions,
  4667. NULL,
  4668. &StreamNames,
  4669. &StreamHandles,
  4670. NULL,
  4671. &StreamCount
  4672. );
  4673. if ( HResult == NO_ERROR ) {
  4674. *Context = LsapAllocateLsaHeap( sizeof( EXPORT_CONTEXT ) );
  4675. if ( *Context ){
  4676. ((PEXPORT_CONTEXT) *Context)->Flag = CONTEXT_FOR_EXPORT;
  4677. if (Flags & CREATE_FOR_DIR) {
  4678. (( PEXPORT_CONTEXT ) *Context)->Flag |= CONTEXT_OPEN_FOR_DIR;
  4679. }
  4680. ((PEXPORT_CONTEXT) *Context)->Handle = HSourceFile;
  4681. ((PEXPORT_CONTEXT ) *Context)->ContextID = EFS_CONTEXT_ID;
  4682. ((PEXPORT_CONTEXT) *Context)->NumberOfStreams = StreamCount;
  4683. ((PEXPORT_CONTEXT) *Context)->StreamHandles = StreamHandles;
  4684. ((PEXPORT_CONTEXT) *Context)->StreamNames = StreamNames;
  4685. ((PEXPORT_CONTEXT) *Context)->StreamInfoBase = StreamInfoBase;
  4686. } else {
  4687. //
  4688. // Out of memory
  4689. //
  4690. CleanupOpenFileStreams(
  4691. StreamHandles,
  4692. StreamNames,
  4693. NULL,
  4694. StreamInfoBase,
  4695. HSourceFile,
  4696. StreamCount
  4697. );
  4698. StreamHandles = NULL;
  4699. StreamNames = NULL;
  4700. StreamInfoBase = NULL;
  4701. HSourceFile = 0;
  4702. NtStatus = STATUS_INSUFFICIENT_RESOURCES;
  4703. }
  4704. } else {
  4705. //
  4706. // Open streams wrong, free StreamInfoBase
  4707. //
  4708. if (StreamInfoBase) {
  4709. LsapFreeLsaHeap( StreamInfoBase );
  4710. StreamInfoBase = NULL;
  4711. }
  4712. CloseHandle( HSourceFile );
  4713. HSourceFile = 0;
  4714. if ( TokenHandle ){
  4715. CloseHandle( TokenHandle );
  4716. }
  4717. return HResult;
  4718. }
  4719. } else {
  4720. //
  4721. // Get stream info wrong
  4722. //
  4723. CloseHandle( HSourceFile );
  4724. HSourceFile = 0;
  4725. }
  4726. }
  4727. }
  4728. if ( TokenHandle ){
  4729. CloseHandle( TokenHandle );
  4730. }
  4731. return RtlNtStatusToDosError( NtStatus );
  4732. }
  4733. VOID
  4734. EfsCloseFileRaw(
  4735. IN PVOID Context
  4736. )
  4737. /*++
  4738. Routine Description:
  4739. This routine frees the resources allocated by the CreateRaw
  4740. Arguments:
  4741. Context - Created by the EfsOpenFileRaw.
  4742. Return Value:
  4743. NO.
  4744. --*/
  4745. {
  4746. if ( !Context || (((PEXPORT_CONTEXT) Context)->ContextID != EFS_CONTEXT_ID) ){
  4747. return;
  4748. }
  4749. if ( !(((PEXPORT_CONTEXT) Context)->Flag & CONTEXT_INVALID) ){
  4750. if ( ((PEXPORT_CONTEXT) Context)->Flag & CONTEXT_FOR_IMPORT ){
  4751. //
  4752. // Free import context
  4753. //
  4754. CleanupOpenFileStreams(
  4755. NULL,
  4756. NULL,
  4757. NULL,
  4758. NULL,
  4759. ((PIMPORT_CONTEXT) Context)->Handle,
  4760. 0
  4761. );
  4762. //
  4763. // Defensive code
  4764. //
  4765. ((PIMPORT_CONTEXT) Context)->Flag |= CONTEXT_INVALID;
  4766. } else {
  4767. //
  4768. // Free export context
  4769. //
  4770. CleanupOpenFileStreams(
  4771. ((PEXPORT_CONTEXT) Context)->StreamHandles,
  4772. ((PEXPORT_CONTEXT) Context)->StreamNames,
  4773. NULL,
  4774. ((PEXPORT_CONTEXT) Context)->StreamInfoBase,
  4775. ((PEXPORT_CONTEXT) Context)->Handle,
  4776. ((PEXPORT_CONTEXT) Context)->NumberOfStreams
  4777. );
  4778. //
  4779. // Defensive code
  4780. //
  4781. ((PEXPORT_CONTEXT) Context)->Flag |= CONTEXT_INVALID;
  4782. }
  4783. }
  4784. LsapFreeLsaHeap( Context);
  4785. }
  4786. long EfsReadFileRaw(
  4787. PVOID Context,
  4788. PVOID EfsOutPipe
  4789. )
  4790. /*++
  4791. Routine Description:
  4792. This routine is used to read encrypted file's raw data. It uses
  4793. NTFS FSCTL to get the data.
  4794. Arguments:
  4795. Context -- Context handle.
  4796. EfsOutPipe -- Pipe handle.
  4797. Return Value:
  4798. The result of operation.
  4799. --*/
  4800. {
  4801. VOID *FsctlInput = NULL;
  4802. VOID *WorkBuffer = NULL;
  4803. VOID *BufPointer;
  4804. VOID *FsctlOutput;
  4805. USHORT *PUShort;
  4806. PULONG PUlong;
  4807. ULONG FsctlInputLength;
  4808. ULONG EfsDataLength;
  4809. ULONG FsctlOutputLength;
  4810. ULONG SendDataLength;
  4811. ULONG WkBufLength;
  4812. ULONG BytesAdvanced;
  4813. DWORD HResult = NO_ERROR;
  4814. BOOLEAN MoreToRead = TRUE;
  4815. BOOLEAN StreamEncrypted = TRUE;
  4816. ULONG StreamIndex;
  4817. LONGLONG StreamOffset;
  4818. NTSTATUS NtStatus;
  4819. IO_STATUS_BLOCK IoStatusBlock;
  4820. FILE_BASIC_INFORMATION StreamInfo;
  4821. ULONG ii;
  4822. if ( !Context ||
  4823. ( ( (PEXPORT_CONTEXT) Context)->Flag &
  4824. ( CONTEXT_FOR_IMPORT | CONTEXT_INVALID )) ||
  4825. (((PEXPORT_CONTEXT) Context)->ContextID != EFS_CONTEXT_ID)
  4826. ){
  4827. //
  4828. // Flush the pipe and return error.
  4829. //
  4830. HResult = EFSSendPipeData( (char *)&SendDataLength, 0, EfsOutPipe );
  4831. return ERROR_ACCESS_DENIED;
  4832. }
  4833. //
  4834. // Allocate necessary memory
  4835. //
  4836. FsctlInput = LsapAllocateLsaHeap( FSCTL_EXPORT_INPUT_LENGTH );
  4837. //
  4838. // Try to allocate a reasonable size buffer. The size can be fine tuned later, but should
  4839. // at least one page plus 4K. FSCTL_OUTPUT_LESS_LENGTH should be n * page size.
  4840. // FSCTL_OUTPUT_MIN_LENGTH can be fine tuned later. It should be at least one page
  4841. // plus 4K.
  4842. //
  4843. WkBufLength = FSCTL_OUTPUT_INITIAL_LENGTH;
  4844. while ( !WorkBuffer && WkBufLength >= FSCTL_OUTPUT_MIN_LENGTH ){
  4845. //
  4846. // Sector alignment is required here.
  4847. //
  4848. WorkBuffer = VirtualAlloc(
  4849. NULL,
  4850. WkBufLength,
  4851. MEM_COMMIT,
  4852. PAGE_READWRITE
  4853. );
  4854. if ( !WorkBuffer ){
  4855. //
  4856. // Memory allocation failed.
  4857. // Try smaller allocation.
  4858. //
  4859. WkBufLength -= FSCTL_OUTPUT_LESS_LENGTH;
  4860. }
  4861. }
  4862. if ( !WorkBuffer || !FsctlInput ){
  4863. //
  4864. // Not enough memory to run export
  4865. //
  4866. if ( WorkBuffer ){
  4867. VirtualFree(
  4868. WorkBuffer,
  4869. 0,
  4870. MEM_RELEASE
  4871. );
  4872. }
  4873. if ( FsctlInput ){
  4874. LsapFreeLsaHeap( FsctlInput );
  4875. }
  4876. //
  4877. // Flush the pipe and return error.
  4878. //
  4879. HResult = EFSSendPipeData( (char *)&SendDataLength, 0, EfsOutPipe );
  4880. return ERROR_OUTOFMEMORY;
  4881. }
  4882. RtlZeroMemory( FsctlInput, FSCTL_EXPORT_INPUT_LENGTH );
  4883. RtlZeroMemory( WorkBuffer, WkBufLength );
  4884. //
  4885. // Prepare the export file header
  4886. //
  4887. (( PEFSEXP_FILE_HEADER )WorkBuffer )->VersionID = EFS_EXP_FORMAT_CURRENT_VERSION;
  4888. RtlCopyMemory( &((( PEFSEXP_FILE_HEADER )WorkBuffer )->FileSignature[0]),
  4889. FILE_SIGNATURE,
  4890. EFS_SIGNATURE_LENGTH * sizeof( WCHAR )
  4891. );
  4892. BufPointer = (char *) WorkBuffer + sizeof ( EFSEXP_FILE_HEADER );
  4893. (( PEFSEXP_STREAM_HEADER )BufPointer )->Length = sizeof (USHORT) +
  4894. sizeof (EFSEXP_STREAM_HEADER);
  4895. RtlCopyMemory( &((( PEFSEXP_STREAM_HEADER )BufPointer )->StreamSignature[0]),
  4896. STREAM_SIGNATURE,
  4897. EFS_SIGNATURE_LENGTH * sizeof( WCHAR )
  4898. );
  4899. (( PEFSEXP_STREAM_HEADER )BufPointer )->NameLength = sizeof (USHORT);
  4900. BufPointer = (char *)BufPointer + sizeof (EFSEXP_STREAM_HEADER);
  4901. PUShort = (USHORT *)BufPointer;
  4902. *PUShort = EFS_STREAM_ID;
  4903. //
  4904. // Let's send out the File header and stream header
  4905. //
  4906. SendDataLength = (ULONG)((char *)BufPointer - (char *)WorkBuffer) + sizeof (USHORT);
  4907. HResult = EFSSendPipeData( (char *)WorkBuffer, SendDataLength, EfsOutPipe );
  4908. if (HResult != NO_ERROR) {
  4909. VirtualFree(
  4910. WorkBuffer,
  4911. 0,
  4912. MEM_RELEASE
  4913. );
  4914. LsapFreeLsaHeap( FsctlInput );
  4915. //
  4916. // Flush the pipe and return error.
  4917. //
  4918. (void) EFSSendPipeData( (char *)&SendDataLength, 0, EfsOutPipe );
  4919. return HResult;
  4920. }
  4921. //
  4922. // Reset BufPointer so that it is aligned again.
  4923. //
  4924. RtlZeroMemory( WorkBuffer, SendDataLength );
  4925. BufPointer = WorkBuffer;
  4926. RtlCopyMemory( &((( PEFSEXP_DATA_HEADER )BufPointer )->DataSignature[0]),
  4927. DATA_SIGNATURE,
  4928. EFS_SIGNATURE_LENGTH * sizeof( WCHAR )
  4929. );
  4930. FsctlOutput = (char *)BufPointer + sizeof ( EFSEXP_DATA_HEADER );
  4931. FsctlOutputLength = WkBufLength - ( (ULONG) (( char* ) FsctlOutput - ( char* )WorkBuffer) );
  4932. //
  4933. // Issue the FSCTL to get the $EFS
  4934. //
  4935. EfsDataLength = FsctlInputLength = COMMON_FSCTL_HEADER_SIZE;
  4936. ( VOID )SendHandle(
  4937. ((PEXPORT_CONTEXT) Context)->Handle,
  4938. (PUCHAR)FsctlInput + 3 * sizeof( ULONG ),
  4939. &EfsDataLength
  4940. );
  4941. ( VOID ) EncryptFSCTLData(
  4942. EFS_GET_ATTRIBUTE,
  4943. 0,
  4944. 0,
  4945. (PUCHAR)FsctlInput + 3 * sizeof(ULONG),
  4946. EfsDataLength,
  4947. (PUCHAR)FsctlInput,
  4948. &FsctlInputLength
  4949. );
  4950. NtStatus = NtFsControlFile(
  4951. ((PEXPORT_CONTEXT) Context)->Handle,
  4952. 0,
  4953. NULL,
  4954. NULL,
  4955. &IoStatusBlock,
  4956. FSCTL_ENCRYPTION_FSCTL_IO,
  4957. FsctlInput,
  4958. FsctlInputLength,
  4959. FsctlOutput,
  4960. FsctlOutputLength
  4961. );
  4962. if (!NT_SUCCESS( NtStatus )) {
  4963. //
  4964. // Check if the output data buffer too small
  4965. // Try again if it is.
  4966. //
  4967. if ( NtStatus == STATUS_BUFFER_TOO_SMALL ){
  4968. ULONG EfsMetaDataLength;
  4969. ULONG BytesInBuffer;
  4970. VOID *TmpBuffer;
  4971. EfsMetaDataLength = *((ULONG *)FsctlOutput);
  4972. BytesInBuffer = (ULONG) (( char* ) FsctlOutput - ( char* )WorkBuffer);
  4973. WkBufLength = EfsMetaDataLength + BytesInBuffer;
  4974. // Make it a multiple of 4K
  4975. WkBufLength = ((WkBufLength + FSCTL_OUTPUT_MISC_LENGTH - 1) / FSCTL_OUTPUT_MISC_LENGTH) * FSCTL_OUTPUT_MISC_LENGTH;
  4976. TmpBuffer = VirtualAlloc(
  4977. NULL,
  4978. WkBufLength,
  4979. MEM_COMMIT,
  4980. PAGE_READWRITE
  4981. );
  4982. if (TmpBuffer) {
  4983. RtlCopyMemory(TmpBuffer, WorkBuffer, BytesInBuffer);
  4984. VirtualFree(
  4985. WorkBuffer,
  4986. 0,
  4987. MEM_RELEASE
  4988. );
  4989. WorkBuffer = TmpBuffer;
  4990. FsctlOutput = (char *)WorkBuffer + BytesInBuffer;
  4991. FsctlOutputLength = WkBufLength - BytesInBuffer;
  4992. BufPointer = WorkBuffer;
  4993. NtStatus = NtFsControlFile(
  4994. ((PEXPORT_CONTEXT) Context)->Handle,
  4995. 0,
  4996. NULL,
  4997. NULL,
  4998. &IoStatusBlock,
  4999. FSCTL_ENCRYPTION_FSCTL_IO,
  5000. FsctlInput,
  5001. FsctlInputLength,
  5002. FsctlOutput,
  5003. FsctlOutputLength
  5004. );
  5005. } else {
  5006. NtStatus = STATUS_INSUFFICIENT_RESOURCES;
  5007. }
  5008. }
  5009. }
  5010. if ( NT_SUCCESS(NtStatus)){
  5011. (( PEFSEXP_DATA_HEADER )BufPointer )->Length = sizeof (EFSEXP_DATA_HEADER) + *((ULONG *)FsctlOutput);
  5012. //
  5013. // Send out the $EFS stream
  5014. //
  5015. SendDataLength = WkBufLength - FsctlOutputLength + *((ULONG *)FsctlOutput);
  5016. HResult = EFSSendPipeData( (char *)WorkBuffer, SendDataLength, EfsOutPipe );
  5017. //
  5018. // Now begin to processing other data streams
  5019. //
  5020. StreamIndex = 0;
  5021. StreamOffset = 0;
  5022. if (((PEXPORT_CONTEXT) Context)->NumberOfStreams == 0) {
  5023. MoreToRead = FALSE;
  5024. } else {
  5025. ( (PREQUEST_RAW_ENCRYPTED_DATA)FsctlInput )->Length = WkBufLength - FSCTL_OUTPUT_MISC_LENGTH;
  5026. FsctlInputLength = sizeof ( REQUEST_RAW_ENCRYPTED_DATA );
  5027. }
  5028. while ( (HResult == NO_ERROR) && MoreToRead ){
  5029. //
  5030. // Fill the request header
  5031. //
  5032. ( (PREQUEST_RAW_ENCRYPTED_DATA)FsctlInput )->FileOffset = StreamOffset;
  5033. //
  5034. // Prepare output data
  5035. //
  5036. BufPointer = WorkBuffer ;
  5037. if ( 0 == StreamOffset ){
  5038. //
  5039. // Check if the stream is encrypted or not
  5040. // For the current version, we only support non-encrypted
  5041. // stream in directory file. Non-encrypted stream in normal
  5042. // file may be exported but import is not supported. EFS does
  5043. // not support mixed data stream in a file.
  5044. //
  5045. NtStatus = NtQueryInformationFile(
  5046. ((PEXPORT_CONTEXT) Context)->StreamHandles[ StreamIndex ],
  5047. &IoStatusBlock,
  5048. &StreamInfo,
  5049. sizeof (FILE_BASIC_INFORMATION),
  5050. FileBasicInformation
  5051. );
  5052. if ( !NT_SUCCESS( NtStatus ) ){
  5053. //
  5054. // Error occured. Quit processing.
  5055. //
  5056. HResult = RtlNtStatusToDosError( NtStatus );
  5057. break;
  5058. }
  5059. if ( StreamInfo.FileAttributes & FILE_ATTRIBUTE_ENCRYPTED ){
  5060. StreamEncrypted = TRUE;
  5061. (( PEFSEXP_STREAM_HEADER )BufPointer )->Flag = 0;
  5062. } else {
  5063. StreamEncrypted = FALSE;
  5064. (( PEFSEXP_STREAM_HEADER )BufPointer )->Flag = STREAM_NOT_ENCRYPTED;
  5065. }
  5066. //
  5067. // A new stream started. Insert a stream header
  5068. //
  5069. (( PEFSEXP_STREAM_HEADER )BufPointer )->NameLength =
  5070. ((PEXPORT_CONTEXT) Context)->StreamNames[ StreamIndex ].Length;
  5071. SendDataLength = (( PEFSEXP_STREAM_HEADER )BufPointer )->Length =
  5072. (( PEFSEXP_STREAM_HEADER )BufPointer )->NameLength +
  5073. sizeof (EFSEXP_STREAM_HEADER);
  5074. RtlCopyMemory( &((( PEFSEXP_STREAM_HEADER )BufPointer )->StreamSignature[0]),
  5075. STREAM_SIGNATURE,
  5076. EFS_SIGNATURE_LENGTH * sizeof( WCHAR )
  5077. );
  5078. (( PEFSEXP_STREAM_HEADER )BufPointer )->Reserved[0] =
  5079. (( PEFSEXP_STREAM_HEADER )BufPointer )->Reserved[1] =
  5080. 0;
  5081. BufPointer = (char *)BufPointer + sizeof (EFSEXP_STREAM_HEADER);
  5082. RtlCopyMemory( BufPointer,
  5083. ((PEXPORT_CONTEXT) Context)->StreamNames[ StreamIndex ].Buffer,
  5084. ((PEXPORT_CONTEXT) Context)->StreamNames[ StreamIndex ].Length
  5085. );
  5086. //
  5087. // Let's send out the data so that we can better aligned for data section
  5088. //
  5089. HResult = EFSSendPipeData( (char *)WorkBuffer, SendDataLength, EfsOutPipe );
  5090. if (HResult != NO_ERROR) {
  5091. break;
  5092. } else {
  5093. BufPointer = WorkBuffer;
  5094. }
  5095. }
  5096. //
  5097. // Prepare data header
  5098. //
  5099. (( PEFSEXP_DATA_HEADER )BufPointer )->Flag = 0;
  5100. RtlCopyMemory( &((( PEFSEXP_DATA_HEADER )BufPointer )->DataSignature[0]),
  5101. DATA_SIGNATURE,
  5102. EFS_SIGNATURE_LENGTH * sizeof( WCHAR )
  5103. );
  5104. FsctlOutput = (char *)BufPointer + sizeof ( EFSEXP_DATA_HEADER );
  5105. FsctlOutputLength = WkBufLength - (ULONG)( ( char* ) FsctlOutput - ( char* )WorkBuffer);
  5106. //
  5107. // Read raw data
  5108. //
  5109. if ( StreamEncrypted ){
  5110. //
  5111. // Stream Encrypted. This is a sync call.
  5112. //
  5113. NtStatus = NtFsControlFile(
  5114. ((PEXPORT_CONTEXT) Context)->StreamHandles[ StreamIndex ],
  5115. 0,
  5116. NULL,
  5117. NULL,
  5118. &IoStatusBlock,
  5119. FSCTL_READ_RAW_ENCRYPTED,
  5120. FsctlInput,
  5121. FsctlInputLength,
  5122. FsctlOutput,
  5123. FsctlOutputLength
  5124. );
  5125. if ( !NT_SUCCESS( NtStatus ) && ( STATUS_END_OF_FILE != NtStatus) ){
  5126. //
  5127. // Error occured. Quit processing.
  5128. //
  5129. HResult = RtlNtStatusToDosError( NtStatus );
  5130. break;
  5131. }
  5132. //
  5133. // Calculate the length of data send to caller
  5134. //
  5135. SendDataLength = ((PENCRYPTED_DATA_INFO)FsctlOutput)->OutputBufferOffset;
  5136. for ( ii=0; ii < ((PENCRYPTED_DATA_INFO)FsctlOutput)->NumberOfDataBlocks; ii++){
  5137. SendDataLength += ((PENCRYPTED_DATA_INFO)FsctlOutput)->DataBlockSize[ii];
  5138. }
  5139. (( PEFSEXP_DATA_HEADER )BufPointer )->Length = SendDataLength +
  5140. sizeof ( EFSEXP_DATA_HEADER );
  5141. SendDataLength += (ULONG)(( char* ) FsctlOutput - ( char* )WorkBuffer);
  5142. //
  5143. // Check if this is the last stream block
  5144. //
  5145. BytesAdvanced = ((PENCRYPTED_DATA_INFO)FsctlOutput)->NumberOfDataBlocks <<
  5146. ((PENCRYPTED_DATA_INFO)FsctlOutput)->DataUnitShift;
  5147. if ( ( STATUS_END_OF_FILE == NtStatus ) ||
  5148. (((PENCRYPTED_DATA_INFO)FsctlOutput)->BytesWithinFileSize < BytesAdvanced)
  5149. ) {
  5150. //
  5151. // Last block in this stream
  5152. //
  5153. StreamOffset = 0;
  5154. StreamIndex++;
  5155. if ( StreamIndex >= ((PEXPORT_CONTEXT) Context)->NumberOfStreams ){
  5156. MoreToRead = FALSE;
  5157. HResult = NO_ERROR;
  5158. }
  5159. if ( STATUS_END_OF_FILE == NtStatus ){
  5160. //
  5161. // End of file. No need to send data to caller
  5162. //
  5163. continue;
  5164. }
  5165. } else {
  5166. //
  5167. // More data block to be read for this stream.
  5168. //
  5169. StreamOffset = ((PENCRYPTED_DATA_INFO)FsctlOutput)->StartingFileOffset
  5170. + BytesAdvanced;
  5171. }
  5172. } else {
  5173. //
  5174. // Not encrypted stream. Use normal read.
  5175. //
  5176. NtStatus = NtReadFile(
  5177. ((PEXPORT_CONTEXT) Context)->StreamHandles[ StreamIndex ],
  5178. 0,
  5179. NULL,
  5180. NULL,
  5181. &IoStatusBlock,
  5182. FsctlOutput,
  5183. FsctlOutputLength,
  5184. (PLARGE_INTEGER)&StreamOffset,
  5185. NULL
  5186. );
  5187. if ( !NT_SUCCESS( NtStatus ) && ( STATUS_END_OF_FILE != NtStatus) ){
  5188. //
  5189. // Error occured. Quit processing.
  5190. //
  5191. HResult = RtlNtStatusToDosError( NtStatus );
  5192. break;
  5193. }
  5194. //
  5195. // Calculate the length of data send to caller
  5196. //
  5197. SendDataLength = (ULONG)IoStatusBlock.Information;
  5198. (( PEFSEXP_DATA_HEADER )BufPointer )->Length = SendDataLength +
  5199. sizeof ( EFSEXP_DATA_HEADER );
  5200. SendDataLength += (ULONG)(( char* ) FsctlOutput - ( char* )WorkBuffer);
  5201. //
  5202. // Check if this is the last stream block
  5203. //
  5204. BytesAdvanced = (ULONG)IoStatusBlock.Information;
  5205. if ( ( STATUS_END_OF_FILE == NtStatus ) || (FsctlOutputLength > BytesAdvanced)) {
  5206. //
  5207. // Last block in this stream
  5208. //
  5209. StreamOffset = 0;
  5210. StreamIndex++;
  5211. if ( StreamIndex >= ((PEXPORT_CONTEXT) Context)->NumberOfStreams ){
  5212. MoreToRead = FALSE;
  5213. HResult = NO_ERROR;
  5214. }
  5215. if ( STATUS_END_OF_FILE == NtStatus ){
  5216. //
  5217. // End of file. No need to send data to caller
  5218. //
  5219. continue;
  5220. }
  5221. } else {
  5222. //
  5223. // More data block to be read for this stream.
  5224. //
  5225. StreamOffset += BytesAdvanced;
  5226. }
  5227. }
  5228. HResult = EFSSendPipeData( (char *)WorkBuffer, SendDataLength, EfsOutPipe );
  5229. }//while
  5230. } else {
  5231. //
  5232. // Read $EFS wrong
  5233. //
  5234. HResult = RtlNtStatusToDosError( NtStatus );
  5235. }
  5236. //
  5237. // End the sending data with length of 0 byte. (This flushes the pipe.)
  5238. //
  5239. EFSSendPipeData( (char *)WorkBuffer, 0, EfsOutPipe );
  5240. //
  5241. // Finished. Clean up the memory.
  5242. //
  5243. VirtualFree(
  5244. WorkBuffer,
  5245. 0,
  5246. MEM_RELEASE
  5247. );
  5248. LsapFreeLsaHeap( FsctlInput );
  5249. return HResult;
  5250. }
  5251. ULONG
  5252. CheckSignature(
  5253. void *Signature
  5254. )
  5255. /*++
  5256. Routine Description:
  5257. This routine returns the signature type.
  5258. Arguments:
  5259. Signature - Signature string.
  5260. Return Value:
  5261. The type of signature. 0 for bogus signature.
  5262. --*/
  5263. {
  5264. if ( !memcmp( Signature, FILE_SIGNATURE, SIG_LENGTH )){
  5265. return SIG_EFS_FILE;
  5266. }
  5267. if ( !memcmp( Signature, STREAM_SIGNATURE, SIG_LENGTH )){
  5268. return SIG_EFS_STREAM;
  5269. }
  5270. if ( !memcmp( Signature, DATA_SIGNATURE, SIG_LENGTH )){
  5271. return SIG_EFS_DATA;
  5272. }
  5273. return SIG_NO_MATCH;
  5274. }
  5275. long
  5276. EfsWriteFileRaw(
  5277. PVOID Context,
  5278. PVOID EfsInPipe
  5279. )
  5280. /*++
  5281. Routine Description:
  5282. This routine is used to write encrypted file's raw data. It uses
  5283. NTFS FSCTL to put the data.
  5284. Arguments:
  5285. Context -- Context handle.
  5286. EfsInPipe -- Pipe handle.
  5287. Return Value:
  5288. The result of operation.
  5289. --*/
  5290. {
  5291. DWORD HResult = NO_ERROR;
  5292. ULONG GetDataLength;
  5293. ULONG NextToRead;
  5294. ULONG FsctlInputLength;
  5295. ULONG BytesInBuffer;
  5296. VOID *WorkBuffer = NULL;
  5297. VOID *ReadBuffer = NULL;
  5298. VOID *FsctlInput;
  5299. VOID *BufPointer;
  5300. NTSTATUS NtStatus;
  5301. IO_STATUS_BLOCK IoStatusBlock;
  5302. HANDLE CurrentStream = 0;
  5303. LONGLONG StreamOffset;
  5304. ULONG SigID;
  5305. UNICODE_STRING StreamName;
  5306. OBJECT_ATTRIBUTES ObjectAttributes;
  5307. PEFSEXP_STREAM_HEADER StreamHeader;
  5308. TOKEN_PRIVILEGES Privs;
  5309. PTOKEN_PRIVILEGES OldPrivs = NULL;
  5310. HANDLE TokenHandle = 0;
  5311. DWORD ReturnLength;
  5312. BOOL GotToken;
  5313. BOOLEAN PrivilegeEnabled = FALSE;
  5314. BOOLEAN MoreByteToWrite = TRUE;
  5315. BOOLEAN CrntStrIsDefault = FALSE;
  5316. BOOLEAN CrntStreamEncrypted = TRUE;
  5317. if ( !Context ||
  5318. !( ((PIMPORT_CONTEXT) Context)->Flag & CONTEXT_FOR_IMPORT ) ||
  5319. ( ((PIMPORT_CONTEXT) Context)->Flag & CONTEXT_INVALID ) ||
  5320. (((PEXPORT_CONTEXT) Context)->ContextID != EFS_CONTEXT_ID)
  5321. ){
  5322. return ERROR_ACCESS_DENIED;
  5323. }
  5324. //
  5325. // Allocate necessary memory
  5326. //
  5327. WorkBuffer = VirtualAlloc(
  5328. NULL,
  5329. FSCTL_OUTPUT_INITIAL_LENGTH,
  5330. MEM_COMMIT,
  5331. PAGE_READWRITE
  5332. );
  5333. if ( !WorkBuffer ){
  5334. return ERROR_OUTOFMEMORY;
  5335. }
  5336. //
  5337. // Read in the file headers first.
  5338. //
  5339. GetDataLength = sizeof ( EFSEXP_FILE_HEADER ) +
  5340. sizeof ( EFSEXP_STREAM_HEADER ) +
  5341. sizeof ( USHORT ) +
  5342. sizeof ( EFSEXP_DATA_HEADER ) +
  5343. sizeof ( ULONG );
  5344. HResult = EFSReceivePipeData( (char *)WorkBuffer, &GetDataLength, EfsInPipe );
  5345. if ( NO_ERROR != HResult ){
  5346. VirtualFree(
  5347. WorkBuffer,
  5348. 0,
  5349. MEM_RELEASE
  5350. );
  5351. return HResult;
  5352. }
  5353. //
  5354. // Verify file format
  5355. //
  5356. if ( SIG_EFS_FILE != CheckSignature(
  5357. (char *)WorkBuffer +
  5358. sizeof( ULONG)
  5359. ) ||
  5360. SIG_EFS_STREAM != CheckSignature(
  5361. (char *)WorkBuffer +
  5362. sizeof( EFSEXP_FILE_HEADER ) +
  5363. sizeof( ULONG)
  5364. ) ||
  5365. SIG_EFS_DATA != CheckSignature(
  5366. (char *)WorkBuffer +
  5367. sizeof( EFSEXP_FILE_HEADER ) +
  5368. sizeof ( EFSEXP_STREAM_HEADER ) +
  5369. sizeof ( USHORT ) +
  5370. sizeof( ULONG)
  5371. ) ||
  5372. EFS_STREAM_ID != *((USHORT *)(
  5373. (char *)WorkBuffer +
  5374. sizeof( EFSEXP_FILE_HEADER ) +
  5375. sizeof ( EFSEXP_STREAM_HEADER )
  5376. )) ||
  5377. EFS_EXP_FORMAT_CURRENT_VERSION != ((PEFSEXP_FILE_HEADER)WorkBuffer)->VersionID ){
  5378. //
  5379. // Signature does not match. This includes file which has less bytes than
  5380. // expected head information.
  5381. //
  5382. VirtualFree(
  5383. WorkBuffer,
  5384. 0,
  5385. MEM_RELEASE
  5386. );
  5387. return ERROR_BAD_FORMAT;
  5388. }
  5389. //
  5390. // Read in $EFS
  5391. //
  5392. RtlCopyMemory( WorkBuffer, (char *)WorkBuffer + GetDataLength - sizeof(ULONG), sizeof( ULONG ) );
  5393. BytesInBuffer = sizeof(ULONG);
  5394. BufPointer = (char *)WorkBuffer + BytesInBuffer;
  5395. //
  5396. // The read will include the length of the next block.
  5397. //
  5398. NextToRead = GetDataLength = *((PULONG)WorkBuffer) ;
  5399. FsctlInputLength = FSCTL_OUTPUT_INITIAL_LENGTH - BytesInBuffer;
  5400. if ((NextToRead + NextToRead + FSCTL_OUTPUT_MISC_LENGTH) > (FSCTL_OUTPUT_INITIAL_LENGTH - BytesInBuffer)) {
  5401. //
  5402. // We need a large buffer to hold 2 $EFS plus some head info
  5403. //
  5404. VOID *TmpBuffer;
  5405. ULONG NewBufferLength;
  5406. NewBufferLength = ((NextToRead + NextToRead + FSCTL_OUTPUT_MISC_LENGTH + BytesInBuffer
  5407. + FSCTL_OUTPUT_MISC_LENGTH - 1) / FSCTL_OUTPUT_MISC_LENGTH) * FSCTL_OUTPUT_MISC_LENGTH;
  5408. TmpBuffer = VirtualAlloc(
  5409. NULL,
  5410. NewBufferLength,
  5411. MEM_COMMIT,
  5412. PAGE_READWRITE
  5413. );
  5414. if (TmpBuffer) {
  5415. RtlCopyMemory( TmpBuffer, WorkBuffer, BytesInBuffer);
  5416. VirtualFree(
  5417. WorkBuffer,
  5418. 0,
  5419. MEM_RELEASE
  5420. );
  5421. WorkBuffer = TmpBuffer;
  5422. BufPointer = (char *)WorkBuffer + BytesInBuffer;
  5423. FsctlInputLength = NewBufferLength - BytesInBuffer;
  5424. } else {
  5425. VirtualFree(
  5426. WorkBuffer,
  5427. 0,
  5428. MEM_RELEASE
  5429. );
  5430. return ERROR_OUTOFMEMORY;
  5431. }
  5432. }
  5433. HResult = EFSReceivePipeData( (char *)BufPointer, &NextToRead, EfsInPipe );
  5434. if ( NO_ERROR != HResult ){
  5435. VirtualFree(
  5436. WorkBuffer,
  5437. 0,
  5438. MEM_RELEASE
  5439. );
  5440. return HResult;
  5441. }
  5442. if ( GetDataLength > NextToRead){
  5443. //
  5444. // No data stream followed $EFS. This is either a 0 length file
  5445. // Or a directory file.
  5446. //
  5447. MoreByteToWrite = FALSE;
  5448. NextToRead = 0;
  5449. } else {
  5450. NextToRead = *(ULONG UNALIGNED *)(( char *) BufPointer + GetDataLength - sizeof (ULONG));
  5451. }
  5452. //
  5453. // The $EFS is in. Write it out!
  5454. // First prepare the FsctlInput
  5455. //
  5456. FsctlInput = (char*) BufPointer + GetDataLength;
  5457. FsctlInputLength -= GetDataLength;
  5458. //
  5459. // Send FsctlInputData to the server
  5460. //
  5461. HResult = GetOverWriteEfsAttrFsctlInput(
  5462. (( PIMPORT_CONTEXT ) Context)->Flag,
  5463. (( PIMPORT_CONTEXT ) Context)->DesiredAccess,
  5464. ( char * )BufPointer - sizeof (ULONG),
  5465. GetDataLength,
  5466. (char *)FsctlInput,
  5467. &FsctlInputLength
  5468. );
  5469. if ( NO_ERROR != HResult ){
  5470. VirtualFree(
  5471. WorkBuffer,
  5472. 0,
  5473. MEM_RELEASE
  5474. );
  5475. return HResult;
  5476. }
  5477. NtStatus = NtFsControlFile(
  5478. ((PIMPORT_CONTEXT) Context)->Handle,
  5479. 0,
  5480. NULL,
  5481. NULL,
  5482. &IoStatusBlock,
  5483. FSCTL_SET_ENCRYPTION ,
  5484. FsctlInput,
  5485. FsctlInputLength,
  5486. NULL,
  5487. NULL
  5488. );
  5489. if ( NT_SUCCESS( NtStatus )){
  5490. DWORD ShareMode = 0;
  5491. //
  5492. // $EFS is written now
  5493. //
  5494. StreamOffset = 0;
  5495. //
  5496. // ********* Trick Trick Trick *********
  5497. // NTFS will have better performance if align the data block.
  5498. // We already have the length field of the block which is a ULONG
  5499. // field. Here we start our offset at sizeof (ULONG).
  5500. // Not only performance, now is required by NTFS. Otherwise it will
  5501. // fail.
  5502. //
  5503. BufPointer = (char *)WorkBuffer + sizeof (ULONG);
  5504. while ( MoreByteToWrite ){
  5505. GetDataLength = NextToRead;
  5506. //
  5507. // The read will include the length of the next block.
  5508. // No backward reading here.
  5509. //
  5510. HResult = EFSReceivePipeData( (char *)BufPointer, &GetDataLength, EfsInPipe );
  5511. if ( NO_ERROR != HResult ){
  5512. break;
  5513. }
  5514. if ( GetDataLength < NextToRead ){
  5515. //
  5516. // End of file reached
  5517. //
  5518. MoreByteToWrite = FALSE;
  5519. NextToRead = 0;
  5520. } else {
  5521. //
  5522. // Prepare for next read block. Be careful about the alignment here.
  5523. //
  5524. RtlCopyMemory((char *) &NextToRead,
  5525. (char *) BufPointer + GetDataLength - sizeof (ULONG),
  5526. sizeof (ULONG)
  5527. );
  5528. }
  5529. SigID = CheckSignature( BufPointer );
  5530. if ( SIG_EFS_STREAM == SigID ){
  5531. //
  5532. // This is a stream block. Create a new stream.
  5533. //
  5534. StreamHeader = (PEFSEXP_STREAM_HEADER)((char *)BufPointer - sizeof( ULONG ));
  5535. if ( StreamHeader->Flag & STREAM_NOT_ENCRYPTED ){
  5536. CrntStreamEncrypted = FALSE;
  5537. } else {
  5538. CrntStreamEncrypted = TRUE;
  5539. }
  5540. StreamName.Length = (USHORT) StreamHeader->NameLength;
  5541. StreamName.Buffer = ( USHORT* )((char *)BufPointer +
  5542. sizeof ( EFSEXP_STREAM_HEADER ) -
  5543. sizeof ( ULONG ));
  5544. if ( CurrentStream && !CrntStrIsDefault){
  5545. //
  5546. // Close the previous stream
  5547. //
  5548. NtClose(CurrentStream);
  5549. CurrentStream = 0;
  5550. }
  5551. if ( (DEF_STR_LEN == StreamName.Length) &&
  5552. !memcmp( StreamName.Buffer,
  5553. DEFAULT_STREAM,
  5554. StreamName.Length
  5555. )
  5556. ){
  5557. //
  5558. // Default data stream to be processed.
  5559. // This is the most case. We need to optimize this!!!
  5560. //
  5561. CurrentStream = ((PIMPORT_CONTEXT) Context)->Handle;
  5562. CrntStrIsDefault = TRUE;
  5563. } else {
  5564. //
  5565. // Other data streams
  5566. //
  5567. if ( (((( PIMPORT_CONTEXT ) Context)->CreateOptions) & FILE_OPEN_FOR_BACKUP_INTENT) &&
  5568. ( !PrivilegeEnabled) ){
  5569. //
  5570. // Enable the Privilege. We only enable once. If fail, we return.
  5571. //
  5572. PrivilegeEnabled = TRUE;
  5573. OldPrivs = ( TOKEN_PRIVILEGES *) LsapAllocateLsaHeap(sizeof( TOKEN_PRIVILEGES ));
  5574. if ( OldPrivs == NULL ){
  5575. HResult = ERROR_NOT_ENOUGH_MEMORY;
  5576. break;
  5577. }
  5578. //
  5579. // We're impersonating, use the thread token.
  5580. //
  5581. GotToken = OpenThreadToken(
  5582. GetCurrentThread(),
  5583. TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
  5584. FALSE,
  5585. &TokenHandle
  5586. );
  5587. if ( GotToken ) {
  5588. //
  5589. // We've got a token handle
  5590. //
  5591. Privs.PrivilegeCount = 1;
  5592. Privs.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
  5593. Privs.Privileges[0].Luid = RtlConvertLongToLuid(SE_RESTORE_PRIVILEGE);
  5594. ReturnLength = sizeof( TOKEN_PRIVILEGES );
  5595. (VOID) AdjustTokenPrivileges (
  5596. TokenHandle,
  5597. FALSE,
  5598. &Privs,
  5599. sizeof( TOKEN_PRIVILEGES ),
  5600. OldPrivs,
  5601. &ReturnLength
  5602. );
  5603. HResult = GetLastError();
  5604. //
  5605. // Caller will call RpcRevertToSelf().
  5606. // OldPrivs is not needed any more.
  5607. //
  5608. LsapFreeLsaHeap( OldPrivs );
  5609. OldPrivs = NULL;
  5610. if ( ERROR_SUCCESS != HResult ) {
  5611. //
  5612. // Privilege adjust failed
  5613. //
  5614. CloseHandle( TokenHandle );
  5615. TokenHandle = 0;
  5616. break;
  5617. }
  5618. } else {
  5619. //
  5620. // We did not get the handle.
  5621. //
  5622. TokenHandle = 0;
  5623. HResult = GetLastError();
  5624. LsapFreeLsaHeap( OldPrivs );
  5625. OldPrivs = NULL;
  5626. break;
  5627. }
  5628. if (((PIMPORT_CONTEXT) Context)->DesiredAccess & DELETE) {
  5629. ShareMode = FILE_SHARE_DELETE;
  5630. }
  5631. }
  5632. StreamName.MaximumLength = StreamName.Length;
  5633. CrntStrIsDefault = FALSE;
  5634. InitializeObjectAttributes(
  5635. &ObjectAttributes,
  5636. &StreamName,
  5637. 0,
  5638. ((PIMPORT_CONTEXT) Context)->Handle,
  5639. NULL
  5640. );
  5641. NtStatus = NtCreateFile(
  5642. &CurrentStream,
  5643. ((PIMPORT_CONTEXT) Context)->DesiredAccess,
  5644. &ObjectAttributes,
  5645. &IoStatusBlock,
  5646. (PLARGE_INTEGER) NULL,
  5647. ((PIMPORT_CONTEXT) Context)->Attribute,
  5648. ShareMode,
  5649. ((PIMPORT_CONTEXT) Context)->CreateDisposition,
  5650. ((PIMPORT_CONTEXT) Context)->CreateOptions,
  5651. (PVOID) NULL,
  5652. 0L
  5653. );
  5654. if ( !NT_SUCCESS( NtStatus ) ){
  5655. HResult = RtlNtStatusToDosError( NtStatus );
  5656. break;
  5657. }
  5658. }
  5659. //
  5660. // Stream header processed. Adjust BufPointer to make it consistant with ReadRaw
  5661. //
  5662. BufPointer = (char *)WorkBuffer + sizeof (ULONG);
  5663. continue;
  5664. }
  5665. if ( SIG_EFS_DATA != SigID ){
  5666. //
  5667. // Corrupted file
  5668. //
  5669. HResult = ERROR_FILE_CORRUPT;
  5670. break;
  5671. }
  5672. //
  5673. // Processing the data block
  5674. // After all the above is done, this should be a piece of cake!
  5675. //
  5676. FsctlInput = (char *)BufPointer + sizeof (EFSEXP_DATA_HEADER) - sizeof (ULONG);
  5677. FsctlInputLength = GetDataLength - sizeof (EFSEXP_DATA_HEADER);
  5678. if ( !MoreByteToWrite ){
  5679. //
  5680. // Adjust for the last block. There is no extra length
  5681. // field for the next block.
  5682. //
  5683. FsctlInputLength += sizeof (ULONG);
  5684. }
  5685. if ( CrntStreamEncrypted ){
  5686. //
  5687. // Most of the case.
  5688. //
  5689. //
  5690. // finally writing data out
  5691. //
  5692. NtStatus = NtFsControlFile(
  5693. CurrentStream,
  5694. 0,
  5695. NULL,
  5696. NULL,
  5697. &IoStatusBlock,
  5698. FSCTL_WRITE_RAW_ENCRYPTED,
  5699. FsctlInput,
  5700. FsctlInputLength,
  5701. NULL,
  5702. 0
  5703. );
  5704. } else {
  5705. //
  5706. // Currently only support plain data stream on directory
  5707. //
  5708. NtStatus = NtWriteFile(
  5709. CurrentStream,
  5710. 0,
  5711. NULL,
  5712. NULL,
  5713. &IoStatusBlock,
  5714. FsctlInput,
  5715. FsctlInputLength,
  5716. NULL,
  5717. NULL
  5718. );
  5719. }
  5720. if ( !NT_SUCCESS( NtStatus ) ){
  5721. HResult = RtlNtStatusToDosError( NtStatus );
  5722. break;
  5723. }
  5724. BufPointer = (char *)WorkBuffer + sizeof (ULONG);
  5725. HResult = NO_ERROR;
  5726. } //while loop
  5727. } else {
  5728. //
  5729. // Writing $EFS error
  5730. //
  5731. HResult = RtlNtStatusToDosError( NtStatus );
  5732. }
  5733. if ( CurrentStream && !CrntStrIsDefault ){
  5734. NtClose(CurrentStream);
  5735. }
  5736. if ( TokenHandle ){
  5737. CloseHandle( TokenHandle );
  5738. }
  5739. VirtualFree(
  5740. WorkBuffer,
  5741. 0,
  5742. MEM_RELEASE
  5743. );
  5744. return HResult;
  5745. }
  5746. DWORD
  5747. GetOverWriteEfsAttrFsctlInput(
  5748. ULONG Flag,
  5749. ULONG AccessFlag,
  5750. char *InputData,
  5751. ULONG InputDataLength,
  5752. char *OutputData,
  5753. ULONG *OutputDataLength
  5754. )
  5755. /*++
  5756. Routine Description:
  5757. This routine is used to prepare the FSCTL input data buffer for
  5758. EFS_OVERWRITE_ATTRIBUTE used in import.
  5759. Arguments:
  5760. Flag -- Indicate the type of the target.
  5761. AccessFlag -- Indicate the kind of access required.
  5762. InputData -- Required input data ($EFS)
  5763. InputDataLength -- The length of the input data.
  5764. OutputData -- The prepared data as the result of this routine.
  5765. OutputDataLength -- The length of the output data.
  5766. Return Value:
  5767. The result of operation.
  5768. --*/
  5769. {
  5770. DWORD HResult = NO_ERROR;
  5771. PEFS_KEY Fek = NULL;
  5772. PEFS_DATA_STREAM_HEADER NewEfs = NULL;
  5773. ULONG EfsDataLength = 0 ;
  5774. ULONG OutBufLen = *OutputDataLength;
  5775. BOOLEAN WithFek = FALSE;
  5776. PBYTE SourceEfs;
  5777. ULONG CipherSubCode;
  5778. HANDLE hToken;
  5779. HANDLE hProfile;
  5780. EFS_USER_INFO EfsUserInfo;
  5781. if ( !(Flag & CONTEXT_OPEN_FOR_DIR) ){
  5782. //
  5783. // Not for directory file. Check if we can get
  5784. // FEK or not.
  5785. //
  5786. if (EfspGetUserInfo( &EfsUserInfo )) {
  5787. if (EfspLoadUserProfile( &EfsUserInfo, &hToken, &hProfile )) {
  5788. HResult = DecryptFek(
  5789. &EfsUserInfo,
  5790. ( PEFS_DATA_STREAM_HEADER ) InputData,
  5791. &Fek,
  5792. &NewEfs,
  5793. 0
  5794. );
  5795. EfspUnloadUserProfile( hToken, hProfile );
  5796. } else {
  5797. HResult = GetLastError();
  5798. }
  5799. EfspFreeUserInfo( &EfsUserInfo );
  5800. } else {
  5801. HResult = GetLastError();
  5802. }
  5803. if ( NO_ERROR == HResult ){
  5804. WithFek = TRUE;
  5805. } else {
  5806. if ( AccessFlag & FILE_WRITE_DATA ){
  5807. //
  5808. // A general user without the key.
  5809. //
  5810. return ERROR_ACCESS_DENIED;
  5811. } else {
  5812. HResult = NO_ERROR;
  5813. }
  5814. }
  5815. }
  5816. if ( WithFek ){
  5817. //
  5818. // Calculate the length of output buffer
  5819. // and the offset to put the $EFS
  5820. //
  5821. *OutputDataLength = 3 * sizeof(ULONG) +
  5822. 2 * EFS_KEY_SIZE( Fek );
  5823. if (NewEfs){
  5824. SourceEfs = (PBYTE) NewEfs;
  5825. } else {
  5826. SourceEfs = (PBYTE) InputData;
  5827. }
  5828. *OutputDataLength += *(PULONG)SourceEfs;
  5829. if (OutBufLen >= *OutputDataLength) {
  5830. EfsDataLength = *OutputDataLength - 3 * sizeof(ULONG);
  5831. ( VOID ) SendEfs(
  5832. Fek,
  5833. (PEFS_DATA_STREAM_HEADER) SourceEfs,
  5834. (PBYTE) OutputData + 3 * sizeof(ULONG),
  5835. &EfsDataLength
  5836. );
  5837. } else {
  5838. HResult = ERROR_INSUFFICIENT_BUFFER;
  5839. }
  5840. //
  5841. // Free the memory we have allocated.
  5842. //
  5843. if ( Fek ){
  5844. LsapFreeLsaHeap( Fek );
  5845. }
  5846. if ( NewEfs ){
  5847. LsapFreeLsaHeap( NewEfs );
  5848. }
  5849. CipherSubCode = WRITE_EFS_ATTRIBUTE | SET_EFS_KEYBLOB;
  5850. } else {
  5851. //
  5852. // No FEK required.
  5853. //
  5854. *OutputDataLength = COMMON_FSCTL_HEADER_SIZE +
  5855. *(PULONG)InputData;
  5856. if (OutBufLen >= *OutputDataLength) {
  5857. EfsDataLength = *OutputDataLength - 3 * sizeof(ULONG);
  5858. ( VOID ) SendHandleAndEfs(
  5859. (HANDLE) ULongToPtr(Flag),
  5860. (PEFS_DATA_STREAM_HEADER) InputData,
  5861. (PBYTE) OutputData + 3 * sizeof(ULONG),
  5862. &EfsDataLength
  5863. );
  5864. } else {
  5865. HResult = ERROR_INSUFFICIENT_BUFFER;
  5866. }
  5867. CipherSubCode = WRITE_EFS_ATTRIBUTE;
  5868. }
  5869. if ( NO_ERROR == HResult ) {
  5870. ( VOID ) EncryptFSCTLData(
  5871. EFS_OVERWRITE_ATTRIBUTE,
  5872. EFS_ENCRYPT_STREAM,
  5873. CipherSubCode,
  5874. (PBYTE) OutputData + 3 * sizeof(ULONG),
  5875. EfsDataLength,
  5876. (PBYTE) OutputData,
  5877. OutputDataLength
  5878. );
  5879. }
  5880. return HResult;
  5881. }
  5882. DWORD
  5883. CheckVolumeSpace(
  5884. PFILE_FS_SIZE_INFORMATION VolInfo,
  5885. PEFS_STREAM_SIZE StreamSizes,
  5886. PHANDLE StreamHandles,
  5887. ULONG StreamCount
  5888. )
  5889. /*++
  5890. Routine Description:
  5891. This routine estimates if the volume has enough disk space to do the encryption or
  5892. decryption operation. The estimates is not accurate. System overheads are not included.
  5893. Real available space could be more or less when the operation begins. If we are not sure,
  5894. the operation will continue until we really run out of space.
  5895. Arguments:
  5896. VolInfo -- Information to calculate how much space left.
  5897. StreamSizes -- Information to calculate how much space needed.
  5898. StreamCount -- Number of data streams.
  5899. Return Value:
  5900. ERROR_SUCCESS returned if there might be enough space.
  5901. --*/
  5902. {
  5903. LARGE_INTEGER SpaceLeft;
  5904. LARGE_INTEGER SpaceNeeded;
  5905. ULONG ClusterSize;
  5906. ULONG ii;
  5907. SpaceLeft = VolInfo->AvailableAllocationUnits;
  5908. ClusterSize = VolInfo->SectorsPerAllocationUnit * VolInfo->BytesPerSector;
  5909. SpaceLeft.QuadPart *= ClusterSize;
  5910. for ( ii = 0, SpaceNeeded.QuadPart = 0; ii < StreamCount; ii++)
  5911. {
  5912. if ( StreamSizes[ii].StreamFlag & ( FILE_ATTRIBUTE_COMPRESSED | FILE_ATTRIBUTE_SPARSE_FILE ) ){
  5913. FILE_STANDARD_INFORMATION StreamStdInfo;
  5914. IO_STATUS_BLOCK IoStatusBlock;
  5915. NTSTATUS Status;
  5916. //
  5917. // Get File Attributes
  5918. //
  5919. Status = NtQueryInformationFile(
  5920. StreamHandles[ii],
  5921. &IoStatusBlock,
  5922. &StreamStdInfo,
  5923. sizeof ( FILE_STANDARD_INFORMATION ),
  5924. FileStandardInformation
  5925. );
  5926. if (!NT_SUCCESS(Status)){
  5927. //
  5928. // We got error. We are not sure if we have enough space. Give it a try.
  5929. //
  5930. return ERROR_SUCCESS;
  5931. }
  5932. if ( StreamSizes[ii].StreamFlag & FILE_ATTRIBUTE_SPARSE_FILE ){
  5933. //
  5934. // A sparse file (may be compressed). The more accurate way is to query
  5935. // the ranges. Even with that is still a rough estimate. For better performance,
  5936. // we use the STD info.
  5937. //
  5938. SpaceNeeded.QuadPart += StreamStdInfo.AllocationSize.QuadPart;
  5939. } else {
  5940. //
  5941. // Compressed file. Using Virtual Allocation Size + Total Allocation Size
  5942. //
  5943. SpaceNeeded.QuadPart += StreamSizes[ii].AllocSize.QuadPart + StreamStdInfo.AllocationSize.QuadPart;
  5944. }
  5945. } else {
  5946. SpaceNeeded.QuadPart += StreamSizes[ii].AllocSize.QuadPart;
  5947. }
  5948. if ( SpaceNeeded.QuadPart >= SpaceLeft.QuadPart ){
  5949. return ERROR_DISK_FULL;
  5950. }
  5951. }
  5952. return ERROR_SUCCESS;
  5953. }
  5954. DWORD
  5955. CompressStreams(
  5956. PEFS_STREAM_SIZE StreamSizes,
  5957. PHANDLE StreamHandles,
  5958. ULONG State,
  5959. ULONG StreamCount
  5960. )
  5961. /*++
  5962. Routine Description:
  5963. This routine compresses or decompresses the passed in streams.
  5964. Arguments:
  5965. StreamSizes -- Holding streams' original state info.
  5966. StreamHandles -- Stream handles.
  5967. State -- New compressed state.
  5968. StreamCount -- Number of data streams.
  5969. Return Value:
  5970. ERROR_SUCCESS returned if there might be enough space.
  5971. --*/
  5972. {
  5973. DWORD rc = ERROR_SUCCESS;
  5974. ULONG Length;
  5975. ULONG ii;
  5976. BOOL b = TRUE;
  5977. for (ii = 0; ii < StreamCount; ii++){
  5978. b = DeviceIoControl(
  5979. StreamHandles[ii],
  5980. FSCTL_SET_COMPRESSION,
  5981. &State,
  5982. sizeof(USHORT),
  5983. NULL,
  5984. 0,
  5985. &Length,
  5986. FALSE
  5987. );
  5988. if ( !b ){
  5989. rc = GetLastError();
  5990. break;
  5991. }
  5992. }
  5993. if ( !b ){
  5994. //
  5995. // Error happened. Try to restore the stream state.
  5996. //
  5997. for ( ULONG jj = 0; jj < ii; jj++){
  5998. if ( StreamSizes[ jj ].StreamFlag & FILE_ATTRIBUTE_COMPRESSED ){
  5999. State = COMPRESSION_FORMAT_DEFAULT;
  6000. } else {
  6001. State = COMPRESSION_FORMAT_NONE;
  6002. }
  6003. //
  6004. // Error is not checked. We can only recover the state as much
  6005. // as we can.
  6006. //
  6007. (VOID) DeviceIoControl(
  6008. StreamHandles[jj],
  6009. FSCTL_SET_COMPRESSION,
  6010. &State,
  6011. sizeof(USHORT),
  6012. NULL,
  6013. 0,
  6014. &Length,
  6015. FALSE
  6016. );
  6017. }
  6018. }
  6019. return rc;
  6020. }
  6021. DWORD
  6022. CheckOpenSection(
  6023. PEFS_STREAM_SIZE StreamSizes,
  6024. PHANDLE StreamHandles,
  6025. ULONG StreamCount
  6026. )
  6027. /*++
  6028. Routine Description:
  6029. This routine set EOF of a stream to 0 and then back to its original size.
  6030. All the stream content is lost. Valid length is set to 0. This process will also
  6031. speed up a compressed file encryption.
  6032. Arguments:
  6033. StreamSizes -- Holding streams' original state info.
  6034. StreamHandles -- Stream handles.
  6035. StreamCount -- Number of data streams.
  6036. Return Value:
  6037. ERROR_SUCCESS returned if succeed.
  6038. --*/
  6039. {
  6040. ULONG ii;
  6041. FILE_END_OF_FILE_INFORMATION FileSize;
  6042. IO_STATUS_BLOCK IoStatusBlock;
  6043. NTSTATUS Status = STATUS_SUCCESS;
  6044. for (ii = 0; ii < StreamCount; ii++){
  6045. FileSize.EndOfFile.QuadPart = 0;
  6046. Status = NtSetInformationFile(
  6047. StreamHandles[ii],
  6048. &IoStatusBlock,
  6049. &FileSize,
  6050. sizeof(FileSize),
  6051. FileEndOfFileInformation
  6052. );
  6053. if ( !NT_SUCCESS(Status) ){
  6054. //
  6055. // A section handle may be open on the stream.
  6056. //
  6057. break;
  6058. }
  6059. }
  6060. if ( NT_SUCCESS(Status) ){
  6061. for (ii = 0; ii < StreamCount; ii++){
  6062. FileSize.EndOfFile = StreamSizes[ii].EOFSize;
  6063. Status = NtSetInformationFile(
  6064. StreamHandles[ii],
  6065. &IoStatusBlock,
  6066. &FileSize,
  6067. sizeof(FileSize),
  6068. FileEndOfFileInformation
  6069. );
  6070. if ( !NT_SUCCESS(Status) ){
  6071. break;
  6072. }
  6073. }
  6074. }
  6075. return RtlNtStatusToDosError( Status );
  6076. }
  6077. DWORD
  6078. CopyStreamSection(
  6079. HANDLE Target,
  6080. HANDLE SrcMapping,
  6081. PLARGE_INTEGER Offset,
  6082. PLARGE_INTEGER DataLength,
  6083. PLARGE_INTEGER AllocationGranularity
  6084. )
  6085. /*++
  6086. Routine Description:
  6087. This routine copies a section of data from source stream
  6088. to target stream.
  6089. Arguments:
  6090. Target -- Destination stream handle.
  6091. SrcMapping -- Source stream mapping handle.
  6092. Offset -- Data offdset in the stream.
  6093. DataLength -- Byte count to be copied.
  6094. AllocationGranularity -- Allocation granularity.
  6095. Return Value:
  6096. Results of the operation.
  6097. --*/
  6098. {
  6099. LARGE_INTEGER RemainingData = *DataLength;
  6100. LARGE_INTEGER StreamOffset = *Offset;
  6101. ULONG BytesToCopy;
  6102. PVOID pbFile;
  6103. DWORD BytesWritten;
  6104. BOOL b;
  6105. DWORD rc = NO_ERROR;
  6106. while ( RemainingData.QuadPart > 0 ) {
  6107. //
  6108. // Determine number of bytes to be mapped
  6109. //
  6110. if ( RemainingData.QuadPart < AllocationGranularity->QuadPart ) {
  6111. BytesToCopy = RemainingData.LowPart;
  6112. } else {
  6113. BytesToCopy = AllocationGranularity->LowPart;
  6114. }
  6115. pbFile = MapViewOfFile(
  6116. SrcMapping,
  6117. FILE_MAP_READ,
  6118. StreamOffset.HighPart,
  6119. StreamOffset.LowPart,
  6120. BytesToCopy
  6121. );
  6122. if (pbFile != NULL) {
  6123. //
  6124. // Write the data to the target stream
  6125. //
  6126. b = WriteFile(
  6127. Target,
  6128. pbFile,
  6129. BytesToCopy,
  6130. &BytesWritten,
  6131. NULL
  6132. );
  6133. UnmapViewOfFile( pbFile );
  6134. LARGE_INTEGER BytesCopied;
  6135. BytesCopied.HighPart = 0;
  6136. BytesCopied.LowPart = BytesToCopy;
  6137. RemainingData.QuadPart -= BytesCopied.QuadPart;
  6138. StreamOffset.QuadPart += BytesCopied.QuadPart;
  6139. if (!b) {
  6140. rc = GetLastError();
  6141. DebugLog((DEB_ERROR, "WriteFile failed, error = %d\n", rc ));
  6142. break;
  6143. }
  6144. } else {
  6145. rc = GetLastError();
  6146. DebugLog((DEB_ERROR, "MapViewOfFile failed, error = %d\n" ,rc));
  6147. break;
  6148. }
  6149. }
  6150. return rc;
  6151. }
  6152. NTSTATUS
  6153. GetFileEfsStream(
  6154. IN HANDLE hFile,
  6155. OUT PEFS_DATA_STREAM_HEADER * pEfsStream
  6156. )
  6157. /*++
  6158. Routine Description:
  6159. Get the $EFS from the passed file or directory
  6160. Arguments:
  6161. hFile - An open handle the the file or directory of interest.
  6162. pEfsStream - Returns a pointer to a block of memory containing the EFS stream
  6163. for the passed file. Free with LsapFreeLsaHeap();
  6164. Return Value:
  6165. Status of operation.
  6166. --*/
  6167. {
  6168. ULONG Index;
  6169. ULONG cbOutputData;
  6170. ULONG EfsDataLength;
  6171. NTSTATUS Status;
  6172. IO_STATUS_BLOCK IoStatusBlock;
  6173. ULONG TmpOutputData;
  6174. *pEfsStream = NULL;
  6175. //
  6176. // Now we got a handle to the parent directory in ParentDir.
  6177. // Allocate input and output data buffer
  6178. //
  6179. cbOutputData = sizeof( ULONG );
  6180. //
  6181. // PSC, [EFS_FC, CSC , SK, H, H, [SK, H, H]sk]sk
  6182. // PSC, CSC are ignored in this FSCTL call
  6183. //
  6184. const ULONG InputDataSize = (2 * sizeof(DriverSessionKey)) + (7 * sizeof(ULONG));
  6185. BYTE InputData[InputDataSize];
  6186. ULONG cbInputData = InputDataSize;
  6187. //
  6188. // Prepare an input data for making a FSCTL call to get the $EFS
  6189. //
  6190. EfsDataLength = 2 * sizeof(DriverSessionKey) + 4 * sizeof(ULONG);
  6191. SendHandle( hFile, InputData + 3*sizeof(ULONG), &EfsDataLength );
  6192. (VOID) EncryptFSCTLData(
  6193. EFS_GET_ATTRIBUTE,
  6194. 0,
  6195. 0,
  6196. InputData + (3 * sizeof(ULONG)),
  6197. EfsDataLength,
  6198. InputData,
  6199. &cbInputData
  6200. );
  6201. //
  6202. // First call to get the size
  6203. //
  6204. Status = NtFsControlFile(
  6205. hFile,
  6206. 0,
  6207. NULL,
  6208. NULL,
  6209. &IoStatusBlock,
  6210. FSCTL_ENCRYPTION_FSCTL_IO,
  6211. InputData,
  6212. cbInputData,
  6213. &TmpOutputData,
  6214. cbOutputData
  6215. );
  6216. ASSERT(!NT_SUCCESS( Status ));
  6217. if (Status == STATUS_BUFFER_TOO_SMALL) {
  6218. //
  6219. // Check if the output data buffer too small
  6220. // Try again if it is.
  6221. //
  6222. cbOutputData = TmpOutputData;
  6223. *pEfsStream = (PEFS_DATA_STREAM_HEADER)LsapAllocateLsaHeap( cbOutputData );
  6224. if ( *pEfsStream ) {
  6225. Status = NtFsControlFile(
  6226. hFile,
  6227. 0,
  6228. NULL,
  6229. NULL,
  6230. &IoStatusBlock,
  6231. FSCTL_ENCRYPTION_FSCTL_IO,
  6232. InputData,
  6233. cbInputData,
  6234. *pEfsStream,
  6235. cbOutputData
  6236. );
  6237. } else {
  6238. Status = STATUS_INSUFFICIENT_RESOURCES;
  6239. }
  6240. if ( !NT_SUCCESS( Status ) ){
  6241. if ( *pEfsStream ){
  6242. LsapFreeLsaHeap( *pEfsStream );
  6243. *pEfsStream = NULL;
  6244. }
  6245. }
  6246. }
  6247. return Status;
  6248. }
  6249. ULONG
  6250. StringInfoCmp(
  6251. IN PFILE_STREAM_INFORMATION StreamInfoBaseSrc,
  6252. IN PFILE_STREAM_INFORMATION StreamInfoBaseDst,
  6253. IN ULONG StreamInfoSize
  6254. )
  6255. /*++
  6256. Routine Description:
  6257. This routine compares to blocks FILE_STREAM_INFORMATION. The StreamAllocationSize
  6258. cound differ and they should still be thought as eaqual.
  6259. Arguments:
  6260. StreamInfoBaseSrc - Source block
  6261. StreamInfoBaseDst - Dstination block
  6262. StreamInfoSize - Block size in bytes
  6263. Return Value:
  6264. 0 if compares same.
  6265. --*/
  6266. {
  6267. ULONG rc;
  6268. rc = memcmp(StreamInfoBaseSrc, StreamInfoBaseDst, StreamInfoSize);
  6269. if (rc) {
  6270. do {
  6271. rc = memcmp(StreamInfoBaseSrc->StreamName,
  6272. StreamInfoBaseDst->StreamName,
  6273. StreamInfoBaseSrc->StreamNameLength
  6274. );
  6275. if (StreamInfoBaseSrc->NextEntryOffset){
  6276. StreamInfoBaseSrc = (PFILE_STREAM_INFORMATION)((PCHAR) StreamInfoBaseSrc + StreamInfoBaseSrc->NextEntryOffset);
  6277. } else {
  6278. StreamInfoBaseSrc = NULL;
  6279. }
  6280. if (StreamInfoBaseDst->NextEntryOffset){
  6281. StreamInfoBaseDst = (PFILE_STREAM_INFORMATION)((PCHAR) StreamInfoBaseDst + StreamInfoBaseDst->NextEntryOffset);
  6282. } else {
  6283. StreamInfoBaseDst = NULL;
  6284. }
  6285. if (((StreamInfoBaseSrc == NULL) || (StreamInfoBaseDst == NULL)) && (StreamInfoBaseSrc != StreamInfoBaseDst)) {
  6286. rc = 1;
  6287. }
  6288. } while ( (rc == 0) && StreamInfoBaseSrc );
  6289. }
  6290. return rc;
  6291. }
  6292. //
  6293. // Beta 2 API
  6294. //
  6295. DWORD
  6296. AddUsersToFileSrv(
  6297. IN PEFS_USER_INFO pEfsUserInfo,
  6298. IN LPCTSTR lpFileName,
  6299. IN DWORD nUsers,
  6300. IN PENCRYPTION_CERTIFICATE * pEncryptionCertificates
  6301. )
  6302. /*++
  6303. Routine Description:
  6304. This routine will add an entry in the DDF field of the passed file
  6305. for each certificate passed.
  6306. The file will not be modified at all if any errors occur
  6307. during processing.
  6308. Arguments:
  6309. lpFileName - Supplies the name of the file to be encrypted. File may
  6310. be local or remote. It will be opened for exclusive access.
  6311. dwCertificates - Supplies the number of certificate structures in the
  6312. pEncryptionCertificates array.
  6313. pEncryptionCertificates - Supplies an array of pointers to certificate
  6314. structures, one for each user to be added to the file.
  6315. Return Value:
  6316. This routine will fail under the following circumstances:
  6317. Passed file is not encrypted.
  6318. Passed file cannot be opened for exclusive access.
  6319. Caller does not have keys to decrypt the file.
  6320. A passed certificate was not structurally valid. In this case,
  6321. the entire operation will fail.
  6322. And all the other reasons why an EFS operation can fail
  6323. (EFS not present, no recovery policy, etc)
  6324. --*/
  6325. {
  6326. BOOL b = FALSE;
  6327. DWORD rc = ERROR_SUCCESS;
  6328. //
  6329. // Open the passed file and get the EFS stream
  6330. //
  6331. //
  6332. // Open for READ_ATTRIBUTES so we don't go through all the noise of
  6333. // decrypting the FEK when we don't really care to (we're going to have to
  6334. // do that here anyway). We could open the file just to be sure the decrypt
  6335. // is going to work, but there's no point in speeding up the failure case.
  6336. //
  6337. PEFS_DATA_STREAM_HEADER pEfsStream = NULL;
  6338. HANDLE hFile;
  6339. DWORD FileAttributes;
  6340. DWORD Flags = 0;
  6341. FileAttributes = GetFileAttributes( lpFileName );
  6342. if (FileAttributes == -1) {
  6343. return GetLastError();
  6344. }
  6345. if (FileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
  6346. Flags = FILE_FLAG_BACKUP_SEMANTICS;
  6347. }
  6348. hFile = CreateFile(
  6349. lpFileName,
  6350. FILE_READ_ATTRIBUTES | FILE_WRITE_DATA,
  6351. 0,
  6352. NULL,
  6353. OPEN_EXISTING,
  6354. Flags,
  6355. NULL
  6356. );
  6357. if (hFile != INVALID_HANDLE_VALUE) {
  6358. //
  6359. // Get the EFS stream
  6360. //
  6361. NTSTATUS Status;
  6362. Status = GetFileEfsStream(
  6363. hFile,
  6364. &pEfsStream
  6365. );
  6366. if (NT_SUCCESS( Status )) {
  6367. //
  6368. // Decrypt the FEK, if possible
  6369. //
  6370. PEFS_KEY Fek;
  6371. PEFS_DATA_STREAM_HEADER UpdatedEfs = NULL;
  6372. rc = DecryptFek( pEfsUserInfo, pEfsStream, &Fek, &UpdatedEfs, 0 );
  6373. if (rc == ERROR_SUCCESS) {
  6374. if (UpdatedEfs != NULL) {
  6375. //
  6376. // Something changed since the last time this file was
  6377. // opened.
  6378. //
  6379. LsapFreeLsaHeap( pEfsStream );
  6380. pEfsStream = UpdatedEfs;
  6381. UpdatedEfs = NULL;
  6382. }
  6383. //
  6384. // For each certificate passed to us,
  6385. // add it to the EFS stream.
  6386. //
  6387. for (DWORD i=0; i<nUsers ; i++) {
  6388. PENCRYPTION_CERTIFICATE pEncryptionCert;
  6389. BOOLEAN bRet;
  6390. __try{
  6391. pEncryptionCert= pEncryptionCertificates[i];
  6392. bRet = AddUserToEFS(
  6393. pEfsStream,
  6394. pEncryptionCert->pUserSid,
  6395. Fek,
  6396. pEncryptionCert->pCertBlob->pbData,
  6397. pEncryptionCert->pCertBlob->cbData,
  6398. &UpdatedEfs
  6399. );
  6400. } __except (EXCEPTION_EXECUTE_HANDLER) {
  6401. bRet = FALSE;
  6402. SetLastError( ERROR_INVALID_PARAMETER );
  6403. }
  6404. if (bRet) {
  6405. //
  6406. // Toss the old EFS stream and pick up the new one.
  6407. //
  6408. if (UpdatedEfs) {
  6409. b = TRUE;
  6410. LsapFreeLsaHeap( pEfsStream );
  6411. pEfsStream = UpdatedEfs;
  6412. UpdatedEfs = NULL;
  6413. }
  6414. } else {
  6415. b = FALSE;
  6416. rc = GetLastError();
  6417. break;
  6418. }
  6419. }
  6420. //
  6421. // If we got out with everything working,
  6422. // set the new EFS stream on the file. Otherwise,
  6423. // clean up and fail the entire operation.
  6424. //
  6425. if (b) {
  6426. //
  6427. // Set the new EFS stream on the file.
  6428. //
  6429. if (!EfspSetEfsOnFile( hFile, pEfsStream, NULL )) {
  6430. rc = GetLastError();
  6431. }
  6432. }
  6433. }
  6434. LsapFreeLsaHeap( pEfsStream );
  6435. } else {
  6436. rc = RtlNtStatusToDosError( Status );
  6437. }
  6438. CloseHandle( hFile );
  6439. } else {
  6440. rc = GetLastError();
  6441. }
  6442. return( rc );
  6443. }
  6444. BOOL
  6445. EfspSetEfsOnFile(
  6446. IN HANDLE hFile,
  6447. PEFS_DATA_STREAM_HEADER pEfsStream,
  6448. IN PEFS_KEY pNewFek OPTIONAL
  6449. )
  6450. /*++
  6451. Routine Description:
  6452. The routine sets the passed EFS stream onto the passed file. The
  6453. file must be open for WRITE_DATA access.
  6454. Arguments:
  6455. hFile - Supplies a handle to the file being modified.
  6456. pEfsStream - Supplies the new EFS stream to be placed on the file.
  6457. Return Value:
  6458. TRUE on success, FALSE on failure. Call GetLastError() for more details.
  6459. --*/
  6460. {
  6461. BOOL b = FALSE;
  6462. DWORD OutputDataLength = 0;
  6463. DWORD EfsDataLength = 0;
  6464. PBYTE OutputData = NULL;
  6465. if (ARGUMENT_PRESENT( pNewFek )) {
  6466. OutputDataLength = 3 * sizeof(ULONG) + 2 * EFS_KEY_SIZE( pNewFek ) + pEfsStream->Length;
  6467. EfsDataLength = OutputDataLength - 3 * sizeof(ULONG);
  6468. OutputData = (PBYTE)LsapAllocateLsaHeap( OutputDataLength );
  6469. if (OutputData) {
  6470. b = SendEfs(
  6471. pNewFek,
  6472. pEfsStream,
  6473. (PBYTE) OutputData + 3 * sizeof(ULONG),
  6474. &EfsDataLength
  6475. );
  6476. }
  6477. } else {
  6478. //
  6479. // Not changing the FEK on the file.
  6480. //
  6481. OutputDataLength = COMMON_FSCTL_HEADER_SIZE + pEfsStream->Length;
  6482. EfsDataLength = OutputDataLength - 3 * sizeof(ULONG);
  6483. OutputData = (PBYTE)LsapAllocateLsaHeap( OutputDataLength );
  6484. if (OutputData) {
  6485. b = SendHandleAndEfs(
  6486. hFile,
  6487. pEfsStream,
  6488. (PBYTE) OutputData + 3 * sizeof(ULONG),
  6489. &EfsDataLength
  6490. );
  6491. }
  6492. }
  6493. if (b) {
  6494. DWORD Attributes = WRITE_EFS_ATTRIBUTE;
  6495. if (ARGUMENT_PRESENT( pNewFek )) {
  6496. Attributes |= SET_EFS_KEYBLOB;
  6497. }
  6498. b = EncryptFSCTLData(
  6499. EFS_OVERWRITE_ATTRIBUTE,
  6500. EFS_ENCRYPT_STREAM,
  6501. Attributes,
  6502. (PBYTE) OutputData + 3 * sizeof(ULONG),
  6503. EfsDataLength,
  6504. (PBYTE) OutputData,
  6505. &OutputDataLength
  6506. );
  6507. //
  6508. // As currently implemented, this routine cannot fail.
  6509. //
  6510. ASSERT(b);
  6511. NTSTATUS NtStatus;
  6512. IO_STATUS_BLOCK IoStatusBlock;
  6513. DWORD FsControl;
  6514. if (ARGUMENT_PRESENT( pNewFek )) {
  6515. FsControl = FSCTL_SET_ENCRYPTION;
  6516. } else {
  6517. FsControl = FSCTL_ENCRYPTION_FSCTL_IO;
  6518. }
  6519. NtStatus = NtFsControlFile(
  6520. hFile,
  6521. 0,
  6522. NULL,
  6523. NULL,
  6524. &IoStatusBlock,
  6525. FsControl,
  6526. OutputData,
  6527. OutputDataLength,
  6528. NULL,
  6529. NULL
  6530. );
  6531. if ( NT_SUCCESS( NtStatus )){
  6532. b = TRUE;
  6533. } else {
  6534. b = FALSE;
  6535. SetLastError( RtlNtStatusToDosError( NtStatus ) );
  6536. }
  6537. }
  6538. if (OutputData != NULL) {
  6539. LsapFreeLsaHeap( OutputData );
  6540. }
  6541. return( b );
  6542. }
  6543. DWORD
  6544. QueryUsersOnFileSrv(
  6545. IN LPCTSTR lpFileName,
  6546. OUT PDWORD pnUsers,
  6547. OUT PENCRYPTION_CERTIFICATE_HASH ** pUsers
  6548. )
  6549. /*++
  6550. Routine Description:
  6551. This routine will return a buffer containing the certificate hashes
  6552. and SIDs for the users who can decrypt the specified file.
  6553. Note that the current user does not need to be able to decrypt the
  6554. file.
  6555. Arguments:
  6556. lpFileName - Supplies the file to be examined. This file will be opened
  6557. for exclusive access. The caller must have READ_ATTRIBUTES access to
  6558. the file.
  6559. pnUsers - Returns the number of entries in the pHashes array. This field will be
  6560. set even if pHashes is NULL.
  6561. pHashes - Supplies a buffer to be filled with an array of ENCRYPTION_CERTIFICATE_HASH
  6562. structures, one for each user listed in the DDF of the file. This parameter may
  6563. be NULL if the caller is trying to determine the required size.
  6564. Return Value:
  6565. This routine will fail if:
  6566. The passed file is not encrypted.
  6567. The passed buffer is non-NULL but not large enough.
  6568. The current user does not have READ_ATTRIBUTES access to the file.
  6569. --*/
  6570. {
  6571. //
  6572. // Open the file
  6573. //
  6574. BOOL b = FALSE;
  6575. HANDLE hFile;
  6576. PEFS_DATA_STREAM_HEADER pEfsStream;
  6577. DWORD rc = ERROR_SUCCESS;
  6578. DWORD FileAttributes;
  6579. DWORD Flags = 0;
  6580. *pnUsers = NULL;
  6581. *pUsers = NULL;
  6582. FileAttributes = GetFileAttributes( lpFileName );
  6583. if (FileAttributes == -1) {
  6584. return GetLastError();
  6585. }
  6586. if (FileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
  6587. Flags = FILE_FLAG_BACKUP_SEMANTICS;
  6588. }
  6589. hFile = CreateFile(
  6590. lpFileName,
  6591. FILE_READ_ATTRIBUTES,
  6592. 0,
  6593. NULL,
  6594. OPEN_EXISTING,
  6595. Flags,
  6596. NULL
  6597. );
  6598. if (hFile != INVALID_HANDLE_VALUE) {
  6599. //
  6600. // Get the EFS stream
  6601. //
  6602. NTSTATUS Status;
  6603. Status = GetFileEfsStream(
  6604. hFile,
  6605. &pEfsStream
  6606. );
  6607. if (NT_SUCCESS( Status )) {
  6608. PENCRYPTED_KEYS pDDF = (PENCRYPTED_KEYS)OFFSET_TO_POINTER( DataDecryptionField, pEfsStream );
  6609. __try {
  6610. //
  6611. // We may have gotten corrupted bits off the disk. We can't
  6612. // verify the checksum on the EfsStream, because we don't have the
  6613. // FEK (and we don't want to require the caller to have to decrypt
  6614. // the file to get this information). So wrap this call in a
  6615. // try-except so we don't risk blowing up.
  6616. //
  6617. b = QueryCertsFromEncryptedKeys(
  6618. pDDF,
  6619. pnUsers,
  6620. pUsers
  6621. );
  6622. if (!b) {
  6623. rc = GetLastError();
  6624. }
  6625. } __except (EXCEPTION_EXECUTE_HANDLER) {
  6626. b = FALSE;
  6627. rc = GetExceptionCode();
  6628. if (ERROR_NOACCESS == rc) {
  6629. rc = ERROR_FILE_CORRUPT;
  6630. }
  6631. }
  6632. LsapFreeLsaHeap( pEfsStream );
  6633. } else {
  6634. rc = RtlNtStatusToDosError( Status );
  6635. }
  6636. CloseHandle( hFile );
  6637. } else {
  6638. rc = GetLastError();
  6639. }
  6640. if (rc != ERROR_SUCCESS) {
  6641. DebugLog((DEB_WARN, "QueryUsersOnFileSrv returning %x\n" ,rc ));
  6642. }
  6643. return( rc );
  6644. }
  6645. DWORD
  6646. QueryRecoveryAgentsSrv(
  6647. IN LPCTSTR lpFileName,
  6648. OUT PDWORD pnRecoveryAgents,
  6649. OUT PENCRYPTION_CERTIFICATE_HASH ** pRecoveryAgents
  6650. )
  6651. /*++
  6652. Routine Description:
  6653. This routine will return a buffer containing the certificate hashes
  6654. for the recovery agents on the passed file.
  6655. Note that the current user does not need to be able to decrypt the
  6656. file.
  6657. [ Should we combine this routine with the one above, and just take a
  6658. flag? Or should there be one routine that returns everything, perhaps
  6659. with a mark for each user that is in the DRF? There are several ways
  6660. to do this. ]
  6661. Arguments:
  6662. lpFileName - Supplies the file to be examined. This file will be opened
  6663. for exclusive access. The caller must have READ_ATTRIBUTES access to
  6664. the file.
  6665. pcbBuffer - Supplies/returns the size of the buffer passed in the in pHashes
  6666. parameter. If pHashes is NULL, the function will succeed and the required
  6667. size will be returned.
  6668. pHashes - Supplies a buffer to be filled with an array of ENCRYPTION_CERTIFICATE_HASH
  6669. structures, one for each user listed in the DRF of the file. This parameter may
  6670. be NULL if the caller is trying to determine the required size.
  6671. Return Value:
  6672. This routine will fail if:
  6673. The passed file is not encrypted.
  6674. The passed buffer is non-NULL but not large enough.
  6675. The current user does not have READ_ATTRIBUTES access to the file.
  6676. --*/
  6677. {
  6678. //
  6679. // Open the file
  6680. //
  6681. BOOL b = FALSE;
  6682. HANDLE hFile;
  6683. PEFS_DATA_STREAM_HEADER pEfsStream;
  6684. DWORD rc = ERROR_SUCCESS;
  6685. DWORD FileAttributes;
  6686. DWORD Flags = 0;
  6687. *pnRecoveryAgents = 0;
  6688. *pRecoveryAgents = NULL;
  6689. FileAttributes = GetFileAttributes( lpFileName );
  6690. if (FileAttributes == -1) {
  6691. return GetLastError();
  6692. }
  6693. if (FileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
  6694. Flags = FILE_FLAG_BACKUP_SEMANTICS;
  6695. }
  6696. hFile = CreateFile(
  6697. lpFileName,
  6698. FILE_READ_ATTRIBUTES,
  6699. 0,
  6700. NULL,
  6701. OPEN_EXISTING,
  6702. Flags,
  6703. NULL
  6704. );
  6705. if (hFile != INVALID_HANDLE_VALUE) {
  6706. //
  6707. // Get the EFS stream
  6708. //
  6709. NTSTATUS Status;
  6710. Status = GetFileEfsStream(
  6711. hFile,
  6712. &pEfsStream
  6713. );
  6714. if (NT_SUCCESS( Status )) {
  6715. PENCRYPTED_KEYS pDRF = (PENCRYPTED_KEYS)OFFSET_TO_POINTER( DataRecoveryField, pEfsStream );
  6716. if ( (PVOID)pDRF != (PVOID)pEfsStream) {
  6717. __try {
  6718. b = QueryCertsFromEncryptedKeys(
  6719. pDRF,
  6720. pnRecoveryAgents,
  6721. pRecoveryAgents
  6722. );
  6723. if (!b) {
  6724. rc = GetLastError();
  6725. }
  6726. } __except (EXCEPTION_EXECUTE_HANDLER) {
  6727. b = FALSE;
  6728. rc = GetExceptionCode();
  6729. if (ERROR_NOACCESS == rc) {
  6730. rc = ERROR_FILE_CORRUPT;
  6731. }
  6732. }
  6733. }
  6734. LsapFreeLsaHeap( pEfsStream );
  6735. } else {
  6736. rc = RtlNtStatusToDosError( Status );
  6737. }
  6738. CloseHandle( hFile );
  6739. } else {
  6740. rc = GetLastError();
  6741. }
  6742. if (rc != ERROR_SUCCESS) {
  6743. DebugLog((DEB_WARN, "QueryRecoveryAgentsSrv returning %x\n" ,rc ));
  6744. }
  6745. return( rc );
  6746. }
  6747. DWORD
  6748. RemoveUsersFromFileSrv(
  6749. IN PEFS_USER_INFO pEfsUserInfo,
  6750. IN LPCTSTR lpFileName,
  6751. IN DWORD nUsers,
  6752. IN PENCRYPTION_CERTIFICATE_HASH * pHashes
  6753. )
  6754. /*++
  6755. Routine Description:
  6756. This routine will remove the passed users from the list
  6757. of people who can decrypt the passed file.
  6758. The file will not be modified at all if any errors occur
  6759. during processing.
  6760. Arguments:
  6761. lpFileName - Supplies a pointer to the file to be edited. This file
  6762. will be opened for exclusive access.
  6763. nHashes - Supplies the number of hashes in the pHashes array.
  6764. pHashes - Supplies an array of pointers to hash structures for subjects to be
  6765. removed from the file.
  6766. Return Value:
  6767. This function will fail if:
  6768. The passed file is not encrypted.
  6769. The user does not have sufficient access to the file.
  6770. --*/
  6771. {
  6772. PEFS_DATA_STREAM_HEADER UpdatedEfs = NULL;
  6773. HANDLE hFile;
  6774. PEFS_DATA_STREAM_HEADER pEfsStream = NULL;
  6775. DWORD rc = ERROR_SUCCESS;
  6776. PEFS_KEY Fek = NULL;
  6777. DWORD FileAttributes;
  6778. DWORD Flags = 0;
  6779. FileAttributes = GetFileAttributes( lpFileName );
  6780. if (FileAttributes == -1) {
  6781. return GetLastError();
  6782. }
  6783. if (FileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
  6784. Flags = FILE_FLAG_BACKUP_SEMANTICS;
  6785. }
  6786. hFile = CreateFile(
  6787. lpFileName,
  6788. FILE_READ_ATTRIBUTES| FILE_WRITE_DATA,
  6789. 0,
  6790. NULL,
  6791. OPEN_EXISTING,
  6792. Flags,
  6793. NULL
  6794. );
  6795. if (hFile != INVALID_HANDLE_VALUE) {
  6796. //
  6797. // Get the EFS stream
  6798. //
  6799. NTSTATUS Status;
  6800. Status = GetFileEfsStream(
  6801. hFile,
  6802. &pEfsStream
  6803. );
  6804. if (NT_SUCCESS( Status )) {
  6805. rc = DecryptFek( pEfsUserInfo, pEfsStream, &Fek, &UpdatedEfs, 0 );
  6806. if (ERROR_SUCCESS == rc) {
  6807. //
  6808. // If we got an EFS stream back, toss the
  6809. // one from the file and use it.
  6810. //
  6811. if ( UpdatedEfs != NULL ) {
  6812. LsapFreeLsaHeap( pEfsStream );
  6813. pEfsStream = UpdatedEfs;
  6814. UpdatedEfs = NULL;
  6815. }
  6816. if (RemoveUsersFromEfsStream(
  6817. pEfsStream,
  6818. nUsers,
  6819. pHashes,
  6820. Fek,
  6821. &UpdatedEfs
  6822. )) {
  6823. //
  6824. // If we got an EFS stream back, toss the old EFS
  6825. // stream and pick up the new one. We'll only get
  6826. // an EFS stream back if we found someone to remove.
  6827. //
  6828. if (UpdatedEfs != NULL) {
  6829. LsapFreeLsaHeap( pEfsStream );
  6830. pEfsStream = UpdatedEfs;
  6831. UpdatedEfs = NULL;
  6832. if (!EfspSetEfsOnFile( hFile, pEfsStream, NULL )) {
  6833. rc = GetLastError();
  6834. }
  6835. }
  6836. } else {
  6837. rc = GetLastError();
  6838. }
  6839. if (UpdatedEfs != NULL) {
  6840. LsapFreeLsaHeap( UpdatedEfs );
  6841. }
  6842. LsapFreeLsaHeap( Fek );
  6843. }
  6844. LsapFreeLsaHeap( pEfsStream );
  6845. } else {
  6846. rc = RtlNtStatusToDosError( Status );
  6847. }
  6848. CloseHandle( hFile );
  6849. } else {
  6850. rc = GetLastError();
  6851. }
  6852. return( rc );
  6853. }
  6854. DWORD
  6855. SetFileEncryptionKeySrv(
  6856. IN PEFS_USER_INFO pEfsUserInfo,
  6857. IN PENCRYPTION_CERTIFICATE pEncryptionCertificate
  6858. )
  6859. {
  6860. DWORD rc = ERROR_SUCCESS;
  6861. PBYTE pbHash = NULL;
  6862. DWORD cbHash;
  6863. //
  6864. // Get the current cert hash
  6865. //
  6866. (void) GetCurrentHash(
  6867. pEfsUserInfo,
  6868. &pbHash,
  6869. &cbHash
  6870. );
  6871. //
  6872. // If no certificate was passed, call the code to create
  6873. // a new user key from scratch.
  6874. //
  6875. if (!ARGUMENT_PRESENT( pEncryptionCertificate )) {
  6876. //
  6877. // Create a new key
  6878. //
  6879. rc = EfspReplaceUserKeyInformation( pEfsUserInfo );
  6880. } else {
  6881. __try{
  6882. if ( pEncryptionCertificate->pCertBlob ){
  6883. rc = EfspInstallCertAsUserKey( pEfsUserInfo, pEncryptionCertificate );
  6884. } else {
  6885. rc = ERROR_INVALID_PARAMETER;
  6886. }
  6887. } __except (EXCEPTION_EXECUTE_HANDLER) {
  6888. rc = ERROR_INVALID_PARAMETER;
  6889. }
  6890. }
  6891. if ( (ERROR_SUCCESS == rc) && pbHash) {
  6892. //
  6893. // Operation succeeded and there was a current key. Make our best effort
  6894. // to mark the old cert as archived.
  6895. //
  6896. PCCERT_CONTEXT pCertContext;
  6897. pCertContext = GetCertContextFromCertHash(
  6898. pbHash,
  6899. cbHash,
  6900. CERT_STORE_DEFER_CLOSE_UNTIL_LAST_FREE_FLAG | CERT_SYSTEM_STORE_CURRENT_USER
  6901. );
  6902. if (pCertContext != NULL) {
  6903. CRYPT_DATA_BLOB dataBlob = {0, NULL};
  6904. //
  6905. // This is best effort. We do not need to check the return code.
  6906. //
  6907. (void) CertSetCertificateContextProperty(
  6908. pCertContext,
  6909. CERT_ARCHIVED_PROP_ID,
  6910. 0,
  6911. &dataBlob
  6912. );
  6913. CertFreeCertificateContext( pCertContext );
  6914. }
  6915. }
  6916. if (pbHash) {
  6917. LsapFreeLsaHeap(pbHash);
  6918. }
  6919. return( rc );
  6920. }
  6921. DWORD
  6922. DuplicateEncryptionInfoFileSrv (
  6923. PEFS_USER_INFO pEfsUserInfo,
  6924. LPCWSTR lpSrcFileName,
  6925. LPCWSTR lpDestFileName,
  6926. LPCWSTR lpDestUncName,
  6927. DWORD dwCreationDistribution,
  6928. DWORD dwAttributes,
  6929. PEFS_RPC_BLOB pRelativeSD,
  6930. BOOL bInheritHandle
  6931. )
  6932. /*++
  6933. Routine Description:
  6934. This routine will transfer the EFS information from the source file
  6935. to the target file. It assumes
  6936. The caller has FILE_READ_ATTRIBUTES access to the source file
  6937. The caller has WRITE_ATTRIBUTE and WRITE_DATA access to the target. If the target
  6938. is encrypted, the caller must be able to decrypt it.
  6939. Arguments:
  6940. pEfsUserInfo - Supplies the user info structure for the current caller.
  6941. lpSrcFileName - Supplies a pointer to the name of the source file.
  6942. lpDestFileName - Supplies a pointer to the name of the destination file.
  6943. dwCreationDistribution - CreationDistribution used in CreateFile.
  6944. dwAttributes - File attributes used in CreateFile.
  6945. pRelativeSD - Relative Security Descriptor.
  6946. BOOL - bInheritHandle.
  6947. Return Value:
  6948. Win32 error.
  6949. --*/
  6950. {
  6951. //
  6952. // Get the encryption information off of the src file.
  6953. //
  6954. HANDLE hSrcFile;
  6955. HANDLE hDestFile;
  6956. DWORD rc = ERROR_SUCCESS;
  6957. BOOLEAN fResult = FALSE;
  6958. PEFS_KEY Fek;
  6959. DWORD FileAttributes;
  6960. DWORD FileAttributesDst;
  6961. DWORD FlagsSrc = 0;
  6962. DWORD creationDistribution = 0;
  6963. FileAttributes = GetFileAttributes( lpSrcFileName );
  6964. if (FileAttributes == -1) {
  6965. return GetLastError();
  6966. }
  6967. if (FileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
  6968. FlagsSrc = FILE_FLAG_BACKUP_SEMANTICS;
  6969. }
  6970. //
  6971. // Try to open the file.
  6972. //
  6973. hSrcFile = CreateFile(
  6974. lpSrcFileName,
  6975. FILE_READ_ATTRIBUTES,
  6976. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  6977. NULL,
  6978. OPEN_EXISTING,
  6979. FlagsSrc,
  6980. NULL
  6981. );
  6982. if (hSrcFile != INVALID_HANDLE_VALUE) {
  6983. NTSTATUS Status;
  6984. PEFS_DATA_STREAM_HEADER pEfsStream;
  6985. Status = GetFileEfsStream(
  6986. hSrcFile,
  6987. &pEfsStream
  6988. );
  6989. if (NT_SUCCESS( Status )) {
  6990. PEFS_DATA_STREAM_HEADER NewEfs = NULL;
  6991. GUID NewId;
  6992. //
  6993. // We need to change the file ID here. DecryptFek will recalculate
  6994. // the checksum for us.
  6995. //
  6996. RPC_STATUS RpcStatus = UuidCreate ( &NewId );
  6997. if (RpcStatus == ERROR_SUCCESS || RpcStatus == RPC_S_UUID_LOCAL_ONLY) {
  6998. RtlCopyMemory( &(pEfsStream->EfsId), &NewId, sizeof( GUID ) );
  6999. }
  7000. rc = DecryptFek(
  7001. pEfsUserInfo,
  7002. pEfsStream,
  7003. &Fek,
  7004. &NewEfs,
  7005. 0
  7006. );
  7007. if (rc == ERROR_SUCCESS) {
  7008. //
  7009. // Got the $EFS, now prepares to create destination
  7010. //
  7011. FileAttributesDst = GetFileAttributes( lpDestFileName );
  7012. if (FileAttributesDst == -1) {
  7013. rc = GetLastError();
  7014. FileAttributesDst = 0;
  7015. if ((ERROR_FILE_NOT_FOUND == rc) || (ERROR_PATH_NOT_FOUND == rc)) {
  7016. rc = ERROR_SUCCESS;
  7017. if (FileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
  7018. creationDistribution = FILE_CREATE;
  7019. //
  7020. // Force the new destination to be a directory
  7021. //
  7022. dwAttributes |= FILE_ATTRIBUTE_DIRECTORY;
  7023. }
  7024. }
  7025. } else {
  7026. //
  7027. // File exist. Check if Dir to Dir or File to File
  7028. //
  7029. if (dwCreationDistribution == CREATE_NEW) {
  7030. //
  7031. // The file is already existed. CREATE_NEW will fail.
  7032. //
  7033. rc = ERROR_FILE_EXISTS;
  7034. } else if (FileAttributes & FILE_ATTRIBUTE_DIRECTORY){
  7035. if (!(FileAttributesDst & FILE_ATTRIBUTE_DIRECTORY)) {
  7036. rc = ERROR_DS_SRC_AND_DST_OBJECT_CLASS_MISMATCH;
  7037. } else {
  7038. if (FileAttributesDst & FILE_ATTRIBUTE_ENCRYPTED) {
  7039. creationDistribution = FILE_OPEN;
  7040. }
  7041. }
  7042. } else {
  7043. if (FileAttributesDst & FILE_ATTRIBUTE_DIRECTORY) {
  7044. rc = ERROR_DS_SRC_AND_DST_OBJECT_CLASS_MISMATCH;
  7045. }
  7046. }
  7047. }
  7048. //
  7049. // Now we can Create/open the destination.
  7050. // We have not validate the share access yet. We will use the UNC name
  7051. // to validate if it is a network session.
  7052. //
  7053. OBJECT_ATTRIBUTES Obja;
  7054. UNICODE_STRING DstNtName;
  7055. LPWSTR DstFileName = NULL;
  7056. LPWSTR LongFileName = NULL;
  7057. DWORD FileNameLength;
  7058. BOOL b = TRUE;
  7059. ULONG CreateOptions = 0;
  7060. IO_STATUS_BLOCK IoStatusBlock;
  7061. RtlInitUnicodeString(
  7062. &DstNtName,
  7063. NULL
  7064. );
  7065. if (rc == ERROR_SUCCESS) {
  7066. if (lpDestUncName) {
  7067. if ( (FileNameLength = wcslen(lpDestUncName)) >= MAX_PATH ) {
  7068. //
  7069. // We need \\?\UNC\server\share\dir\file format to open the file.
  7070. //
  7071. DstFileName = LongFileName = (LPWSTR)LsapAllocateLsaHeap( (FileNameLength + 8) * sizeof (WCHAR) );
  7072. if (!LongFileName) {
  7073. rc = ERROR_NOT_ENOUGH_MEMORY;
  7074. } else {
  7075. wcscpy(LongFileName, L"\\\\?\\UNC");
  7076. wcscat(LongFileName, &lpDestUncName[1]);
  7077. }
  7078. } else {
  7079. DstFileName = (LPWSTR) lpDestUncName;
  7080. }
  7081. } else {
  7082. DstFileName = (LPWSTR) lpDestFileName;
  7083. }
  7084. }
  7085. if ( rc != ERROR_SUCCESS ) {
  7086. if (NewEfs) {
  7087. LsapFreeLsaHeap( NewEfs );
  7088. }
  7089. LsapFreeLsaHeap( Fek );
  7090. LsapFreeLsaHeap( pEfsStream );
  7091. CloseHandle( hSrcFile );
  7092. return rc;
  7093. }
  7094. b = RtlDosPathNameToNtPathName_U(
  7095. DstFileName,
  7096. &DstNtName,
  7097. NULL,
  7098. NULL
  7099. );
  7100. if ( b ){
  7101. if (!creationDistribution) {
  7102. creationDistribution = (dwCreationDistribution == CREATE_NEW) ? FILE_CREATE : FILE_OVERWRITE_IF;
  7103. }
  7104. if (FileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
  7105. CreateOptions = FILE_DIRECTORY_FILE;
  7106. } else {
  7107. //
  7108. // NTFS does not support FILE_NO_COPRESSION for the dir.
  7109. //
  7110. CreateOptions |= FILE_NO_COMPRESSION;
  7111. }
  7112. //
  7113. // Encryption bit is not needed. We will encrypt it any way.
  7114. //
  7115. dwAttributes &= ~(FILE_ATTRIBUTE_ENCRYPTED | FILE_ATTRIBUTE_READONLY);
  7116. InitializeObjectAttributes(
  7117. &Obja,
  7118. &DstNtName,
  7119. bInheritHandle ? OBJ_INHERIT | OBJ_CASE_INSENSITIVE : OBJ_CASE_INSENSITIVE,
  7120. 0,
  7121. pRelativeSD? pRelativeSD->pbData:NULL
  7122. );
  7123. Status = NtCreateFile(
  7124. &hDestFile,
  7125. FILE_READ_DATA | FILE_WRITE_DATA | FILE_WRITE_ATTRIBUTES | FILE_READ_ATTRIBUTES | SYNCHRONIZE,
  7126. &Obja,
  7127. &IoStatusBlock,
  7128. NULL,
  7129. dwAttributes,
  7130. 0,
  7131. creationDistribution,
  7132. CreateOptions | FILE_SYNCHRONOUS_IO_NONALERT,
  7133. NULL,
  7134. 0
  7135. );
  7136. if ( NT_SUCCESS(Status) && lpDestUncName ) {
  7137. //
  7138. // If this is a net session, we need to close the loopback handle.
  7139. // This handle is not good to send large FSCTL request.
  7140. // In this case, the file should already exist or overwritten.
  7141. // No parameters for create new file are needed, such as SD.
  7142. //
  7143. RtlFreeHeap(
  7144. RtlProcessHeap(),
  7145. 0,
  7146. DstNtName.Buffer
  7147. );
  7148. RtlInitUnicodeString(
  7149. &DstNtName,
  7150. NULL
  7151. );
  7152. CloseHandle( hDestFile );
  7153. Status = STATUS_NO_SUCH_FILE;
  7154. b = RtlDosPathNameToNtPathName_U(
  7155. lpDestFileName,
  7156. &DstNtName,
  7157. NULL,
  7158. NULL
  7159. );
  7160. if ( b ){
  7161. InitializeObjectAttributes(
  7162. &Obja,
  7163. &DstNtName,
  7164. bInheritHandle ? OBJ_INHERIT | OBJ_CASE_INSENSITIVE : OBJ_CASE_INSENSITIVE,
  7165. 0,
  7166. NULL
  7167. );
  7168. Status = NtCreateFile(
  7169. &hDestFile,
  7170. FILE_READ_DATA | FILE_WRITE_DATA | FILE_WRITE_ATTRIBUTES | FILE_READ_ATTRIBUTES | SYNCHRONIZE,
  7171. &Obja,
  7172. &IoStatusBlock,
  7173. NULL,
  7174. dwAttributes,
  7175. 0,
  7176. FILE_OPEN,
  7177. CreateOptions | FILE_SYNCHRONOUS_IO_NONALERT,
  7178. NULL,
  7179. 0
  7180. );
  7181. }
  7182. }
  7183. if (NT_SUCCESS(Status)) {
  7184. //
  7185. // Work around for FILE_NO_COMPRESSION
  7186. //
  7187. if ((FileAttributesDst & FILE_ATTRIBUTE_COMPRESSED) || ((dwCreationDistribution == CREATE_NEW) && (FileAttributes & FILE_ATTRIBUTE_DIRECTORY))) {
  7188. //
  7189. // Let's decompressed the dir
  7190. //
  7191. USHORT State = COMPRESSION_FORMAT_NONE;
  7192. ULONG Length;
  7193. //
  7194. // Attempt to uncompress the directory. Best effort. If it fails, we still continue.
  7195. //
  7196. b = DeviceIoControl(
  7197. hDestFile,
  7198. FSCTL_SET_COMPRESSION,
  7199. &State,
  7200. sizeof(USHORT),
  7201. NULL,
  7202. 0,
  7203. &Length,
  7204. FALSE
  7205. );
  7206. }
  7207. if (!EfspSetEfsOnFile( hDestFile, NewEfs? NewEfs : pEfsStream, Fek )) {
  7208. rc = GetLastError();
  7209. if ( ERROR_INVALID_FUNCTION == rc ) {
  7210. //
  7211. // lpDestFileName is a local path. Change it to be a volume name.
  7212. //
  7213. DWORD FileSystemFlags;
  7214. WCHAR RootDirName[4];
  7215. wcsncpy(RootDirName, lpDestFileName, 3);
  7216. RootDirName[3] = 0;
  7217. if(GetVolumeInformation(
  7218. RootDirName,
  7219. NULL, // Volume name.
  7220. 0, // Volume name length.
  7221. NULL, // Serial number.
  7222. NULL, // Maximum length.
  7223. &FileSystemFlags,
  7224. NULL, // File system type.
  7225. 0
  7226. )){
  7227. if (!(FileSystemFlags & FILE_SUPPORTS_ENCRYPTION)) {
  7228. //
  7229. // Let's map the error.
  7230. //
  7231. rc = ERROR_VOLUME_NOT_SUPPORT_EFS;
  7232. if (dwCreationDistribution == CREATE_NEW) {
  7233. CloseHandle( hDestFile );
  7234. hDestFile = 0;
  7235. DeleteFileW(lpDestFileName);
  7236. }
  7237. }
  7238. }
  7239. }
  7240. }
  7241. if (hDestFile) {
  7242. CloseHandle( hDestFile );
  7243. }
  7244. } else {
  7245. rc = RtlNtStatusToDosError( Status );
  7246. }
  7247. } else {
  7248. rc = GetLastError();
  7249. }
  7250. if (DstNtName.Buffer) {
  7251. RtlFreeHeap(
  7252. RtlProcessHeap(),
  7253. 0,
  7254. DstNtName.Buffer
  7255. );
  7256. }
  7257. if (LongFileName) {
  7258. LsapFreeLsaHeap( LongFileName );
  7259. }
  7260. if (NewEfs) {
  7261. LsapFreeLsaHeap( NewEfs );
  7262. }
  7263. LsapFreeLsaHeap( Fek );
  7264. }
  7265. LsapFreeLsaHeap( pEfsStream );
  7266. } else {
  7267. rc = RtlNtStatusToDosError( Status );
  7268. }
  7269. CloseHandle( hSrcFile );
  7270. } else {
  7271. rc = GetLastError();
  7272. }
  7273. return( rc );
  7274. }
  7275. VOID
  7276. EfsLogEntry (
  7277. WORD wType,
  7278. WORD wCategory,
  7279. DWORD dwEventID,
  7280. WORD wNumStrings,
  7281. DWORD dwDataSize,
  7282. LPCTSTR *lpStrings,
  7283. LPVOID lpRawData
  7284. )
  7285. /*++
  7286. Routine Description:
  7287. This routine wraps the call to ReportEvent.
  7288. Arguments:
  7289. See info for ReportEvent.
  7290. Return Value:
  7291. None.
  7292. --*/
  7293. {
  7294. HANDLE EventHandleLog;
  7295. EventHandleLog = RegisterEventSource(
  7296. NULL,
  7297. EFSSOURCE
  7298. );
  7299. if ( EventHandleLog ){
  7300. ReportEvent(
  7301. EventHandleLog,
  7302. wType,
  7303. wCategory,
  7304. dwEventID,
  7305. NULL,
  7306. wNumStrings,
  7307. dwDataSize,
  7308. lpStrings,
  7309. lpRawData
  7310. );
  7311. DeregisterEventSource( EventHandleLog );
  7312. }
  7313. }
  7314. DWORD
  7315. EfsFileKeyInfoSrv(
  7316. IN LPCWSTR lpFileName,
  7317. IN DWORD InfoClass,
  7318. OUT PDWORD nbData,
  7319. OUT PBYTE *pbData
  7320. )
  7321. /*++
  7322. Routine Description:
  7323. This routine gets the internal info about the encryption used on the file.
  7324. Arguments:
  7325. lpFileName - File name.
  7326. nbData - Length of pbData returned.
  7327. pbData - Info returned
  7328. Return Value:
  7329. Win32 error.
  7330. --*/
  7331. {
  7332. PEFS_KEY Fek = NULL;
  7333. HANDLE hFile;
  7334. PEFS_DATA_STREAM_HEADER pEfsStream = NULL;
  7335. NTSTATUS Status;
  7336. DWORD rc = ERROR_SUCCESS;
  7337. DWORD FileAttributes;
  7338. DWORD Flags = 0;
  7339. EFS_USER_INFO EfsUserInfo;
  7340. PEFS_KEY_INFO pKeyInfo;
  7341. *nbData = 0;
  7342. *pbData = NULL;
  7343. if (InfoClass != BASIC_KEY_INFO) {
  7344. return ERROR_INVALID_PARAMETER;
  7345. }
  7346. FileAttributes = GetFileAttributes( lpFileName );
  7347. if (FileAttributes == -1) {
  7348. return GetLastError();
  7349. }
  7350. if ((FileAttributes & FILE_ATTRIBUTE_ENCRYPTED) == 0) {
  7351. return ERROR_FILE_NOT_ENCRYPTED;
  7352. }
  7353. if (FileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
  7354. Flags = FILE_FLAG_BACKUP_SEMANTICS;
  7355. }
  7356. hFile = CreateFile(
  7357. lpFileName,
  7358. FILE_READ_ATTRIBUTES,
  7359. 0,
  7360. NULL,
  7361. OPEN_EXISTING,
  7362. Flags,
  7363. NULL
  7364. );
  7365. if (hFile == INVALID_HANDLE_VALUE) {
  7366. return GetLastError();
  7367. }
  7368. Status = GetFileEfsStream(
  7369. hFile,
  7370. &pEfsStream
  7371. );
  7372. CloseHandle(hFile);
  7373. if (NT_SUCCESS( Status )){
  7374. if (EfspGetUserInfo( &EfsUserInfo )) {
  7375. HANDLE hToken;
  7376. HANDLE hProfile;
  7377. if (EfspLoadUserProfile( &EfsUserInfo, &hToken, &hProfile )) {
  7378. rc = EfsGetFek(
  7379. &EfsUserInfo,
  7380. pEfsStream,
  7381. &Fek
  7382. );
  7383. if (ERROR_SUCCESS == rc) {
  7384. pKeyInfo = (PEFS_KEY_INFO) MIDL_user_allocate( sizeof(EFS_KEY_INFO) );
  7385. pKeyInfo->dwVersion = 1;
  7386. pKeyInfo->Entropy = Fek->Entropy;
  7387. pKeyInfo->Algorithm = Fek->Algorithm;
  7388. pKeyInfo->KeyLength = Fek->KeyLength;
  7389. *pbData = (PBYTE) pKeyInfo;
  7390. *nbData = sizeof(EFS_KEY_INFO);
  7391. LsapFreeLsaHeap( Fek );
  7392. }
  7393. EfspUnloadUserProfile( hToken, hProfile );
  7394. }
  7395. EfspFreeUserInfo( &EfsUserInfo );
  7396. }
  7397. } else {
  7398. rc = RtlNtStatusToDosError( Status );
  7399. }
  7400. LsapFreeLsaHeap( pEfsStream );
  7401. return rc;
  7402. }