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.

1414 lines
38 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. efsrtl.c
  5. Abstract:
  6. This module contains the code that implements the EFS
  7. call back routines.
  8. Author:
  9. Robert Gu (robertg) 08-Dec-1996
  10. Environment:
  11. Kernel mode
  12. Revision History:
  13. --*/
  14. #include "efsrtl.h"
  15. #ifdef ALLOC_PRAGMA
  16. #pragma alloc_text(PAGE, EfsEncryptKeyFsData)
  17. #pragma alloc_text(PAGE, EfsOpenFile)
  18. #pragma alloc_text(PAGE, EfsFileControl)
  19. #pragma alloc_text(PAGE, EfsRead)
  20. #pragma alloc_text(PAGE, EfsWrite)
  21. #pragma alloc_text(PAGE, EfsFreeContext)
  22. #pragma alloc_text(PAGE, EfsMountVolumn)
  23. #pragma alloc_text(PAGE, EfsDismountVolumn)
  24. #pragma alloc_text(PAGE, EfsDismountVolumn)
  25. #endif
  26. VOID
  27. EfsEncryptKeyFsData(
  28. IN PVOID DataBuffer,
  29. IN ULONG DataLength,
  30. IN ULONG DataEncOffset,
  31. IN ULONG RefdataEncOffset,
  32. IN ULONG RefdataEncLength
  33. )
  34. /*++
  35. Routine Description:
  36. This is called by EFS driver to prepare a FSCTL input data buffer.
  37. The result data will be in the format of
  38. SUB-CODE plain text, [FSCTL_CODE, SUB-CODE, refdata, [refdata]sk, $EFS]sk
  39. Arguments:
  40. DataBuffer -- Point to a buffer holding the FSCTL input data.
  41. DataLength -- Input data length.
  42. DataEncOffset -- The offset of the first byte to be encrypted.
  43. RefdataEncOffset -- The offset of the first reference byte to be encrypted.
  44. Second round encryption.
  45. RefdataEncLength -- The length of the refdata.
  46. Return Value:
  47. No.
  48. --*/
  49. {
  50. LONG bytesToBeEnc;
  51. PUCHAR pWorkData;
  52. ULONG encryptionRound;
  53. PAGED_CODE();
  54. //
  55. // Data to be encrypted must be in the blocks of DES_BLOCKLEN
  56. //
  57. ASSERT( ((DataLength - DataEncOffset) % DES_BLOCKLEN) == 0 );
  58. ASSERT( (RefdataEncLength % DES_BLOCKLEN) == 0 );
  59. //
  60. // Encrypt the reference data first. Reference data is the data we used to
  61. // verify the caller. The data can be in the form FEK or sessionKey or
  62. // sessionKey plus some changeable data
  63. //
  64. pWorkData = ((PUCHAR)DataBuffer) + RefdataEncOffset;
  65. bytesToBeEnc = (LONG) RefdataEncLength;
  66. encryptionRound = 1;
  67. do {
  68. while ( bytesToBeEnc > 0 ) {
  69. //
  70. // Encrypt data with DES
  71. //
  72. des( pWorkData,
  73. pWorkData,
  74. &(EfsData.SessionDesTable[0]),
  75. ENCRYPT
  76. );
  77. pWorkData += DES_BLOCKLEN;
  78. bytesToBeEnc -= DES_BLOCKLEN;
  79. }
  80. //
  81. // Then encrypt the whole data except the header bytes.
  82. //
  83. pWorkData = ((PUCHAR)DataBuffer) + DataEncOffset;
  84. bytesToBeEnc = (LONG) (DataLength - DataEncOffset);
  85. encryptionRound++;
  86. } while ( encryptionRound < 3 );
  87. return;
  88. }
  89. NTSTATUS
  90. EfsOpenFile(
  91. IN OBJECT_HANDLE FileHdl,
  92. IN OBJECT_HANDLE ParentDir OPTIONAL,
  93. IN PIO_STACK_LOCATION IrpSp,
  94. IN ULONG FileDirFlag,
  95. IN ULONG SystemState,
  96. IN PIRP_CONTEXT IrpContext,
  97. IN PDEVICE_OBJECT VolDo,
  98. IN PVOID PfileKeyContext,
  99. IN OUT PVOID *PContext,
  100. IN OUT PULONG PContextLength,
  101. IN OUT PVOID *PCreateContext,
  102. IN OUT PBOOLEAN Reserved
  103. )
  104. /*++
  105. Routine Description:
  106. This is a call back routine. It will be called back by file system when
  107. an encrypted file is opened or a new file under encrypted directory is
  108. created.
  109. Arguments:
  110. FileHdl -- An object handle of the file
  111. ParentDir - An object handle of the parent. Can be null for create file in
  112. root directory. It will be used by EFS only a new file is created.
  113. IrpSp -- Irp Stack Location pointer.
  114. FileDirFlag -- Indicating the status of the parent of the stream, may have four values,
  115. FILE_NEW, FILE_EXISTING, DIRECTORY_NEW and DIRECTORY_EXISTING and the
  116. status of the stream itself.
  117. IrpContext - Used in NtOfsCreateAttributeEx().
  118. VolDo - A pointer to the volumn device object.
  119. PContext - Not used by EFS.
  120. PContextLength - Not used by EFS.
  121. Return Value:
  122. Result of the operation.
  123. File system should fail the CREATE IRP if fail code returned.
  124. --*/
  125. {
  126. NTSTATUS ntStatus = STATUS_SUCCESS;
  127. PEFS_CONTEXT pEFSContext;
  128. ULONG efsLength;
  129. PVOID efsStreamData;
  130. ULONG information;
  131. IN PFILE_OBJECT fileObject = IrpSp->FileObject;
  132. /*
  133. PIO_SECURITY_CONTEXT sContext;
  134. sContext = IrpSp->Parameters.Create.SecurityContext;
  135. DbgPrint( "\n Create: Desired Access %x\n", sContext->DesiredAccess );
  136. DbgPrint( "\n Create: Original Desired Access %x\n", sContext->AccessState->OriginalDesiredAccess );
  137. DbgPrint( "\n Create: PrevGrant Access %x\n", sContext->AccessState->PreviouslyGrantedAccess );
  138. DbgPrint( "\n Create: Remaining Desired Access %x\n", sContext->AccessState->RemainingDesiredAccess );
  139. */
  140. PAGED_CODE();
  141. //
  142. // If read/write data is not required, we will always succeed the call.
  143. // Treadted as plain text file. No encryption/decryption will be involved.
  144. //
  145. CheckValidKeyBlock(*PContext,"Please contact RobertG if you see this. EfsOpenFile() in.\n");
  146. #if DBG
  147. if ( (EFSTRACEALL | EFSTRACELIGHT ) & EFSDebug ){
  148. DbgPrint( "\n EFSFILTER: ****** EFS RTL CREATE ****** \n" );
  149. DbgPrint( "EFSFILTER: FileDir %x\n", FileDirFlag );
  150. DbgPrint( "EFSFILTER: Access %x\n", IrpSp->Parameters.Create.SecurityContext->AccessState->PreviouslyGrantedAccess );
  151. }
  152. #endif
  153. if ( FALSE == EfsData.EfsInitialized ){
  154. //
  155. // Not initialized yet.
  156. //
  157. return STATUS_INVALID_DEVICE_REQUEST;
  158. }
  159. if ( (IrpSp->Parameters.Create.FileAttributes & FILE_ATTRIBUTE_SYSTEM) &&
  160. ( FileDirFlag & (FILE_NEW | DIRECTORY_NEW) )){
  161. //
  162. // Do not encrypt SYSTEM File if creating new file
  163. //
  164. return STATUS_SUCCESS;
  165. }
  166. if ( (IrpSp->Parameters.Create.FileAttributes & FILE_ATTRIBUTE_ENCRYPTED) &&
  167. ((FileDirFlag & EXISTING_FILE_ENCRYPTED) == 0) &&
  168. ((FileDirFlag & (FILE_NEW | DIRECTORY_NEW) ) == 0)){
  169. //
  170. // Do not encrypt a stream if the file is not encrypted
  171. //
  172. return STATUS_SUCCESS;
  173. }
  174. if ( (FileDirFlag & (FILE_EXISTING | DIRECTORY_EXISTING)) &&
  175. !( FileDirFlag & STREAM_NEW ) &&
  176. !( IrpSp->Parameters.Create.SecurityContext->AccessState->PreviouslyGrantedAccess &
  177. ( FILE_APPEND_DATA | FILE_READ_DATA | FILE_WRITE_DATA | FILE_EXECUTE ))
  178. ) {
  179. return STATUS_SUCCESS;
  180. }
  181. //
  182. // Allocate the EFS context block
  183. //
  184. *PCreateContext = (PEFS_CONTEXT)ExAllocateFromNPagedLookasideList(&(EfsData.EfsContextPool));
  185. if ( NULL == *PCreateContext){
  186. return STATUS_INSUFFICIENT_RESOURCES;
  187. }
  188. pEFSContext = (PEFS_CONTEXT)*PCreateContext;
  189. //
  190. // Set initial status value and initialize the event
  191. //
  192. RtlZeroMemory( pEFSContext, sizeof( EFS_CONTEXT ) );
  193. pEFSContext->Status = NO_FURTHER_PROCESSING;
  194. pEFSContext->Flags = SystemState;
  195. KeInitializeEvent(&( pEFSContext->FinishEvent ), SynchronizationEvent, FALSE);
  196. switch (FileDirFlag & FILE_DIR_TYPE) {
  197. case FILE_EXISTING:
  198. //
  199. // An existing file. Either a new stream created or
  200. // an existing stream opened
  201. // The user must be verified.
  202. // Trying to open $EFS on the file.
  203. //
  204. #if DBG
  205. if ( (EFSTRACEALL | EFSTRACELIGHT ) & EFSDebug ){
  206. DbgPrint( " EFSFILTER: ****** File Existed ****** \n" );
  207. }
  208. #endif
  209. try{
  210. ntStatus = EfsReadEfsData(
  211. FileHdl,
  212. IrpContext,
  213. &efsStreamData,
  214. &efsLength,
  215. &information
  216. );
  217. } finally {
  218. if (AbnormalTermination()) {
  219. ExFreeToNPagedLookasideList(&(EfsData.EfsContextPool), pEFSContext );
  220. *PCreateContext = NULL;
  221. }
  222. }
  223. if ( EFS_READ_SUCCESSFUL == information ){
  224. #if DBG
  225. if ( (EFSTRACEALL | EFSTRACELIGHT ) & EFSDebug ){
  226. DbgPrint( " EFSFILTER: ****** $EFS Existed ****** \n" );
  227. }
  228. #endif
  229. //
  230. // Check if multi-stream.
  231. //
  232. if ( PfileKeyContext && SkipCheckStream(IrpSp, efsStreamData)) {
  233. //
  234. // Skip calling the user mode code
  235. //
  236. ExFreePool(efsStreamData);
  237. efsStreamData = NULL;
  238. if ( NULL == *PContext ) {
  239. *PContext = GetKeyBlobBuffer(((PKEY_BLOB)PfileKeyContext)->AlgorithmID);
  240. if (*PContext) {
  241. *PContextLength = ((PKEY_BLOB) *PContext)->KeyLength;
  242. RtlCopyMemory( *PContext, PfileKeyContext, ((PKEY_BLOB)PfileKeyContext)->KeyLength );
  243. } else {
  244. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  245. ExFreeToNPagedLookasideList(&(EfsData.EfsContextPool), pEFSContext );
  246. *PCreateContext = NULL;
  247. }
  248. }
  249. if (*PContext) {
  250. if ( FileDirFlag & STREAM_NEW ){
  251. //
  252. // New stream, we need to turn on the bit
  253. //
  254. #if DBG
  255. if ( EFSTRACEALL & EFSDebug ){
  256. DbgPrint("Cache New Named String\n");
  257. }
  258. #endif
  259. pEFSContext->Status = TURN_ON_ENCRYPTION_BIT | TURN_ON_BIT_ONLY | NO_OPEN_CACHE_CHECK;
  260. } else {
  261. //
  262. // Open existing stream, no further actions required.
  263. //
  264. #if DBG
  265. if ( EFSTRACEALL & EFSDebug ){
  266. DbgPrint("Cache Existing Named String\n");
  267. }
  268. #endif
  269. ExFreeToNPagedLookasideList(&(EfsData.EfsContextPool), pEFSContext );
  270. *PCreateContext = NULL;
  271. ntStatus = STATUS_SUCCESS;
  272. }
  273. }
  274. } else {
  275. //
  276. // Set the pointers in context block
  277. //
  278. pEFSContext->EfsStreamData = efsStreamData;
  279. pEFSContext->Status = VERIFY_USER_REQUIRED;
  280. if ( NULL == *PContext ) {
  281. //
  282. // Do not check open cache. We need the key blob.
  283. //
  284. pEFSContext->Status |= NO_OPEN_CACHE_CHECK;
  285. }
  286. if ( FileDirFlag & STREAM_NEW ) {
  287. #if DBG
  288. if ( (EFSTRACEALL | EFSTRACELIGHT ) & EFSDebug ){
  289. DbgPrint( " EFSFILTER: ****** File Existed & Stream New ****** \n" );
  290. }
  291. #endif
  292. pEFSContext->Status |= TURN_ON_ENCRYPTION_BIT;
  293. }
  294. }
  295. }
  296. //
  297. // If EFS_READ_SUCCESSFUL != information
  298. // ntStatus might still be STATUS_SUCCESS which means it is not
  299. // encrypted by EFS and we succeeded call.
  300. // Should we fail the call?
  301. //
  302. break;
  303. case FILE_NEW:
  304. //
  305. // A new file created
  306. // New FEK, DDF, DRF needed
  307. // Trying to open $EFS on the parent directory
  308. //
  309. #if DBG
  310. if ( (EFSTRACEALL | EFSTRACELIGHT ) & EFSDebug ){
  311. DbgPrint( " EFSFILTER: ****** File New ****** \n" );
  312. }
  313. #endif
  314. try {
  315. ntStatus = EfsReadEfsData(
  316. ParentDir,
  317. IrpContext,
  318. &efsStreamData,
  319. &efsLength,
  320. &information
  321. );
  322. } finally {
  323. if (AbnormalTermination()) {
  324. ExFreeToNPagedLookasideList(&(EfsData.EfsContextPool), pEFSContext );
  325. *PCreateContext = NULL;
  326. }
  327. }
  328. if ( EFS_READ_SUCCESSFUL == information ){
  329. #if DBG
  330. if ( (EFSTRACEALL | EFSTRACELIGHT ) & EFSDebug ){
  331. DbgPrint( " EFSFILTER: ****** Parent $EFS Existed ****** \n" );
  332. }
  333. #endif
  334. //
  335. // Set the pointers in context block
  336. //
  337. pEFSContext->EfsStreamData = efsStreamData;
  338. pEFSContext->Status = NEW_FILE_EFS_REQUIRED |
  339. TURN_ON_ENCRYPTION_BIT |
  340. NO_OPEN_CACHE_CHECK;
  341. } else if ( OPEN_EFS_FAIL == information ) {
  342. pEFSContext->EfsStreamData = NULL;
  343. pEFSContext->Status = NEW_FILE_EFS_REQUIRED |
  344. TURN_ON_ENCRYPTION_BIT |
  345. NO_OPEN_CACHE_CHECK;
  346. ntStatus = STATUS_SUCCESS;
  347. }
  348. //
  349. // If EFS_READ_SUCCESSFUL != information
  350. // ntStatus might still be STATUS_SUCCESS which means it is not
  351. // encrypted by EFS and we succeeded call.
  352. // Should we fail the call?
  353. //
  354. break;
  355. case DIRECTORY_NEW:
  356. #if DBG
  357. if ( (EFSTRACEALL | EFSTRACELIGHT ) & EFSDebug ){
  358. DbgPrint( " EFSFILTER: ****** Directory New ****** \n" );
  359. }
  360. #endif
  361. //
  362. // A new directory created
  363. // New Public keys needed
  364. // Trying to open $EFS on the parent directory
  365. //
  366. try {
  367. ntStatus = EfsReadEfsData(
  368. ParentDir,
  369. IrpContext,
  370. &efsStreamData,
  371. &efsLength,
  372. &information
  373. );
  374. } finally {
  375. if (AbnormalTermination()) {
  376. ExFreeToNPagedLookasideList(&(EfsData.EfsContextPool), pEFSContext );
  377. *PCreateContext = NULL;
  378. }
  379. }
  380. if ( EFS_READ_SUCCESSFUL == information ){
  381. #if DBG
  382. if ( (EFSTRACEALL | EFSTRACELIGHT ) & EFSDebug ){
  383. DbgPrint( " EFSFILTER: ****** Parent $EFS Existed ****** \n" );
  384. }
  385. #endif
  386. //
  387. // Set the pointers in context block
  388. //
  389. pEFSContext->EfsStreamData = efsStreamData;
  390. pEFSContext->Status = NEW_DIR_EFS_REQUIRED |
  391. TURN_ON_ENCRYPTION_BIT |
  392. NO_OPEN_CACHE_CHECK;
  393. } else if ( OPEN_EFS_FAIL == information ) {
  394. pEFSContext->EfsStreamData = NULL;
  395. pEFSContext->Status = NEW_DIR_EFS_REQUIRED |
  396. TURN_ON_ENCRYPTION_BIT |
  397. NO_OPEN_CACHE_CHECK;
  398. ntStatus = STATUS_SUCCESS;
  399. }
  400. //
  401. // If EFS_READ_SUCCESSFUL != information
  402. // ntStatus might still be STATUS_SUCCESS which means it is not
  403. // encrypted by EFS and we succeeded call.
  404. // Should we fail the call?
  405. //
  406. break;
  407. case DIRECTORY_EXISTING:
  408. #if DBG
  409. if ( EFSTRACEALL & EFSDebug ){
  410. DbgPrint( " EFSFILTER: ****** Directory Existed ****** \n" );
  411. }
  412. #endif
  413. //
  414. // An existing directory. Either a new stream created or
  415. // an existing stream opened
  416. // We do not encrypt data stream for Directory. Ignore this.
  417. //
  418. default:
  419. break;
  420. }
  421. CheckValidKeyBlock(*PContext,"Please contact RobertG if you see this. EfsOpenFile() Out.\n");
  422. return ntStatus;
  423. }
  424. NTSTATUS
  425. EfsFileControl(
  426. IN PVOID PInputBuffer,
  427. IN ULONG InputDataLength,
  428. OUT PVOID POutputBuffer OPTIONAL,
  429. IN OUT PULONG POutputBufferLength,
  430. IN ULONG EncryptionFlag,
  431. IN ULONG AccessFlag,
  432. IN ULONG SystemState,
  433. IN ULONG FsControlCode,
  434. IN OBJECT_HANDLE FileHdl,
  435. IN PIRP_CONTEXT IrpContext,
  436. IN PDEVICE_OBJECT VolDo,
  437. IN ATTRIBUTE_HANDLE StreamHdl,
  438. IN OUT PVOID *PContext,
  439. IN OUT PULONG PContextLength
  440. )
  441. /*++
  442. Routine Description:
  443. This is a call back routine. It will be called back by file system to
  444. support EFS's FSCTL APIs
  445. Arguments:
  446. PInputBuffer - Pointer to the input data buffer. The first 4 bytes are
  447. for information to Ntfs or some other drivers only. The EFS related
  448. data are encrypted in the following bytes. The first 4 encrypted
  449. bytes are subfunction code in the form of EFS_XXX. General package
  450. looks like this,
  451. Subcode plain text, EFS subfunction code, EFS subcode cipher text, FSCTL specific data.
  452. InputDataLength - The length of the input data buffer.
  453. POutputBuffer - Pointer to the output data buffer.
  454. POutputBufferLength - The length of the output data.
  455. EncryptionFlag - Indicating if this stream is encrypted or not.
  456. AccessFlag - Indicating the desired access when the stream is opened.
  457. FsControlCode - Indicating what FSCTL was originally called.
  458. FileHdl - Used to access the $EFS.
  459. IrpContext - Irp context used to call NtOfsCreateAttributeEx().
  460. VolDo - A pointer to the volumn device object.
  461. StreamHdl - Stream to be worked on.
  462. PContext - BLOB(key) for READ or WRITE later.
  463. PContextLength - The length of the context.
  464. Return Value:
  465. STATUS_SUCCESS for successful operation.
  466. --*/
  467. {
  468. ULONG functionCode;
  469. ULONG bytesSame;
  470. ULONG efsLength;
  471. ULONG workOffset;
  472. ULONG information;
  473. PUCHAR pCmdContext = NULL;
  474. PVOID efsStreamData = NULL;
  475. NTSTATUS ntStatus;
  476. ATTRIBUTE_HANDLE attribute;
  477. BOOLEAN verifyInput;
  478. PAGED_CODE();
  479. CheckValidKeyBlock(*PContext,"Please contact RobertG if you see this. EfsFileControl() in.\n");
  480. #if DBG
  481. if ( (EFSTRACEALL | EFSTRACELIGHT ) & EFSDebug ){
  482. DbgPrint( "\n EFSFILTER: ****** EFS RTL FSCTL ****** \n" );
  483. }
  484. #endif
  485. if ( (NULL == PInputBuffer) || ( FALSE == EfsData.EfsInitialized )){
  486. return STATUS_INVALID_DEVICE_REQUEST;
  487. }
  488. //
  489. // Input data is encrypted by DES with sessionKey.
  490. // As long as we do not change the algorithm for the input data
  491. // We need guarantee the data length is in multiple of DES block size.
  492. // The first four bytes is always in plain text intended to hold the data
  493. // the NTFS is interested in.
  494. // The general format of input data is,
  495. // Sub-code plain text, [FsCode, Sub-code cipher text, [FsData]]sk
  496. //
  497. if ((InputDataLength < sizeof(FSCTL_INPUT)) || ((( InputDataLength - sizeof( ULONG )) % DES_BLOCKLEN ) != 0)) {
  498. return STATUS_INVALID_DEVICE_REQUEST;
  499. }
  500. pCmdContext = ExAllocatePoolWithTag(
  501. PagedPool,
  502. InputDataLength,
  503. 'csfE'
  504. );
  505. if ( NULL == pCmdContext ){
  506. return STATUS_INSUFFICIENT_RESOURCES;
  507. }
  508. //
  509. // Decrypt FSCTL input buffer. No CBC is used.
  510. //
  511. try {
  512. RtlCopyMemory( pCmdContext, PInputBuffer, InputDataLength );
  513. } except (EXCEPTION_EXECUTE_HANDLER) {
  514. ntStatus = GetExceptionCode();
  515. ExFreePool( pCmdContext );
  516. if (FsRtlIsNtstatusExpected( ntStatus)) {
  517. return ntStatus;
  518. } else {
  519. return STATUS_INVALID_USER_BUFFER;
  520. }
  521. }
  522. workOffset = sizeof( ULONG );
  523. while ( workOffset < InputDataLength ){
  524. des( pCmdContext + workOffset,
  525. pCmdContext + workOffset,
  526. &(EfsData.SessionDesTable[0]),
  527. DECRYPT
  528. );
  529. workOffset += DES_BLOCKLEN;
  530. }
  531. functionCode = ((PFSCTL_INPUT)pCmdContext)->EfsFsCode;
  532. #if DBG
  533. if ( (EFSTRACEALL | EFSTRACELIGHT ) & EFSDebug ){
  534. DbgPrint( "\n EFSFILTER: EFS RTL FSCTL=%x \n", functionCode);
  535. }
  536. #endif
  537. //
  538. // Check the codes match for set encrypt and decrypt to guard the integrity
  539. // of the encryption status. The NTFS is going to set/clear the bits. We really
  540. // want to make sure the FSCTL is issued by the right module.
  541. //
  542. if ( FSCTL_SET_ENCRYPTION == FsControlCode){
  543. if (SystemState & SYSTEM_IS_READONLY) {
  544. ExFreePool( pCmdContext );
  545. return STATUS_MEDIA_WRITE_PROTECTED;
  546. }
  547. if ( EFS_SET_ENCRYPT == functionCode ){
  548. if ( ((PFSCTL_INPUT)pCmdContext)->PlainSubCode !=
  549. (((PFSCTL_INPUT)pCmdContext)->CipherSubCode & ~EFS_FSCTL_ON_DIR ) ){
  550. ExFreePool( pCmdContext );
  551. return STATUS_INVALID_DEVICE_REQUEST;
  552. }
  553. } else if ( (EFS_SET_ATTRIBUTE != functionCode) &&
  554. (EFS_OVERWRITE_ATTRIBUTE != functionCode) ){
  555. ExFreePool( pCmdContext );
  556. return STATUS_INVALID_DEVICE_REQUEST;
  557. }
  558. }
  559. switch ( functionCode ){
  560. case EFS_SET_ATTRIBUTE:
  561. //
  562. // Write $EFS and/or set key Blob
  563. // subCode is a bit mask for the combination of write $EFS and set blob
  564. // [FsData] = FEK, [FEK]sk, [$EFS]
  565. // FEK == sessionKey when set key Blob is not required
  566. //
  567. // We cannot check access rights here. This call will be made if the
  568. // user creates a new file and without any access requirement. We
  569. // still want to setup FEK inside this call.
  570. //
  571. if ( !EfsVerifyKeyFsData(
  572. &(((PFSCTL_INPUT)pCmdContext)->EfsFsData[0]),
  573. InputDataLength) ){
  574. //
  575. // Input data format error
  576. //
  577. ExFreePool( pCmdContext );
  578. return STATUS_INVALID_PARAMETER;
  579. }
  580. try {
  581. ntStatus = SetEfsData(
  582. pCmdContext,
  583. InputDataLength,
  584. SystemState,
  585. FileHdl,
  586. IrpContext,
  587. PContext,
  588. PContextLength
  589. );
  590. } finally {
  591. ExFreePool( pCmdContext );
  592. }
  593. CheckValidKeyBlock(*PContext,"Please contact RobertG if you see this. EfsFileControl() Out 1.\n");
  594. return ntStatus;
  595. case EFS_SET_ENCRYPT:
  596. if ( !( AccessFlag & ( READ_DATA_ACCESS | WRITE_DATA_ACCESS ))){
  597. //
  598. // Check access flag
  599. //
  600. ExFreePool( pCmdContext );
  601. return STATUS_ACCESS_DENIED;
  602. }
  603. try {
  604. ntStatus = EfsSetEncrypt(
  605. pCmdContext,
  606. InputDataLength,
  607. EncryptionFlag,
  608. FileHdl,
  609. IrpContext,
  610. PContext,
  611. PContextLength
  612. );
  613. } finally {
  614. ExFreePool( pCmdContext );
  615. }
  616. CheckValidKeyBlock(*PContext,"Please contact RobertG if you see this. EfsFileControl() Out 2.\n");
  617. return ntStatus;
  618. case EFS_GET_ATTRIBUTE:
  619. //
  620. // Provide read access to $EFS for EFS service
  621. // Verify the input data format first.
  622. //
  623. try {
  624. if ( (NULL == POutputBuffer) ||
  625. (*POutputBufferLength < sizeof(ULONG)) ||
  626. !EfsVerifyGeneralFsData(
  627. &(((PFSCTL_INPUT)pCmdContext)->EfsFsData[0]),
  628. InputDataLength)){
  629. ExFreePool( pCmdContext );
  630. return STATUS_INVALID_PARAMETER;
  631. }
  632. } except(EXCEPTION_EXECUTE_HANDLER) {
  633. ntStatus = GetExceptionCode();
  634. ExFreePool( pCmdContext );
  635. if (FsRtlIsNtstatusExpected( ntStatus)) {
  636. return ntStatus;
  637. } else {
  638. return STATUS_INVALID_USER_BUFFER;
  639. }
  640. }
  641. if ( !(EncryptionFlag & STREAM_ENCRYPTED) ){
  642. ExFreePool( pCmdContext );
  643. return STATUS_INVALID_DEVICE_REQUEST;
  644. }
  645. //
  646. // Try to read an existing $EFS
  647. //
  648. try {
  649. ntStatus = EfsReadEfsData(
  650. FileHdl,
  651. IrpContext,
  652. &efsStreamData,
  653. &efsLength,
  654. &information
  655. );
  656. } finally {
  657. ExFreePool( pCmdContext );
  658. pCmdContext = NULL;
  659. }
  660. if ( EFS_READ_SUCCESSFUL == information ){
  661. //
  662. // Everything is OK. We do not check user ID here,
  663. // we suppose that has been checked by the service.
  664. //
  665. try {
  666. ntStatus = STATUS_SUCCESS;
  667. if ( efsLength > *POutputBufferLength ) {
  668. * (ULONG *) POutputBuffer = efsLength;
  669. *POutputBufferLength = sizeof(ULONG);
  670. ExFreePool( efsStreamData );
  671. return STATUS_BUFFER_TOO_SMALL;
  672. }
  673. RtlCopyMemory(POutputBuffer, efsStreamData, efsLength);
  674. *POutputBufferLength = efsLength;
  675. } except (EXCEPTION_EXECUTE_HANDLER) {
  676. ntStatus = GetExceptionCode();
  677. if (!FsRtlIsNtstatusExpected( ntStatus)) {
  678. ntStatus = STATUS_INVALID_USER_BUFFER;
  679. }
  680. }
  681. ExFreePool( efsStreamData );
  682. return ntStatus;
  683. } else if ( ( OPEN_EFS_FAIL == information ) ||
  684. ( EFS_FORMAT_ERROR == information ) ) {
  685. //
  686. // EFS does not exist or not encrypted by the EFS ?
  687. //
  688. ntStatus = STATUS_INVALID_DEVICE_REQUEST;
  689. }
  690. //
  691. // Other error while opening $EFS
  692. //
  693. return ntStatus;
  694. case EFS_DEL_ATTRIBUTE:
  695. if (SystemState & SYSTEM_IS_READONLY) {
  696. ExFreePool( pCmdContext );
  697. return STATUS_MEDIA_WRITE_PROTECTED;
  698. }
  699. if ( !( AccessFlag & WRITE_DATA_ACCESS )){
  700. //
  701. // Check access flag
  702. //
  703. ExFreePool( pCmdContext );
  704. return STATUS_ACCESS_DENIED;
  705. }
  706. //
  707. // Delete $EFS after all the stream has been decrypted.
  708. //
  709. if ( EncryptionFlag ){
  710. //
  711. // Stream has not been decrypted
  712. //
  713. ExFreePool( pCmdContext );
  714. return STATUS_INVALID_DEVICE_REQUEST;
  715. }
  716. //
  717. // [FsData] = SessionKey, Handle, Handle, [SessionKey, Handle, Handle]sk
  718. // Verify the FsData format.
  719. //
  720. if ( !EfsVerifyGeneralFsData(
  721. &(((PFSCTL_INPUT)pCmdContext)->EfsFsData[0]),
  722. InputDataLength) ){
  723. //
  724. // Input data format error
  725. //
  726. ExFreePool( pCmdContext );
  727. return STATUS_INVALID_PARAMETER;
  728. }
  729. //
  730. // Delete the $EFS stream
  731. //
  732. try {
  733. ntStatus = EfsDeleteEfsData( FileHdl, IrpContext );
  734. } finally {
  735. ExFreePool( pCmdContext );
  736. }
  737. return ntStatus;
  738. case EFS_ENCRYPT_DONE:
  739. //
  740. // Change the transition state of $EFS to normal state
  741. // Fall through intended.
  742. //
  743. #if DBG
  744. if ( EFSTRACEALL & EFSDebug ){
  745. DbgPrint( "\n EFSFILTER: Encryption Done %x\n", functionCode );
  746. }
  747. #endif
  748. case EFS_DECRYPT_BEGIN:
  749. if (SystemState & SYSTEM_IS_READONLY) {
  750. ExFreePool( pCmdContext );
  751. return STATUS_MEDIA_WRITE_PROTECTED;
  752. }
  753. if ( !( AccessFlag & WRITE_DATA_ACCESS )){
  754. //
  755. // Check access flag
  756. //
  757. ExFreePool( pCmdContext );
  758. return STATUS_ACCESS_DENIED;
  759. }
  760. //
  761. // Mark the transition state of $EFS
  762. //
  763. try {
  764. ntStatus = EfsModifyEfsState(
  765. functionCode,
  766. pCmdContext,
  767. InputDataLength,
  768. FileHdl,
  769. IrpContext
  770. );
  771. } finally {
  772. ExFreePool( pCmdContext );
  773. }
  774. return ntStatus;
  775. case EFS_OVERWRITE_ATTRIBUTE:
  776. if ( !( AccessFlag &
  777. ( WRITE_DATA_ACCESS |
  778. RESTORE_ACCESS ))){
  779. //
  780. // Check access flag
  781. //
  782. ExFreePool( pCmdContext );
  783. return STATUS_ACCESS_DENIED;
  784. }
  785. //
  786. // Mostly used in import
  787. // Overwrite $EFS and/or set key Blob
  788. // subCode is a bit mask for the combination of write $EFS and set blob
  789. //
  790. if ( ((PFSCTL_INPUT)pCmdContext)->CipherSubCode & SET_EFS_KEYBLOB ){
  791. verifyInput = EfsVerifyKeyFsData(
  792. &(((PFSCTL_INPUT)pCmdContext)->EfsFsData[0]),
  793. InputDataLength
  794. );
  795. } else {
  796. verifyInput = EfsVerifyGeneralFsData(
  797. &(((PFSCTL_INPUT)pCmdContext)->EfsFsData[0]),
  798. InputDataLength
  799. );
  800. }
  801. if ( !verifyInput ){
  802. //
  803. // Input data format error
  804. //
  805. ExFreePool( pCmdContext );
  806. return STATUS_INVALID_PARAMETER;
  807. }
  808. try {
  809. ntStatus = SetEfsData(
  810. pCmdContext,
  811. InputDataLength,
  812. SystemState,
  813. FileHdl,
  814. IrpContext,
  815. PContext,
  816. PContextLength
  817. );
  818. } finally {
  819. ExFreePool( pCmdContext );
  820. }
  821. CheckValidKeyBlock(*PContext,"Please contact RobertG if you see this. EfsFileControl() Out 3.\n");
  822. return ntStatus;
  823. default:
  824. // ASSERT (FALSE);
  825. ExFreePool( pCmdContext );
  826. return STATUS_INVALID_DEVICE_REQUEST;
  827. }
  828. CheckValidKeyBlock(*PContext,"Please contact RobertG if you see this. EfsFileControl() Out 4.\n");
  829. }
  830. NTSTATUS
  831. EfsRead(
  832. IN OUT PUCHAR InOutBuffer,
  833. IN PLARGE_INTEGER Offset,
  834. IN ULONG BufferSize,
  835. IN PVOID Context
  836. )
  837. /*++
  838. Routine Description:
  839. This is a call back routine. It will be called back by file system and
  840. decrypt the data in the buffer provided by the file system.
  841. Arguments:
  842. InOutBuffer - Pointer to the data block to be decrypted.
  843. Offset - Pointer to the offset of the block in the file. Relative to the
  844. beginning of the file.
  845. BufferSize - Length of the data block.
  846. Context - Information needed to decrypt the file. Passed to the file
  847. system on EfsOpenFile()
  848. Return Value:
  849. This routine will not cause error. Unless the memory passed in is not
  850. valid. In that case, memory flush will occur.
  851. --*/
  852. {
  853. ULONGLONG chainBlockIV[2];
  854. PUCHAR pWorkBuffer = InOutBuffer;
  855. EfsDecFunc pDecryptFunc;
  856. PAGED_CODE();
  857. #if DBG
  858. if ( EFSTRACEALL & EFSDebug ){
  859. DbgPrint( "\n EFSFILTER: READ Bytes = %x, Offset = %x\n", BufferSize, Offset->QuadPart);
  860. }
  861. #endif
  862. //
  863. // Data length should be in multiple of the chunk (512 Bytes)
  864. // Data offset (relative to the begining of the stream) should
  865. // Start at chunk boundary
  866. //
  867. CheckValidKeyBlock(Context,"Please contact RobertG if you see this. EfsRead() in.\n");
  868. ASSERT (BufferSize % CHUNK_SIZE == 0);
  869. ASSERT (Offset->QuadPart % CHUNK_SIZE == 0);
  870. switch (((PKEY_BLOB)Context)->AlgorithmID){
  871. case CALG_3DES:
  872. chainBlockIV[0] = Offset->QuadPart + EFS_IV;
  873. pDecryptFunc = EFSDes3Dec;
  874. break;
  875. case CALG_DESX:
  876. chainBlockIV[0] = Offset->QuadPart + EFS_IV;
  877. pDecryptFunc = EFSDesXDec;
  878. break;
  879. case CALG_AES_256:
  880. chainBlockIV[0] = Offset->QuadPart + EFS_AES_IVL;
  881. chainBlockIV[1] = Offset->QuadPart + EFS_AES_IVH;
  882. pDecryptFunc = EFSAesDec;
  883. break;
  884. case CALG_DES:
  885. default:
  886. chainBlockIV[0] = Offset->QuadPart + EFS_IV;
  887. pDecryptFunc = EFSDesDec;
  888. break;
  889. }
  890. while ( BufferSize > 0 ){
  891. pDecryptFunc(pWorkBuffer,
  892. (PUCHAR) &chainBlockIV[0],
  893. (PKEY_BLOB) Context,
  894. CHUNK_SIZE
  895. );
  896. pWorkBuffer += CHUNK_SIZE;
  897. chainBlockIV[0] += CHUNK_SIZE;
  898. if (((PKEY_BLOB)Context)->AlgorithmID == CALG_AES_256) {
  899. chainBlockIV[1] += CHUNK_SIZE;
  900. }
  901. BufferSize -= CHUNK_SIZE;
  902. }
  903. CheckValidKeyBlock(Context,"Please contact RobertG if you see this. EfsRead() out.\n");
  904. return ( STATUS_SUCCESS );
  905. }
  906. NTSTATUS
  907. EfsWrite(
  908. IN PUCHAR InBuffer,
  909. OUT PUCHAR OutBuffer,
  910. IN PLARGE_INTEGER Offset,
  911. IN ULONG BufferSize,
  912. IN PUCHAR Context
  913. )
  914. /*++
  915. Routine Description:
  916. This is a call back routine. It will be called back by file system and
  917. encrypt the data in the buffer provided by the file system.
  918. Note: The input data buffer can only be touched once.
  919. Arguments:
  920. InBuffer - Pointer to the data block to be encrypted.
  921. OutBuffer - Pointer to the data buffer to hold the encrypted data.
  922. Offset - Pointer to the offset of the block in the file. Relative to the
  923. beginning of the file.
  924. BufferSize - Length of the data block.
  925. Context - Information needed to decrypt the file. Passed to the file
  926. system on EfsOpenFile()
  927. Return Value:
  928. This routine will not cause error. Unless the memory passed in is not
  929. valid. In that case, memory flush will occur.
  930. --*/
  931. {
  932. ULONGLONG chainBlockIV[2];
  933. PUCHAR pWorkInBuffer = InBuffer;
  934. PUCHAR pWorkOutBuffer = OutBuffer;
  935. EfsEncFunc pEncryptFunc;
  936. PAGED_CODE();
  937. //
  938. // Data length should be in multiple of the chunk (512 Bytes)
  939. // Data offset (relative to the begining of the stream) should
  940. // Start at chunk boundary
  941. //
  942. CheckValidKeyBlock(Context,"Please contact RobertG if you see this. EfsWrite() in.\n");
  943. ASSERT (BufferSize % CHUNK_SIZE == 0);
  944. ASSERT (Offset->QuadPart % CHUNK_SIZE == 0);
  945. #if DBG
  946. if ( EFSTRACEALL & EFSDebug ){
  947. DbgPrint( "\n EFSFILTER: WRITE Bytes = %x, Offset = %x\n", BufferSize, Offset->QuadPart);
  948. }
  949. #endif
  950. switch (((PKEY_BLOB)Context)->AlgorithmID){
  951. case CALG_3DES:
  952. chainBlockIV[0] = Offset->QuadPart + EFS_IV;
  953. pEncryptFunc = EFSDes3Enc;
  954. break;
  955. case CALG_DESX:
  956. chainBlockIV[0] = Offset->QuadPart + EFS_IV;
  957. pEncryptFunc = EFSDesXEnc;
  958. break;
  959. case CALG_AES_256:
  960. chainBlockIV[0] = Offset->QuadPart + EFS_AES_IVL;
  961. chainBlockIV[1] = Offset->QuadPart + EFS_AES_IVH;
  962. pEncryptFunc = EFSAesEnc;
  963. break;
  964. case CALG_DES:
  965. default:
  966. chainBlockIV[0] = Offset->QuadPart + EFS_IV;
  967. pEncryptFunc = EFSDesEnc;
  968. break;
  969. }
  970. while ( BufferSize > 0 ){
  971. pEncryptFunc(pWorkInBuffer,
  972. pWorkOutBuffer,
  973. (PUCHAR) &chainBlockIV,
  974. (PKEY_BLOB)Context,
  975. CHUNK_SIZE
  976. );
  977. pWorkInBuffer += CHUNK_SIZE;
  978. pWorkOutBuffer += CHUNK_SIZE;
  979. chainBlockIV[0] += CHUNK_SIZE;
  980. if (((PKEY_BLOB)Context)->AlgorithmID == CALG_AES_256) {
  981. chainBlockIV[1] += CHUNK_SIZE;
  982. }
  983. BufferSize -= CHUNK_SIZE;
  984. }
  985. CheckValidKeyBlock(Context,"Please contact RobertG if you see this. EfsWrite() out.\n");
  986. return STATUS_SUCCESS;
  987. }
  988. VOID
  989. EfsFreeContext(
  990. IN OUT PVOID *PContext
  991. )
  992. /*++
  993. Routine Description:
  994. This is a call back routine. It will be called back by file system to
  995. free the context block.
  996. Arguments:
  997. PContext - Context block to be freed.
  998. Return Value:
  999. This routine will not cause error. Unless the memory passed in is not
  1000. valid.
  1001. --*/
  1002. {
  1003. PAGED_CODE();
  1004. #if DBG
  1005. if ( EFSTRACEALL & EFSDebug ){
  1006. DbgPrint( " EFSFILTER: ****** Free Key ****** \n" );
  1007. }
  1008. #endif
  1009. CheckValidKeyBlock(*PContext,"Please contact RobertG if you see this. EfsFreeContext() in.\n");
  1010. if (*PContext){
  1011. FreeMemoryBlock(PContext);
  1012. }
  1013. }
  1014. NTSTATUS
  1015. EfsMountVolumn(
  1016. IN PDEVICE_OBJECT VolDo,
  1017. IN PDEVICE_OBJECT RealDevice
  1018. )
  1019. /*++
  1020. Routine Description:
  1021. This is a call back routine. It will be called back by file system
  1022. when a volumn needs to be attached
  1023. Arguments:
  1024. VolDo - Volume device object
  1025. RealDevice - Volume real device object
  1026. Return Value:
  1027. The status of operation.
  1028. --*/
  1029. {
  1030. PDEVICE_OBJECT fsfDeviceObject;
  1031. PDEVICE_OBJECT deviceObject;
  1032. NTSTATUS status = STATUS_SUCCESS;
  1033. PAGED_CODE();
  1034. #if DBG
  1035. if ( EFSTRACEALL & EFSDebug ){
  1036. DbgPrint( "\n *****EFSFILTER: RTL mount.***** \n" );
  1037. }
  1038. #endif
  1039. return STATUS_SUCCESS;
  1040. }
  1041. VOID
  1042. EfsDismountVolumn(
  1043. IN PDEVICE_OBJECT VolDo
  1044. )
  1045. /*++
  1046. Routine Description:
  1047. This is a call back routine. It will be called back by file system
  1048. when a volumn is dismounted
  1049. Arguments:
  1050. VolDo - volumn's device object.
  1051. Return Value:
  1052. No return value.
  1053. --*/
  1054. {
  1055. PAGED_CODE();
  1056. #if DBG
  1057. if ( EFSTRACEALL & EFSDebug ){
  1058. DbgPrint( "EFSFILTER: Dismount callback. \n" );
  1059. }
  1060. #endif
  1061. }