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.

3050 lines
80 KiB

  1. /*++
  2. Copyright (c) 1997-1999 Microsoft Corporation
  3. Module Name:
  4. efsinit.cxx
  5. Abstract:
  6. EFS (Encrypting File System) Server
  7. Author:
  8. Robert Reichel (RobertRe) July 4, 1997
  9. Robert Gu (RobertGu) Jan 7, 1998
  10. Environment:
  11. Revision History:
  12. --*/
  13. #include <lsapch.hxx>
  14. extern "C" {
  15. #include <nt.h>
  16. #include <ntdef.h>
  17. #include <ntrtl.h>
  18. #include <nturtl.h>
  19. #include <windows.h>
  20. #include <stdio.h>
  21. #include <efsstruc.h>
  22. #include "lsasrvp.h"
  23. #include "debug.h"
  24. #include "efssrv.hxx"
  25. #include "userkey.h"
  26. #include <cfgmgr32.h>
  27. #include <initguid.h>
  28. #include <mountmgr.h>
  29. #include <Userenv.h>
  30. }
  31. #define TIME_UNIT 10000000 // 1 TIME_UNIT == 1 second
  32. #define CERT_VALID_TIME 86400 // seconds - Default cache length 1 day
  33. //
  34. // Local prototypes of CFGMGR32 functions for dynamic load
  35. //
  36. typedef CMAPI CONFIGRET (WINAPI *
  37. CM_GET_DEVICE_INTERFACE_LISTW)(
  38. IN LPGUID,
  39. IN DEVINSTID_W,
  40. OUT PWCHAR,
  41. IN ULONG,
  42. IN ULONG );
  43. typedef CMAPI CONFIGRET (WINAPI *
  44. CM_GET_DEVICE_INTERFACE_LIST_SIZEW)(
  45. IN PULONG,
  46. IN LPGUID,
  47. IN DEVINSTID_W,
  48. IN ULONG
  49. );
  50. typedef CONFIGRET ( * CMP_WAITSERVICESAVAILABLE)(
  51. IN HMACHINE
  52. );
  53. //
  54. // Extern Vars
  55. //
  56. extern RTL_RESOURCE RecoveryPolicyResource;
  57. extern CURRENT_RECOVERY_POLICY CurrentRecoveryPolicy;
  58. extern "C" BOOLEAN EfsDisabled;
  59. //
  60. // Event handle used to sync with the driver
  61. //
  62. HANDLE EfsInitEventHandle = 0;
  63. //
  64. // Efs event handle to get policy change notification
  65. //
  66. HANDLE EfsPolicyEventHandle = 0;
  67. HANDLE EfsWaitHandle = 0;
  68. EFS_POL_CALLBACK EfsPolCallBack;
  69. BOOLEAN EfsServerInitialized = FALSE;
  70. extern "C" BOOLEAN EfsPersonalVer = TRUE;
  71. BOOLEAN EfspInDomain = FALSE;
  72. //
  73. // Cache values
  74. //
  75. HCRYPTPROV hProvVerify = 0;
  76. WCHAR EfsComputerName[MAX_COMPUTERNAME_LENGTH + 1];
  77. LIST_ENTRY UserCacheList;
  78. RTL_CRITICAL_SECTION GuardCacheListLock;
  79. LONG UserCacheListLimit = 5; // We might read this number from the registry in the future
  80. LONG UserCacheListCount = 0;
  81. LONGLONG CACHE_CERT_VALID_TIME;
  82. LONG RecoveryCertIsValidating = 0;
  83. static PSID LocalSystemSid;
  84. DWORD
  85. InitRecoveryPolicy(
  86. VOID
  87. );
  88. DWORD
  89. SetDefaultRecoveryPolicy(
  90. VOID
  91. );
  92. DWORD
  93. ParseRecoveryPolicy_1_1(
  94. IN PLSAPR_POLICY_DOMAIN_EFS_INFO PolicyEfsInfo OPTIONAL,
  95. OUT PCURRENT_RECOVERY_POLICY ParsedRecoveryPolicy
  96. );
  97. VOID
  98. EfsGetRegSettings(
  99. VOID
  100. );
  101. NTSTATUS
  102. EfsServerInit(
  103. VOID
  104. )
  105. /*++
  106. Routine Description:
  107. This routine is called during server initialization to allow
  108. EFS to initialize its data structures and inform the EFS Driver
  109. that it's up and running.
  110. Arguments:
  111. None.
  112. Return Value:
  113. None.
  114. --*/
  115. {
  116. OBJECT_ATTRIBUTES ObjA;
  117. NTSTATUS Status;
  118. UNICODE_STRING EfsInitEventName;
  119. OSVERSIONINFOEX Osvi;
  120. DWORD Result;
  121. DWORD nSize = MAX_COMPUTERNAME_LENGTH + 1;
  122. CACHE_CERT_VALID_TIME = (LONGLONG) CERT_VALID_TIME;
  123. CACHE_CERT_VALID_TIME *= (LONGLONG) TIME_UNIT;
  124. if ( !GetComputerName ( EfsComputerName, &nSize )){
  125. KdPrint(("EfsServerInit - GetComputerName failed 0x%lx\n", GetLastError()));
  126. return STATUS_UNSUCCESSFUL;
  127. }
  128. Osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
  129. if (GetVersionEx((LPOSVERSIONINFO)&Osvi)){
  130. if ((Osvi.wProductType == VER_NT_WORKSTATION) && ( Osvi.wSuiteMask & VER_SUITE_PERSONAL)) {
  131. EfsPersonalVer = TRUE;
  132. return STATUS_UNSUCCESSFUL;
  133. } else {
  134. EfsPersonalVer = FALSE;
  135. }
  136. } else {
  137. //
  138. // Treat as personal
  139. //
  140. EfsPersonalVer = TRUE;
  141. return STATUS_UNSUCCESSFUL;
  142. }
  143. //
  144. // Init the cache list
  145. //
  146. InitializeListHead(&UserCacheList);
  147. Status = RtlInitializeCriticalSection(&GuardCacheListLock);
  148. if (!NT_SUCCESS(Status)) {
  149. return Status;
  150. }
  151. EfsGetRegSettings();
  152. Status = InitDriverSessionKey();
  153. if (!NT_SUCCESS(Status)) {
  154. KdPrint(("EfsServerInit - EFS Init Session Key failed 0x%lx\n", Status));
  155. return( Status );
  156. }
  157. DebugLog((DEB_TRACE_EFS, "In EfsServerInit\n" ));
  158. //
  159. // Zero out the initial recovery policy structure
  160. //
  161. Result = ParseRecoveryPolicy_1_1(
  162. NULL,
  163. &CurrentRecoveryPolicy
  164. );
  165. //
  166. // Determine if we're in a domain or not. This must be done
  167. // before checking the recovery policy.
  168. //
  169. EfspRoleChangeCallback( (POLICY_NOTIFICATION_INFORMATION_CLASS)NULL );
  170. Status = LsaIRegisterPolicyChangeNotificationCallback(
  171. &EfspRoleChangeCallback,
  172. PolicyNotifyDnsDomainInformation
  173. );
  174. //
  175. // Try to get the current recovery policy.
  176. //
  177. __try
  178. {
  179. RtlInitializeResource( &RecoveryPolicyResource );
  180. }
  181. __except (EXCEPTION_EXECUTE_HANDLER)
  182. {
  183. Status = GetExceptionCode();
  184. }
  185. if ( !NT_SUCCESS( Status ) ) {
  186. return Status ;
  187. }
  188. Result = InitRecoveryPolicy();
  189. if (ERROR_SUCCESS != Result) {
  190. //
  191. // We couldn't initialize our recovery policy. Continue to
  192. // initialize the server so that the driver can proceed.
  193. //
  194. DebugLog((DEB_ERROR, "EfsServerInit - EFS Init Recovery Policy failed 0x%lx\n\n" ,Result ));
  195. }
  196. //
  197. // Try to establish connection with the driver.
  198. // Normally, the driver has not been loaded yet. Create
  199. // an event and wait for the driver. If the event already
  200. // exists, signal it.
  201. //
  202. RtlInitUnicodeString( &EfsInitEventName, L"\\EFSInitEvent" );
  203. InitializeObjectAttributes(
  204. &ObjA,
  205. &EfsInitEventName,
  206. 0,
  207. NULL,
  208. NULL
  209. );
  210. Status = NtCreateEvent(
  211. &EfsInitEventHandle,
  212. EVENT_MODIFY_STATE,
  213. &ObjA,
  214. NotificationEvent,
  215. FALSE
  216. );
  217. if (!NT_SUCCESS(Status)) {
  218. if (STATUS_OBJECT_NAME_COLLISION == Status) {
  219. //
  220. // EFS driver has been loaded.
  221. // Open and signal the event. Event handle will be closed
  222. // in GenerateDriverSessionKey()
  223. //
  224. Status = NtOpenEvent(
  225. &EfsInitEventHandle,
  226. EVENT_MODIFY_STATE,
  227. &ObjA
  228. );
  229. //
  230. // If the EFS Init event could not be opened, the EFS Server cannot
  231. // synchronize with the EFS Driver so neither component will
  232. // function correctly.
  233. //
  234. if (!NT_SUCCESS(Status)) {
  235. KdPrint(("EfsServerInit - Connection with the driver failed 0x%lx\n",Status));
  236. return( Status );
  237. }
  238. //
  239. // Signal the EFS Init Event. If the signalling fails, the EFS Server
  240. // is not able to synchronize properly with the EFS Driver.
  241. // This is a serious error which prevents both components from
  242. // functioning correctly.
  243. //
  244. Status = NtSetEvent( EfsInitEventHandle, NULL );
  245. if (!NT_SUCCESS(Status)) {
  246. KdPrint(("EfsServerInit - Init Event Set failed 0x%lx\n",Status));
  247. return( Status );
  248. }
  249. } else {
  250. //
  251. // Other unexpected error
  252. //
  253. KdPrint(("EfsServerInit - Event handling failed 0x%lx\n",Status));
  254. return( Status );
  255. }
  256. }
  257. SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;
  258. Status = RtlAllocateAndInitializeSid(
  259. &NtAuthority,
  260. 1,
  261. SECURITY_LOCAL_SYSTEM_RID,
  262. 0, 0, 0, 0, 0, 0, 0,
  263. &LocalSystemSid
  264. );
  265. Status = LsaIRegisterPolicyChangeNotificationCallback(
  266. &RecoveryInformationCallback,
  267. PolicyNotifyDomainEfsInformation
  268. );
  269. //
  270. // Check EFS disable policy if a DC member
  271. //
  272. if (EfspInDomain) {
  273. //
  274. // Only do this if in the domain
  275. //
  276. EfsPolicyEventHandle = CreateEvent(NULL, TRUE, FALSE, NULL);
  277. if (EfsPolicyEventHandle) {
  278. HANDLE waitHandle;
  279. EfsPolCallBack.EfsDisable = &EfsDisabled;
  280. EfsPolCallBack.EfsPolicyEventHandle = &EfsPolicyEventHandle;
  281. //
  282. // We got the event handle. Let's register it to the GP notification.
  283. // If we can't wait on it, we don't need to register it.
  284. //
  285. if (RegisterGPNotification(EfsPolicyEventHandle, TRUE)){
  286. if (!NT_SUCCESS(RtlRegisterWait(
  287. &EfsWaitHandle,
  288. EfsPolicyEventHandle,
  289. EfsGetPolRegSettings,
  290. &EfsPolCallBack,
  291. INFINITE,
  292. WT_EXECUTEONLYONCE))){
  293. //
  294. // We couldn't use the thread pool.
  295. //
  296. UnregisterGPNotification(EfsPolicyEventHandle);
  297. CloseHandle(EfsPolicyEventHandle);
  298. EfsPolicyEventHandle = 0;
  299. }
  300. } else {
  301. //
  302. // We failed to register. No need to wait for the notification.
  303. //
  304. //RtlDeregisterWait(EfsWaitHandle);
  305. CloseHandle(EfsPolicyEventHandle);
  306. EfsPolicyEventHandle = 0;
  307. }
  308. }
  309. //
  310. // Now let's read the policy data left by the last session.
  311. // Pass in &EfsDisabled so that later we could easily change this to
  312. // include more features, such as algorithms controlled by the policy.
  313. //
  314. EfsApplyLastPolicy(&EfsDisabled);
  315. } else {
  316. //
  317. // Delete the possible left over key if there is. We may move this to
  318. // DC disjoin later.
  319. //
  320. EfsRemoveKey();
  321. }
  322. EfsServerInitialized = TRUE;
  323. if (NT_SUCCESS( Status )) {
  324. DebugLog((DEB_TRACE_EFS, "EFS Server initialized successfully\n" ));
  325. } else {
  326. DebugLog((DEB_ERROR, "EFS Server Init failed, Status = %x\n" ,Status ));
  327. }
  328. return( Status );
  329. }
  330. NTSTATUS
  331. InitDriverSessionKey(
  332. VOID
  333. )
  334. /*++
  335. Routine Description:
  336. Generates a session key to be used by the driver and the server
  337. for sending information back and forth securely.
  338. Arguments:
  339. None.
  340. Return Value:
  341. STATUS_SUCCESS on success, STATUS_UNSUCCESSFUL otherwise.
  342. --*/
  343. {
  344. BOOL rc;
  345. //
  346. // hProvVerify will remain open until the process is shut down.
  347. // CryptReleaseContext(hProvVerify, 0) will not be called for this handle.
  348. //
  349. //
  350. if (!CryptAcquireContext(&hProvVerify, NULL, MS_DEF_PROV, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) {
  351. KdPrint(("InitDriverSessionKey - CryptAcquireContext failed, error = %x\n", GetLastError()));
  352. return( STATUS_UNSUCCESSFUL );
  353. }
  354. rc = CryptGenRandom( hProvVerify, SESSION_KEY_SIZE, DriverSessionKey );
  355. if (!rc) {
  356. return( STATUS_UNSUCCESSFUL );
  357. } else {
  358. LsaPid = (HANDLE) LongToPtr(GetCurrentProcessId());
  359. deskey( &DesTable, DriverSessionKey );
  360. return( STATUS_SUCCESS );
  361. }
  362. }
  363. NTSTATUS
  364. GenerateDriverSessionKey(
  365. OUT PEFS_INIT_DATAEXG InitDataExg
  366. )
  367. /*++
  368. Routine Description:
  369. Actually it just sends the pre-created session key back to the
  370. caller. The key is generated in InitDriverSessionKey.
  371. Arguments:
  372. InitDataExg - Supplies a pointer to a structure in which to put
  373. the initial data to be sent to the driver.
  374. Return Value:
  375. STATUS_SUCCESS.
  376. --*/
  377. {
  378. memcpy( InitDataExg->Key, DriverSessionKey, SESSION_KEY_SIZE );
  379. InitDataExg->LsaProcessID = LsaPid;
  380. if ( EfsInitEventHandle ){
  381. //
  382. // Connection to driver established
  383. //
  384. NtClose( EfsInitEventHandle );
  385. EfsInitEventHandle = 0;
  386. }
  387. return( STATUS_SUCCESS );
  388. }
  389. inline
  390. VOID
  391. AcquireRecoveryPolicyWriteLock()
  392. {
  393. BOOL b = RtlAcquireResourceExclusive( &RecoveryPolicyResource, TRUE );
  394. ASSERT( b );
  395. }
  396. inline
  397. VOID
  398. ReleaseRecoveryPolicyWriteLock()
  399. {
  400. RtlReleaseResource( &RecoveryPolicyResource );
  401. }
  402. DWORD
  403. InitRecoveryPolicy(
  404. VOID
  405. )
  406. /*++
  407. Routine Description:
  408. This routine is used to initialize the current recovery policy.
  409. Arguments:
  410. None
  411. Return Value:
  412. None.
  413. --*/
  414. {
  415. //
  416. // Attempt to query the recovery policy
  417. // from LSA, and if there isn't any,
  418. // attempt to create a default set.
  419. //
  420. DWORD Result = ERROR_SUCCESS;
  421. PLSAPR_POLICY_DOMAIN_EFS_INFO PolicyEfsInfo = NULL;
  422. NTSTATUS Status = LsarQueryDomainInformationPolicy(
  423. LsapPolicyHandle,
  424. PolicyDomainEfsInformation,
  425. (PLSAPR_POLICY_DOMAIN_INFORMATION *)&PolicyEfsInfo
  426. );
  427. if (!NT_SUCCESS( Status )) {
  428. return( RtlNtStatusToDosError(Status) );
  429. }
  430. //
  431. // We're going to parse it right into the global that maintains
  432. // the current recovery data, so take the write lock.
  433. //
  434. AcquireRecoveryPolicyWriteLock();
  435. //
  436. // Free the old parsed recovery bits
  437. //
  438. FreeParsedRecoveryPolicy( &CurrentRecoveryPolicy );
  439. Result = ParseRecoveryPolicy_1_1( PolicyEfsInfo, &CurrentRecoveryPolicy );
  440. if (PolicyEfsInfo != NULL) {
  441. LsaIFree_LSAPR_POLICY_DOMAIN_INFORMATION (
  442. PolicyDomainEfsInformation,
  443. (PLSAPR_POLICY_DOMAIN_INFORMATION)PolicyEfsInfo
  444. );
  445. }
  446. ReleaseRecoveryPolicyWriteLock();
  447. return( Result );
  448. }
  449. DWORD
  450. ParseRecoveryPolicy_1_1(
  451. IN PLSAPR_POLICY_DOMAIN_EFS_INFO PolicyEfsInfo OPTIONAL,
  452. OUT PCURRENT_RECOVERY_POLICY ParsedRecoveryPolicy
  453. )
  454. /*++
  455. Routine Description:
  456. This routine takes the currently defined recovery policy and parses
  457. it into a form that can be used conveniently.
  458. Arguments:
  459. PolicyEfsInfo - Optionally supplies a pointer to the current
  460. recovery policy from the LSA.
  461. ParsedRecoveryPolicy - Returns a structure containing recovery information
  462. in an easy-to-digest format.
  463. Return Value:
  464. return-value - Description of conditions needed to return value. - or -
  465. None.
  466. --*/
  467. {
  468. //
  469. // Fill in the contents of the ParsedRecoveryPolicy structure
  470. // with the contents of the passed policy information.
  471. //
  472. PRECOVERY_POLICY_1_1 RecoveryPolicy;
  473. DWORD Found = 0;
  474. PRECOVERY_KEY_1_1 RecoveryKey;
  475. DWORD rc = ERROR_SUCCESS;
  476. BOOL b = FALSE;
  477. if (PolicyEfsInfo == NULL) {
  478. //
  479. // NULL recovery policy
  480. //
  481. ParsedRecoveryPolicy->PolicyStatus = RECOVERY_POLICY_NULL;
  482. goto NoPolicy1;
  483. }
  484. RecoveryPolicy = (PRECOVERY_POLICY_1_1)PolicyEfsInfo->EfsBlob;
  485. if (RecoveryPolicy == NULL) {
  486. //
  487. // Empty recovery policy
  488. //
  489. ParsedRecoveryPolicy->PolicyStatus = RECOVERY_POLICY_EMPTY;
  490. goto NoPolicy1;
  491. }
  492. ParsedRecoveryPolicy->dwKeyCount = RecoveryPolicy->RecoveryPolicyHeader.RecoveryKeyCount;
  493. if (ParsedRecoveryPolicy->dwKeyCount == 0) {
  494. ParsedRecoveryPolicy->PolicyStatus = RECOVERY_POLICY_NO_AGENT;
  495. goto NoPolicy1;
  496. }
  497. __try {
  498. //
  499. // Scan the recovery data looking for recovery keys in a format we understand
  500. //
  501. ULONG i;
  502. RecoveryKey = (PRECOVERY_KEY_1_1) &(RecoveryPolicy->RecoveryKeyList[0]);
  503. for (i=0 ; i< (ParsedRecoveryPolicy->dwKeyCount) ; i++) {
  504. PEFS_PUBLIC_KEY_INFO PublicKeyInfo = &RecoveryKey->PublicKeyInfo;
  505. if (* ((ULONG UNALIGNED *) &(PublicKeyInfo->KeySourceTag)) == EfsCertificate) {
  506. Found++;
  507. }
  508. RecoveryKey = (PRECOVERY_KEY_1_1)( ((PBYTE)RecoveryKey) + * ((ULONG UNALIGNED *) &(RecoveryKey->TotalLength)) );
  509. }
  510. if (0 == Found) {
  511. ParsedRecoveryPolicy->PolicyStatus = RECOVERY_POLICY_BAD_POLICY;
  512. goto NoPolicy1;
  513. } else {
  514. ParsedRecoveryPolicy->Base = (PBYTE)LsapAllocateLsaHeap( 7 * sizeof( PVOID ) * Found );
  515. if (ParsedRecoveryPolicy->Base) {
  516. ZeroMemory( ParsedRecoveryPolicy->Base, 7 * sizeof( PVOID ) * Found);
  517. PBYTE Base = ParsedRecoveryPolicy->Base;
  518. ParsedRecoveryPolicy->pbHash = (PBYTE *)Base;
  519. Base += Found * sizeof(PVOID);
  520. ParsedRecoveryPolicy->cbHash = (PDWORD)Base;
  521. Base += Found * sizeof(PVOID);
  522. ParsedRecoveryPolicy->pbPublicKeys = (PBYTE *)Base;
  523. Base += Found * sizeof(PVOID);
  524. ParsedRecoveryPolicy->cbPublicKeys = (PDWORD)Base;
  525. Base += Found * sizeof(PVOID);
  526. ParsedRecoveryPolicy->lpDisplayInfo = (LPWSTR *)Base;
  527. Base += Found * sizeof(PVOID);
  528. ParsedRecoveryPolicy->pCertContext = (PCCERT_CONTEXT *)Base;
  529. Base += Found * sizeof(PVOID);
  530. ParsedRecoveryPolicy->pSid = (PSID *)Base;
  531. } else {
  532. ParsedRecoveryPolicy->PolicyStatus = RECOVERY_POLICY_NO_MEMORY;
  533. return( ERROR_NOT_ENOUGH_MEMORY );
  534. }
  535. ParsedRecoveryPolicy->dwKeyCount = Found;
  536. ParsedRecoveryPolicy->PolicyStatus = RECOVERY_POLICY_OK;
  537. //
  538. // Make a copy of the policy information so we can free what we were passed in the caller
  539. //
  540. RecoveryKey = (PRECOVERY_KEY_1_1) &(RecoveryPolicy->RecoveryKeyList[0]);
  541. for (i=0 ; i< (ParsedRecoveryPolicy->dwKeyCount) ; i++) {
  542. PEFS_PUBLIC_KEY_INFO PublicKeyInfo = &RecoveryKey->PublicKeyInfo;
  543. if (* ((ULONG UNALIGNED *) &(PublicKeyInfo->KeySourceTag)) == EfsCertificate) {
  544. b = ParseRecoveryCertificate( PublicKeyInfo,
  545. &ParsedRecoveryPolicy->pbHash[i],
  546. &ParsedRecoveryPolicy->cbHash[i],
  547. &ParsedRecoveryPolicy->pbPublicKeys[i],
  548. &ParsedRecoveryPolicy->cbPublicKeys[i],
  549. &ParsedRecoveryPolicy->lpDisplayInfo[i],
  550. &ParsedRecoveryPolicy->pCertContext[i],
  551. &ParsedRecoveryPolicy->pSid[i]
  552. );
  553. if (!b) {
  554. break;
  555. }
  556. }
  557. RecoveryKey = (PRECOVERY_KEY_1_1)( ((PBYTE)RecoveryKey) + * ((ULONG UNALIGNED *) &(RecoveryKey->TotalLength)) );
  558. }
  559. }
  560. } __except (EXCEPTION_EXECUTE_HANDLER) {
  561. b = FALSE;
  562. //
  563. // There was something wrong with the recovery policy.
  564. // Return this so we can at least print out an error.
  565. //
  566. rc = GetExceptionCode();
  567. }
  568. if (!b) {
  569. //
  570. // Something failed, clean up
  571. //
  572. rc = GetLastError();
  573. FreeParsedRecoveryPolicy( ParsedRecoveryPolicy );
  574. ParsedRecoveryPolicy->PolicyStatus = RECOVERY_POLICY_UNKNOWN_BAD;
  575. DebugLog((DEB_WARN, "Error parsing recovery policy\n" ));
  576. }
  577. //
  578. // Policy refreshed. The Cert validation needs to be refreshed.
  579. //
  580. ParsedRecoveryPolicy->CertValidated = CERT_NOT_VALIDATED;
  581. return( rc );
  582. NoPolicy1:
  583. ParsedRecoveryPolicy->dwKeyCount = 0;
  584. ParsedRecoveryPolicy->TimeStamp.QuadPart = 0;
  585. ParsedRecoveryPolicy->CertValidated = CERT_NOT_VALIDATED;
  586. ParsedRecoveryPolicy->Base = NULL;
  587. ParsedRecoveryPolicy->pbHash = NULL;
  588. ParsedRecoveryPolicy->cbHash = NULL;
  589. ParsedRecoveryPolicy->pbPublicKeys = NULL;
  590. ParsedRecoveryPolicy->cbPublicKeys = NULL;
  591. ParsedRecoveryPolicy->lpDisplayInfo = NULL;
  592. ParsedRecoveryPolicy->pCertContext = NULL;
  593. ParsedRecoveryPolicy->pSid = NULL;
  594. return( ERROR_SUCCESS );
  595. }
  596. VOID
  597. FreeParsedRecoveryPolicy(
  598. PCURRENT_RECOVERY_POLICY ParsedRecoveryPolicy
  599. )
  600. /*++
  601. Routine Description:
  602. This routine will free the allocated memory in a
  603. CURRENT_RECOVERY_POLICY structure.
  604. Arguments:
  605. ParsedRecoveryPolicy - Supplies a structure that has
  606. had data parsed into it.
  607. Return Value:
  608. None.
  609. --*/
  610. {
  611. //
  612. // Walk through the recovery policy and free everything
  613. //
  614. DWORD i;
  615. if (ParsedRecoveryPolicy->Base) {
  616. for (i=0; i<ParsedRecoveryPolicy->dwKeyCount; i++) {
  617. if (ParsedRecoveryPolicy->pbHash[i] != NULL) {
  618. LsapFreeLsaHeap( ParsedRecoveryPolicy->pbHash[i] );
  619. }
  620. if (ParsedRecoveryPolicy->pbPublicKeys[i] != NULL) {
  621. LsapFreeLsaHeap( ParsedRecoveryPolicy->pbPublicKeys[i] );
  622. }
  623. if (ParsedRecoveryPolicy->lpDisplayInfo[i] != NULL) {
  624. LsapFreeLsaHeap( ParsedRecoveryPolicy->lpDisplayInfo[i] );
  625. }
  626. if (ParsedRecoveryPolicy->pCertContext[i] != NULL) {
  627. CertFreeCertificateContext( ParsedRecoveryPolicy->pCertContext[i] );
  628. }
  629. if (ParsedRecoveryPolicy->pSid[i] != NULL) {
  630. LsapFreeLsaHeap( ParsedRecoveryPolicy->pSid[i] );
  631. }
  632. }
  633. LsapFreeLsaHeap( ParsedRecoveryPolicy->Base );
  634. }
  635. //
  636. // Paranoia
  637. //
  638. ParsedRecoveryPolicy->Base = NULL;
  639. ParsedRecoveryPolicy->CertValidated = CERT_NOT_VALIDATED;
  640. ParsedRecoveryPolicy->PolicyStatus = RECOVERY_POLICY_NULL;
  641. ParsedRecoveryPolicy->dwKeyCount = 0;
  642. ParsedRecoveryPolicy->pbHash = NULL;
  643. ParsedRecoveryPolicy->cbHash = NULL;
  644. ParsedRecoveryPolicy->pbPublicKeys = NULL;
  645. ParsedRecoveryPolicy->cbPublicKeys = NULL;
  646. ParsedRecoveryPolicy->lpDisplayInfo = NULL;
  647. ParsedRecoveryPolicy->pCertContext = NULL;
  648. ParsedRecoveryPolicy->pSid = NULL;
  649. }
  650. DWORD WINAPI
  651. EFSRecover(
  652. IN LPVOID Param
  653. )
  654. /*++
  655. Routine Description:
  656. Enumerate the volumes and do the possible recovery jobs caused by
  657. power outage or crash during encryption or decryption.
  658. Arguments:
  659. Param -- Standard parameter for thread. Not used.
  660. Return Value:
  661. Operation result.
  662. --*/
  663. {
  664. CONFIGRET RetCode;
  665. WCHAR *VolBuffer;
  666. WCHAR *PathName;
  667. ULONG VolOffset;
  668. ULONG bufLen;
  669. HMODULE hCfgMgr ;
  670. CMP_WAITSERVICESAVAILABLE pCMP_WaitServicesAvailable ;
  671. CM_GET_DEVICE_INTERFACE_LIST_SIZEW pCM_Get_Device_Interface_List_Size ;
  672. CM_GET_DEVICE_INTERFACE_LISTW pCM_Get_Device_Interface_List ;
  673. // hCfgMgr = LoadLibrary( TEXT("cfgmgr32.dll" ) );
  674. hCfgMgr = LoadLibrary( TEXT("setupapi.dll" ) );
  675. if ( hCfgMgr )
  676. {
  677. pCMP_WaitServicesAvailable = (CMP_WAITSERVICESAVAILABLE)
  678. GetProcAddress( hCfgMgr,
  679. "CMP_WaitServicesAvailable" );
  680. pCM_Get_Device_Interface_List_Size = (CM_GET_DEVICE_INTERFACE_LIST_SIZEW)
  681. GetProcAddress( hCfgMgr,
  682. "CM_Get_Device_Interface_List_SizeW" );
  683. pCM_Get_Device_Interface_List = (CM_GET_DEVICE_INTERFACE_LISTW)
  684. GetProcAddress( hCfgMgr,
  685. "CM_Get_Device_Interface_ListW" );
  686. if ( (!pCMP_WaitServicesAvailable) ||
  687. (!pCM_Get_Device_Interface_List_Size) ||
  688. (!pCM_Get_Device_Interface_List) )
  689. {
  690. FreeLibrary( hCfgMgr );
  691. return GetLastError() ;
  692. }
  693. } else {
  694. return GetLastError() ;
  695. }
  696. RetCode = pCMP_WaitServicesAvailable( NULL );
  697. if ( CR_SUCCESS != RetCode ){
  698. FreeLibrary( hCfgMgr );
  699. return RetCode;
  700. }
  701. RetCode = pCM_Get_Device_Interface_List_Size(
  702. &bufLen,
  703. (LPGUID)&MOUNTDEV_MOUNTED_DEVICE_GUID,
  704. NULL,
  705. CM_GET_DEVICE_INTERFACE_LIST_PRESENT
  706. );
  707. if ( CR_SUCCESS == RetCode ){
  708. VolBuffer = (WCHAR *) LsapAllocateLsaHeap( bufLen * sizeof(WCHAR) );
  709. PathName = (WCHAR *) LsapAllocateLsaHeap( MAX_PATH_LENGTH );
  710. if ( (NULL != VolBuffer) && (NULL != PathName) ){
  711. RetCode = pCM_Get_Device_Interface_List(
  712. (LPGUID)&MOUNTDEV_MOUNTED_DEVICE_GUID,
  713. NULL,
  714. VolBuffer,
  715. bufLen,
  716. CM_GET_DEVICE_INTERFACE_LIST_PRESENT
  717. );
  718. if ( CR_SUCCESS == RetCode ){
  719. VolOffset = 0;
  720. while (*(VolBuffer + VolOffset)) {
  721. //
  722. // See if recovery is needed on the volume
  723. //
  724. wcscpy(PathName, VolBuffer + VolOffset);
  725. wcscat(PathName, EFSDIR);
  726. TryRecoverVol(VolBuffer + VolOffset, PathName);
  727. while (*(VolBuffer + VolOffset++));
  728. }
  729. } else {
  730. HANDLE EventHandleLog = RegisterEventSource(
  731. NULL,
  732. EFSSOURCE
  733. );
  734. if ( EventHandleLog ){
  735. ReportEvent(
  736. EventHandleLog,
  737. EVENTLOG_ERROR_TYPE,
  738. 0,
  739. EFS_GET_VOLUMES_ERROR,
  740. NULL,
  741. 0,
  742. 4,
  743. NULL,
  744. &RetCode
  745. );
  746. DeregisterEventSource( EventHandleLog );
  747. }
  748. if ( CR_REGISTRY_ERROR == RetCode ){
  749. //
  750. // Map CR error to winerror
  751. //
  752. RetCode = ERROR_REGISTRY_CORRUPT;
  753. }
  754. }
  755. LsapFreeLsaHeap( VolBuffer );
  756. LsapFreeLsaHeap( PathName );
  757. } else {
  758. if ( NULL != PathName ){
  759. LsapFreeLsaHeap( PathName );
  760. }
  761. if ( NULL != VolBuffer ) {
  762. LsapFreeLsaHeap( VolBuffer );
  763. }
  764. RetCode = ERROR_NOT_ENOUGH_MEMORY;
  765. }
  766. } else {
  767. DWORD RetCode1 = GetLastError();
  768. HANDLE EventHandleLog = RegisterEventSource(
  769. NULL,
  770. EFSSOURCE
  771. );
  772. if ( EventHandleLog ){
  773. ReportEvent(
  774. EventHandleLog,
  775. EVENTLOG_ERROR_TYPE,
  776. 0,
  777. EFS_PNP_NOT_READY,
  778. NULL,
  779. 0,
  780. 4,
  781. NULL,
  782. &RetCode1
  783. );
  784. DeregisterEventSource( EventHandleLog );
  785. }
  786. if ( CR_REGISTRY_ERROR == RetCode1 ){
  787. //
  788. // Map CR error to winerror
  789. //
  790. RetCode = ERROR_REGISTRY_CORRUPT;
  791. }
  792. }
  793. FreeLibrary( hCfgMgr );
  794. return RetCode;
  795. }
  796. void
  797. TryRecoverVol(
  798. IN const WCHAR *VolumeName,
  799. IN WCHAR *CacheDir
  800. )
  801. /*++
  802. Routine Description:
  803. Do the possible recovery jobs caused by
  804. power outage or crash during encryption or decryption on the volume.
  805. Arguments:
  806. VolumeName -- volume name to be checked.
  807. CacheDir -- EFSCACHE dir. The buffer can be used in this routine.
  808. Return Value:
  809. None.
  810. --*/
  811. {
  812. HANDLE EfsCacheDir;
  813. LPWIN32_FIND_DATA FindFileInfo;
  814. HANDLE FindHandle;
  815. //
  816. // Check if the directory EFSCACHE exist or not
  817. //
  818. EfsCacheDir = CreateFile(
  819. CacheDir,
  820. GENERIC_READ,
  821. FILE_SHARE_READ,
  822. NULL,
  823. OPEN_EXISTING,
  824. FILE_FLAG_BACKUP_SEMANTICS,
  825. 0
  826. );
  827. if (EfsCacheDir == INVALID_HANDLE_VALUE){
  828. //
  829. // No recovery needed
  830. //
  831. return;
  832. }
  833. CloseHandle(EfsCacheDir);
  834. //
  835. // Search the possible log file
  836. //
  837. FindFileInfo = ( LPWIN32_FIND_DATA ) LsapAllocateLsaHeap ( sizeof ( WIN32_FIND_DATA ));
  838. ASSERT( FindFileInfo );
  839. if ( NULL == FindFileInfo ){
  840. return;
  841. }
  842. wcscat(CacheDir, EFSLOGPATTERN);
  843. FindHandle = FindFirstFile( CacheDir, FindFileInfo );
  844. if (FindHandle == INVALID_HANDLE_VALUE){
  845. //
  846. // No LogFile found. No recovery needed
  847. //
  848. LsapFreeLsaHeap( FindFileInfo);
  849. return;
  850. }
  851. //
  852. // Log file found. FT procedure begins
  853. //
  854. HANDLE EventHandleLog = RegisterEventSource(
  855. NULL,
  856. EFSSOURCE
  857. );
  858. if ( EventHandleLog ){
  859. //
  860. // Error in handling Event Log should not prevent real FT job.
  861. //
  862. ReportEvent(
  863. EventHandleLog,
  864. EVENTLOG_INFORMATION_TYPE,
  865. 0,
  866. EFS_FT_STARTED,
  867. NULL,
  868. 0,
  869. 0,
  870. NULL,
  871. NULL
  872. );
  873. }
  874. for (;;){
  875. BOOL b;
  876. TryRecoverFile( VolumeName, FindFileInfo, EventHandleLog );
  877. b = FindNextFile( FindHandle, FindFileInfo );
  878. if ( !b ) {
  879. break;
  880. }
  881. }
  882. if ( EventHandleLog ){
  883. DeregisterEventSource( EventHandleLog );
  884. }
  885. LsapFreeLsaHeap( FindFileInfo);
  886. FindClose( FindHandle );
  887. return;
  888. }
  889. void
  890. TryRecoverFile(
  891. IN const WCHAR *VolumeName,
  892. IN LPWIN32_FIND_DATA FindFileInfo,
  893. IN HANDLE EventHandleLog
  894. )
  895. /*++
  896. Routine Description:
  897. Do the possible recovery jobs caused by
  898. power outage or crash during encryption or decryption for the file.
  899. Arguments:
  900. VolumeName -- volume name the log file is in.
  901. FindFileInfo -- Information about this log file.
  902. Return Value:
  903. None.
  904. --*/
  905. {
  906. WCHAR *FileName;
  907. HANDLE LogFile;
  908. HANDLE TmpFile;
  909. HANDLE Target;
  910. HANDLE VolumeHandle;
  911. LPWSTR TargetName;
  912. LPWSTR TmpName = NULL;
  913. LOGHEADER FileHeader;
  914. ULONG SectorSize;
  915. BYTE *ReadBuffer;
  916. BYTE *StatusBuffer;
  917. BOOL b;
  918. ULONG BufferSize;
  919. DWORD BytesRead;
  920. ULONG CheckSum;
  921. EFS_ACTION_STATUS Action;
  922. NTSTATUS Status;
  923. UNICODE_STRING FileId;
  924. VolumeHandle = CreateFile(
  925. VolumeName,
  926. GENERIC_READ,
  927. FILE_SHARE_READ | FILE_SHARE_WRITE,
  928. NULL,
  929. OPEN_EXISTING,
  930. FILE_FLAG_BACKUP_SEMANTICS,
  931. 0
  932. );
  933. if ( INVALID_HANDLE_VALUE == VolumeHandle ){
  934. //
  935. // Directory on this volume opened successfully. It is unlikely that we will
  936. // come here.
  937. //
  938. return;
  939. }
  940. FileName = (WCHAR *) LsapAllocateLsaHeap( MAX_PATH_LENGTH );
  941. //
  942. // Out of memory is unlikely at the boot time
  943. //
  944. ASSERT (FileName);
  945. if ( NULL == FileName ){
  946. CloseHandle( VolumeHandle );
  947. return;
  948. }
  949. //
  950. // Construct the log file name
  951. //
  952. wcscpy( FileName, VolumeName );
  953. wcscat( FileName, EFSDIR );
  954. wcscat( FileName, L"\\");
  955. wcscat( FileName, FindFileInfo->cFileName);
  956. LogFile = CreateFile(
  957. FileName,
  958. GENERIC_READ | GENERIC_WRITE | DELETE,
  959. 0,
  960. NULL,
  961. OPEN_EXISTING,
  962. 0,
  963. 0
  964. );
  965. if ( INVALID_HANDLE_VALUE == LogFile ){
  966. DWORD ErrCode = GetLastError();
  967. if ( EventHandleLog ){
  968. ReportEvent(
  969. EventHandleLog,
  970. EVENTLOG_ERROR_TYPE,
  971. 0,
  972. EFS_OPEN_LOGFILE_ERROR,
  973. NULL,
  974. 0,
  975. 4,
  976. NULL,
  977. &ErrCode
  978. );
  979. }
  980. CloseHandle( VolumeHandle );
  981. LsapFreeLsaHeap(FileName);
  982. return;
  983. }
  984. b = ReadFile(
  985. LogFile,
  986. &FileHeader,
  987. sizeof( LOGHEADER ),
  988. &BytesRead,
  989. NULL
  990. );
  991. if ( !b ){
  992. //
  993. // File IO error
  994. //
  995. DWORD ErrCode = GetLastError();
  996. if ( EventHandleLog ){
  997. ReportEvent(
  998. EventHandleLog,
  999. EVENTLOG_ERROR_TYPE,
  1000. 0,
  1001. EFS_READ_LOGFILE_ERROR,
  1002. NULL,
  1003. 0,
  1004. 4,
  1005. NULL,
  1006. &ErrCode
  1007. );
  1008. }
  1009. CloseHandle( LogFile );
  1010. CloseHandle( VolumeHandle );
  1011. LsapFreeLsaHeap(FileName);
  1012. return;
  1013. }
  1014. if ( 0 == BytesRead ){
  1015. //
  1016. // Zero length log file. Nothing started. Delete it.
  1017. //
  1018. MarkFileForDelete( LogFile );
  1019. CloseHandle( LogFile );
  1020. CloseHandle( VolumeHandle );
  1021. LsapFreeLsaHeap(FileName);
  1022. return;
  1023. }
  1024. if ( (BytesRead < sizeof( LOGHEADER )) ||
  1025. (LOGSIGLEN * sizeof (WCHAR) != RtlCompareMemory(
  1026. &(FileHeader.SIGNATURE[0]),
  1027. LOGSIG,
  1028. LOGSIGLEN * sizeof (WCHAR)
  1029. )) ||
  1030. ( LOGVERID != FileHeader.VerID )){
  1031. //
  1032. // Probably not our log file
  1033. //
  1034. if ( EventHandleLog ){
  1035. ReportEvent(
  1036. EventHandleLog,
  1037. EVENTLOG_INFORMATION_TYPE,
  1038. 0,
  1039. EFS_LOGFILE_FORMAT_ERROR,
  1040. NULL,
  1041. 0,
  1042. 0,
  1043. NULL,
  1044. NULL
  1045. );
  1046. }
  1047. CloseHandle( LogFile );
  1048. CloseHandle( VolumeHandle );
  1049. LsapFreeLsaHeap(FileName);
  1050. return;
  1051. }
  1052. //
  1053. // Read in the whole header to continue the process
  1054. //
  1055. SectorSize = FileHeader.SectorSize;
  1056. BufferSize = FileHeader.HeaderBlockSize;
  1057. ASSERT( BufferSize % SectorSize == 0 );
  1058. ReadBuffer = (BYTE *) LsapAllocateLsaHeap( BufferSize );
  1059. //
  1060. // StatusBuffer must be aligned for cached IO.
  1061. // LsapAllocateLsaHeap() is not aligned.
  1062. //
  1063. if ((FileHeader.Flag & LOG_DIRECTORY) == 0) {
  1064. StatusBuffer = (BYTE *) VirtualAlloc(
  1065. NULL,
  1066. FileHeader.OffsetStatus2 - FileHeader.OffsetStatus1,
  1067. MEM_COMMIT,
  1068. PAGE_READWRITE
  1069. );
  1070. } else {
  1071. StatusBuffer = NULL;
  1072. }
  1073. ASSERT( (FileHeader.OffsetStatus2 - FileHeader.OffsetStatus1) % SectorSize == 0 );
  1074. ASSERT( ReadBuffer );
  1075. if ( (NULL == ReadBuffer) || ((NULL == StatusBuffer) && ((FileHeader.Flag & LOG_DIRECTORY) == 0)) ){
  1076. //
  1077. // Out of memory is almost impossible during the boot time.
  1078. //
  1079. if ( ReadBuffer ) {
  1080. LsapFreeLsaHeap(ReadBuffer);
  1081. }
  1082. if ( StatusBuffer ) {
  1083. VirtualFree(
  1084. StatusBuffer,
  1085. 0,
  1086. MEM_RELEASE
  1087. );
  1088. }
  1089. CloseHandle( LogFile );
  1090. CloseHandle( VolumeHandle );
  1091. LsapFreeLsaHeap(FileName);
  1092. return;
  1093. }
  1094. SetFilePointer( LogFile, 0, NULL, FILE_BEGIN);
  1095. b = ReadFile(
  1096. LogFile,
  1097. ReadBuffer,
  1098. BufferSize,
  1099. &BytesRead,
  1100. NULL
  1101. );
  1102. if ( !b || ( BytesRead != BufferSize ) ){
  1103. //
  1104. // File IO error, Should sent out some debug Info?
  1105. //
  1106. DWORD ErrCode = GetLastError();
  1107. if ( EventHandleLog ){
  1108. ReportEvent(
  1109. EventHandleLog,
  1110. EVENTLOG_ERROR_TYPE,
  1111. 0,
  1112. EFS_READ_LOGFILE_ERROR,
  1113. NULL,
  1114. 0,
  1115. 4,
  1116. NULL,
  1117. &ErrCode
  1118. );
  1119. }
  1120. CloseHandle( LogFile );
  1121. CloseHandle( VolumeHandle );
  1122. LsapFreeLsaHeap(ReadBuffer);
  1123. VirtualFree(
  1124. StatusBuffer,
  1125. 0,
  1126. MEM_RELEASE
  1127. );
  1128. LsapFreeLsaHeap(FileName);
  1129. return;
  1130. }
  1131. CheckSum = GetCheckSum(ReadBuffer, FileHeader.HeaderSize );
  1132. if (CheckSum == *(ULONG* ) (ReadBuffer + BufferSize - sizeof(ULONG))){
  1133. OBJECT_ATTRIBUTES Obja;
  1134. IO_STATUS_BLOCK IoStatusBlock;
  1135. //
  1136. // The header is in good condition. Get TargetName and TmpName for the error
  1137. // msg in system log.
  1138. //
  1139. TargetName = (WCHAR *)( ReadBuffer + FileHeader.TargetFilePathOffset );
  1140. if ( (FileHeader.Flag & LOG_DIRECTORY) == 0 ){
  1141. //
  1142. // Operation was on File not on Directory
  1143. // The real status is in Status block. Read in the status block.
  1144. // Log file may updated. We need to reopen it with non-cached IO.
  1145. //
  1146. CloseHandle( LogFile );
  1147. LogFile = CreateFile(
  1148. FileName,
  1149. GENERIC_READ | GENERIC_WRITE | DELETE,
  1150. 0,
  1151. NULL,
  1152. OPEN_EXISTING,
  1153. FILE_FLAG_NO_BUFFERING,
  1154. 0
  1155. );
  1156. //
  1157. // Log File name is done. We are going to use FileName memory space
  1158. // to get a temp file name.
  1159. //
  1160. if ( INVALID_HANDLE_VALUE == LogFile ){
  1161. //
  1162. // Log File cannot be open as non-cached IO. Try next time.
  1163. // This is weird.
  1164. //
  1165. DWORD ErrCode = GetLastError();
  1166. ASSERT (FALSE);
  1167. if ( EventHandleLog ){
  1168. ReportEvent(
  1169. EventHandleLog,
  1170. EVENTLOG_ERROR_TYPE,
  1171. 0,
  1172. EFS_OPEN_LOGFILE_NC_ERROR,
  1173. NULL,
  1174. 0,
  1175. 4,
  1176. NULL,
  1177. &ErrCode
  1178. );
  1179. }
  1180. LsapFreeLsaHeap(FileName);
  1181. CloseHandle( VolumeHandle );
  1182. LsapFreeLsaHeap(ReadBuffer);
  1183. VirtualFree(
  1184. StatusBuffer,
  1185. 0,
  1186. MEM_RELEASE
  1187. );
  1188. return;
  1189. }
  1190. //
  1191. // Open the temp file first.
  1192. //
  1193. TmpName = (WCHAR *)( ReadBuffer + FileHeader.TempFilePathOffset );
  1194. FileId.Buffer = (WCHAR *) &(FileHeader.TempFileInternalName);
  1195. FileId.Length = FileId.MaximumLength = sizeof (LARGE_INTEGER);
  1196. InitializeObjectAttributes(
  1197. &Obja,
  1198. &FileId,
  1199. 0,
  1200. VolumeHandle,
  1201. NULL
  1202. );
  1203. Status = NtCreateFile(
  1204. &TmpFile,
  1205. GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE,
  1206. &Obja,
  1207. &IoStatusBlock,
  1208. NULL,
  1209. 0,
  1210. 0,
  1211. FILE_OPEN,
  1212. FILE_OPEN_BY_FILE_ID | FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_REPARSE_POINT,
  1213. NULL,
  1214. 0
  1215. );
  1216. if (NT_SUCCESS( Status )){
  1217. OBJECT_NAME_INFORMATION *ATempFileName;
  1218. ULONG PathLength;
  1219. //
  1220. // Temp file opened with File ID. File open by ID cannot be deleted. So
  1221. // we need to get a name and reopen it using the name with DELETE
  1222. // access
  1223. //
  1224. ATempFileName = (OBJECT_NAME_INFORMATION *)FileName;
  1225. Status = NtQueryObject(
  1226. TmpFile,
  1227. ObjectNameInformation,
  1228. ATempFileName,
  1229. MAX_PATH_LENGTH,
  1230. &PathLength
  1231. );
  1232. if ( NT_SUCCESS( Status ) ){
  1233. CloseHandle(TmpFile);
  1234. TmpFile = 0;
  1235. InitializeObjectAttributes(
  1236. &Obja,
  1237. &(ATempFileName->Name),
  1238. 0,
  1239. 0,
  1240. NULL
  1241. );
  1242. Status = NtCreateFile(
  1243. &TmpFile,
  1244. GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE | DELETE,
  1245. &Obja,
  1246. &IoStatusBlock,
  1247. NULL,
  1248. 0,
  1249. 0,
  1250. FILE_OPEN,
  1251. FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_REPARSE_POINT,
  1252. NULL,
  1253. 0
  1254. );
  1255. if (!NT_SUCCESS( Status )){
  1256. //
  1257. // Well, we cannot open with the name got. Strange.
  1258. // Reopen it with File ID. Temp file is not going to be deleted.
  1259. //
  1260. ASSERT(FALSE);
  1261. if ( EventHandleLog ){
  1262. LPWSTR lpStrings[2];
  1263. lpStrings[1] = TargetName;
  1264. lpStrings[0] = TmpName;
  1265. ReportEvent(
  1266. EventHandleLog,
  1267. EVENTLOG_WARNING_TYPE,
  1268. 0,
  1269. EFS_TMP_OPEN_NAME_ERROR,
  1270. NULL,
  1271. 2,
  1272. 4,
  1273. (LPCTSTR *) &lpStrings[0],
  1274. &Status
  1275. );
  1276. }
  1277. InitializeObjectAttributes(
  1278. &Obja,
  1279. &FileId,
  1280. 0,
  1281. VolumeHandle,
  1282. NULL
  1283. );
  1284. Status = NtCreateFile(
  1285. &TmpFile,
  1286. GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE,
  1287. &Obja,
  1288. &IoStatusBlock,
  1289. NULL,
  1290. 0,
  1291. 0,
  1292. FILE_OPEN,
  1293. FILE_OPEN_BY_FILE_ID | FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_REPARSE_POINT,
  1294. NULL,
  1295. 0
  1296. );
  1297. if (!NT_SUCCESS( Status )){
  1298. //
  1299. // Well, more strange. We cannot even open the file we opened
  1300. // Nothing we can do this time. Try next time.
  1301. //
  1302. if ( EventHandleLog ){
  1303. LPWSTR lpStrings[2];
  1304. lpStrings[1] = TargetName;
  1305. lpStrings[0] = TmpName;
  1306. ReportEvent(
  1307. EventHandleLog,
  1308. EVENTLOG_WARNING_TYPE,
  1309. 0,
  1310. EFS_TMP_FILEID_ERROR,
  1311. NULL,
  1312. 2,
  1313. 4,
  1314. (LPCTSTR*) &lpStrings[0],
  1315. &Status
  1316. );
  1317. }
  1318. LsapFreeLsaHeap(FileName);
  1319. CloseHandle( VolumeHandle );
  1320. LsapFreeLsaHeap(ReadBuffer);
  1321. VirtualFree(
  1322. StatusBuffer,
  1323. 0,
  1324. MEM_RELEASE
  1325. );
  1326. return;
  1327. }
  1328. }
  1329. } else {
  1330. if ( EventHandleLog ){
  1331. LPWSTR lpStrings[2];
  1332. lpStrings[0] = TargetName;
  1333. lpStrings[1] = TmpName;
  1334. ReportEvent(
  1335. EventHandleLog,
  1336. EVENTLOG_WARNING_TYPE,
  1337. 0,
  1338. EFS_TMP_FILENAME_ERROR,
  1339. NULL,
  1340. 2,
  1341. 4,
  1342. (LPCTSTR*) &lpStrings[0],
  1343. &Status
  1344. );
  1345. }
  1346. }
  1347. //
  1348. // If a name cannot be got, the following apply.
  1349. // Temp file is existed. But we cannot get a name. Weird.
  1350. // The recover will go on. But the temp file will not be deleted
  1351. //
  1352. } else {
  1353. //
  1354. // Temp file is not exist. May be deleted by our operations.
  1355. // Make sure the handle is 0.
  1356. //
  1357. TmpFile = 0;
  1358. }
  1359. //
  1360. // FileName is done.
  1361. //
  1362. LsapFreeLsaHeap(FileName);
  1363. FileName = NULL;
  1364. Status = ReadLogFile(
  1365. LogFile,
  1366. StatusBuffer,
  1367. FileHeader.OffsetStatus1,
  1368. FileHeader.OffsetStatus2
  1369. );
  1370. if (!NT_SUCCESS( Status )) {
  1371. //
  1372. // Status copies are not valid. Nothing have started or we can do nothing
  1373. // to recover. Delete the log file.
  1374. //
  1375. MarkFileForDelete( LogFile );
  1376. CloseHandle( LogFile );
  1377. if ( TmpFile ){
  1378. CloseHandle( TmpFile );
  1379. }
  1380. CloseHandle( VolumeHandle );
  1381. LsapFreeLsaHeap(ReadBuffer);
  1382. VirtualFree(
  1383. StatusBuffer,
  1384. 0,
  1385. MEM_RELEASE
  1386. );
  1387. return;
  1388. }
  1389. Action = * (EFS_ACTION_STATUS *) (StatusBuffer + sizeof (ULONG));
  1390. } else {
  1391. //
  1392. // Operations were on a directory
  1393. //
  1394. if ( FileHeader.Flag & LOG_DECRYPTION ){
  1395. Action = BeginDecryptDir;
  1396. } else {
  1397. Action = BeginEncryptDir;
  1398. }
  1399. TmpFile = 0;
  1400. }
  1401. //
  1402. // Open the target file.
  1403. //
  1404. if (StatusBuffer) {
  1405. VirtualFree(
  1406. StatusBuffer,
  1407. 0,
  1408. MEM_RELEASE
  1409. );
  1410. }
  1411. FileId.Buffer = (WCHAR* ) &(FileHeader.TargetFileInternalName);
  1412. FileId.Length = FileId.MaximumLength = sizeof (LARGE_INTEGER);
  1413. InitializeObjectAttributes(
  1414. &Obja,
  1415. &FileId,
  1416. 0,
  1417. VolumeHandle,
  1418. NULL
  1419. );
  1420. Status = NtCreateFile(
  1421. &Target,
  1422. GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE ,
  1423. &Obja,
  1424. &IoStatusBlock,
  1425. NULL,
  1426. 0,
  1427. 0,
  1428. FILE_OPEN,
  1429. FILE_OPEN_BY_FILE_ID | FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_REPARSE_POINT,
  1430. NULL,
  1431. 0
  1432. );
  1433. if (!NT_SUCCESS( Status )) {
  1434. //
  1435. // OOPS! We can not open the target. What can we do without the target.
  1436. // Delete the log file.
  1437. //
  1438. if ( EventHandleLog ){
  1439. ReportEvent(
  1440. EventHandleLog,
  1441. EVENTLOG_WARNING_TYPE,
  1442. 0,
  1443. EFS_TARGET_OPEN_ERROR,
  1444. NULL,
  1445. 1,
  1446. 4,
  1447. (LPCTSTR*) &TargetName,
  1448. &Status
  1449. );
  1450. }
  1451. MarkFileForDelete( LogFile );
  1452. CloseHandle( LogFile );
  1453. CloseHandle( VolumeHandle );
  1454. if ( TmpFile ){
  1455. CloseHandle( TmpFile );
  1456. }
  1457. LsapFreeLsaHeap(ReadBuffer);
  1458. return;
  1459. }
  1460. //
  1461. // We survived so far. Now is the show time!
  1462. //
  1463. DoRecover(
  1464. Target,
  1465. TmpFile,
  1466. LogFile,
  1467. TargetName,
  1468. TmpName,
  1469. FileHeader.OffsetStatus2 - FileHeader.OffsetStatus1,
  1470. FileHeader.OffsetStatus1,
  1471. Action,
  1472. EventHandleLog
  1473. );
  1474. CloseHandle ( Target );
  1475. if ( TmpFile ){
  1476. CloseHandle( TmpFile );
  1477. }
  1478. } else {
  1479. //
  1480. // The header is not fully written. Nothing could have be done.
  1481. // Just delete the log file and we are done.
  1482. //
  1483. MarkFileForDelete( LogFile );
  1484. if (StatusBuffer) {
  1485. VirtualFree(
  1486. StatusBuffer,
  1487. 0,
  1488. MEM_RELEASE
  1489. );
  1490. }
  1491. LsapFreeLsaHeap(FileName);
  1492. }
  1493. LsapFreeLsaHeap(ReadBuffer);
  1494. CloseHandle( LogFile );
  1495. CloseHandle( VolumeHandle );
  1496. return;
  1497. }
  1498. NTSTATUS
  1499. ReadLogFile(
  1500. IN HANDLE LogFile,
  1501. OUT BYTE* ReadBuffer,
  1502. IN ULONG FirstCopy,
  1503. IN ULONG SecondCopy
  1504. )
  1505. /*++
  1506. Routine Description:
  1507. Read Status Log Information.
  1508. Arguments:
  1509. LogFile -- A handle to the log file
  1510. ReadBuffer -- Buffer for the output data.
  1511. FirstCopy -- Offset of first status information copy in the logfile.
  1512. SecondCopy -- Offset of second status information copy in the logfile.
  1513. Return Value:
  1514. The status of operation.
  1515. --*/
  1516. {
  1517. ULONG ReadBytes;
  1518. NTSTATUS Status;
  1519. IO_STATUS_BLOCK IoStatusBlock;
  1520. LARGE_INTEGER ByteOffset;
  1521. ULONG CheckSum;
  1522. BOOLEAN WrongCheckSum = FALSE;
  1523. //
  1524. // Write out the header sector
  1525. //
  1526. ByteOffset.QuadPart = (LONGLONG) FirstCopy;
  1527. ReadBytes = SecondCopy - FirstCopy;
  1528. Status = NtReadFile(
  1529. LogFile,
  1530. 0,
  1531. NULL,
  1532. NULL,
  1533. &IoStatusBlock,
  1534. ReadBuffer,
  1535. ReadBytes,
  1536. &ByteOffset,
  1537. NULL
  1538. );
  1539. if ( NT_SUCCESS(Status) ) {
  1540. //
  1541. // Check the integrity of the data
  1542. //
  1543. CheckSum = GetCheckSum( ReadBuffer, 2 * sizeof (ULONG) );
  1544. if ( CheckSum != *(ULONG *)( ReadBuffer + ReadBytes - sizeof (ULONG) )){
  1545. WrongCheckSum = TRUE;
  1546. }
  1547. }
  1548. if ( !NT_SUCCESS(Status) || WrongCheckSum ) {
  1549. ByteOffset.QuadPart = (LONGLONG) SecondCopy;
  1550. Status = NtReadFile(
  1551. LogFile,
  1552. 0,
  1553. NULL,
  1554. NULL,
  1555. &IoStatusBlock,
  1556. ReadBuffer,
  1557. ReadBytes,
  1558. &ByteOffset,
  1559. NULL
  1560. );
  1561. if ( NT_SUCCESS(Status) ) {
  1562. //
  1563. // Check the integrity of the data
  1564. //
  1565. CheckSum = GetCheckSum( ReadBuffer, 2 * sizeof (ULONG) );
  1566. if ( CheckSum != *(ULONG *)( ReadBuffer + ReadBytes - sizeof (ULONG) )){
  1567. //
  1568. // Both status copy are bad.
  1569. //
  1570. Status = STATUS_FILE_CORRUPT_ERROR;
  1571. }
  1572. }
  1573. }
  1574. return Status;
  1575. }
  1576. NTSTATUS
  1577. DoRecover(
  1578. IN HANDLE Target,
  1579. IN HANDLE TmpFile OPTIONAL,
  1580. IN HANDLE LogFile,
  1581. IN LPCWSTR TargetName,
  1582. IN LPCWSTR TmpName OPTIONAL,
  1583. IN ULONG StatusCopySize,
  1584. IN ULONG StatusStartOffset,
  1585. IN ULONG Action,
  1586. IN HANDLE EventHandleLog
  1587. )
  1588. /*++
  1589. Routine Description:
  1590. Do the real dirty recovery job here.
  1591. Arguments:
  1592. Target -- A handle to the target file or directory.
  1593. TmpFile -- A handle to the temp file if Target is a file.
  1594. LogFile -- A handle to the log file.
  1595. TargetName -- Target file name. This info is used for error log only.
  1596. TmpName -- Temp backup file name. This info is used for error log only.
  1597. StatusCopySize -- Log file status copy section size.
  1598. StatusStartOffset -- Offset of status copy in the log file.
  1599. Action -- The status to begin.
  1600. EventHandleLog -- Event log handle.
  1601. Return Value:
  1602. The status of operation.
  1603. --*/
  1604. {
  1605. NTSTATUS Status = STATUS_SUCCESS;
  1606. EFSP_OPERATION Operation = EncryptRecovering;
  1607. if ( ( BeginEncryptDir == Action ) || ( BeginDecryptDir == Action ) ){
  1608. //
  1609. // In both cases, we will do Decrypt on the directory
  1610. //
  1611. Status = DecryptDir( Target, TargetName );
  1612. if ( NT_SUCCESS(Status) ) {
  1613. //
  1614. // The operation was successful
  1615. //
  1616. if ( EventHandleLog ){
  1617. ReportEvent(
  1618. EventHandleLog,
  1619. EVENTLOG_INFORMATION_TYPE,
  1620. 0,
  1621. EFS_TARGET_RECOVERED,
  1622. NULL,
  1623. 1,
  1624. 0,
  1625. (LPCTSTR*) &TargetName,
  1626. NULL
  1627. );
  1628. }
  1629. MarkFileForDelete( LogFile );
  1630. } else {
  1631. //
  1632. // EFS driver might not be loaded. Log the information.
  1633. //
  1634. if ( EventHandleLog ){
  1635. ReportEvent(
  1636. EventHandleLog,
  1637. EVENTLOG_ERROR_TYPE,
  1638. 0,
  1639. EFS_DRIVER_MISSING,
  1640. NULL,
  1641. 1,
  1642. 0,
  1643. (LPCTSTR*) &TargetName,
  1644. NULL
  1645. );
  1646. }
  1647. }
  1648. } else {
  1649. //
  1650. // File operations
  1651. //
  1652. switch ( Action ) {
  1653. case EncryptionMessup:
  1654. //
  1655. // The original file is messed up due to the unknown reason.
  1656. // Operation required,
  1657. // Same as EncryptTmpFileWritten.
  1658. //
  1659. Operation = EncryptRecovering;
  1660. // ***** Fall through intended *****
  1661. case DecryptTmpFileWritten:
  1662. //
  1663. // Temp file is created and written during the decryption. The original file is probably
  1664. // damaged. Operation required,
  1665. // Same as the EncryptTmpFileWritten. The file will end up as plain text.
  1666. //
  1667. if ( DecryptTmpFileWritten == Action ){
  1668. Operation = DecryptRecovering;
  1669. }
  1670. //
  1671. // ***** Fall through intended *****
  1672. //
  1673. case EncryptTmpFileWritten:
  1674. if ( EncryptTmpFileWritten == Action ){
  1675. Operation = EncryptRecovering;
  1676. }
  1677. //
  1678. // Temp file is created and written during the encryption. The original file is probably
  1679. // damaged. Operation required,
  1680. // FSCTL decrypt each stream, copy the data back to the original file. Log file
  1681. // will be updated to BeginEncryptFile after all the streams are copied back. Then
  1682. // continue the case indicated in BeginEncryptFile.
  1683. //
  1684. if ( !TmpFile ){
  1685. //
  1686. // Temp backup not existed or open failed, we can do nothing for this.
  1687. // Log the error information and quit.
  1688. //
  1689. if ( EventHandleLog ){
  1690. LPCWSTR lpStrings[2];
  1691. lpStrings[1] = TargetName;
  1692. lpStrings[0] = TmpName;
  1693. ReportEvent(
  1694. EventHandleLog,
  1695. EVENTLOG_ERROR_TYPE,
  1696. 0,
  1697. EFS_TMPFILE_MISSING,
  1698. NULL,
  1699. 2,
  1700. 4,
  1701. &lpStrings[0],
  1702. &Status
  1703. );
  1704. }
  1705. return STATUS_NO_SUCH_FILE;
  1706. }
  1707. Status = RestoreTarget(
  1708. Target,
  1709. TmpFile,
  1710. TargetName,
  1711. TmpName,
  1712. EventHandleLog,
  1713. Operation
  1714. );
  1715. if ( NT_SUCCESS(Status) ) {
  1716. WriteLogFile(
  1717. LogFile,
  1718. StatusCopySize,
  1719. StatusStartOffset,
  1720. BeginEncryptFile
  1721. );
  1722. } else {
  1723. return Status;
  1724. }
  1725. // ***** Fall through intended *****
  1726. case DecryptionDone:
  1727. //
  1728. // All the streams are marked decrypted. The file might still have the flag set.
  1729. // Operation required,
  1730. // Same as BeginEncryptFile.
  1731. //
  1732. // ***** Fall through intended *****
  1733. case EncryptionBackout:
  1734. //
  1735. // Encryption failed but we managed the original streams back. The file might
  1736. // be in a transition status.
  1737. // Operation required,
  1738. // Same as BeginEncryptFile.
  1739. //
  1740. // ***** Fall through intended *****
  1741. case BeginEncryptFile:
  1742. //
  1743. // File encryption just begin. Original file is not changed.
  1744. // Operation required,
  1745. // Remove the $EFS, remove the tempfile if existed and remove the log file.
  1746. //
  1747. Status = SendGenFsctl(
  1748. Target,
  1749. EFS_DECRYPT_FILE,
  1750. EFS_DECRYPT_FILE,
  1751. EFS_SET_ENCRYPT,
  1752. FSCTL_SET_ENCRYPTION
  1753. );
  1754. if ( NT_SUCCESS(Status) ) {
  1755. if ( TmpFile ){
  1756. MarkFileForDelete( TmpFile );
  1757. }
  1758. MarkFileForDelete( LogFile );
  1759. if ( EventHandleLog ){
  1760. ReportEvent(
  1761. EventHandleLog,
  1762. EVENTLOG_INFORMATION_TYPE,
  1763. 0,
  1764. EFS_TARGET_RECOVERED,
  1765. NULL,
  1766. 1,
  1767. 0,
  1768. &TargetName,
  1769. NULL
  1770. );
  1771. }
  1772. } else {
  1773. //
  1774. // EFS driver may not be loaded. Write the log info.
  1775. //
  1776. if ( EventHandleLog ){
  1777. ReportEvent(
  1778. EventHandleLog,
  1779. EVENTLOG_ERROR_TYPE,
  1780. 0,
  1781. EFS_DRIVER_MISSING,
  1782. NULL,
  1783. 1,
  1784. 0,
  1785. &TargetName,
  1786. NULL
  1787. );
  1788. }
  1789. }
  1790. break;
  1791. case BeginDecryptFile:
  1792. //
  1793. // File decryption just begin. Original file is not changed.
  1794. // Operation required,
  1795. // Set the transition status to normal, remove the tempfile if existed and
  1796. // remove the log file.
  1797. //
  1798. // ***** Fall through intended *****
  1799. case EncryptionDone:
  1800. //
  1801. // All the streams were encrypted. The original file might be in transition status.
  1802. // Operation required,
  1803. // FSCTL to set the transition status to normal. Update the log status to
  1804. // EncryptionSrcDone. Continue to EncryptionSrcDone.
  1805. //
  1806. Status = SendGenFsctl(
  1807. Target,
  1808. 0,
  1809. 0,
  1810. EFS_ENCRYPT_DONE,
  1811. FSCTL_ENCRYPTION_FSCTL_IO
  1812. );
  1813. if ( !NT_SUCCESS(Status) ) {
  1814. //
  1815. // EFS driver might not be loaded. Log error.
  1816. //
  1817. if ( EventHandleLog ){
  1818. ReportEvent(
  1819. EventHandleLog,
  1820. EVENTLOG_ERROR_TYPE,
  1821. 0,
  1822. EFS_DRIVER_MISSING,
  1823. NULL,
  1824. 1,
  1825. 0,
  1826. &TargetName,
  1827. NULL
  1828. );
  1829. }
  1830. return Status;
  1831. }
  1832. // ***** Fall through intended *****
  1833. case EncryptionSrcDone:
  1834. //
  1835. // The original file is encrypted successfully. The temp file might still be left.
  1836. // Operation required,
  1837. // Remove the temp file if existed and remove the log file.
  1838. //
  1839. if ( TmpFile ){
  1840. MarkFileForDelete( TmpFile );
  1841. }
  1842. MarkFileForDelete( LogFile );
  1843. if ( EventHandleLog ){
  1844. ReportEvent(
  1845. EventHandleLog,
  1846. EVENTLOG_INFORMATION_TYPE,
  1847. 0,
  1848. EFS_TARGET_RECOVERED,
  1849. NULL,
  1850. 1,
  1851. 0,
  1852. &TargetName,
  1853. NULL
  1854. );
  1855. }
  1856. break;
  1857. default:
  1858. //
  1859. // Not our log file or tempered by someone.
  1860. // Write to the log to notify the user.
  1861. //
  1862. Status = STATUS_FILE_CORRUPT_ERROR;
  1863. break;
  1864. }
  1865. }
  1866. return Status;
  1867. }
  1868. NTSTATUS
  1869. DecryptDir(
  1870. IN HANDLE Target,
  1871. IN LPCWSTR TargetName
  1872. )
  1873. /*++
  1874. Routine Description:
  1875. Decrypt a directory.
  1876. Arguments:
  1877. Target -- A handle to the target file or directory.
  1878. TargetName -- Target file name. This info is used for error log only.
  1879. Return Value:
  1880. The status of operation.
  1881. --*/
  1882. {
  1883. NTSTATUS Status = STATUS_SUCCESS;
  1884. Status = SendGenFsctl(
  1885. Target,
  1886. EFS_DECRYPT_STREAM,
  1887. EFS_DECRYPT_DIRSTR,
  1888. EFS_SET_ENCRYPT,
  1889. FSCTL_SET_ENCRYPTION
  1890. );
  1891. if ( NT_SUCCESS( Status ) ){
  1892. Status = SendGenFsctl(
  1893. Target,
  1894. EFS_DECRYPT_FILE,
  1895. EFS_DECRYPT_DIRFILE,
  1896. EFS_SET_ENCRYPT,
  1897. FSCTL_SET_ENCRYPTION
  1898. );
  1899. }
  1900. return Status;
  1901. }
  1902. NTSTATUS
  1903. RestoreTarget(
  1904. IN HANDLE Target,
  1905. IN HANDLE TmpFile,
  1906. IN LPCWSTR TargetName,
  1907. IN LPCWSTR TmpName,
  1908. IN HANDLE EventHandleLog,
  1909. EFSP_OPERATION Operation
  1910. )
  1911. /*++
  1912. Routine Description:
  1913. Copy all the streams in the temp backup file to the original target file.
  1914. Arguments:
  1915. Target -- A handle to the target file or directory.
  1916. TmpFile -- A handle to the temp file if Target is a file.
  1917. TargetName -- Target file name. This info is used for error log only.
  1918. TmpName -- Temp backup file name. This info is used for error log only.
  1919. Operation -- Indicate if encryption or decryption was tried.
  1920. Return Value:
  1921. The status of operation.
  1922. --*/
  1923. {
  1924. NTSTATUS Status;
  1925. DWORD hResult;
  1926. PFILE_STREAM_INFORMATION StreamInfoBase = NULL;
  1927. ULONG StreamInfoSize = 0;
  1928. ULONG StreamCount = 0;
  1929. PEFS_STREAM_SIZE StreamSizes;
  1930. PHANDLE StreamHandles;
  1931. PUNICODE_STRING StreamNames;
  1932. Status = GetStreamInformation(
  1933. TmpFile,
  1934. &StreamInfoBase,
  1935. &StreamInfoSize
  1936. );
  1937. if ( NT_SUCCESS( Status ) ){
  1938. hResult = OpenFileStreams(
  1939. TmpFile,
  1940. FILE_SHARE_DELETE, // have to share with delete-ers, since the main stream is open for delete
  1941. OPEN_FOR_FTR,
  1942. StreamInfoBase,
  1943. FILE_READ_DATA | FILE_WRITE_DATA | FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES | SYNCHRONIZE,
  1944. FILE_OPEN,
  1945. FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_REPARSE_POINT,
  1946. NULL,
  1947. &StreamNames, // Free this but not the contents!
  1948. &StreamHandles, // Free this
  1949. &StreamSizes, // Free this
  1950. &StreamCount
  1951. );
  1952. if (hResult == ERROR_SUCCESS) {
  1953. ULONG FsInputDataSize;
  1954. PUCHAR FsInputData;
  1955. PHANDLE TargetStreamHandles;
  1956. LONG ArrIndex;
  1957. TargetStreamHandles = ( PHANDLE ) LsapAllocateLsaHeap(StreamCount * sizeof (HANDLE));
  1958. if ( TargetStreamHandles ){
  1959. //
  1960. // Open streams at the original target file
  1961. //
  1962. for ( ArrIndex = 0; ArrIndex < (LONG) StreamCount; ArrIndex++){
  1963. if ( StreamHandles[ArrIndex] == TmpFile ){
  1964. TargetStreamHandles[ArrIndex] = Target;
  1965. } else {
  1966. OBJECT_ATTRIBUTES Obja;
  1967. IO_STATUS_BLOCK IoStatusBlock;
  1968. InitializeObjectAttributes(
  1969. &Obja,
  1970. &StreamNames[ArrIndex],
  1971. 0,
  1972. Target,
  1973. NULL
  1974. );
  1975. Status = NtCreateFile(
  1976. &TargetStreamHandles[ArrIndex],
  1977. GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE,
  1978. &Obja,
  1979. &IoStatusBlock,
  1980. NULL,
  1981. 0,
  1982. 0,
  1983. FILE_OPEN_IF,
  1984. FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_REPARSE_POINT,
  1985. NULL,
  1986. 0
  1987. );
  1988. if (!NT_SUCCESS( Status )){
  1989. if ( EventHandleLog ){
  1990. ReportEvent(
  1991. EventHandleLog,
  1992. EVENTLOG_ERROR_TYPE,
  1993. 0,
  1994. EFS_TARGET_STREAM_OPEN_ERROR,
  1995. NULL,
  1996. 1,
  1997. 4,
  1998. &TargetName,
  1999. &Status
  2000. );
  2001. }
  2002. break;
  2003. }
  2004. }
  2005. }
  2006. if ( NT_SUCCESS( Status ) ){
  2007. //
  2008. // Adjust ArrIndex for clean up
  2009. //
  2010. ArrIndex--;
  2011. //
  2012. // Make a FSCTL request input data block
  2013. //
  2014. FsInputDataSize = 7 * sizeof( ULONG ) + 2 * sizeof(DriverSessionKey);
  2015. FsInputData = (PUCHAR) LsapAllocateLsaHeap(FsInputDataSize);
  2016. if ( FsInputData ){
  2017. BOOLEAN CleanupSuccessful;
  2018. ( VOID )GetDecryptFsInput(
  2019. Target,
  2020. FsInputData,
  2021. &FsInputDataSize
  2022. );
  2023. hResult = CopyFileStreams(
  2024. StreamHandles, // handles to streams on the backup file
  2025. TargetStreamHandles, // Handles to the streams on the original file
  2026. StreamCount, // number of streams
  2027. StreamSizes, // sizes of streams
  2028. Operation, // mark StreamHandles as Decrypted before copy
  2029. FsInputData, // FSCTL input data
  2030. FsInputDataSize, // FSCTL input data size
  2031. &CleanupSuccessful
  2032. );
  2033. LsapFreeLsaHeap( FsInputData );
  2034. if ( hResult != ERROR_SUCCESS ){
  2035. if ( EventHandleLog ){
  2036. ReportEvent(
  2037. EventHandleLog,
  2038. EVENTLOG_ERROR_TYPE,
  2039. 0,
  2040. EFS_STREAM_COPY_ERROR,
  2041. NULL,
  2042. 1,
  2043. 4,
  2044. &TargetName,
  2045. &hResult
  2046. );
  2047. }
  2048. Status = STATUS_UNSUCCESSFUL;
  2049. }
  2050. } else {
  2051. //
  2052. // Out of memory. Almost impossible during LSA init.
  2053. //
  2054. ASSERT(FALSE);
  2055. Status = STATUS_INSUFFICIENT_RESOURCES;
  2056. }
  2057. }
  2058. //
  2059. // Clean up TargetStreamHandles at the target.
  2060. //
  2061. while (ArrIndex >= 0){
  2062. if ( TargetStreamHandles[ArrIndex] != Target ){
  2063. CloseHandle(TargetStreamHandles[ArrIndex]);
  2064. }
  2065. ArrIndex--;
  2066. }
  2067. LsapFreeLsaHeap( TargetStreamHandles );
  2068. }
  2069. //
  2070. // Clean up StreamHandles and etc.
  2071. //
  2072. for (ArrIndex = 0; ArrIndex< (LONG) StreamCount ; ArrIndex++) {
  2073. if ( StreamHandles[ArrIndex] != TmpFile){
  2074. NtClose( StreamHandles[ArrIndex] );
  2075. }
  2076. }
  2077. LsapFreeLsaHeap( StreamHandles);
  2078. LsapFreeLsaHeap( StreamNames);
  2079. LsapFreeLsaHeap( StreamSizes);
  2080. } else {
  2081. //
  2082. // Not all the requested streams could be opened.
  2083. // Write the log info.
  2084. //
  2085. if ( EventHandleLog ){
  2086. LPCWSTR lpStrings[2];
  2087. lpStrings[1] = TargetName;
  2088. lpStrings[0] = TmpName;
  2089. ReportEvent(
  2090. EventHandleLog,
  2091. EVENTLOG_ERROR_TYPE,
  2092. 0,
  2093. EFS_TMP_STREAM_OPEN_ERROR,
  2094. NULL,
  2095. 2,
  2096. 4,
  2097. &lpStrings[0],
  2098. &hResult
  2099. );
  2100. }
  2101. Status = STATUS_UNSUCCESSFUL;
  2102. }
  2103. LsapFreeLsaHeap( StreamInfoBase );
  2104. } else {
  2105. //
  2106. // Stream info cannot be got. Write LOG info.
  2107. //
  2108. if ( EventHandleLog ){
  2109. LPCWSTR lpStrings[2];
  2110. lpStrings[1] = TargetName;
  2111. lpStrings[0] = TmpName;
  2112. ReportEvent(
  2113. EventHandleLog,
  2114. EVENTLOG_ERROR_TYPE,
  2115. 0,
  2116. EFS_TMP_STREAM_INFO_ERROR,
  2117. NULL,
  2118. 2,
  2119. 4,
  2120. &lpStrings[0],
  2121. &Status
  2122. );
  2123. }
  2124. }
  2125. return Status;
  2126. }
  2127. BOOL
  2128. ParseRecoveryCertificate(
  2129. IN PEFS_PUBLIC_KEY_INFO pPublicKeyInfo,
  2130. OUT PBYTE * pbHash,
  2131. OUT PDWORD cbHash,
  2132. OUT PBYTE * pbPublicKey,
  2133. OUT PDWORD cbPublicKey,
  2134. OUT LPWSTR * lpDisplayInfo,
  2135. OUT PCCERT_CONTEXT * pCertContext,
  2136. OUT PSID * pSid
  2137. )
  2138. /*++
  2139. Routine Description:
  2140. This routine takes a certificate passed in the recovery policy and
  2141. extracts the interesting information.
  2142. Arguments:
  2143. pPublicKeyInfo - Takes the public key info structure from the
  2144. recovery policy.
  2145. pbHash - Returns the hash of the passed certificate.
  2146. cbHash - Returns the lengh in bytes of the returned hash.
  2147. pbPublicKey - Returns a pointer to the public key blob of the certificate.
  2148. cbPublicKey - Returns the length in bytes of the public key.
  2149. lpDisplayInfo - Returns display information about the certificate.
  2150. pCertContext - Cert context for the passed certificate.
  2151. pSid - Returns SID of the recovery agent
  2152. Return Value:
  2153. TRUE on success, FALSE on failure. Call GetLastError() for more details.
  2154. --*/
  2155. {
  2156. //
  2157. // Get the certificate out of the public key info structure
  2158. //
  2159. PEFS_PUBLIC_KEY_INFO pAlignedPublicKeyInfo;
  2160. BOOLEAN freeAlignedInfo;
  2161. DWORD rc = ERROR_SUCCESS;
  2162. rc = EfsAlignBlock(
  2163. pPublicKeyInfo,
  2164. (PVOID *)&pAlignedPublicKeyInfo,
  2165. &freeAlignedInfo
  2166. );
  2167. if (!pAlignedPublicKeyInfo) {
  2168. //
  2169. // OOM. Treat it as not current.
  2170. //
  2171. rc = ERROR_NOT_ENOUGH_MEMORY;
  2172. return FALSE;
  2173. }
  2174. ASSERT( pAlignedPublicKeyInfo->KeySourceTag == EfsCertificate );
  2175. //
  2176. // Initialize OUT parameters
  2177. //
  2178. *pbHash = NULL;
  2179. *pbPublicKey = NULL;
  2180. *lpDisplayInfo = NULL;
  2181. *pCertContext = NULL;
  2182. *pSid = NULL;
  2183. PBYTE pbCert = (PBYTE)OFFSET_TO_POINTER(CertificateInfo.Certificate, pAlignedPublicKeyInfo);
  2184. DWORD cbCert = pAlignedPublicKeyInfo->CertificateInfo.CertificateLength;
  2185. *pCertContext = CertCreateCertificateContext(
  2186. CRYPT_ASN_ENCODING,
  2187. (const PBYTE)pbCert,
  2188. cbCert);
  2189. if (*pCertContext) {
  2190. PCERT_INFO pCertInfo = (*pCertContext)->pCertInfo;
  2191. CERT_PUBLIC_KEY_INFO * pSubjectPublicKeyInfo = &pCertInfo->SubjectPublicKeyInfo;
  2192. CRYPT_BIT_BLOB * PublicKey = &pSubjectPublicKeyInfo->PublicKey;
  2193. *cbPublicKey = 0;
  2194. if (CryptDecodeObject(
  2195. CRYPT_ASN_ENCODING,
  2196. RSA_CSP_PUBLICKEYBLOB,
  2197. PublicKey->pbData,
  2198. PublicKey->cbData,
  2199. 0,
  2200. NULL,
  2201. cbPublicKey
  2202. )) {
  2203. if (*pbPublicKey = (PBYTE)LsapAllocateLsaHeap( *cbPublicKey )) {
  2204. if (CryptDecodeObject(
  2205. CRYPT_ASN_ENCODING,
  2206. RSA_CSP_PUBLICKEYBLOB,
  2207. PublicKey->pbData,
  2208. PublicKey->cbData,
  2209. 0,
  2210. *pbPublicKey,
  2211. cbPublicKey
  2212. )) {
  2213. //
  2214. // Get the certificate hash
  2215. //
  2216. *cbHash = 0;
  2217. if (CertGetCertificateContextProperty(
  2218. *pCertContext,
  2219. CERT_HASH_PROP_ID,
  2220. NULL,
  2221. cbHash
  2222. )) {
  2223. *pbHash = (PBYTE)LsapAllocateLsaHeap( *cbHash );
  2224. if (*pbHash) {
  2225. if (CertGetCertificateContextProperty(
  2226. *pCertContext,
  2227. CERT_HASH_PROP_ID,
  2228. *pbHash,
  2229. cbHash
  2230. )) {
  2231. //
  2232. // Get the display information
  2233. //
  2234. *lpDisplayInfo = EfspGetCertDisplayInformation( *pCertContext );
  2235. if (*lpDisplayInfo == NULL) {
  2236. rc = GetLastError();
  2237. }
  2238. //
  2239. // Try to get the recovery agent SID
  2240. // This info is not very important. If we fail, we should continue.
  2241. //
  2242. if (pAlignedPublicKeyInfo->PossibleKeyOwner) {
  2243. DWORD SidLength;
  2244. PSID RecSid = (PSID) OFFSET_TO_POINTER( PossibleKeyOwner, pAlignedPublicKeyInfo );
  2245. SidLength = GetLengthSid(RecSid);
  2246. *pSid = (PSID)LsapAllocateLsaHeap( SidLength );
  2247. if (*pSid) {
  2248. RtlCopyMemory( *pSid, RecSid, SidLength );
  2249. }
  2250. }
  2251. } else {
  2252. rc = GetLastError();
  2253. }
  2254. } else {
  2255. rc = ERROR_NOT_ENOUGH_MEMORY;
  2256. }
  2257. } else {
  2258. rc = GetLastError();
  2259. }
  2260. } else {
  2261. rc = GetLastError();
  2262. }
  2263. } else {
  2264. rc = ERROR_NOT_ENOUGH_MEMORY;
  2265. }
  2266. } else {
  2267. rc = GetLastError();
  2268. }
  2269. } else {
  2270. rc = GetLastError();
  2271. }
  2272. if (freeAlignedInfo) {
  2273. LsapFreeLsaHeap( pAlignedPublicKeyInfo );
  2274. }
  2275. if (rc != ERROR_SUCCESS) {
  2276. //
  2277. // Free the stuff we were going to return
  2278. //
  2279. if (*pbHash != NULL) {
  2280. LsapFreeLsaHeap( *pbHash );
  2281. *pbHash = NULL;
  2282. }
  2283. if (*pbPublicKey != NULL) {
  2284. LsapFreeLsaHeap( *pbPublicKey );
  2285. *pbPublicKey = NULL;
  2286. }
  2287. if (*lpDisplayInfo != NULL) {
  2288. LsapFreeLsaHeap( *lpDisplayInfo );
  2289. *lpDisplayInfo = NULL;
  2290. }
  2291. if (*pCertContext != NULL) {
  2292. CertFreeCertificateContext( *pCertContext );
  2293. *pCertContext = NULL;
  2294. }
  2295. if (*pSid != NULL) {
  2296. LsapFreeLsaHeap( *pSid );
  2297. *pSid = NULL;
  2298. }
  2299. }
  2300. SetLastError( rc );
  2301. return( rc == ERROR_SUCCESS );
  2302. }