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

1916 lines
43 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. efsrtlsp.c
  5. Abstract:
  6. This module will provide EFS RTL support routines.
  7. Author:
  8. Robert Gu (robertg) 20-Dec-1996
  9. Environment:
  10. Kernel Mode Only
  11. Revision History:
  12. --*/
  13. #include "efsrtl.h"
  14. #ifdef ALLOC_PRAGMA
  15. #pragma alloc_text(PAGE, EfsReadEfsData)
  16. #pragma alloc_text(PAGE, EfsVerifyGeneralFsData)
  17. #pragma alloc_text(PAGE, EfsVerifyKeyFsData)
  18. #pragma alloc_text(PAGE, EfsDeleteEfsData)
  19. #pragma alloc_text(PAGE, EfsSetEncrypt)
  20. #pragma alloc_text(PAGE, EfsEncryptStream)
  21. #pragma alloc_text(PAGE, EfsEncryptFile)
  22. #pragma alloc_text(PAGE, EfsDecryptStream)
  23. #pragma alloc_text(PAGE, EfsDecryptFile)
  24. #pragma alloc_text(PAGE, EfsEncryptDir)
  25. #pragma alloc_text(PAGE, EfsModifyEfsState)
  26. #pragma alloc_text(PAGE, GetEfsStreamOffset)
  27. #pragma alloc_text(PAGE, SetEfsData)
  28. #pragma alloc_text(PAGE, EfsFindInCache)
  29. #pragma alloc_text(PAGE, EfsRefreshCache)
  30. #pragma alloc_text(PAGE, SkipCheckStream)
  31. #endif
  32. NTSTATUS
  33. EfsReadEfsData(
  34. IN OBJECT_HANDLE FileHdl,
  35. IN PIRP_CONTEXT IrpContext,
  36. OUT PVOID *EfsStreamData,
  37. OUT PULONG PEfsStreamLength,
  38. OUT PULONG Information
  39. )
  40. /*++
  41. Routine Description:
  42. This is an internal support routine. The purpose is to reduce the code size.
  43. It is used to read $EFS data and set the context block.
  44. Arguments:
  45. FileHdl -- An object handle to access the attached $EFS
  46. IrpContext -- Used in NtOfsCreateAttributeEx().
  47. EfsStreamData -- Point to $EFS data read.
  48. Information -- Return the processing information
  49. Return Value:
  50. Result of the operation.
  51. The value will be used to return to NTFS.
  52. --*/
  53. {
  54. NTSTATUS ntStatus;
  55. ATTRIBUTE_HANDLE attribute = NULL;
  56. LONGLONG attriOffset;
  57. ULONG efsLength;
  58. PVOID efsMapBuffer = NULL;
  59. MAP_HANDLE efsMapHandle;
  60. PAGED_CODE();
  61. if (EfsStreamData) {
  62. *EfsStreamData = NULL;
  63. }
  64. try {
  65. ntStatus = NtOfsCreateAttributeEx(
  66. IrpContext,
  67. FileHdl,
  68. EfsData.EfsName,
  69. $LOGGED_UTILITY_STREAM,
  70. OPEN_EXISTING,
  71. TRUE,
  72. &attribute
  73. );
  74. if (NT_SUCCESS(ntStatus)){
  75. LONGLONG attrLength;
  76. NtOfsInitializeMapHandle(&efsMapHandle);
  77. //
  78. // Prepare to map and read the $EFS data
  79. //
  80. attrLength = NtOfsQueryLength ( attribute );
  81. if (attrLength <= sizeof ( EFS_DATA_STREAM_HEADER ) ){
  82. //
  83. // Not our $EFS
  84. //
  85. NtOfsCloseAttribute(IrpContext, attribute);
  86. *Information = EFS_FORMAT_ERROR;
  87. ntStatus = STATUS_SUCCESS;
  88. leave;
  89. }
  90. if ( attrLength > EFS_MAX_LENGTH) {
  91. //
  92. // EFS stream too long ( > 256K )
  93. // We might support that in the future
  94. // In that case, we need multiple map window
  95. //
  96. NtOfsCloseAttribute(IrpContext, attribute);
  97. *Information = EFS_FORMAT_ERROR;
  98. ntStatus = STATUS_SUCCESS;
  99. leave;
  100. }
  101. attriOffset = 0;
  102. *PEfsStreamLength = efsLength = (ULONG) attrLength;
  103. NtOfsMapAttribute(
  104. IrpContext,
  105. attribute,
  106. attriOffset,
  107. efsLength,
  108. &efsMapBuffer,
  109. &efsMapHandle
  110. );
  111. //
  112. // Double check the EFS
  113. //
  114. if ( efsLength != *(ULONG *)efsMapBuffer){
  115. //
  116. // Not our $EFS
  117. //
  118. NtOfsReleaseMap(IrpContext, &efsMapHandle);
  119. NtOfsCloseAttribute(IrpContext, attribute);
  120. *Information = EFS_FORMAT_ERROR;
  121. ntStatus = STATUS_SUCCESS;
  122. leave;
  123. }
  124. //
  125. // Allocate memory for $EFS
  126. //
  127. if ( EfsStreamData ){
  128. //
  129. // $EFS must be read
  130. //
  131. *EfsStreamData = ExAllocatePoolWithTag(
  132. PagedPool,
  133. efsLength,
  134. 'msfE'
  135. );
  136. if ( NULL == *EfsStreamData ){
  137. NtOfsReleaseMap(IrpContext, &efsMapHandle);
  138. NtOfsCloseAttribute(IrpContext, attribute);
  139. *Information = OUT_OF_MEMORY;
  140. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  141. leave;
  142. }
  143. RtlCopyMemory(*EfsStreamData, efsMapBuffer, efsLength);
  144. }
  145. NtOfsReleaseMap(IrpContext, &efsMapHandle);
  146. NtOfsCloseAttribute(IrpContext, attribute);
  147. *Information = EFS_READ_SUCCESSFUL;
  148. ntStatus = STATUS_SUCCESS;
  149. } else {
  150. //
  151. // Open failed. Not encrypted by EFS.
  152. //
  153. *Information = OPEN_EFS_FAIL;
  154. ntStatus = STATUS_SUCCESS;
  155. }
  156. } finally {
  157. if (AbnormalTermination()) {
  158. //
  159. // Get the exception status
  160. //
  161. *Information = NTOFS_EXCEPTION;
  162. if (*EfsStreamData) {
  163. ExFreePool(*EfsStreamData);
  164. *EfsStreamData = NULL;
  165. }
  166. if (efsMapBuffer) {
  167. NtOfsReleaseMap(IrpContext, &efsMapHandle);
  168. }
  169. if (attribute) {
  170. NtOfsCloseAttribute(IrpContext, attribute);
  171. }
  172. }
  173. }
  174. return ntStatus;
  175. }
  176. BOOLEAN
  177. EfsVerifyGeneralFsData(
  178. IN PUCHAR DataOffset,
  179. IN ULONG InputDataLength
  180. )
  181. /*++
  182. Routine Description:
  183. This is an internal support routine. The purpose is to verify the general
  184. FSCTL input data to see if it is sent by EFS component or not.
  185. General EFS data format is like the following,
  186. SessionKey, Handle, Handle, [SessionKey, Handle, Handle]sk
  187. Arguments:
  188. DataOffset -- Point to a buffer holding the FSCTL general data part.
  189. InputDataLength -- The length of the FSCTL input puffer
  190. Return Value:
  191. TRUE if verified.
  192. --*/
  193. {
  194. ULONG bytesSame;
  195. ULONG minLength;
  196. PAGED_CODE();
  197. minLength = 4 * DES_BLOCKLEN + 3 * sizeof(ULONG);
  198. if (InputDataLength < minLength){
  199. return FALSE;
  200. }
  201. //
  202. // Decrypt the encrypted data part.
  203. //
  204. des( DataOffset + 2 * DES_BLOCKLEN,
  205. DataOffset + 2 * DES_BLOCKLEN,
  206. &(EfsData.SessionDesTable[0]),
  207. DECRYPT
  208. );
  209. des( DataOffset + 3 * DES_BLOCKLEN,
  210. DataOffset + 3 * DES_BLOCKLEN,
  211. &(EfsData.SessionDesTable[0]),
  212. DECRYPT
  213. );
  214. bytesSame = (ULONG)RtlCompareMemory(
  215. DataOffset,
  216. DataOffset + 2 * DES_BLOCKLEN,
  217. 2 * DES_BLOCKLEN
  218. );
  219. if (( 2 * DES_BLOCKLEN ) != bytesSame ){
  220. //
  221. // Input data format error
  222. //
  223. return FALSE;
  224. }
  225. bytesSame = (ULONG)RtlCompareMemory(
  226. DataOffset,
  227. &(EfsData.SessionKey[0]),
  228. DES_KEYSIZE
  229. );
  230. if ( DES_KEYSIZE != bytesSame ){
  231. //
  232. // Input data is not set by EFS component.
  233. // The session key does not match.
  234. //
  235. return FALSE;
  236. }
  237. return TRUE;
  238. }
  239. BOOLEAN
  240. EfsVerifyKeyFsData(
  241. IN PUCHAR DataOffset,
  242. IN ULONG InputDataLength
  243. )
  244. /*++
  245. Routine Description:
  246. This is an internal support routine. The purpose is to verify the
  247. FSCTL input data with FEK encrypted to see if it is sent by EFS
  248. component or not.
  249. Key EFS data format is like the following,
  250. FEK, [FEK]sk, [$EFS]
  251. Arguments:
  252. DataOffset -- Point to a buffer holding the FSCTL general data part.
  253. InputDataLength -- The length of the FSCTL input puffer
  254. Return Value:
  255. TRUE if verified.
  256. --*/
  257. {
  258. ULONG bytesSame;
  259. LONG encLength;
  260. PUCHAR encBuffer;
  261. PAGED_CODE();
  262. encLength = EFS_KEY_SIZE( ((PEFS_KEY)DataOffset) );
  263. if ( (InputDataLength < (2 * encLength + 3 * sizeof(ULONG))) ||
  264. (0 != ( encLength % DES_BLOCKLEN )) ||
  265. ( encLength <= 0 )){
  266. return FALSE;
  267. }
  268. //
  269. // Decrypt the encrypted data part.
  270. //
  271. encBuffer = DataOffset + encLength;
  272. while ( encLength > 0 ){
  273. des( encBuffer,
  274. encBuffer,
  275. &(EfsData.SessionDesTable[0]),
  276. DECRYPT
  277. );
  278. encBuffer += DES_BLOCKLEN;
  279. encLength -= DES_BLOCKLEN;
  280. }
  281. //
  282. // Compare the two parts.
  283. //
  284. encLength = EFS_KEY_SIZE( ((PEFS_KEY)DataOffset) );
  285. bytesSame = (ULONG)RtlCompareMemory(
  286. DataOffset,
  287. DataOffset + encLength,
  288. encLength
  289. );
  290. if ( ((ULONG) encLength) != bytesSame ){
  291. //
  292. // Input data format error
  293. //
  294. return FALSE;
  295. }
  296. return TRUE;
  297. }
  298. NTSTATUS
  299. EfsDeleteEfsData(
  300. IN OBJECT_HANDLE FileHdl,
  301. IN PIRP_CONTEXT IrpContext
  302. )
  303. /*++
  304. Routine Description:
  305. This is an internal support routine. It deletes $EFS.
  306. Arguments:
  307. FileHdl -- An object handle to access the attached $EFS.
  308. IrpContext -- Used in NtOfsCreateAttributeEx().
  309. Return Value:
  310. Result of the operation.
  311. The value will be used to return to NTFS.
  312. --*/
  313. {
  314. ATTRIBUTE_HANDLE attribute = NULL;
  315. NTSTATUS ntStatus;
  316. PAGED_CODE();
  317. //
  318. // Delete the $EFS stream
  319. //
  320. try {
  321. ntStatus = NtOfsCreateAttributeEx(
  322. IrpContext,
  323. FileHdl,
  324. EfsData.EfsName,
  325. $LOGGED_UTILITY_STREAM,
  326. OPEN_EXISTING,
  327. TRUE,
  328. &attribute
  329. );
  330. if (NT_SUCCESS(ntStatus)){
  331. NtOfsDeleteAttribute( IrpContext, FileHdl, attribute );
  332. }
  333. } finally {
  334. if (attribute) {
  335. //
  336. // According to BrianAn, we shouldn't get exception below.
  337. //
  338. NtOfsCloseAttribute(IrpContext, attribute);
  339. }
  340. }
  341. return ntStatus;
  342. }
  343. NTSTATUS
  344. EfsSetEncrypt(
  345. IN PUCHAR InputData,
  346. IN ULONG InputDataLength,
  347. IN ULONG EncryptionFlag,
  348. IN OBJECT_HANDLE FileHdl,
  349. IN PIRP_CONTEXT IrpContext,
  350. IN OUT PVOID *Context,
  351. IN OUT PULONG PContextLength
  352. )
  353. /*++
  354. Routine Description:
  355. This is an internal support routine. It process the call of
  356. FSCTL_SET_ENCRYPT.
  357. Arguments:
  358. InputData -- Input data buffer of FSCTL.
  359. InputDataLength -- The length of input data.
  360. EncryptionFlag -- Indicating if this stream is encrypted or not.
  361. FileHdl -- An object handle to access the attached $EFS.
  362. IrpContext -- Used in NtOfsCreateAttributeEx().
  363. Context -- Blob(key) for READ or WRITE later.
  364. PContextLength -- Length og the key Blob
  365. Return Value:
  366. Result of the operation.
  367. The value will be used to return to NTFS.
  368. --*/
  369. {
  370. PAGED_CODE();
  371. switch ( ((PFSCTL_INPUT)InputData)->CipherSubCode ){
  372. case EFS_ENCRYPT_STREAM:
  373. return EfsEncryptStream(
  374. InputData,
  375. InputDataLength,
  376. EncryptionFlag,
  377. FileHdl,
  378. IrpContext,
  379. Context,
  380. PContextLength
  381. );
  382. case EFS_ENCRYPT_FILE:
  383. return EfsEncryptFile(
  384. InputData,
  385. InputDataLength,
  386. EncryptionFlag,
  387. FileHdl,
  388. IrpContext,
  389. Context
  390. );
  391. case EFS_DECRYPT_STREAM:
  392. return EfsDecryptStream(
  393. InputData,
  394. InputDataLength,
  395. EncryptionFlag,
  396. FileHdl,
  397. IrpContext,
  398. Context,
  399. PContextLength
  400. );
  401. case EFS_DECRYPT_FILE:
  402. case EFS_DECRYPT_DIRFILE:
  403. return EfsDecryptFile(
  404. InputData,
  405. InputDataLength,
  406. FileHdl,
  407. IrpContext
  408. );
  409. case EFS_ENCRYPT_DIRSTR:
  410. return EfsEncryptDir(
  411. InputData,
  412. InputDataLength,
  413. EncryptionFlag,
  414. FileHdl,
  415. IrpContext
  416. );
  417. break;
  418. case EFS_DECRYPT_DIRSTR:
  419. //
  420. // EFS ignore this case.\
  421. //
  422. break;
  423. default:
  424. break;
  425. }
  426. return STATUS_SUCCESS;
  427. }
  428. NTSTATUS
  429. EfsEncryptStream(
  430. IN PUCHAR InputData,
  431. IN ULONG InputDataLength,
  432. IN ULONG EncryptionFlag,
  433. IN OBJECT_HANDLE FileHdl,
  434. IN PIRP_CONTEXT IrpContext,
  435. IN OUT PVOID *Context,
  436. IN OUT PULONG PContextLength
  437. )
  438. /*++
  439. Routine Description:
  440. This is an internal support routine. It process the call of
  441. FSCTL_SET_ENCRYPT for encrypting a stream. It verifies the caller
  442. and set the key Blob for the stream.
  443. Arguments:
  444. InputData -- Input data buffer of FSCTL.
  445. InputDataLength -- The length of input data.
  446. EncryptionFlag - Indicating if this stream is encrypted or not.
  447. FileHdl -- An object handle to access the attached $EFS.
  448. IrpContext -- Used in NtOfsCreateAttributeEx().
  449. Context -- Blob(key) for READ or WRITE later.
  450. PContextLength -- Length of the key Blob
  451. Return Value:
  452. Result of the operation.
  453. The value will be used to return to NTFS.
  454. --*/
  455. {
  456. ULONG efsLength;
  457. ULONG information;
  458. PVOID efsStreamData = NULL;
  459. PVOID efsKeyBlob = NULL;
  460. PEFS_KEY efsKey = NULL;
  461. NTSTATUS ntStatus;
  462. ULONG bytesSame;
  463. PAGED_CODE();
  464. if ( EncryptionFlag & STREAM_ENCRYPTED ) {
  465. //
  466. // Stream already encrypted
  467. //
  468. return STATUS_SUCCESS;
  469. }
  470. if ( *Context ){
  471. //
  472. // The key Blob is already set without the bit set first.
  473. // Not set by EFS
  474. //
  475. return STATUS_INVALID_DEVICE_REQUEST;
  476. }
  477. //
  478. // [FsData] = FEK, [FEK]sk, $EFS
  479. //
  480. if ( !EfsVerifyKeyFsData(
  481. &(((PFSCTL_INPUT)InputData)->EfsFsData[0]),
  482. InputDataLength) ){
  483. //
  484. // Input data format error
  485. //
  486. return STATUS_INVALID_PARAMETER;
  487. }
  488. //
  489. // Try to read an existing $EFS
  490. //
  491. ntStatus = EfsReadEfsData(
  492. FileHdl,
  493. IrpContext,
  494. &efsStreamData,
  495. &efsLength,
  496. &information
  497. );
  498. if ( EFS_READ_SUCCESSFUL == information ){
  499. BOOLEAN continueProcess = TRUE;
  500. ULONG efsOffset;
  501. efsOffset = GetEfsStreamOffset( InputData );
  502. if ( 0 == (EncryptionFlag & FILE_ENCRYPTED) ){
  503. //
  504. // File is not encrypted, but $EFS exist. Invalid status.
  505. // May caused by a crash during the SET_ENCRYPT file call.
  506. //
  507. ntStatus = STATUS_INVALID_DEVICE_REQUEST;
  508. continueProcess = FALSE;
  509. } else if ( efsLength != ( InputDataLength - efsOffset )) {
  510. //
  511. // $EFS stream length does not match
  512. //
  513. ntStatus = STATUS_INVALID_PARAMETER;
  514. continueProcess = FALSE;
  515. }
  516. if ( !continueProcess ) {
  517. ExFreePool( efsStreamData );
  518. return ntStatus;
  519. }
  520. //
  521. // Got the $EFS. Now double check the match of the $EFS stream.
  522. // EFS use the same $EFS for all the stream within a file.
  523. // Skip comparing the length and status fields.
  524. //
  525. bytesSame = (ULONG)RtlCompareMemory(
  526. (PUCHAR)efsStreamData + 2 * sizeof(ULONG),
  527. InputData + efsOffset + 2 * sizeof(ULONG),
  528. efsLength - 2 * sizeof(ULONG)
  529. );
  530. ExFreePool( efsStreamData );
  531. if ( bytesSame != efsLength - 2 * sizeof(ULONG) ){
  532. //
  533. // The EFS are not the same length
  534. //
  535. return STATUS_INVALID_PARAMETER;
  536. }
  537. efsKey = (PEFS_KEY)&(((PFSCTL_INPUT)InputData)->EfsFsData[0]);
  538. efsKeyBlob = GetKeyBlobBuffer(efsKey->Algorithm);
  539. if ( NULL == efsKeyBlob ){
  540. return STATUS_INSUFFICIENT_RESOURCES;
  541. }
  542. if (!SetKeyTable( efsKeyBlob, efsKey )){
  543. ExFreeToNPagedLookasideList(((PKEY_BLOB)efsKeyBlob)->MemSource, efsKeyBlob);
  544. //
  545. // We might be able to return a better error code if needed.
  546. // This is not in the CreateFile() path.
  547. //
  548. return STATUS_ACCESS_DENIED;
  549. }
  550. *Context = efsKeyBlob;
  551. *PContextLength = ((PKEY_BLOB)efsKeyBlob)->KeyLength;
  552. return STATUS_SUCCESS;
  553. }
  554. //
  555. // Try to encrypt a stream but the $EFS is not there.
  556. // EFS server will always call encrypt on a file first.
  557. //
  558. return STATUS_INVALID_DEVICE_REQUEST;
  559. }
  560. NTSTATUS
  561. EfsEncryptFile(
  562. IN PUCHAR InputData,
  563. IN ULONG InputDataLength,
  564. IN ULONG EncryptionFlag,
  565. IN OBJECT_HANDLE FileHdl,
  566. IN PIRP_CONTEXT IrpContext,
  567. IN OUT PVOID *Context
  568. )
  569. /*++
  570. Routine Description:
  571. This is an internal support routine. It process the call of
  572. FSCTL_SET_ENCRYPT for encrypting a file. It does not deal with
  573. the stream, it only writes the initial $EFS and put the file in
  574. a transition status so that no one else can open the file.
  575. Arguments:
  576. InputData -- Input data buffer of FSCTL.
  577. InputDataLength -- The length of input data.
  578. EncryptionFlag - Indicating if this stream is encrypted or not.
  579. FileHdl -- An object handle to access the attached $EFS.
  580. IrpContext -- Used in NtOfsCreateAttributeEx().
  581. Context - BLOB(key) for READ or WRITE later.
  582. Return Value:
  583. Result of the operation.
  584. The value will be used to return to NTFS.
  585. --*/
  586. {
  587. ULONG efsLength;
  588. ULONG information;
  589. ULONG efsOffset;
  590. PVOID efsStreamData = NULL;
  591. PVOID efsKeyBlob = NULL;
  592. NTSTATUS ntStatus;
  593. ATTRIBUTE_HANDLE attribute = NULL;
  594. PAGED_CODE();
  595. if ( EncryptionFlag & FILE_ENCRYPTED ){
  596. //
  597. // File encrypted.
  598. //
  599. return STATUS_INVALID_DEVICE_REQUEST;
  600. }
  601. //
  602. // [FsData] = FEK, [FEK]sk, $EFS
  603. //
  604. if ( !EfsVerifyKeyFsData(
  605. &(((PFSCTL_INPUT)InputData)->EfsFsData[0]),
  606. InputDataLength) ){
  607. //
  608. // Input data format error
  609. //
  610. return STATUS_INVALID_PARAMETER;
  611. }
  612. //
  613. // Allocate memory for $EFS
  614. // Create the $EFS, if there is one, overwrite it.
  615. //
  616. efsOffset = GetEfsStreamOffset( InputData );
  617. efsLength = InputDataLength - efsOffset;
  618. try {
  619. ntStatus = NtOfsCreateAttributeEx(
  620. IrpContext,
  621. FileHdl,
  622. EfsData.EfsName,
  623. $LOGGED_UTILITY_STREAM,
  624. CREATE_NEW,
  625. TRUE,
  626. &attribute
  627. );
  628. #if DBG
  629. if ( (EFSTRACEALL | EFSTRACELIGHT ) & EFSDebug ){
  630. DbgPrint( "\n EFSFILTER: Create Attr. Status %x\n", ntStatus );
  631. }
  632. #endif
  633. if (NT_SUCCESS(ntStatus)){
  634. LONGLONG attriOffset = 0;
  635. LONGLONG attriLength = (LONGLONG) efsLength;
  636. NtOfsSetLength(
  637. IrpContext,
  638. attribute,
  639. attriLength
  640. );
  641. //
  642. // Write the $EFS with transition status
  643. //
  644. *(PULONG)(InputData + efsOffset + sizeof(ULONG)) =
  645. EFS_STREAM_TRANSITION;
  646. NtOfsPutData(
  647. IrpContext,
  648. attribute,
  649. attriOffset,
  650. efsLength,
  651. InputData + efsOffset
  652. );
  653. NtOfsFlushAttribute (IrpContext, attribute, FALSE);
  654. }
  655. } finally {
  656. if (attribute) {
  657. NtOfsCloseAttribute(IrpContext, attribute);
  658. }
  659. }
  660. return ntStatus;
  661. }
  662. NTSTATUS
  663. EfsDecryptStream(
  664. IN PUCHAR InputData,
  665. IN ULONG InputDataLength,
  666. IN ULONG EncryptionFlag,
  667. IN OBJECT_HANDLE FileHdl,
  668. IN PIRP_CONTEXT IrpContext,
  669. IN OUT PVOID *Context,
  670. IN OUT PULONG PContextLength
  671. )
  672. /*++
  673. Routine Description:
  674. This is an internal support routine. It process the call of
  675. FSCTL_SET_ENCRYPT for decrypting a stream. It sets the key Blob to NULL.
  676. Arguments:
  677. InputData -- Input data buffer of FSCTL.
  678. EncryptionFlag - Indicating if this stream is encrypted or not.
  679. FileHdl -- An object handle to access the attached $EFS.
  680. IrpContext -- Used in NtOfsCreateAttributeEx().
  681. Context -- Blob(key) for READ or WRITE later.
  682. PContextLength -- Length of the key Blob.
  683. Return Value:
  684. Result of the operation.
  685. The value will be used to return to NTFS.
  686. --*/
  687. {
  688. ULONG efsLength;
  689. ULONG information;
  690. NTSTATUS ntStatus;
  691. PAGED_CODE();
  692. if ( 0 == (EncryptionFlag & STREAM_ENCRYPTED) ) {
  693. //
  694. // Stream already decrypted
  695. //
  696. return STATUS_SUCCESS;
  697. }
  698. if ( 0 == (EncryptionFlag & FILE_ENCRYPTED)){
  699. //
  700. // File decrypted but the stream is still encrypted.
  701. //
  702. return STATUS_INVALID_DEVICE_REQUEST;
  703. }
  704. //
  705. // [FsData] = SessionKey, Handle, Handle, [SessionKey, Handle, Handle]sk
  706. // Verify the FsData format.
  707. //
  708. if (!EfsVerifyGeneralFsData(
  709. &(((PFSCTL_INPUT)InputData)->EfsFsData[0]),
  710. InputDataLength)){
  711. return STATUS_INVALID_PARAMETER;
  712. }
  713. //
  714. // Try to read an existing $EFS
  715. //
  716. ntStatus = EfsReadEfsData(
  717. FileHdl,
  718. IrpContext,
  719. NULL,
  720. &efsLength,
  721. &information
  722. );
  723. if ( EFS_READ_SUCCESSFUL == information ){
  724. //
  725. // Everything is OK. We do not check user ID here,
  726. // we suppose that has been checked during the Open path.
  727. // Clear the key Blob. The caller should flushed this
  728. // stream before the FSCTL is issued.
  729. //
  730. if ( *Context ){
  731. CheckValidKeyBlock(*Context,"Please contact RobertG if you see this line, efsrtlsp.c.\n");
  732. FreeMemoryBlock(Context);
  733. *PContextLength = 0;
  734. }
  735. return STATUS_SUCCESS;
  736. } else if ( ( OPEN_EFS_FAIL == information ) ||
  737. ( EFS_FORMAT_ERROR == information ) ) {
  738. //
  739. // EFS does not exist or not encrypted by the EFS ?
  740. //
  741. ntStatus = STATUS_INVALID_DEVICE_REQUEST;
  742. }
  743. //
  744. // Other error while opening $EFS
  745. //
  746. return ntStatus;
  747. }
  748. NTSTATUS
  749. EfsDecryptFile(
  750. IN PUCHAR InputData,
  751. IN ULONG InputDataLength,
  752. IN OBJECT_HANDLE FileHdl,
  753. IN PIRP_CONTEXT IrpContext
  754. )
  755. /*++
  756. Routine Description:
  757. This is an internal support routine. It process the call of
  758. FSCTL_SET_ENCRYPT for decrypting a file. It deletes the $EFS. NTFS
  759. will clear the bit if STATUS_SUCCESS returned.
  760. Arguments:
  761. InputData -- Input data buffer of FSCTL.
  762. EncryptionFlag - Indicating if this stream is encrypted or not.
  763. FileHdl -- An object handle to access the attached $EFS.
  764. IrpContext -- Used in NtOfsCreateAttributeEx().
  765. Context - BLOB(key) for READ or WRITE later.
  766. Return Value:
  767. Result of the operation.
  768. The value will be used to return to NTFS.
  769. --*/
  770. {
  771. ULONG efsLength;
  772. ULONG information;
  773. NTSTATUS ntStatus;
  774. PAGED_CODE();
  775. //
  776. // It is possible to have following situations,
  777. // File bit set but no $EFS. Crash inside this call last time.
  778. // File bit not set, $EFS exist. Crash inside EFS_ENCRYPT_FILE.
  779. //
  780. //
  781. // [FsData] = SessionKey, Handle, Handle, [SessionKey, Handle, Handle]sk
  782. // Verify the FsData format.
  783. //
  784. if (!EfsVerifyGeneralFsData(
  785. &(((PFSCTL_INPUT)InputData)->EfsFsData[0]),
  786. InputDataLength)){
  787. return STATUS_INVALID_PARAMETER;
  788. }
  789. //
  790. // Try to read an existing $EFS
  791. //
  792. ntStatus = EfsReadEfsData(
  793. FileHdl,
  794. IrpContext,
  795. NULL,
  796. &efsLength,
  797. &information
  798. );
  799. if ( EFS_READ_SUCCESSFUL == information ){
  800. //
  801. // Everything is OK.
  802. //
  803. return ( EfsDeleteEfsData( FileHdl, IrpContext ) );
  804. } else if ( OPEN_EFS_FAIL == information ){
  805. //
  806. // Bit set, no $EFS. OK, NTFS will clear the bit.
  807. //
  808. return STATUS_SUCCESS;
  809. }
  810. return STATUS_INVALID_DEVICE_REQUEST;
  811. }
  812. NTSTATUS
  813. EfsEncryptDir(
  814. IN PUCHAR InputData,
  815. IN ULONG InputDataLength,
  816. IN ULONG EncryptionFlag,
  817. IN OBJECT_HANDLE FileHdl,
  818. IN PIRP_CONTEXT IrpContext
  819. )
  820. /*++
  821. Routine Description:
  822. This is an internal support routine. It process the call of
  823. FSCTL_SET_ENCRYPT for encrypting a directory. It writes initial $EFS.
  824. Arguments:
  825. InputData -- Input data buffer of FSCTL.
  826. InputDataLength -- The length of input data.
  827. EncryptionFlag - Indicating if this stream is encrypted or not.
  828. FileHdl -- An object handle to access the attached $EFS.
  829. IrpContext -- Used in NtOfsCreateAttributeEx().
  830. Context - BLOB(key) for READ or WRITE later.
  831. Return Value:
  832. Result of the operation.
  833. The value will be used to return to NTFS.
  834. --*/
  835. {
  836. ULONG efsLength;
  837. ULONG information;
  838. ULONG efsStreamOffset;
  839. PVOID efsStreamData = NULL;
  840. PVOID efsKeyBlob = NULL;
  841. NTSTATUS ntStatus;
  842. ATTRIBUTE_HANDLE attribute = NULL;
  843. PAGED_CODE();
  844. if ( EncryptionFlag & STREAM_ENCRYPTED ){
  845. //
  846. // Dir string already encrypted.
  847. //
  848. return STATUS_INVALID_DEVICE_REQUEST;
  849. }
  850. //
  851. // [FsData] = SessionKey, Handle, Handle, [SessionKey, Handle, Handle]sk
  852. // Verify the FsData format.
  853. //
  854. if (!EfsVerifyGeneralFsData(
  855. &(((PFSCTL_INPUT)InputData)->EfsFsData[0]),
  856. InputDataLength)){
  857. return STATUS_INVALID_PARAMETER;
  858. }
  859. //
  860. // Allocate memory for $EFS
  861. // Create the $EFS, if there is one, overwrite it.
  862. //
  863. efsStreamOffset = FIELD_OFFSET( FSCTL_INPUT, EfsFsData[0] )
  864. + FIELD_OFFSET( GENERAL_FS_DATA, EfsData[0]);
  865. efsLength = InputDataLength - efsStreamOffset;
  866. try {
  867. ntStatus = NtOfsCreateAttributeEx(
  868. IrpContext,
  869. FileHdl,
  870. EfsData.EfsName,
  871. $LOGGED_UTILITY_STREAM,
  872. CREATE_NEW,
  873. TRUE,
  874. &attribute
  875. );
  876. if (NT_SUCCESS(ntStatus)){
  877. LONGLONG attriOffset = 0;
  878. LONGLONG attriLength = (LONGLONG) efsLength;
  879. NtOfsSetLength(
  880. IrpContext,
  881. attribute,
  882. attriLength
  883. );
  884. //
  885. // Write the $EFS
  886. //
  887. NtOfsPutData(
  888. IrpContext,
  889. attribute,
  890. attriOffset,
  891. efsLength,
  892. InputData + efsStreamOffset
  893. );
  894. NtOfsFlushAttribute (IrpContext, attribute, FALSE);
  895. }
  896. } finally {
  897. if (attribute) {
  898. NtOfsCloseAttribute(IrpContext, attribute);
  899. }
  900. }
  901. return ntStatus;
  902. }
  903. NTSTATUS
  904. EfsModifyEfsState(
  905. IN ULONG FunctionCode,
  906. IN PUCHAR InputData,
  907. IN ULONG InputDataLength,
  908. IN OBJECT_HANDLE FileHdl,
  909. IN PIRP_CONTEXT IrpContext
  910. )
  911. /*++
  912. Routine Description:
  913. This is an internal support routine. It modifies the state field of $EFS.
  914. Arguments:
  915. FunctionCode -- EFS private code for FSCTL
  916. InputData -- Input data buffer of FSCTL.
  917. FileHdl -- An object handle to access the attached $EFS.
  918. IrpContext -- Used in NtOfsCreateAttributeEx().
  919. Return Value:
  920. Result of the operation.
  921. The value will be used to return to NTFS.
  922. --*/
  923. {
  924. NTSTATUS ntStatus;
  925. ATTRIBUTE_HANDLE attribute = NULL;
  926. PAGED_CODE();
  927. //
  928. // [FsData] = SessionKey, Handle, Handle, [SessionKey, Handle, Handle]sk
  929. // Verify the FsData format.
  930. //
  931. if (!EfsVerifyGeneralFsData(
  932. &(((PFSCTL_INPUT)InputData)->EfsFsData[0]),
  933. InputDataLength)){
  934. return STATUS_INVALID_PARAMETER;
  935. }
  936. try {
  937. ntStatus = NtOfsCreateAttributeEx(
  938. IrpContext,
  939. FileHdl,
  940. EfsData.EfsName,
  941. $LOGGED_UTILITY_STREAM,
  942. OPEN_EXISTING,
  943. TRUE,
  944. &attribute
  945. );
  946. if (NT_SUCCESS(ntStatus)){
  947. ULONG efsStatus = EFS_STREAM_NORMAL;
  948. if ( EFS_DECRYPT_BEGIN == FunctionCode ){
  949. efsStatus = EFS_STREAM_TRANSITION;
  950. }
  951. //
  952. // Modify the status
  953. //
  954. NtOfsPutData(
  955. IrpContext,
  956. attribute,
  957. (LONGLONG) &((( EFS_STREAM * ) 0)->Status),
  958. sizeof( efsStatus ),
  959. &efsStatus
  960. );
  961. NtOfsFlushAttribute (IrpContext, attribute, FALSE);
  962. }
  963. } finally {
  964. if (attribute) {
  965. NtOfsCloseAttribute(IrpContext, attribute);
  966. }
  967. }
  968. return ntStatus;
  969. }
  970. ULONG
  971. GetEfsStreamOffset(
  972. IN PUCHAR InputData
  973. )
  974. /*++
  975. Routine Description:
  976. This is an internal support routine. It calculates the offset of $EFS.
  977. Arguments:
  978. InputData -- Input data buffer of FSCTL.
  979. The format is always PSC, EfsCode, CSC, FEK, FEK, $EFS
  980. Return Value:
  981. The offset of $EFS in InputData.
  982. --*/
  983. {
  984. ULONG efsOffset;
  985. efsOffset = FIELD_OFFSET( FSCTL_INPUT, EfsFsData[0]);
  986. efsOffset += 2 * EFS_KEY_SIZE( ((PEFS_KEY)(InputData + efsOffset)) );
  987. return efsOffset;
  988. }
  989. NTSTATUS
  990. SetEfsData(
  991. PUCHAR InputData,
  992. IN ULONG InputDataLength,
  993. IN ULONG SystemState,
  994. IN OBJECT_HANDLE FileHdl,
  995. IN PIRP_CONTEXT IrpContext,
  996. IN OUT PVOID *PContext,
  997. IN OUT PULONG PContextLength
  998. )
  999. /*++
  1000. Routine Description:
  1001. This is an internal support routine. It sets the $EFS to the file.
  1002. Arguments:
  1003. InputData -- Input data buffer of FSCTL.
  1004. InputDataLength -- Input data length.
  1005. FileHdl -- Used to access the $EFS.
  1006. IrpContext -- Used to access the $EFS.
  1007. PContext -- BLOB(key) for READ or WRITE later.
  1008. PContextLength - The length of the context.
  1009. Return Value:
  1010. STATUS_SUCCESS or NT error
  1011. --*/
  1012. {
  1013. ULONG bytesSame;
  1014. ULONG efsLength;
  1015. PVOID efsStreamData = NULL;
  1016. PVOID efsKeyBlob = NULL;
  1017. NTSTATUS ntStatus = STATUS_SUCCESS;
  1018. ATTRIBUTE_HANDLE attribute = NULL;
  1019. PEFS_KEY efsKey;
  1020. PNPAGED_LOOKASIDE_LIST tmpMemSrc;
  1021. PAGED_CODE();
  1022. if ( ((PFSCTL_INPUT)InputData)->CipherSubCode & SET_EFS_KEYBLOB ){
  1023. //
  1024. // Set the key blob is required
  1025. //
  1026. efsKey = (PEFS_KEY) &(((PFSCTL_INPUT)InputData)->EfsFsData[0]);
  1027. efsKeyBlob = GetKeyBlobBuffer(efsKey->Algorithm);
  1028. if ( NULL == efsKeyBlob ){
  1029. return STATUS_INSUFFICIENT_RESOURCES;
  1030. }
  1031. if (!SetKeyTable(
  1032. efsKeyBlob,
  1033. (PEFS_KEY) &(((PFSCTL_INPUT)InputData)->EfsFsData[0])
  1034. )){
  1035. ExFreeToNPagedLookasideList(((PKEY_BLOB)efsKeyBlob)->MemSource, efsKeyBlob);
  1036. return STATUS_ACCESS_DENIED;
  1037. }
  1038. if ( (((PFSCTL_INPUT)InputData)->EfsFsCode == EFS_SET_ATTRIBUTE ) &&
  1039. *PContext ){
  1040. bytesSame = (ULONG)RtlCompareMemory(
  1041. efsKeyBlob,
  1042. *PContext,
  1043. ((PKEY_BLOB)efsKeyBlob)->KeyLength
  1044. );
  1045. ExFreeToNPagedLookasideList(((PKEY_BLOB)efsKeyBlob)->MemSource, efsKeyBlob);
  1046. efsKeyBlob = NULL;
  1047. if ( bytesSame != ((PKEY_BLOB)(*PContext))->KeyLength ) {
  1048. //
  1049. // The new key blob is not the same one as in the memory
  1050. //
  1051. return STATUS_INVALID_PARAMETER;
  1052. }
  1053. }
  1054. //
  1055. // Defer the setting of key blob until the $EFS is written
  1056. // successfully.
  1057. //
  1058. }
  1059. if ( ((PFSCTL_INPUT)InputData)->CipherSubCode & WRITE_EFS_ATTRIBUTE ){
  1060. //
  1061. // Write $EFS is required. Either create or overwrite the EFS
  1062. //
  1063. ULONG efsOffset;
  1064. if (SystemState & SYSTEM_IS_READONLY) {
  1065. if ( efsKeyBlob ){
  1066. ExFreeToNPagedLookasideList(((PKEY_BLOB)efsKeyBlob)->MemSource, efsKeyBlob);
  1067. }
  1068. return STATUS_MEDIA_WRITE_PROTECTED;
  1069. }
  1070. if ( (((PFSCTL_INPUT)InputData)->EfsFsCode == EFS_SET_ATTRIBUTE ) ||
  1071. (((PFSCTL_INPUT)InputData)->CipherSubCode & SET_EFS_KEYBLOB) ){
  1072. efsOffset = GetEfsStreamOffset( InputData );
  1073. } else {
  1074. efsOffset = COMMON_FSCTL_HEADER_SIZE;
  1075. }
  1076. efsLength = InputDataLength - efsOffset;
  1077. try {
  1078. ntStatus = NtOfsCreateAttributeEx(
  1079. IrpContext,
  1080. FileHdl,
  1081. EfsData.EfsName,
  1082. $LOGGED_UTILITY_STREAM,
  1083. CREATE_OR_OPEN,
  1084. TRUE,
  1085. &attribute
  1086. );
  1087. if (NT_SUCCESS(ntStatus)){
  1088. LONGLONG attriOffset = 0;
  1089. LONGLONG attriLength = (LONGLONG) efsLength;
  1090. NtOfsSetLength(
  1091. IrpContext,
  1092. attribute,
  1093. attriLength
  1094. );
  1095. NtOfsPutData(
  1096. IrpContext,
  1097. attribute,
  1098. attriOffset,
  1099. efsLength,
  1100. InputData + efsOffset
  1101. );
  1102. NtOfsFlushAttribute (IrpContext, attribute, FALSE);
  1103. } else {
  1104. //
  1105. // Create or Open $EFS fail
  1106. //
  1107. if ( efsKeyBlob ){
  1108. ExFreeToNPagedLookasideList(((PKEY_BLOB)efsKeyBlob)->MemSource, efsKeyBlob);
  1109. efsKeyBlob = NULL;
  1110. }
  1111. leave;
  1112. }
  1113. } finally {
  1114. if (AbnormalTermination()) {
  1115. if ( efsKeyBlob ){
  1116. ExFreeToNPagedLookasideList(((PKEY_BLOB)efsKeyBlob)->MemSource, efsKeyBlob);
  1117. efsKeyBlob = NULL;
  1118. }
  1119. }
  1120. if (attribute) {
  1121. NtOfsCloseAttribute(IrpContext, attribute);
  1122. }
  1123. }
  1124. }
  1125. if ( efsKeyBlob && (((PFSCTL_INPUT)InputData)->CipherSubCode & SET_EFS_KEYBLOB) ){
  1126. if ( (((PFSCTL_INPUT)InputData)->EfsFsCode == EFS_SET_ATTRIBUTE ) &&
  1127. ( *PContext == NULL ) ){
  1128. //
  1129. // Set the key blob
  1130. //
  1131. *PContext = efsKeyBlob;
  1132. *PContextLength = ((PKEY_BLOB) efsKeyBlob)->KeyLength;
  1133. } else if ( ((PFSCTL_INPUT)InputData)->EfsFsCode == EFS_OVERWRITE_ATTRIBUTE ) {
  1134. //
  1135. // Overwrite the key blob for legal import user
  1136. //
  1137. if ( *PContext == NULL){
  1138. //
  1139. // The file was not encrypted
  1140. //
  1141. *PContext = efsKeyBlob;
  1142. *PContextLength = ((PKEY_BLOB) efsKeyBlob)->KeyLength;
  1143. } else {
  1144. if ( ((PKEY_BLOB) efsKeyBlob)->KeyLength <= *PContextLength ){
  1145. tmpMemSrc = ((PKEY_BLOB)(*PContext))->MemSource;
  1146. RtlCopyMemory( *PContext, efsKeyBlob, ((PKEY_BLOB) efsKeyBlob)->KeyLength );
  1147. ((PKEY_BLOB)(*PContext))->MemSource = tmpMemSrc;
  1148. //
  1149. // Keep the original buffer length
  1150. //
  1151. if (((PKEY_BLOB) efsKeyBlob)->KeyLength < *PContextLength) {
  1152. ((PKEY_BLOB)(*PContext))->KeyLength = *PContextLength;
  1153. RtlZeroMemory((UCHAR *)(*PContext) + ((PKEY_BLOB) efsKeyBlob)->KeyLength,
  1154. *PContextLength - ((PKEY_BLOB) efsKeyBlob)->KeyLength);
  1155. }
  1156. } else{
  1157. //
  1158. // We could not swap the key blob because the old blob might be in use. Deleting
  1159. // the old blob could bug check the system.
  1160. // This could be avoid if MaximumBlob is defined nonzero in the registry.
  1161. //
  1162. ntStatus = STATUS_EFS_ALG_BLOB_TOO_BIG;
  1163. }
  1164. ExFreeToNPagedLookasideList(((PKEY_BLOB)efsKeyBlob)->MemSource, efsKeyBlob);
  1165. }
  1166. }
  1167. }
  1168. return ntStatus;
  1169. }
  1170. BOOLEAN
  1171. EfsFindInCache(
  1172. IN GUID *EfsId,
  1173. IN PTOKEN_USER UserId
  1174. )
  1175. /*++
  1176. Routine Description:
  1177. This routine will try to find the information in open cache.
  1178. Arguments:
  1179. EfsId - $EFS ID.
  1180. UserId - User ID
  1181. Return Value:
  1182. TRUE, if match found in the cache and the time is not expired. ( 5 second )
  1183. --*/
  1184. {
  1185. PLIST_ENTRY pListHead, pLink;
  1186. POPEN_CACHE pOpenCache;
  1187. LARGE_INTEGER crntTime;
  1188. PSID UserSid;
  1189. PAGED_CODE();
  1190. UserSid = UserId->User.Sid;
  1191. KeQuerySystemTime( &crntTime );
  1192. ExAcquireFastMutex( &(EfsData.EfsOpenCacheMutex) );
  1193. if ( EfsData.EfsOpenCacheList.Flink == &(EfsData.EfsOpenCacheList) ) {
  1194. //
  1195. // list empty
  1196. //
  1197. ExReleaseFastMutex( &(EfsData.EfsOpenCacheMutex) );
  1198. return FALSE;
  1199. }
  1200. for (pLink = EfsData.EfsOpenCacheList.Flink; pLink != &(EfsData.EfsOpenCacheList); pLink = pLink->Flink) {
  1201. pOpenCache = CONTAINING_RECORD(pLink, OPEN_CACHE, CacheChain);
  1202. ASSERT( pLink );
  1203. ASSERT( pLink->Flink );
  1204. if ( !memcmp( &(pOpenCache->EfsId), EfsId, sizeof(GUID)) &&
  1205. (crntTime.QuadPart - pOpenCache->TimeStamp.QuadPart <= EfsData.EfsDriverCacheLength ) &&
  1206. RtlEqualSid ( UserSid, pOpenCache->UserId->User.Sid)
  1207. ) {
  1208. ExReleaseFastMutex( &(EfsData.EfsOpenCacheMutex) );
  1209. return TRUE;
  1210. }
  1211. }
  1212. ExReleaseFastMutex( &(EfsData.EfsOpenCacheMutex) );
  1213. return FALSE;
  1214. }
  1215. NTSTATUS
  1216. EfsRefreshCache(
  1217. IN GUID *EfsId,
  1218. IN PTOKEN_USER UserId
  1219. )
  1220. /*++
  1221. Routine Description:
  1222. This routine will set the latest open information in open cache. It will
  1223. delete the the obsolete info. Cache is refreshed.
  1224. Arguments:
  1225. EfsId - $EFS ID.
  1226. UserId - User ID
  1227. Return Value:
  1228. STATUS_SUCCESS if succeed.
  1229. --*/
  1230. {
  1231. PLIST_ENTRY pListHead, pLink;
  1232. POPEN_CACHE pOpenCache, pTmpCache;
  1233. LARGE_INTEGER crntTime;
  1234. KeQuerySystemTime( &crntTime );
  1235. pOpenCache = (POPEN_CACHE)ExAllocateFromPagedLookasideList(&(EfsData.EfsOpenCachePool));
  1236. if ( NULL == pOpenCache){
  1237. return STATUS_INSUFFICIENT_RESOURCES;
  1238. }
  1239. //
  1240. // Init the node
  1241. //
  1242. RtlZeroMemory( pOpenCache, sizeof( OPEN_CACHE ) );
  1243. RtlCopyMemory( &(pOpenCache->EfsId), EfsId, sizeof( GUID ) );
  1244. pOpenCache->UserId = UserId;
  1245. pOpenCache->TimeStamp.QuadPart = crntTime.QuadPart;
  1246. ExAcquireFastMutex( &(EfsData.EfsOpenCacheMutex) );
  1247. if ( EfsData.EfsOpenCacheList.Flink == &(EfsData.EfsOpenCacheList) ) {
  1248. //
  1249. // list empty
  1250. //
  1251. InsertHeadList(&( EfsData.EfsOpenCacheList ), &( pOpenCache->CacheChain ));
  1252. } else {
  1253. //
  1254. // Search for expired one
  1255. //
  1256. pLink = EfsData.EfsOpenCacheList.Flink;
  1257. while ( pLink != &(EfsData.EfsOpenCacheList) ){
  1258. pTmpCache = CONTAINING_RECORD(pLink, OPEN_CACHE, CacheChain);
  1259. ASSERT( pLink );
  1260. ASSERT( pLink->Flink );
  1261. pLink = pLink->Flink;
  1262. if ( ( (crntTime.QuadPart - pTmpCache->TimeStamp.QuadPart) > EfsData.EfsDriverCacheLength ) ||
  1263. !memcmp( &(pTmpCache->EfsId), EfsId, sizeof(GUID))
  1264. ){
  1265. //
  1266. // Expired node. Delete it.
  1267. //
  1268. RemoveEntryList(&( pTmpCache->CacheChain ));
  1269. ExFreePool( pTmpCache->UserId );
  1270. ExFreeToPagedLookasideList(&(EfsData.EfsOpenCachePool), pTmpCache );
  1271. }
  1272. }
  1273. InsertHeadList(&( EfsData.EfsOpenCacheList ), &( pOpenCache->CacheChain ));
  1274. }
  1275. ExReleaseFastMutex( &(EfsData.EfsOpenCacheMutex) );
  1276. return STATUS_SUCCESS;
  1277. }
  1278. BOOLEAN
  1279. SkipCheckStream(
  1280. IN PIO_STACK_LOCATION IrpSp,
  1281. IN PVOID efsStreamData
  1282. )
  1283. /*++
  1284. Routine Description:
  1285. This routine will check if the related default data stream has just been opened
  1286. or not.
  1287. Arguments:
  1288. EfsId - $EFS ID.
  1289. UserId - User ID
  1290. Return Value:
  1291. TRUE if succeed.
  1292. --*/
  1293. {
  1294. BOOLEAN bRet = TRUE;
  1295. PACCESS_TOKEN accessToken;
  1296. NTSTATUS status;
  1297. PTOKEN_USER UserId;
  1298. PAGED_CODE();
  1299. if ( IrpSp->Parameters.Create.SecurityContext->AccessState->SubjectSecurityContext.ClientToken ){
  1300. accessToken = IrpSp->Parameters.Create.SecurityContext->AccessState->SubjectSecurityContext.ClientToken;
  1301. } else {
  1302. accessToken = IrpSp->Parameters.Create.SecurityContext->AccessState->SubjectSecurityContext.PrimaryToken;
  1303. }
  1304. if (accessToken) {
  1305. //
  1306. // Get User ID
  1307. //
  1308. status = SeQueryInformationToken(
  1309. accessToken,
  1310. TokenUser,
  1311. &UserId
  1312. );
  1313. if ( NT_SUCCESS(status) ){
  1314. if ( EfsFindInCache(
  1315. &((( PEFS_DATA_STREAM_HEADER ) efsStreamData)->EfsId),
  1316. UserId
  1317. )) {
  1318. bRet = TRUE;
  1319. } else {
  1320. bRet = FALSE;
  1321. }
  1322. ExFreePool( UserId );
  1323. }
  1324. } else {
  1325. bRet = FALSE;
  1326. }
  1327. return bRet;
  1328. }