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.

1466 lines
42 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 = 0;
  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=0;
  473. ULONG dataFlushLength = FIELD_OFFSET(GENERAL_FS_DATA, EfsData[0]);
  474. PUCHAR pCmdContext = NULL;
  475. PVOID efsStreamData = NULL;
  476. NTSTATUS ntStatus;
  477. ATTRIBUTE_HANDLE attribute;
  478. BOOLEAN verifyInput;
  479. PAGED_CODE();
  480. CheckValidKeyBlock(*PContext,"Please contact RobertG if you see this. EfsFileControl() in.\n");
  481. #if DBG
  482. if ( (EFSTRACEALL | EFSTRACELIGHT ) & EFSDebug ){
  483. DbgPrint( "\n EFSFILTER: ****** EFS RTL FSCTL ****** \n" );
  484. }
  485. #endif
  486. if ( (NULL == PInputBuffer) || ( FALSE == EfsData.EfsInitialized )){
  487. return STATUS_INVALID_DEVICE_REQUEST;
  488. }
  489. //
  490. // Input data is encrypted by DES with sessionKey.
  491. // As long as we do not change the algorithm for the input data
  492. // We need guarantee the data length is in multiple of DES block size.
  493. // The first four bytes is always in plain text intended to hold the data
  494. // the NTFS is interested in.
  495. // The general format of input data is,
  496. // Sub-code plain text, [FsCode, Sub-code cipher text, [FsData]]sk
  497. //
  498. if ((InputDataLength < (ULONG)(FIELD_OFFSET(FSCTL_INPUT, EfsFsData[0]) + FIELD_OFFSET(GENERAL_FS_DATA, EfsData[0]))) || ((( InputDataLength - sizeof( ULONG )) % DES_BLOCKLEN ) != 0)) {
  499. return STATUS_INVALID_DEVICE_REQUEST;
  500. }
  501. pCmdContext = ExAllocatePoolWithTag(
  502. PagedPool,
  503. InputDataLength,
  504. 'csfE'
  505. );
  506. if ( NULL == pCmdContext ){
  507. return STATUS_INSUFFICIENT_RESOURCES;
  508. }
  509. //
  510. // Decrypt FSCTL input buffer. No CBC is used.
  511. //
  512. try {
  513. RtlCopyMemory( pCmdContext, PInputBuffer, InputDataLength );
  514. } except (EXCEPTION_EXECUTE_HANDLER) {
  515. ntStatus = GetExceptionCode();
  516. ExFreePool( pCmdContext );
  517. if (FsRtlIsNtstatusExpected( ntStatus)) {
  518. return ntStatus;
  519. } else {
  520. return STATUS_INVALID_USER_BUFFER;
  521. }
  522. }
  523. workOffset = sizeof( ULONG );
  524. while ( workOffset < InputDataLength ){
  525. des( pCmdContext + workOffset,
  526. pCmdContext + workOffset,
  527. &(EfsData.SessionDesTable[0]),
  528. DECRYPT
  529. );
  530. workOffset += DES_BLOCKLEN;
  531. }
  532. functionCode = ((PFSCTL_INPUT)pCmdContext)->EfsFsCode;
  533. #if DBG
  534. if ( (EFSTRACEALL | EFSTRACELIGHT ) & EFSDebug ){
  535. DbgPrint( "\n EFSFILTER: EFS RTL FSCTL=%x \n", functionCode);
  536. }
  537. #endif
  538. //
  539. // Check the codes match for set encrypt and decrypt to guard the integrity
  540. // of the encryption status. The NTFS is going to set/clear the bits. We really
  541. // want to make sure the FSCTL is issued by the right module.
  542. //
  543. if ( FSCTL_SET_ENCRYPTION == FsControlCode){
  544. if (SystemState & SYSTEM_IS_READONLY) {
  545. //
  546. // This could be issued from right components
  547. //
  548. RtlSecureZeroMemory(&(((PFSCTL_INPUT)pCmdContext)->EfsFsData[0]), dataFlushLength);
  549. ExFreePool( pCmdContext );
  550. return STATUS_MEDIA_WRITE_PROTECTED;
  551. }
  552. if ( EFS_SET_ENCRYPT == functionCode ){
  553. if ( ((PFSCTL_INPUT)pCmdContext)->PlainSubCode !=
  554. (((PFSCTL_INPUT)pCmdContext)->CipherSubCode & ~EFS_FSCTL_ON_DIR ) ){
  555. ExFreePool( pCmdContext );
  556. return STATUS_INVALID_DEVICE_REQUEST;
  557. }
  558. } else if ( (EFS_SET_ATTRIBUTE != functionCode) &&
  559. (EFS_OVERWRITE_ATTRIBUTE != functionCode) ){
  560. ExFreePool( pCmdContext );
  561. return STATUS_INVALID_DEVICE_REQUEST;
  562. }
  563. }
  564. switch ( functionCode ){
  565. case EFS_SET_ATTRIBUTE:
  566. //
  567. // Write $EFS and/or set key Blob
  568. // subCode is a bit mask for the combination of write $EFS and set blob
  569. // [FsData] = FEK, [FEK]sk, [$EFS]
  570. // FEK == sessionKey when set key Blob is not required
  571. //
  572. // We cannot check access rights here. This call will be made if the
  573. // user creates a new file and without any access requirement. We
  574. // still want to setup FEK inside this call.
  575. //
  576. if ( !EfsVerifyKeyFsData(
  577. &(((PFSCTL_INPUT)pCmdContext)->EfsFsData[0]),
  578. InputDataLength) ){
  579. //
  580. // Input data format error. Could be issued from attacker.
  581. //
  582. ExFreePool( pCmdContext );
  583. return STATUS_INVALID_PARAMETER;
  584. }
  585. try {
  586. ntStatus = SetEfsData(
  587. pCmdContext,
  588. InputDataLength,
  589. SystemState,
  590. FileHdl,
  591. IrpContext,
  592. PContext,
  593. PContextLength
  594. );
  595. } finally {
  596. dataFlushLength = 2 * (EFS_KEY_SIZE((PEFS_KEY) &(((PFSCTL_INPUT)pCmdContext)->EfsFsData[0])));
  597. RtlSecureZeroMemory(&(((PFSCTL_INPUT)pCmdContext)->EfsFsData[0]), dataFlushLength);
  598. ExFreePool( pCmdContext );
  599. }
  600. CheckValidKeyBlock(*PContext,"Please contact RobertG if you see this. EfsFileControl() Out 1.\n");
  601. return ntStatus;
  602. case EFS_SET_ENCRYPT:
  603. if ( !( AccessFlag & ( READ_DATA_ACCESS | WRITE_DATA_ACCESS ))){
  604. //
  605. // Check access flag. Could be called by an attacker.
  606. //
  607. ExFreePool( pCmdContext );
  608. return STATUS_ACCESS_DENIED;
  609. }
  610. try {
  611. ntStatus = EfsSetEncrypt(
  612. pCmdContext,
  613. InputDataLength,
  614. EncryptionFlag,
  615. FileHdl,
  616. IrpContext,
  617. PContext,
  618. PContextLength
  619. );
  620. } finally {
  621. //
  622. // Memory should have been zeroed in EfsSetEncrypt.
  623. //
  624. ExFreePool( pCmdContext );
  625. }
  626. CheckValidKeyBlock(*PContext,"Please contact RobertG if you see this. EfsFileControl() Out 2.\n");
  627. return ntStatus;
  628. case EFS_GET_ATTRIBUTE:
  629. //
  630. // Provide read access to $EFS for EFS service
  631. // Verify the input data format first.
  632. //
  633. try {
  634. if ( (NULL == POutputBuffer) ||
  635. (*POutputBufferLength < sizeof(ULONG)) ||
  636. !EfsVerifyGeneralFsData(
  637. &(((PFSCTL_INPUT)pCmdContext)->EfsFsData[0]),
  638. InputDataLength)){
  639. ExFreePool( pCmdContext );
  640. return STATUS_INVALID_PARAMETER;
  641. }
  642. } except(EXCEPTION_EXECUTE_HANDLER) {
  643. ntStatus = GetExceptionCode();
  644. ExFreePool( pCmdContext );
  645. if (FsRtlIsNtstatusExpected( ntStatus)) {
  646. return ntStatus;
  647. } else {
  648. return STATUS_INVALID_USER_BUFFER;
  649. }
  650. }
  651. if ( !(EncryptionFlag & STREAM_ENCRYPTED) ){
  652. RtlSecureZeroMemory(&(((PFSCTL_INPUT)pCmdContext)->EfsFsData[0]), dataFlushLength);
  653. ExFreePool( pCmdContext );
  654. return STATUS_INVALID_DEVICE_REQUEST;
  655. }
  656. //
  657. // Try to read an existing $EFS
  658. //
  659. try {
  660. ntStatus = EfsReadEfsData(
  661. FileHdl,
  662. IrpContext,
  663. &efsStreamData,
  664. &efsLength,
  665. &information
  666. );
  667. } finally {
  668. //
  669. // Zero pCmdContext. This is not needed if the the input format data
  670. // is not good as in the above error cases, which means some is trying
  671. // to attack us.
  672. //
  673. RtlSecureZeroMemory(&(((PFSCTL_INPUT)pCmdContext)->EfsFsData[0]), dataFlushLength);
  674. ExFreePool( pCmdContext );
  675. pCmdContext = NULL;
  676. }
  677. if ( EFS_READ_SUCCESSFUL == information ){
  678. //
  679. // Everything is OK. We do not check user ID here,
  680. // we suppose that has been checked by the service.
  681. //
  682. try {
  683. ntStatus = STATUS_SUCCESS;
  684. if ( efsLength > *POutputBufferLength ) {
  685. * (ULONG *) POutputBuffer = efsLength;
  686. *POutputBufferLength = sizeof(ULONG);
  687. ExFreePool( efsStreamData );
  688. return STATUS_BUFFER_TOO_SMALL;
  689. }
  690. RtlCopyMemory(POutputBuffer, efsStreamData, efsLength);
  691. *POutputBufferLength = efsLength;
  692. } except (EXCEPTION_EXECUTE_HANDLER) {
  693. ntStatus = GetExceptionCode();
  694. if (!FsRtlIsNtstatusExpected( ntStatus)) {
  695. ntStatus = STATUS_INVALID_USER_BUFFER;
  696. }
  697. }
  698. ExFreePool( efsStreamData );
  699. return ntStatus;
  700. } else if ( ( OPEN_EFS_FAIL == information ) ||
  701. ( EFS_FORMAT_ERROR == information ) ) {
  702. //
  703. // EFS does not exist or not encrypted by the EFS ?
  704. //
  705. ntStatus = STATUS_INVALID_DEVICE_REQUEST;
  706. }
  707. //
  708. // Other error while opening $EFS
  709. //
  710. return ntStatus;
  711. case EFS_DEL_ATTRIBUTE:
  712. if (SystemState & SYSTEM_IS_READONLY) {
  713. RtlSecureZeroMemory(&(((PFSCTL_INPUT)pCmdContext)->EfsFsData[0]), dataFlushLength);
  714. ExFreePool( pCmdContext );
  715. return STATUS_MEDIA_WRITE_PROTECTED;
  716. }
  717. if ( !( AccessFlag & WRITE_DATA_ACCESS )){
  718. //
  719. // Check access flag
  720. //
  721. RtlSecureZeroMemory(&(((PFSCTL_INPUT)pCmdContext)->EfsFsData[0]), dataFlushLength);
  722. ExFreePool( pCmdContext );
  723. return STATUS_ACCESS_DENIED;
  724. }
  725. //
  726. // Delete $EFS after all the stream has been decrypted.
  727. //
  728. if ( EncryptionFlag ){
  729. //
  730. // Stream has not been decrypted
  731. //
  732. RtlSecureZeroMemory(&(((PFSCTL_INPUT)pCmdContext)->EfsFsData[0]), dataFlushLength);
  733. ExFreePool( pCmdContext );
  734. return STATUS_INVALID_DEVICE_REQUEST;
  735. }
  736. //
  737. // [FsData] = SessionKey, Handle, Handle, [SessionKey, Handle, Handle]sk
  738. // Verify the FsData format.
  739. //
  740. if ( !EfsVerifyGeneralFsData(
  741. &(((PFSCTL_INPUT)pCmdContext)->EfsFsData[0]),
  742. InputDataLength) ){
  743. //
  744. // Input data format error. No need to zero attacker provided pCmdContext block.
  745. //
  746. ExFreePool( pCmdContext );
  747. return STATUS_INVALID_PARAMETER;
  748. }
  749. //
  750. // Delete the $EFS stream
  751. //
  752. try {
  753. ntStatus = EfsDeleteEfsData( FileHdl, IrpContext );
  754. } finally {
  755. RtlSecureZeroMemory(&(((PFSCTL_INPUT)pCmdContext)->EfsFsData[0]), dataFlushLength);
  756. ExFreePool( pCmdContext );
  757. }
  758. return ntStatus;
  759. case EFS_ENCRYPT_DONE:
  760. //
  761. // Change the transition state of $EFS to normal state
  762. // Fall through intended.
  763. //
  764. #if DBG
  765. if ( EFSTRACEALL & EFSDebug ){
  766. DbgPrint( "\n EFSFILTER: Encryption Done %x\n", functionCode );
  767. }
  768. #endif
  769. case EFS_DECRYPT_BEGIN:
  770. if (SystemState & SYSTEM_IS_READONLY) {
  771. ExFreePool( pCmdContext );
  772. return STATUS_MEDIA_WRITE_PROTECTED;
  773. }
  774. if ( !( AccessFlag & WRITE_DATA_ACCESS )){
  775. //
  776. // Check access flag
  777. //
  778. ExFreePool( pCmdContext );
  779. return STATUS_ACCESS_DENIED;
  780. }
  781. //
  782. // Mark the transition state of $EFS
  783. //
  784. try {
  785. ntStatus = EfsModifyEfsState(
  786. functionCode,
  787. pCmdContext,
  788. InputDataLength,
  789. FileHdl,
  790. IrpContext
  791. );
  792. } finally {
  793. RtlSecureZeroMemory(&(((PFSCTL_INPUT)pCmdContext)->EfsFsData[0]), dataFlushLength);
  794. ExFreePool( pCmdContext );
  795. }
  796. return ntStatus;
  797. case EFS_OVERWRITE_ATTRIBUTE:
  798. if ( ((PFSCTL_INPUT)pCmdContext)->CipherSubCode & SET_EFS_KEYBLOB ){
  799. //
  800. // FEK, [FEK]sk, [$EFS]
  801. //
  802. dataFlushLength = 2 * (EFS_KEY_SIZE((PEFS_KEY) &(((PFSCTL_INPUT)pCmdContext)->EfsFsData[0])));
  803. } else {
  804. //
  805. // SessionKey, Handle, Handle, [SessionKey, Handle, Handle]sk
  806. //
  807. dataFlushLength = FIELD_OFFSET(GENERAL_FS_DATA, EfsData[0]);
  808. }
  809. if ( !( AccessFlag &
  810. ( WRITE_DATA_ACCESS |
  811. RESTORE_ACCESS ))){
  812. //
  813. // Check access flag
  814. //
  815. RtlSecureZeroMemory(&(((PFSCTL_INPUT)pCmdContext)->EfsFsData[0]), dataFlushLength);
  816. ExFreePool( pCmdContext );
  817. return STATUS_ACCESS_DENIED;
  818. }
  819. //
  820. // Mostly used in import
  821. // Overwrite $EFS and/or set key Blob
  822. // subCode is a bit mask for the combination of write $EFS and set blob
  823. //
  824. if ( ((PFSCTL_INPUT)pCmdContext)->CipherSubCode & SET_EFS_KEYBLOB ){
  825. verifyInput = EfsVerifyKeyFsData(
  826. &(((PFSCTL_INPUT)pCmdContext)->EfsFsData[0]),
  827. InputDataLength
  828. );
  829. } else {
  830. verifyInput = EfsVerifyGeneralFsData(
  831. &(((PFSCTL_INPUT)pCmdContext)->EfsFsData[0]),
  832. InputDataLength
  833. );
  834. }
  835. if ( !verifyInput ){
  836. //
  837. // Input data format error. No need to zero attacker provided memory.
  838. //
  839. ExFreePool( pCmdContext );
  840. return STATUS_INVALID_PARAMETER;
  841. }
  842. try {
  843. ntStatus = SetEfsData(
  844. pCmdContext,
  845. InputDataLength,
  846. SystemState,
  847. FileHdl,
  848. IrpContext,
  849. PContext,
  850. PContextLength
  851. );
  852. } finally {
  853. RtlSecureZeroMemory(&(((PFSCTL_INPUT)pCmdContext)->EfsFsData[0]), dataFlushLength);
  854. ExFreePool( pCmdContext );
  855. }
  856. CheckValidKeyBlock(*PContext,"Please contact RobertG if you see this. EfsFileControl() Out 3.\n");
  857. return ntStatus;
  858. default:
  859. // ASSERT (FALSE);
  860. ExFreePool( pCmdContext );
  861. return STATUS_INVALID_DEVICE_REQUEST;
  862. }
  863. CheckValidKeyBlock(*PContext,"Please contact RobertG if you see this. EfsFileControl() Out 4.\n");
  864. }
  865. NTSTATUS
  866. EfsRead(
  867. IN OUT PUCHAR InOutBuffer,
  868. IN PLARGE_INTEGER Offset,
  869. IN ULONG BufferSize,
  870. IN PVOID Context
  871. )
  872. /*++
  873. Routine Description:
  874. This is a call back routine. It will be called back by file system and
  875. decrypt the data in the buffer provided by the file system.
  876. Arguments:
  877. InOutBuffer - Pointer to the data block to be decrypted.
  878. Offset - Pointer to the offset of the block in the file. Relative to the
  879. beginning of the file.
  880. BufferSize - Length of the data block.
  881. Context - Information needed to decrypt the file. Passed to the file
  882. system on EfsOpenFile()
  883. Return Value:
  884. This routine will not cause error. Unless the memory passed in is not
  885. valid. In that case, memory flush will occur.
  886. --*/
  887. {
  888. ULONGLONG chainBlockIV[2];
  889. PUCHAR pWorkBuffer = InOutBuffer;
  890. EfsDecFunc pDecryptFunc;
  891. PAGED_CODE();
  892. #if DBG
  893. if ( EFSTRACEALL & EFSDebug ){
  894. DbgPrint( "\n EFSFILTER: READ Bytes = %x, Offset = %x\n", BufferSize, Offset->QuadPart);
  895. }
  896. #endif
  897. //
  898. // Data length should be in multiple of the chunk (512 Bytes)
  899. // Data offset (relative to the begining of the stream) should
  900. // Start at chunk boundary
  901. //
  902. CheckValidKeyBlock(Context,"Please contact RobertG if you see this. EfsRead() in.\n");
  903. ASSERT (BufferSize % CHUNK_SIZE == 0);
  904. ASSERT (Offset->QuadPart % CHUNK_SIZE == 0);
  905. switch (((PKEY_BLOB)Context)->AlgorithmID){
  906. case CALG_3DES:
  907. chainBlockIV[0] = Offset->QuadPart + EFS_IV;
  908. pDecryptFunc = EFSDes3Dec;
  909. break;
  910. case CALG_DESX:
  911. chainBlockIV[0] = Offset->QuadPart + EFS_IV;
  912. pDecryptFunc = EFSDesXDec;
  913. break;
  914. case CALG_AES_256:
  915. chainBlockIV[0] = Offset->QuadPart + EFS_AES_IVL;
  916. chainBlockIV[1] = Offset->QuadPart + EFS_AES_IVH;
  917. pDecryptFunc = EFSAesDec;
  918. break;
  919. case CALG_DES:
  920. default:
  921. chainBlockIV[0] = Offset->QuadPart + EFS_IV;
  922. pDecryptFunc = EFSDesDec;
  923. break;
  924. }
  925. while ( BufferSize > 0 ){
  926. pDecryptFunc(pWorkBuffer,
  927. (PUCHAR) &chainBlockIV[0],
  928. (PKEY_BLOB) Context,
  929. CHUNK_SIZE
  930. );
  931. pWorkBuffer += CHUNK_SIZE;
  932. chainBlockIV[0] += CHUNK_SIZE;
  933. if (((PKEY_BLOB)Context)->AlgorithmID == CALG_AES_256) {
  934. chainBlockIV[1] += CHUNK_SIZE;
  935. }
  936. BufferSize -= CHUNK_SIZE;
  937. }
  938. CheckValidKeyBlock(Context,"Please contact RobertG if you see this. EfsRead() out.\n");
  939. return ( STATUS_SUCCESS );
  940. }
  941. NTSTATUS
  942. EfsWrite(
  943. IN PUCHAR InBuffer,
  944. OUT PUCHAR OutBuffer,
  945. IN PLARGE_INTEGER Offset,
  946. IN ULONG BufferSize,
  947. IN PUCHAR Context
  948. )
  949. /*++
  950. Routine Description:
  951. This is a call back routine. It will be called back by file system and
  952. encrypt the data in the buffer provided by the file system.
  953. Note: The input data buffer can only be touched once.
  954. Arguments:
  955. InBuffer - Pointer to the data block to be encrypted.
  956. OutBuffer - Pointer to the data buffer to hold the encrypted data.
  957. Offset - Pointer to the offset of the block in the file. Relative to the
  958. beginning of the file.
  959. BufferSize - Length of the data block.
  960. Context - Information needed to decrypt the file. Passed to the file
  961. system on EfsOpenFile()
  962. Return Value:
  963. This routine will not cause error. Unless the memory passed in is not
  964. valid. In that case, memory flush will occur.
  965. --*/
  966. {
  967. ULONGLONG chainBlockIV[2];
  968. PUCHAR pWorkInBuffer = InBuffer;
  969. PUCHAR pWorkOutBuffer = OutBuffer;
  970. EfsEncFunc pEncryptFunc;
  971. PAGED_CODE();
  972. //
  973. // Data length should be in multiple of the chunk (512 Bytes)
  974. // Data offset (relative to the begining of the stream) should
  975. // Start at chunk boundary
  976. //
  977. CheckValidKeyBlock(Context,"Please contact RobertG if you see this. EfsWrite() in.\n");
  978. ASSERT (BufferSize % CHUNK_SIZE == 0);
  979. ASSERT (Offset->QuadPart % CHUNK_SIZE == 0);
  980. #if DBG
  981. if ( EFSTRACEALL & EFSDebug ){
  982. DbgPrint( "\n EFSFILTER: WRITE Bytes = %x, Offset = %x\n", BufferSize, Offset->QuadPart);
  983. }
  984. #endif
  985. switch (((PKEY_BLOB)Context)->AlgorithmID){
  986. case CALG_3DES:
  987. chainBlockIV[0] = Offset->QuadPart + EFS_IV;
  988. pEncryptFunc = EFSDes3Enc;
  989. break;
  990. case CALG_DESX:
  991. chainBlockIV[0] = Offset->QuadPart + EFS_IV;
  992. pEncryptFunc = EFSDesXEnc;
  993. break;
  994. case CALG_AES_256:
  995. chainBlockIV[0] = Offset->QuadPart + EFS_AES_IVL;
  996. chainBlockIV[1] = Offset->QuadPart + EFS_AES_IVH;
  997. pEncryptFunc = EFSAesEnc;
  998. break;
  999. case CALG_DES:
  1000. default:
  1001. chainBlockIV[0] = Offset->QuadPart + EFS_IV;
  1002. pEncryptFunc = EFSDesEnc;
  1003. break;
  1004. }
  1005. while ( BufferSize > 0 ){
  1006. pEncryptFunc(pWorkInBuffer,
  1007. pWorkOutBuffer,
  1008. (PUCHAR) &chainBlockIV,
  1009. (PKEY_BLOB)Context,
  1010. CHUNK_SIZE
  1011. );
  1012. pWorkInBuffer += CHUNK_SIZE;
  1013. pWorkOutBuffer += CHUNK_SIZE;
  1014. chainBlockIV[0] += CHUNK_SIZE;
  1015. if (((PKEY_BLOB)Context)->AlgorithmID == CALG_AES_256) {
  1016. chainBlockIV[1] += CHUNK_SIZE;
  1017. }
  1018. BufferSize -= CHUNK_SIZE;
  1019. }
  1020. CheckValidKeyBlock(Context,"Please contact RobertG if you see this. EfsWrite() out.\n");
  1021. return STATUS_SUCCESS;
  1022. }
  1023. VOID
  1024. EfsFreeContext(
  1025. IN OUT PVOID *PContext
  1026. )
  1027. /*++
  1028. Routine Description:
  1029. This is a call back routine. It will be called back by file system to
  1030. free the context block.
  1031. Arguments:
  1032. PContext - Context block to be freed.
  1033. Return Value:
  1034. This routine will not cause error. Unless the memory passed in is not
  1035. valid.
  1036. --*/
  1037. {
  1038. PAGED_CODE();
  1039. #if DBG
  1040. if ( EFSTRACEALL & EFSDebug ){
  1041. DbgPrint( " EFSFILTER: ****** Free Key ****** \n" );
  1042. }
  1043. #endif
  1044. CheckValidKeyBlock(*PContext,"Please contact RobertG if you see this. EfsFreeContext() in.\n");
  1045. if (*PContext){
  1046. FreeMemoryBlock(PContext);
  1047. }
  1048. }
  1049. NTSTATUS
  1050. EfsMountVolumn(
  1051. IN PDEVICE_OBJECT VolDo,
  1052. IN PDEVICE_OBJECT RealDevice
  1053. )
  1054. /*++
  1055. Routine Description:
  1056. This is a call back routine. It will be called back by file system
  1057. when a volumn needs to be attached
  1058. Arguments:
  1059. VolDo - Volume device object
  1060. RealDevice - Volume real device object
  1061. Return Value:
  1062. The status of operation.
  1063. --*/
  1064. {
  1065. PDEVICE_OBJECT fsfDeviceObject;
  1066. PDEVICE_OBJECT deviceObject;
  1067. NTSTATUS status = STATUS_SUCCESS;
  1068. PAGED_CODE();
  1069. #if DBG
  1070. if ( EFSTRACEALL & EFSDebug ){
  1071. DbgPrint( "\n *****EFSFILTER: RTL mount.***** \n" );
  1072. }
  1073. #endif
  1074. return STATUS_SUCCESS;
  1075. }
  1076. VOID
  1077. EfsDismountVolumn(
  1078. IN PDEVICE_OBJECT VolDo
  1079. )
  1080. /*++
  1081. Routine Description:
  1082. This is a call back routine. It will be called back by file system
  1083. when a volumn is dismounted
  1084. Arguments:
  1085. VolDo - volumn's device object.
  1086. Return Value:
  1087. No return value.
  1088. --*/
  1089. {
  1090. PAGED_CODE();
  1091. #if DBG
  1092. if ( EFSTRACEALL & EFSDebug ){
  1093. DbgPrint( "EFSFILTER: Dismount callback. \n" );
  1094. }
  1095. #endif
  1096. }