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.

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