Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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