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.

3723 lines
115 KiB

  1. /*++
  2. (c) 1998 Seagate Software, Inc. All rights reserved.
  3. Module Name:
  4. fsafltr.cpp
  5. Abstract:
  6. This class represents a file system filter for NTFS 5.0.
  7. Author:
  8. Chuck Bardeen [cbardeen] 12-Feb-1997
  9. Revision History:
  10. --*/
  11. #include "stdafx.h"
  12. extern "C" {
  13. #include "devioctl.h"
  14. #include <winerror.h>
  15. #include "aclapi.h"
  16. // #define MAC_SUPPORT // NOTE: You must define MAC_SUPPORT in fsaftrcl.cpp to enable all the code
  17. #ifdef MAC_SUPPORT
  18. #include <macfile.h>
  19. #endif
  20. }
  21. #define WSB_TRACE_IS WSB_TRACE_BIT_FSA
  22. #include "wsb.h"
  23. #include "HsmConn.h"
  24. #include "job.h"
  25. #include "fsa.h"
  26. #include "fsafltr.h"
  27. #include "fsaitemr.h"
  28. #ifdef MAC_SUPPORT
  29. extern HANDLE FsaDllSfm;
  30. extern BOOL FsaMacSupportInstalled;
  31. extern "C" {
  32. typedef DWORD (*AdminConnect) (LPWSTR lpwsServerName, PAFP_SERVER_HANDLE phAfpServer);
  33. extern AdminConnect pAfpAdminConnect;
  34. typedef VOID (*AdminDisconnect) (AFP_SERVER_HANDLE hAfpServer);
  35. extern AdminDisconnect pAfpAdminDisconnect;
  36. typedef VOID (*AdminBufferFree) (PVOID pBuffer);
  37. extern AdminBufferFree pAfpAdminBufferFree;
  38. typedef DWORD (*AdminSessionEnum) (AFP_SERVER_HANDLE hAfpServer, LPBYTE *lpbBuffer,
  39. DWORD dwPrefMaxLen, LPDWORD lpdwEntriesRead, LPDWORD lpdwTotalEntries,
  40. LPDWORD lpdwResumeHandle);
  41. extern AdminSessionEnum pAfpAdminSessionEnum;
  42. }
  43. #endif
  44. DWORD FsaIoctlThread(void *pFilterInterface);
  45. DWORD FsaPipeThread(void *pFilterInterface);
  46. HRESULT
  47. CFsaFilter::Cancel(
  48. void
  49. )
  50. /*++
  51. Implements:
  52. IFsaFilter::Cancel().
  53. --*/
  54. {
  55. HRESULT hr = S_OK;
  56. HSM_JOB_STATE oldState;
  57. WsbTraceIn(OLESTR("CFsaFilter::Cancel"), OLESTR(""));
  58. try {
  59. WsbAffirm((HSM_JOB_STATE_ACTIVE == m_state), E_UNEXPECTED);
  60. oldState = m_state;
  61. m_state = HSM_JOB_STATE_CANCELLING;
  62. try {
  63. // TBD - Do whatever it takes to cancel
  64. WsbAssertHr(E_NOTIMPL);
  65. m_state = HSM_JOB_STATE_CANCELLED;
  66. } WsbCatchAndDo(hr, m_state = oldState;);
  67. } WsbCatch(hr);
  68. WsbTraceOut(OLESTR("CFsaFilter::Cancel"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  69. return(hr);
  70. }
  71. HRESULT
  72. CFsaFilter::CancelRecall(
  73. IN IFsaFilterRecall* pRecall
  74. )
  75. /*++
  76. Implements:
  77. IFsaFilter::CancelRecall().
  78. --*/
  79. {
  80. HRESULT hr = S_OK;
  81. CComPtr<IFsaFilterRecallPriv> pRecallPriv;
  82. WsbTraceIn(OLESTR("CFsaFilter::CancelRecall"), OLESTR(""));
  83. try {
  84. WsbAssert(pRecall != 0, E_POINTER);
  85. // Get the private interface and tell the recall to cancel itself.
  86. WsbAffirmHr(pRecall->QueryInterface(IID_IFsaFilterRecallPriv, (void**) &pRecallPriv));
  87. WsbAffirmHr(pRecallPriv->Cancel());
  88. } WsbCatch(hr);
  89. WsbTraceOut(OLESTR("CFsaFilter::CancelRecall"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  90. return(hr);
  91. }
  92. HRESULT
  93. CFsaFilter::CompareTo(
  94. IN IUnknown* pUnknown,
  95. OUT SHORT* pResult
  96. )
  97. /*++
  98. Implements:
  99. IWsbCollectable::CompareTo().
  100. --*/
  101. {
  102. HRESULT hr = S_OK;
  103. CComPtr<IFsaFilter> pFilter;
  104. WsbTraceIn(OLESTR("CFsaFilter::CompareTo"), OLESTR(""));
  105. try {
  106. // Did they give us a valid item to compare to?
  107. WsbAssert(0 != pUnknown, E_POINTER);
  108. // We need the IWsbBool interface to get the value of the object.
  109. WsbAffirmHr(pUnknown->QueryInterface(IID_IFsaFilter, (void**) &pFilter));
  110. // Compare the rules.
  111. hr = CompareToIFilter(pFilter, pResult);
  112. } WsbCatch(hr);
  113. WsbTraceOut(OLESTR("CFsaFilter::CompareTo"), OLESTR("hr = <%ls>, result = <%ls>"), WsbHrAsString(hr), WsbPtrToShortAsString(pResult));
  114. return(hr);
  115. }
  116. HRESULT
  117. CFsaFilter::CompareToIdentifier(
  118. IN GUID id,
  119. OUT SHORT* pResult
  120. )
  121. /*++
  122. Implements:
  123. IFsaFilter::CompareToIdentifier().
  124. --*/
  125. {
  126. HRESULT hr = S_OK;
  127. SHORT aResult = 0;
  128. WsbTraceIn(OLESTR("CFsaFilter::CompareToIdentifier"), OLESTR(""));
  129. try {
  130. aResult = WsbSign( memcmp(&m_id, &id, sizeof(GUID)) );
  131. if (0 != aResult) {
  132. hr = S_FALSE;
  133. }
  134. if (0 != pResult) {
  135. *pResult = aResult;
  136. }
  137. } WsbCatch(hr);
  138. WsbTraceOut(OLESTR("CFsaFilter::CompareToIdentifier"), OLESTR("hr = <%ls>, result = <%d>"), WsbHrAsString(hr), aResult);
  139. return(hr);
  140. }
  141. HRESULT
  142. CFsaFilter::CompareToIFilter(
  143. IN IFsaFilter* pFilter,
  144. OUT SHORT* pResult
  145. )
  146. /*++
  147. Implements:
  148. IFsaFilter::CompareToIFilter().
  149. --*/
  150. {
  151. HRESULT hr = S_OK;
  152. GUID id;
  153. WsbTraceIn(OLESTR("CFsaFilter::CompareToIFilter"), OLESTR(""));
  154. try {
  155. // Did they give us a valid item to compare to?
  156. WsbAssert(0 != pFilter, E_POINTER);
  157. WsbAffirmHr(pFilter->GetIdentifier(&id));
  158. // Either compare the name or the id.
  159. hr = CompareToIdentifier(id, pResult);
  160. } WsbCatch(hr);
  161. WsbTraceOut(OLESTR("CFsaFilter::CompareToIFilter"), OLESTR("hr = <%ls>, result = <%ls>"), WsbHrAsString(hr), WsbPtrToShortAsString(pResult));
  162. return(hr);
  163. }
  164. HRESULT
  165. CFsaFilter::CleanupClients(
  166. void
  167. )
  168. /*++
  169. Implements:
  170. CFsaFilter::CleanupClients()
  171. --*/
  172. {
  173. HRESULT hr = S_OK;
  174. CComPtr<IFsaFilterClient> pClient;
  175. CComPtr<IWsbEnum> pEnum;
  176. FILETIME now, last;
  177. LARGE_INTEGER tNow, tLast;
  178. WsbTraceIn(OLESTR("CFsaFilter::CleanupClients"), OLESTR(""));
  179. EnterCriticalSection(&m_clientLock);
  180. try {
  181. WsbAffirmHr(m_pClients->Enum(&pEnum));
  182. hr = pEnum->First(IID_IFsaFilterClient, (void**) &pClient);
  183. while (S_OK == hr) {
  184. GetSystemTimeAsFileTime(&now);
  185. tNow.LowPart = now.dwLowDateTime;
  186. tNow.HighPart = now.dwHighDateTime;
  187. WsbAffirmHr(pClient->GetLastRecallTime(&last));
  188. tLast.LowPart = last.dwLowDateTime;
  189. tLast.HighPart = last.dwHighDateTime;
  190. //
  191. // Get the time (in 100 nano-second units)
  192. // from the end of the last recall until now.
  193. //
  194. if (tLast.QuadPart != 0) {
  195. tNow.QuadPart -= tLast.QuadPart;
  196. //
  197. // Convert to seconds and check against the expiration time
  198. //
  199. tNow.QuadPart /= (LONGLONG) 10000000;
  200. if (tNow.QuadPart > (LONGLONG) FSA_CLIENT_EXPIRATION_TIME) {
  201. //
  202. // This client structure is old - blow it away
  203. //
  204. WsbTrace(OLESTR("CFsaFilter::CleanupClients - cleaning up old client (%ls)\n"),
  205. WsbLonglongAsString(tNow.QuadPart));
  206. m_pClients->RemoveAndRelease(pClient);
  207. pClient = NULL;
  208. WsbAffirmHr(pEnum->Reset());
  209. }
  210. }
  211. pClient = NULL;
  212. hr = pEnum->Next(IID_IFsaFilterClient, (void**) &pClient);
  213. }
  214. if (hr == WSB_E_NOTFOUND) {
  215. hr = S_OK;
  216. }
  217. } WsbCatch(hr);
  218. LeaveCriticalSection(&m_clientLock);
  219. WsbTraceOut(OLESTR("CFsaFilter::CleanupClients"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  220. return(hr);
  221. }
  222. HRESULT
  223. CFsaFilter::DeleteRecall(
  224. IN IFsaFilterRecall* pRecall
  225. )
  226. /*++
  227. Implements:
  228. IFsaFilter::DeleteRecall().
  229. --*/
  230. {
  231. HRESULT hr = S_OK;
  232. CComPtr<IFsaFilterRecallPriv> pRecallPriv;
  233. WsbTraceIn(OLESTR("CFsaFilter::DeleteRecall"), OLESTR(""));
  234. try {
  235. ULONG numEnt;
  236. WsbAssert(pRecall != 0, E_POINTER);
  237. // Delete the request.
  238. WsbAffirmHr(pRecall->QueryInterface(IID_IFsaFilterRecallPriv, (void**) &pRecallPriv));
  239. WsbAffirmHr(pRecallPriv->Delete());
  240. // Remove it from our collection.
  241. EnterCriticalSection(&m_recallLock);
  242. m_pRecalls->RemoveAndRelease(pRecall);
  243. LeaveCriticalSection(&m_recallLock);
  244. m_pRecalls->GetEntries(&numEnt);
  245. WsbTrace(OLESTR("CFsaFilter::DeleteRecall: Recall queue has %u entries after delete.\n"),
  246. numEnt);
  247. } WsbCatch(hr);
  248. WsbTraceOut(OLESTR("CFsaFilter::DeleteRecall"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  249. return(hr);
  250. }
  251. HRESULT
  252. CFsaFilter::EnumRecalls(
  253. OUT IWsbEnum** ppEnum
  254. )
  255. /*++
  256. Implements:
  257. IFsaFilter::EnumRecalls().
  258. --*/
  259. {
  260. HRESULT hr = S_OK;
  261. try {
  262. WsbAssert(0 != ppEnum, E_POINTER);
  263. EnterCriticalSection(&m_recallLock);
  264. hr = m_pRecalls->Enum(ppEnum);
  265. LeaveCriticalSection(&m_recallLock);
  266. WsbAffirmHr(hr);
  267. } WsbCatch(hr);
  268. return(hr);
  269. }
  270. HRESULT
  271. CFsaFilter::FinalConstruct(
  272. void
  273. )
  274. /*++
  275. Implements:
  276. CComObjectRoot::FinalConstruct().
  277. --*/
  278. {
  279. HRESULT hr = S_OK;
  280. try {
  281. m_bCritSecCreated = FALSE;
  282. //
  283. // These are the default parameters.
  284. // The max recalls and admin exemption setting are configurable via the admin gui.
  285. //
  286. m_minRecallInterval = 10;
  287. m_maxRecallBuffers = RP_MAX_RECALL_BUFFERS;
  288. m_maxRecalls = RP_DEFAULT_RUNAWAY_RECALL_LIMIT;
  289. m_exemptAdmin = FALSE; // By default admin is NOT exempt
  290. m_ioctlHandle = INVALID_HANDLE_VALUE;
  291. m_pipeHandle = INVALID_HANDLE_VALUE;
  292. m_terminateEvent = NULL;
  293. m_pipeThread = NULL;
  294. m_ioctlThread = NULL;
  295. m_pFsaServer = NULL;
  296. WsbAffirmHr(CWsbCollectable::FinalConstruct());
  297. WsbAffirmHr(CoCreateGuid(&m_id));
  298. m_state = HSM_JOB_STATE_IDLE;
  299. //
  300. // Start out enabled
  301. //
  302. m_isEnabled = TRUE;
  303. // Initialize critical sections
  304. WsbAffirmStatus(InitializeCriticalSectionAndSpinCount(&m_clientLock, 0));
  305. if (! InitializeCriticalSectionAndSpinCount(&m_recallLock, 0)) {
  306. DWORD dwErr = GetLastError();
  307. hr = HRESULT_FROM_WIN32(dwErr);
  308. DeleteCriticalSection(&m_clientLock);
  309. WsbAffirmHr(hr);
  310. }
  311. if (! InitializeCriticalSectionAndSpinCount(&m_stateLock, 0)) {
  312. DWORD dwErr = GetLastError();
  313. hr = HRESULT_FROM_WIN32(dwErr);
  314. DeleteCriticalSection(&m_clientLock);
  315. DeleteCriticalSection(&m_recallLock);
  316. WsbAffirmHr(hr);
  317. }
  318. m_bCritSecCreated = TRUE;
  319. // Create the Client List collection.
  320. WsbAffirmHr(CoCreateInstance(CLSID_CWsbOrderedCollection, NULL, CLSCTX_SERVER, IID_IWsbCollection, (void**) &m_pClients));
  321. // Create the Recall List collection.
  322. WsbAffirmHr(CoCreateInstance(CLSID_CWsbOrderedCollection, NULL, CLSCTX_SERVER, IID_IWsbCollection, (void**) &m_pRecalls));
  323. #ifdef MAC_SUPPORT
  324. //
  325. // Attempt to load the Mac support
  326. //
  327. FsaDllSfm = LoadLibrary(L"SFMAPI.DLL");
  328. if (FsaDllSfm != NULL) {
  329. //
  330. // The DLL is there - try importing the functions we will need
  331. //
  332. try {
  333. WsbAffirmPointer((pAfpAdminConnect = (AdminConnect) GetProcAddress((HMODULE) FsaDllSfm, "AfpAdminConnect")));
  334. WsbAffirmPointer((pAfpAdminDisconnect = (AdminDisconnect) GetProcAddress((HMODULE) FsaDllSfm, "AfpAdminDisconnect")));
  335. WsbAffirmPointer((pAfpAdminBufferFree = (AdminBufferFree) GetProcAddress((HMODULE) FsaDllSfm, "AfpAdminBufferFree")));
  336. WsbAffirmPointer((pAfpAdminSessionEnum = (AdminSessionEnum) GetProcAddress((HMODULE) FsaDllSfm, "AfpAdminSessionEnum")));
  337. FsaMacSupportInstalled = TRUE;
  338. } WsbCatchAndDo(hr,
  339. FreeLibrary((HMODULE) FsaDllSfm);
  340. FsaDllSfm = NULL;
  341. );
  342. }
  343. #endif
  344. } WsbCatch(hr);
  345. return(hr);
  346. }
  347. HRESULT
  348. CFsaFilter::FinalRelease(
  349. void
  350. )
  351. /*++
  352. Implements:
  353. CComObjectRoot::FinalRelease().
  354. --*/
  355. {
  356. HRESULT hr = S_OK;
  357. HANDLE pThreadHandles[THREAD_HANDLE_COUNT];
  358. DWORD nThreadCount = 0;
  359. BOOL bThreads = TRUE;
  360. BOOL bTerminated = TRUE;
  361. WsbTraceIn(OLESTR("CFsaFilter::FinalRelease"), OLESTR(""));
  362. #ifdef MAC_SUPPORT
  363. if (FsaDllSfm != NULL) {
  364. FreeLibrary((HMODULE) FsaDllSfm);
  365. FsaDllSfm = NULL;
  366. }
  367. #endif
  368. //
  369. // Stop the ioctl and pipe threads
  370. //
  371. m_state = HSM_JOB_STATE_SUSPENDING;
  372. // But wait until they've completed first.
  373. if ((m_pipeThread) && (m_ioctlThread)) {
  374. pThreadHandles[0] = m_pipeThread;
  375. pThreadHandles[1] = m_ioctlThread;
  376. nThreadCount = 2;
  377. } else if (m_pipeThread) {
  378. pThreadHandles[0] = m_pipeThread;
  379. nThreadCount = 1;
  380. } else if (m_ioctlThread) {
  381. pThreadHandles[0] = m_ioctlThread;
  382. nThreadCount = 1;
  383. } else{
  384. // neither of the threads exist, skip wait.
  385. bThreads = FALSE;
  386. }
  387. if (bThreads) {
  388. switch (WaitForMultipleObjects(nThreadCount, pThreadHandles, TRUE, 20000)) {
  389. case WAIT_FAILED: {
  390. WsbTrace(OLESTR("CFsaFilter::FinalRelease: WaitforMultipleObjects returned error %lu\n"),
  391. GetLastError());
  392. }
  393. // fall through...
  394. case WAIT_TIMEOUT: {
  395. WsbTrace(OLESTR("CFsaFilter::FinalRelease: force-terminating threads.\n"));
  396. // after timeout, force termination on threads
  397. // bTerminated specify if the force-termination succeeds
  398. DWORD dwExitCode;
  399. if (GetExitCodeThread( m_ioctlThread, &dwExitCode)) {
  400. if (dwExitCode == STILL_ACTIVE) { // thread still active
  401. if (!TerminateThread (m_ioctlThread, 0)) {
  402. WsbTrace(OLESTR("CFsaFilter::FinalRelease: TerminateThread returned error %lu\n"),
  403. GetLastError());
  404. bTerminated = FALSE;
  405. }
  406. }
  407. } else {
  408. WsbTrace(OLESTR("CFsaFilter::FinalRelease: GetExitCodeThread returned error %lu\n"),
  409. GetLastError());
  410. bTerminated = FALSE;
  411. }
  412. if (GetExitCodeThread( m_pipeThread, &dwExitCode)) {
  413. if (dwExitCode == STILL_ACTIVE) { // thread still active
  414. if (!TerminateThread (m_pipeThread, 0)) {
  415. WsbTrace(OLESTR("CFsaFilter::FinalRelease: TerminateThread returned error %lu\n"),
  416. GetLastError());
  417. bTerminated = FALSE;
  418. }
  419. }
  420. } else {
  421. WsbTrace(OLESTR("CFsaFilter::FinalRelease: GetExitCodeThread returned error %lu\n"),
  422. GetLastError());
  423. bTerminated = FALSE;
  424. }
  425. break;
  426. }
  427. default:
  428. break;
  429. }
  430. }
  431. if (m_pipeHandle != INVALID_HANDLE_VALUE) {
  432. CloseHandle(m_pipeHandle);
  433. m_pipeHandle = INVALID_HANDLE_VALUE;
  434. }
  435. if (m_ioctlHandle != INVALID_HANDLE_VALUE) {
  436. CloseHandle(m_ioctlHandle);
  437. m_ioctlHandle = INVALID_HANDLE_VALUE;
  438. }
  439. if (m_terminateEvent != NULL) {
  440. CloseHandle(m_terminateEvent);
  441. m_terminateEvent = NULL;
  442. }
  443. if (m_pipeThread != NULL) {
  444. CloseHandle(m_pipeThread);
  445. }
  446. if (m_ioctlThread != NULL) {
  447. CloseHandle(m_ioctlThread);
  448. }
  449. // delete CS only if threads were teriminated properly and CS were created successfully
  450. if (bTerminated && m_bCritSecCreated) {
  451. DeleteCriticalSection(&m_clientLock);
  452. DeleteCriticalSection(&m_recallLock);
  453. DeleteCriticalSection(&m_stateLock);
  454. }
  455. CWsbCollectable::FinalRelease();
  456. WsbTraceOut(OLESTR("CFsaFilter::FinalRelease"), OLESTR(""));
  457. return(hr);
  458. }
  459. HRESULT
  460. CFsaFilter::FindRecall(
  461. IN GUID recallId,
  462. OUT IFsaFilterRecall** pRecall
  463. )
  464. /*++
  465. Implements:
  466. CFsaFilter:FindRecall().
  467. --*/
  468. {
  469. HRESULT hr = S_OK;
  470. CComPtr<IFsaFilterRecallPriv> pRecallPriv;
  471. WsbTraceIn(OLESTR("CFsaFilter::FindRecall"), OLESTR(""));
  472. try {
  473. WsbAffirmHr(CoCreateInstance(CLSID_CFsaFilterRecallNTFS, NULL, CLSCTX_SERVER, IID_IFsaFilterRecallPriv, (void**) &pRecallPriv));
  474. WsbAffirmHr(pRecallPriv->SetIdentifier(recallId));
  475. EnterCriticalSection(&m_recallLock);
  476. hr = m_pRecalls->Find(pRecallPriv, IID_IFsaFilterRecall, (void**) pRecall);
  477. LeaveCriticalSection(&m_recallLock);
  478. WsbAffirmHr(hr);
  479. } WsbCatch(hr);
  480. WsbTraceOut(OLESTR("CFsaFilter::FindRecall"), OLESTR(""));
  481. return(hr);
  482. }
  483. HRESULT
  484. CFsaFilter::GetAdminExemption(
  485. OUT BOOL *pIsExempt
  486. )
  487. /*++
  488. Implements:
  489. IFsaFilter::GetAdminExemption().
  490. --*/
  491. {
  492. HRESULT hr = S_OK;
  493. try {
  494. WsbAssert(0 != pIsExempt, E_POINTER);
  495. *pIsExempt = m_exemptAdmin;
  496. } WsbCatch(hr);
  497. return(hr);
  498. }
  499. HRESULT
  500. CFsaFilter::GetClassID(
  501. OUT CLSID* pClsid
  502. )
  503. /*++
  504. Implements:
  505. IPersist::GetClassID().
  506. --*/
  507. {
  508. HRESULT hr = S_OK;
  509. WsbTraceIn(OLESTR("CFsaFilter::GetClassID"), OLESTR(""));
  510. try {
  511. WsbAssert(0 != pClsid, E_POINTER);
  512. *pClsid = CLSID_CFsaFilterNTFS;
  513. } WsbCatch(hr);
  514. WsbTraceOut(OLESTR("CFsaFilter::GetClassID"), OLESTR("hr = <%ls>, CLSID = <%ls>"), WsbHrAsString(hr), WsbGuidAsString(*pClsid));
  515. return(hr);
  516. }
  517. HRESULT
  518. CFsaFilter::GetIdentifier(
  519. OUT GUID* pId
  520. )
  521. /*++
  522. Implements:
  523. IFsaFilter::GetIdentifier().
  524. --*/
  525. {
  526. HRESULT hr = S_OK;
  527. try {
  528. WsbAssert(0 != pId, E_POINTER);
  529. *pId = m_id;
  530. } WsbCatch(hr);
  531. return(hr);
  532. }
  533. HRESULT
  534. CFsaFilter::GetLogicalName(
  535. OUT OLECHAR** pName,
  536. IN ULONG bufferSize
  537. )
  538. /*++
  539. Implements:
  540. IFsaFilter::GetLogicalName().
  541. --*/
  542. {
  543. HRESULT hr = S_OK;
  544. try {
  545. WsbAssert(0 != pName, E_POINTER);
  546. WsbAssert(m_pFsaServer != 0, E_POINTER);
  547. // This has not been official defined, but for now the logical name will be the same name
  548. // as the FSA, since we will only have one filter.
  549. WsbAffirmHr(m_pFsaServer->GetLogicalName(pName, bufferSize));
  550. } WsbCatch(hr);
  551. return(hr);
  552. }
  553. HRESULT
  554. CFsaFilter::GetMaxRecallBuffers(
  555. OUT ULONG* pMaxBuffers
  556. )
  557. /*++
  558. Implements:
  559. IFsaFilter::GetMaxRecallBuffers().
  560. --*/
  561. {
  562. HRESULT hr = S_OK;
  563. try {
  564. WsbAssert(0 != pMaxBuffers, E_POINTER);
  565. *pMaxBuffers = m_maxRecallBuffers;
  566. } WsbCatch(hr);
  567. return(hr);
  568. }
  569. HRESULT
  570. CFsaFilter::GetMaxRecalls(
  571. OUT ULONG* pMaxRecalls
  572. )
  573. /*++
  574. Implements:
  575. IFsaFilter::GetMaxRecalls().
  576. --*/
  577. {
  578. HRESULT hr = S_OK;
  579. try {
  580. WsbAssert(0 != pMaxRecalls, E_POINTER);
  581. *pMaxRecalls = m_maxRecalls;
  582. } WsbCatch(hr);
  583. return(hr);
  584. }
  585. HRESULT
  586. CFsaFilter::GetMinRecallInterval(
  587. OUT ULONG* pMinInterval
  588. )
  589. /*++
  590. Implements:
  591. IFsaFilter::GetMinRecallInterval().
  592. --*/
  593. {
  594. HRESULT hr = S_OK;
  595. try {
  596. WsbAssert(0 != pMinInterval, E_POINTER);
  597. *pMinInterval = m_minRecallInterval;
  598. } WsbCatch(hr);
  599. return(hr);
  600. }
  601. HRESULT
  602. CFsaFilter::GetSizeMax(
  603. OUT ULARGE_INTEGER* pSize
  604. )
  605. /*++
  606. Implements:
  607. IPersistStream::GetSizeMax().
  608. --*/
  609. {
  610. HRESULT hr = S_OK;
  611. CComPtr<IPersistStream> pPersistStream;
  612. WsbTraceIn(OLESTR("CFsaFilter::GetSizeMax"), OLESTR(""));
  613. try {
  614. WsbAssert(0 != pSize, E_POINTER);
  615. // We are only storing the configuration information, NOT the collections.
  616. pSize->QuadPart = WsbPersistSizeOf(GUID) + 3 * WsbPersistSizeOf(ULONG) + WsbPersistSizeOf(BOOL);
  617. } WsbCatch(hr);
  618. WsbTraceOut(OLESTR("CFsaFilter::GetSizeMax"), OLESTR("hr = <%ls>, Size = <%ls>"), WsbHrAsString(hr), WsbPtrToUliAsString(pSize));
  619. return(hr);
  620. }
  621. HRESULT
  622. CFsaFilter::GetState(
  623. OUT HSM_JOB_STATE* pState
  624. )
  625. /*++
  626. Implements:
  627. IPersistStream::GetState().
  628. --*/
  629. {
  630. HRESULT hr = S_OK;
  631. WsbTraceIn(OLESTR("CFsaFilter::GetState"), OLESTR(""));
  632. try {
  633. WsbAssert(0 != pState, E_POINTER);
  634. *pState = m_state;
  635. } WsbCatch(hr);
  636. WsbTraceOut(OLESTR("CFsaFilter::GetState"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  637. return(hr);
  638. }
  639. HRESULT
  640. CFsaFilter::Init(
  641. IN IFsaServer* pFsaServer
  642. )
  643. /*++
  644. Implements:
  645. IFsaFilterPriv::Init().
  646. --*/
  647. {
  648. HRESULT hr = S_OK;
  649. try {
  650. WsbAssert(0 != pFsaServer, E_POINTER);
  651. // Store the parent FSA?
  652. m_pFsaServer = pFsaServer;
  653. m_isDirty = TRUE;
  654. } WsbCatch(hr);
  655. return(hr);
  656. }
  657. HRESULT
  658. CFsaFilter::IsEnabled(
  659. void
  660. )
  661. /*++
  662. Implements:
  663. IFsaFilter::IsEnabled().
  664. --*/
  665. {
  666. return(m_isEnabled ? S_OK : S_FALSE);
  667. }
  668. HRESULT
  669. CFsaFilter::Load(
  670. IN IStream* pStream
  671. )
  672. /*++
  673. Implements:
  674. IPersistStream::Load().
  675. --*/
  676. {
  677. HRESULT hr = S_OK;
  678. WsbTraceIn(OLESTR("CFsaFilter::Load"), OLESTR(""));
  679. try {
  680. WsbAssert(0 != pStream, E_POINTER);
  681. // Do the easy stuff, but make sure that this order matches the order
  682. // in the save method.
  683. WsbAffirmHr(WsbLoadFromStream(pStream, &m_id));
  684. WsbAffirmHr(WsbLoadFromStream(pStream, &m_maxRecalls));
  685. WsbAffirmHr(WsbLoadFromStream(pStream, &m_minRecallInterval));
  686. WsbAffirmHr(WsbLoadFromStream(pStream, &m_maxRecallBuffers));
  687. WsbAffirmHr(WsbLoadFromStream(pStream, &m_isEnabled));
  688. WsbAffirmHr(WsbLoadFromStream(pStream, &m_exemptAdmin));
  689. } WsbCatch(hr);
  690. WsbTraceOut(OLESTR("CFsaFilter::Load"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  691. return(hr);
  692. }
  693. HRESULT
  694. CFsaFilter::Pause(
  695. void
  696. )
  697. /*++
  698. Implements:
  699. IFsaFilter::Pause().
  700. --*/
  701. {
  702. HRESULT hr = S_OK;
  703. HSM_JOB_STATE oldState;
  704. RP_MSG tmp;
  705. DWORD outSize = 0;
  706. WsbTraceIn(OLESTR("CFsaFilter::Pause"), OLESTR(""));
  707. try {
  708. WsbAffirm((HSM_JOB_STATE_ACTIVE == m_state), E_UNEXPECTED);
  709. oldState = m_state;
  710. m_state = HSM_JOB_STATE_PAUSING;
  711. try {
  712. //
  713. // Tell the kernel mode driver to stop accepting new recall requests.
  714. //
  715. if (m_ioctlHandle != INVALID_HANDLE_VALUE) {
  716. tmp.inout.command = RP_SUSPEND_NEW_RECALLS;
  717. WsbAffirmStatus(DeviceIoControl(m_ioctlHandle, FSCTL_HSM_DATA, &tmp,
  718. sizeof(RP_MSG),
  719. &tmp, sizeof(RP_MSG), &outSize, NULL))
  720. }
  721. m_state = HSM_JOB_STATE_PAUSED;
  722. } WsbCatchAndDo(hr, m_state = oldState;);
  723. } WsbCatch(hr);
  724. WsbTraceOut(OLESTR("CFsaFilter::Pause"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  725. return(hr);
  726. }
  727. HRESULT
  728. CFsaFilter::Resume(
  729. void
  730. )
  731. /*++
  732. Implements:
  733. IFsaFilter::Resume().
  734. --*/
  735. {
  736. HRESULT hr = S_OK;
  737. HSM_JOB_STATE oldState;
  738. RP_MSG tmp;
  739. DWORD outSize = 0;
  740. WsbTraceIn(OLESTR("CFsaFilter::Resume"), OLESTR(""));
  741. try {
  742. WsbAffirm((HSM_JOB_STATE_PAUSED == m_state), E_UNEXPECTED);
  743. oldState = m_state;
  744. m_state = HSM_JOB_STATE_RESUMING;
  745. try {
  746. //
  747. // Tell the kernel mode driver to start accepting recall requests.
  748. //
  749. if (m_ioctlHandle != INVALID_HANDLE_VALUE) {
  750. tmp.inout.command = RP_ALLOW_NEW_RECALLS;
  751. WsbAffirmStatus(DeviceIoControl(m_ioctlHandle, FSCTL_HSM_DATA, &tmp,
  752. sizeof(RP_MSG),
  753. &tmp, sizeof(RP_MSG), &outSize, NULL))
  754. }
  755. m_state = HSM_JOB_STATE_ACTIVE;
  756. } WsbCatchAndDo(hr, m_state = oldState;);
  757. } WsbCatch(hr);
  758. WsbTraceOut(OLESTR("CFsaFilter::Resume"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  759. return(hr);
  760. }
  761. HRESULT
  762. CFsaFilter::Save(
  763. IN IStream* pStream,
  764. IN BOOL clearDirty
  765. )
  766. /*++
  767. Implements:
  768. IPersistStream::Save().
  769. --*/
  770. {
  771. HRESULT hr = S_OK;
  772. CComPtr<IPersistStream> pPersistStream;
  773. WsbTraceIn(OLESTR("CFsaFilter::Save"), OLESTR("clearDirty = <%ls>"), WsbBoolAsString(clearDirty));
  774. try {
  775. WsbAssert(0 != pStream, E_POINTER);
  776. // Do the easy stuff, but make sure that this order matches the order
  777. // in the load method.
  778. WsbAffirmHr(WsbSaveToStream(pStream, m_id));
  779. WsbAffirmHr(WsbSaveToStream(pStream, m_maxRecalls));
  780. WsbAffirmHr(WsbSaveToStream(pStream, m_minRecallInterval));
  781. WsbAffirmHr(WsbSaveToStream(pStream, m_maxRecallBuffers));
  782. WsbAffirmHr(WsbSaveToStream(pStream, m_isEnabled));
  783. WsbAffirmHr(WsbSaveToStream(pStream, m_exemptAdmin));
  784. // If we got it saved and we were asked to clear the dirty bit, then
  785. // do so now.
  786. if (clearDirty) {
  787. m_isDirty = FALSE;
  788. }
  789. } WsbCatch(hr);
  790. WsbTraceOut(OLESTR("CFsaFilter::Save"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  791. return(hr);
  792. }
  793. HRESULT
  794. CFsaFilter::SendCancel(
  795. IN IFsaFilterRecallPriv *pRecallPriv
  796. )
  797. /*++
  798. Implements:
  799. IFsaFilterPriv::SendCancel()
  800. --*/
  801. {
  802. HRESULT hr = S_OK;
  803. RP_MSG tmp;
  804. DWORD outSize;
  805. ULONG numEnt;
  806. ULONGLONG driversId;
  807. CComPtr<IFsaFilterRecall> pRecall;
  808. //Get Drivers ID of failing recall
  809. WsbAffirmHr(pRecallPriv->GetDriversRecallId(&driversId));
  810. tmp.inout.command = RP_RECALL_COMPLETE;
  811. tmp.inout.status = STATUS_CANCELLED;
  812. tmp.msg.rRep.actionFlags = 0;
  813. tmp.msg.rRep.filterId = driversId;
  814. DeviceIoControl(m_ioctlHandle, FSCTL_HSM_DATA, &tmp, sizeof(RP_MSG),
  815. &tmp, sizeof(RP_MSG), &outSize, NULL);
  816. //
  817. // Remove it from our collection
  818. //
  819. EnterCriticalSection(&m_recallLock);
  820. hr = m_pRecalls->RemoveAndRelease(pRecallPriv);
  821. LeaveCriticalSection(&m_recallLock);
  822. WsbAffirmHr(hr);
  823. hr = m_pRecalls->GetEntries(&numEnt);
  824. WsbTrace(OLESTR("CFsaFilter::SendCancel: Recall queue has %u entries after delete\n"),
  825. numEnt);
  826. hr = S_OK;
  827. return(hr);
  828. }
  829. #define FSA_MAX_XFER (1024 * 1024)
  830. #define FSA_MIN_XFER (8 * 1024)
  831. HRESULT
  832. CFsaFilter::SendComplete(
  833. IN IFsaFilterRecallPriv *pRecallPriv,
  834. IN HRESULT status
  835. )
  836. /*++
  837. Implements:
  838. IFsaFilterPriv::SendComplete()
  839. --*/
  840. {
  841. HRESULT hr = S_OK;
  842. RP_MSG tmp;
  843. BOOL code = FALSE;
  844. ULONG numEnt;
  845. BOOL didSend = FALSE;
  846. DWORD ioSize;
  847. CComPtr<IFsaFilterRecall> pRecall;
  848. CWsbStringPtr pName;
  849. try {
  850. ioSize = sizeof(RP_MSG);
  851. WsbAffirmHr(pRecallPriv->QueryInterface(IID_IFsaFilterRecall, (void**) &pRecall));
  852. // Get path of file failing recall.
  853. WsbAffirmHr(pRecall->GetPath((OLECHAR**) &pName, 0))
  854. WsbAssertPointer(pName);
  855. tmp.inout.command = RP_RECALL_COMPLETE;
  856. if (status == S_OK)
  857. tmp.inout.status = 0;
  858. else {
  859. // If the error indicates that Engine is not initialized yet -
  860. // log an error with law severity (it is considered as a normal situation)
  861. if (status != HSM_E_NOT_READY) {
  862. WsbLogEvent(FSA_MESSAGE_RECALL_FAILED, 0, NULL, (OLECHAR*) WsbAbbreviatePath(pName, 120), WsbHrAsString(status), NULL);
  863. } else {
  864. WsbLogEvent(FSA_MESSAGE_RECALL_FAILED_NOT_READY, 0, NULL, (OLECHAR*) WsbAbbreviatePath(pName, 120), WsbHrAsString(status), NULL);
  865. }
  866. tmp.inout.status = TranslateHresultToNtStatus(status);
  867. }
  868. WsbAffirmHr(pRecall->GetRecallFlags(&tmp.msg.rRep.actionFlags));
  869. WsbAffirmHr(pRecallPriv->GetDriversRecallId(&tmp.msg.rRep.filterId));
  870. WsbTrace(OLESTR("CFsaFilter::SendComplete: id = %I64x status = %s\n"),
  871. tmp.msg.rRep.filterId, WsbHrAsString(status));
  872. WsbAffirmHr(pRecallPriv->LogComplete(status));
  873. WsbAffirmStatus(DeviceIoControl(m_ioctlHandle, FSCTL_HSM_DATA, &tmp, ioSize,
  874. &tmp, sizeof(RP_MSG), &ioSize, NULL));
  875. didSend = TRUE;
  876. WsbTrace(OLESTR("CFsaFilter::SendComplete: Ioctl returned %u (%x)\n"), code, GetLastError());
  877. //
  878. // Remove it from our collection
  879. //
  880. EnterCriticalSection(&m_recallLock);
  881. hr = m_pRecalls->RemoveAndRelease(pRecallPriv);
  882. LeaveCriticalSection(&m_recallLock);
  883. WsbAffirmHr(hr);
  884. hr = m_pRecalls->GetEntries(&numEnt);
  885. WsbTrace(OLESTR("CFsaFilter::SendComplete: Recall queue has %u entries after delete\n"),
  886. numEnt);
  887. hr = S_OK;
  888. } WsbCatchAndDo(hr,
  889. RP_MSG aTmp;
  890. //
  891. // Log an event
  892. //
  893. WsbLogEvent(FSA_MESSAGE_RECALL_FAILED, 0, NULL, (OLECHAR*) WsbAbbreviatePath(pName, 120), WsbHrAsString(hr), NULL);
  894. //
  895. // If for some reason we did not tell the filter to complete the IO we
  896. // try it here (with a error indication) so we have done everything possible to keep the
  897. // application from hanging.
  898. //
  899. if (didSend == FALSE) {
  900. WsbAffirmHr(pRecallPriv->GetDriversRecallId(&aTmp.msg.pRep.filterId));
  901. aTmp.inout.command = RP_RECALL_COMPLETE;
  902. aTmp.inout.status = STATUS_FILE_IS_OFFLINE;
  903. aTmp.msg.rRep.actionFlags = 0;
  904. DeviceIoControl(m_ioctlHandle, FSCTL_HSM_DATA, &aTmp, sizeof(RP_MSG),
  905. &aTmp, sizeof(RP_MSG), &ioSize, NULL);
  906. //
  907. // Remove it from our collection
  908. //
  909. EnterCriticalSection(&m_recallLock);
  910. hr = m_pRecalls->RemoveAndRelease(pRecallPriv);
  911. LeaveCriticalSection(&m_recallLock);
  912. }
  913. );
  914. return(hr);
  915. }
  916. HRESULT
  917. CFsaFilter::SetAdminExemption(
  918. IN BOOL isExempt
  919. )
  920. /*++
  921. Implements:
  922. IFsaFilter::SetAdminExemption().
  923. --*/
  924. {
  925. HRESULT hr = S_OK;
  926. m_exemptAdmin = isExempt; // TRUE == Admin is exempt from runaway recall check.
  927. m_isDirty = TRUE;
  928. return(hr);
  929. }
  930. HRESULT
  931. CFsaFilter::SetIdentifier(
  932. IN GUID id
  933. )
  934. /*++
  935. Implements:
  936. IFsaFilterPriv::SetIdentifier().
  937. --*/
  938. {
  939. HRESULT hr = S_OK;
  940. m_id = id;
  941. m_isDirty = TRUE;
  942. return(hr);
  943. }
  944. HRESULT
  945. CFsaFilter::SetIsEnabled(
  946. IN BOOL isEnabled
  947. )
  948. /*++
  949. Implements:
  950. IFsaFilter::SetIsEnabled().
  951. --*/
  952. {
  953. m_isEnabled = isEnabled;
  954. return(S_OK);
  955. }
  956. HRESULT
  957. CFsaFilter::SetMaxRecallBuffers(
  958. IN ULONG maxBuffers
  959. )
  960. /*++
  961. Implements:
  962. IFsaFilter::SetMaxRecallBuffers().
  963. --*/
  964. {
  965. m_maxRecallBuffers = maxBuffers;
  966. m_isDirty = TRUE;
  967. return(S_OK);
  968. }
  969. HRESULT
  970. CFsaFilter::SetMaxRecalls(
  971. IN ULONG maxRecalls
  972. )
  973. /*++
  974. Implements:
  975. IFsaFilter::SetMaxRecalls().
  976. --*/
  977. {
  978. m_maxRecalls = maxRecalls;
  979. m_isDirty = TRUE;
  980. return(S_OK);
  981. }
  982. HRESULT
  983. CFsaFilter::SetMinRecallInterval(
  984. IN ULONG minInterval
  985. )
  986. /*++
  987. Implements:
  988. IFsaFilter::SetMinRecallInterval().
  989. --*/
  990. {
  991. m_minRecallInterval = minInterval;
  992. m_isDirty = TRUE;
  993. return(S_OK);
  994. }
  995. HRESULT
  996. CFsaFilter::StopIoctlThread(
  997. void
  998. )
  999. /*++
  1000. Implements:
  1001. IFsaFilterPriv::StopIoctlThread()
  1002. This stops the IOCTL thread and cancels outstanding IO to the
  1003. kernel mode File System Filter.
  1004. --*/
  1005. {
  1006. HRESULT hr = S_OK;
  1007. RP_MSG tmp;
  1008. DWORD outSize;
  1009. WsbTraceIn(OLESTR("CFsaFilter::StopIoctlThread"), OLESTR(""));
  1010. try {
  1011. //
  1012. // Signal the event to indicate to PipeThread that we are terminating
  1013. // It is important to do this first before setting the state to IDLE,
  1014. // to avoid deadlocks/race conditions
  1015. //
  1016. if (m_terminateEvent != NULL) {
  1017. WsbAffirmStatus(SetEvent(m_terminateEvent));
  1018. }
  1019. if (m_ioctlHandle != INVALID_HANDLE_VALUE) {
  1020. //
  1021. // The right order of shutting down is:
  1022. // 1) Prevent new recalls from starting
  1023. // 2) Canceling outstanding recalls
  1024. // 3) Canceling pending Ioctls
  1025. //
  1026. // Note that (3) above causes the IoctlThread to terminate and close
  1027. // the filter handle before doing so, hence this thread may NOT send
  1028. // any more Ioctls after sending RP_CANCEL_ALL_DEVICEIO !!
  1029. //
  1030. DWORD dwLastErr = NO_ERROR;
  1031. //
  1032. // Tell the filter we are going away and it should fail all recall activity .
  1033. //
  1034. tmp.inout.command = RP_SUSPEND_NEW_RECALLS;
  1035. if (! DeviceIoControl(m_ioctlHandle, FSCTL_HSM_DATA, &tmp,
  1036. sizeof(RP_MSG),
  1037. &tmp, sizeof(RP_MSG), &outSize, NULL)) {
  1038. // Save error
  1039. dwLastErr = GetLastError();
  1040. }
  1041. //
  1042. // Cancel any pending recalls
  1043. //
  1044. tmp.inout.command = RP_CANCEL_ALL_RECALLS;
  1045. if (! DeviceIoControl(m_ioctlHandle, FSCTL_HSM_DATA, &tmp,
  1046. sizeof(RP_MSG),
  1047. &tmp, sizeof(RP_MSG), &outSize, NULL)) {
  1048. // Save error
  1049. if (dwLastErr != NO_ERROR) {
  1050. dwLastErr = GetLastError();
  1051. }
  1052. }
  1053. //
  1054. // Set the filter state to idle
  1055. //
  1056. EnterCriticalSection(&m_stateLock);
  1057. m_state = HSM_JOB_STATE_IDLE;
  1058. //
  1059. // Cancel the IOCTLS in the kernel filter.
  1060. //
  1061. tmp.inout.command = RP_CANCEL_ALL_DEVICEIO;
  1062. BOOL bTmpStatus = DeviceIoControl(m_ioctlHandle, FSCTL_HSM_DATA, &tmp,
  1063. sizeof(RP_MSG),
  1064. &tmp, sizeof(RP_MSG), &outSize, NULL);
  1065. LeaveCriticalSection(&m_stateLock);
  1066. WsbAffirmStatus(bTmpStatus);
  1067. // Throw if a previous error occurred
  1068. if (dwLastErr != NO_ERROR) {
  1069. hr = HRESULT_FROM_WIN32(dwLastErr);
  1070. WsbAffirmHr(hr);
  1071. }
  1072. }
  1073. } WsbCatch(hr);
  1074. WsbTraceOut(OLESTR("CFsaFilter::StopIoctlThread"), OLESTR("Hr = %ls"), WsbHrAsString(hr));
  1075. return(0);
  1076. }
  1077. DWORD FsaIoctlThread(
  1078. void* pVoid
  1079. )
  1080. /*++
  1081. --*/
  1082. {
  1083. HRESULT hr;
  1084. hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
  1085. hr = ((CFsaFilter*) pVoid)->IoctlThread();
  1086. CoUninitialize();
  1087. return(hr);
  1088. }
  1089. DWORD FsaPipeThread(
  1090. void* pVoid
  1091. )
  1092. /*++
  1093. --*/
  1094. {
  1095. HRESULT hr;
  1096. hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
  1097. hr = ((CFsaFilter*) pVoid)->PipeThread();
  1098. CoUninitialize();
  1099. return(hr);
  1100. }
  1101. HRESULT
  1102. CFsaFilter::Start(
  1103. void
  1104. )
  1105. /*++
  1106. Implements:
  1107. IFsaFilter::Start().
  1108. --*/
  1109. {
  1110. HRESULT hr = S_OK;
  1111. HSM_JOB_STATE oldState;
  1112. DWORD tid;
  1113. WsbTraceIn(OLESTR("CFsaFilter::Start"), OLESTR(""));
  1114. try {
  1115. //
  1116. // Create the event that is used to signal termination
  1117. //
  1118. WsbAffirmHandle((m_terminateEvent = CreateEvent(NULL,
  1119. TRUE,
  1120. FALSE,
  1121. NULL)));
  1122. WsbAffirm((HSM_JOB_STATE_IDLE == m_state) || (HSM_JOB_STATE_CANCELLED == m_state), E_UNEXPECTED);
  1123. oldState = m_state;
  1124. m_state = HSM_JOB_STATE_STARTING;
  1125. try {
  1126. // TBD - Do whatever it takes to start.
  1127. //
  1128. // This consists of starting a thread that will issue the IOCTL
  1129. // requests to the kernel mode filter. These IOCTL requests
  1130. // will complete when the kernel mode filter detects that a
  1131. // recall is needed.
  1132. //
  1133. WsbAffirm((m_pipeThread = CreateThread(0, 0, FsaPipeThread, (void*) this, 0, &tid)) != 0, HRESULT_FROM_WIN32(GetLastError()));
  1134. if (m_pipeThread == NULL) {
  1135. m_state = oldState;
  1136. WsbAssertHr(E_FAIL); // TBD What error to return here??
  1137. }
  1138. WsbAffirm((m_ioctlThread = CreateThread(0, 0, FsaIoctlThread, (void*) this, 0, &tid)) != 0, HRESULT_FROM_WIN32(GetLastError()));
  1139. if (m_ioctlThread == NULL) {
  1140. m_state = oldState;
  1141. WsbAssertHr(E_FAIL); // TBD What error to return here??
  1142. }
  1143. } WsbCatchAndDo(hr, m_state = oldState;);
  1144. } WsbCatch(hr);
  1145. WsbTraceOut(OLESTR("CFsaFilter::Start"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  1146. return(hr);
  1147. }
  1148. HRESULT
  1149. CFsaFilter::Test(
  1150. USHORT* passed,
  1151. USHORT* failed
  1152. )
  1153. /*++
  1154. Implements:
  1155. IWsbTestable::Test().
  1156. --*/
  1157. {
  1158. HRESULT hr = S_OK;
  1159. try {
  1160. WsbAssert(0 != passed, E_POINTER);
  1161. WsbAssert(0 != failed, E_POINTER);
  1162. *passed = 0;
  1163. *failed = 0;
  1164. } WsbCatch(hr);
  1165. return(hr);
  1166. }
  1167. NTSTATUS
  1168. CFsaFilter::TranslateHresultToNtStatus(
  1169. HRESULT hr
  1170. )
  1171. /*++
  1172. Implements:
  1173. CFsaFilter::TranslateHresultToNtStatus().
  1174. --*/
  1175. {
  1176. NTSTATUS ntStatus = 0;
  1177. DWORD w32Error;
  1178. switch (hr) {
  1179. case RMS_E_CARTRIDGE_BUSY:
  1180. ntStatus = STATUS_FILE_IS_OFFLINE;
  1181. break;
  1182. case RMS_E_DRIVE_BUSY:
  1183. case RMS_E_TIMEOUT:
  1184. case RMS_E_CARTRIDGE_UNAVAILABLE:
  1185. ntStatus = STATUS_FILE_IS_OFFLINE;
  1186. break;
  1187. case RMS_E_LIBRARY_UNAVAILABLE:
  1188. case RMS_E_NTMS_NOT_CONNECTED:
  1189. ntStatus = STATUS_FILE_IS_OFFLINE;
  1190. break;
  1191. case ERROR_IO_DEVICE:
  1192. ntStatus = STATUS_REMOTE_STORAGE_MEDIA_ERROR;
  1193. break;
  1194. case STATUS_END_OF_FILE:
  1195. ntStatus = hr;
  1196. break;
  1197. case E_FAIL:
  1198. ntStatus = STATUS_FILE_IS_OFFLINE;
  1199. break;
  1200. default:
  1201. if (hr & FACILITY_NT_BIT) {
  1202. //
  1203. // NT status code - return it unchanged (except for removing the facility bit)
  1204. //
  1205. ntStatus = hr & ~(FACILITY_NT_BIT);
  1206. } else if (FACILITY_WIN32 == HRESULT_FACILITY(hr)) {
  1207. w32Error = hr & 0x0000ffff;
  1208. //
  1209. // Now convert the win32 error to a NT status code.
  1210. //
  1211. // Since there does not seem to be any easy macro to do this we convert the most common ones
  1212. // and punt on the rest.
  1213. //
  1214. switch (w32Error) {
  1215. case ERROR_NOT_ENOUGH_MEMORY:
  1216. case ERROR_OUTOFMEMORY:
  1217. ntStatus = STATUS_NO_MEMORY;
  1218. break;
  1219. case ERROR_HANDLE_DISK_FULL:
  1220. case ERROR_DISK_FULL:
  1221. ntStatus = STATUS_DISK_FULL;
  1222. break;
  1223. default:
  1224. ntStatus = STATUS_FILE_IS_OFFLINE;
  1225. break;
  1226. }
  1227. } else {
  1228. ntStatus = STATUS_FILE_IS_OFFLINE;
  1229. }
  1230. break;
  1231. }
  1232. return(ntStatus);
  1233. }
  1234. HRESULT
  1235. CFsaFilter::DoRecallAction(
  1236. PFSA_IOCTL_CONTROL pIoCmd
  1237. )
  1238. /*++
  1239. Implements:
  1240. CFsaFilter::DoRecallAction()
  1241. Find the already created recall object and start the data transfer.
  1242. --*/
  1243. {
  1244. CComPtr<IFsaFilterRecall> pRecall;
  1245. CComPtr<IFsaFilterRecallPriv> pRecallPriv;
  1246. CComPtr<IFsaResource> pRecallResource;
  1247. HRESULT hr = S_OK;
  1248. RP_MSG tmp;
  1249. DWORD outSize;
  1250. BOOL gotToInit = FALSE;
  1251. //
  1252. //
  1253. try {
  1254. //
  1255. // Get the Filter ID and find the recall object.
  1256. //
  1257. pRecall = NULL;
  1258. WsbAffirmHr(CoCreateInstance(CLSID_CFsaFilterRecallNTFS,
  1259. NULL, CLSCTX_SERVER, IID_IFsaFilterRecallPriv,
  1260. (void**) &pRecallPriv));
  1261. WsbAffirmHr(pRecallPriv->SetDriversRecallId(pIoCmd->out.msg.rReq.filterId));
  1262. WsbAffirmHr(pRecallPriv->SetThreadId(pIoCmd->out.msg.rReq.threadId));
  1263. WsbAffirmHr(pRecallPriv->CompareBy(FSA_RECALL_COMPARE_ID));
  1264. EnterCriticalSection(&m_recallLock);
  1265. hr = m_pRecalls->Find(pRecallPriv, IID_IFsaFilterRecall, (void**) &pRecall);
  1266. LeaveCriticalSection(&m_recallLock);
  1267. WsbAffirmHr(hr);
  1268. WsbAffirmHr(pRecall->CheckRecallLimit(m_minRecallInterval, m_maxRecalls, (BOOLEAN)( m_exemptAdmin ? TRUE : FALSE ) ) );
  1269. pRecallPriv = 0;
  1270. WsbAffirmHr(pRecall->QueryInterface(IID_IFsaFilterRecallPriv, (void**) &pRecallPriv));
  1271. WsbTrace(OLESTR("CFsaFilter::DoRecallAction: Recall object Found - Calling StartRecall.\n"));
  1272. // Set marker for event logging. If we have failed before this point
  1273. // we want to issue an event. Init logs it's own events
  1274. //
  1275. gotToInit = TRUE;
  1276. WsbAffirmHr(pRecallPriv->StartRecall(pIoCmd->out.msg.rReq.offset,
  1277. pIoCmd->out.msg.rReq.length));
  1278. WsbTrace(OLESTR("CFsaFilter::DoRecallAction: Recall Started.\n"));
  1279. } WsbCatchAndDo(hr,
  1280. //
  1281. // Something failed while setting up the recall.
  1282. // Free any resources required and
  1283. // tell the kernel mode filter that the recall failed.
  1284. //
  1285. tmp.inout.status = TranslateHresultToNtStatus(hr);
  1286. tmp.inout.command = RP_RECALL_COMPLETE;
  1287. tmp.msg.rRep.actionFlags = 0;
  1288. tmp.msg.rRep.filterId = pIoCmd->out.msg.rReq.filterId;
  1289. DeviceIoControl(m_ioctlHandle, FSCTL_HSM_DATA, &tmp, sizeof(RP_MSG),
  1290. &tmp, sizeof(RP_MSG), &outSize, NULL);
  1291. WsbTrace(OLESTR("CFsaFilter::DoRecallAction: Exception during recall processing.\n"));
  1292. if (FALSE == gotToInit) {
  1293. CWsbStringPtr pName;
  1294. HRESULT hrPath = E_FAIL;
  1295. //
  1296. // If we didn't complete init and the error was not due to the runaway recall limit, then we need to log an event here.
  1297. // Otherwise, an event is already sent.
  1298. //
  1299. // Get path of file failing recall.
  1300. if (pRecall != 0) {
  1301. hrPath = pRecall->GetPath((OLECHAR**) &pName, 0);
  1302. }
  1303. if (SUCCEEDED(hrPath) && ((WCHAR *)pName != NULL)) {
  1304. WsbLogEvent(FSA_MESSAGE_RECALL_FAILED, 0, NULL, (OLECHAR*) WsbAbbreviatePath(pName, 120), WsbHrAsString(hr), NULL);
  1305. } else {
  1306. if (pRecall != 0) {
  1307. WsbLogEvent(FSA_MESSAGE_RECALL_FAILED_NOT_READY, 0, NULL, OLESTR("Path is null"), WsbHrAsString(hr), NULL);
  1308. } else {
  1309. WsbLogEvent(FSA_MESSAGE_RECALL_FAILED_NOT_READY, 0, NULL, OLESTR("File not found"), WsbHrAsString(hr), NULL);
  1310. }
  1311. }
  1312. //
  1313. // We also have to free the recall object
  1314. //
  1315. if (pRecall != NULL) {
  1316. EnterCriticalSection(&m_recallLock);
  1317. m_pRecalls->RemoveAndRelease(pRecall);
  1318. LeaveCriticalSection(&m_recallLock);
  1319. }
  1320. }
  1321. );
  1322. //
  1323. // Cleanup any old client structures
  1324. // TBD This should be async and not in the recall path
  1325. //
  1326. CleanupClients();
  1327. return(hr);
  1328. }
  1329. HRESULT
  1330. CFsaFilter::DoOpenAction(
  1331. PFSA_IOCTL_CONTROL pIoCmd
  1332. )
  1333. /*++
  1334. Implements:
  1335. CFsaFilter::DoOpenAction()
  1336. Create an entry for the user opening the file and start the reall notification identification process.
  1337. --*/
  1338. {
  1339. CComPtr<IFsaFilterClient> pClient, pFoundClient;
  1340. CComPtr<IFsaFilterRecallPriv> pRecallPriv;
  1341. CComPtr<IFsaResource> pRecallResource;
  1342. CComPtr<IFsaScanItem> pScanItem;
  1343. HRESULT hr = S_OK;
  1344. PRP_MSG aTmp = NULL;
  1345. RP_MSG tmp;
  1346. DWORD ioLen, outSize;
  1347. FSA_PLACEHOLDER placeHolder;
  1348. OLECHAR *pPath = NULL;
  1349. DWORD nameLen;
  1350. DWORD dNameLen;
  1351. CWsbStringPtr uName;
  1352. CWsbStringPtr dName;
  1353. CWsbStringPtr idPath;
  1354. WCHAR userName[USER_NAME_LEN];
  1355. WCHAR domainName[USER_NAME_LEN];
  1356. SID_NAME_USE nUse;
  1357. BOOL gotToInit = FALSE;
  1358. LONGLONG fileId;
  1359. BOOL status;
  1360. DWORD lErr;
  1361. //
  1362. // Got a recall request from the filter. Create the
  1363. // necessary objects. The recall is not actually started until the first read or write.
  1364. //
  1365. // See if a client object already exists for the
  1366. // authentication ID given by the filter driver.
  1367. // If it was found then check the runaway recall limit
  1368. // and fail the recall if the limit has been reached.
  1369. // If the client object does not exist then create it
  1370. // and start the identification process (this is done by
  1371. // the client object).
  1372. // Get the resource interface for the volume the file is on.
  1373. // Create the recall object and initialize it.
  1374. //
  1375. try {
  1376. ULONG numEnt;
  1377. //
  1378. // Get the file path from the filter.
  1379. // We get it in a separate call because the path and
  1380. // security information could be very large.
  1381. // Allocate the amount of space we will need and make the
  1382. // IOCTL call to get it.
  1383. //
  1384. ioLen = sizeof(RP_MSG) + pIoCmd->out.msg.oReq.userInfoLen +
  1385. pIoCmd->out.msg.oReq.nameLen;
  1386. WsbAffirmPointer((aTmp = (RP_MSG *) malloc(ioLen)));
  1387. aTmp->inout.command = RP_GET_RECALL_INFO;
  1388. aTmp->msg.riReq.filterId = pIoCmd->out.msg.oReq.filterId;
  1389. status = DeviceIoControl(m_ioctlHandle, FSCTL_HSM_DATA, aTmp,
  1390. ioLen,
  1391. aTmp, ioLen, &outSize, NULL);
  1392. if (!status) {
  1393. lErr = GetLastError();
  1394. if (lErr == ERROR_FILE_NOT_FOUND) {
  1395. //
  1396. // This is OK - the file must have been closed
  1397. // We can just bail out.
  1398. WsbThrow(S_OK);
  1399. } else {
  1400. //
  1401. // Anything else must be an error
  1402. //
  1403. WsbThrow(HRESULT_FROM_WIN32(lErr));
  1404. }
  1405. }
  1406. //
  1407. // The path is UNICODE and in the format of
  1408. // \path\file.ext.
  1409. // or if open by ID the the ID is in the message
  1410. //
  1411. fileId = aTmp->msg.riReq.fileId;
  1412. pPath = (OLECHAR *) ((CHAR *) &aTmp->msg.riReq.userToken +
  1413. pIoCmd->out.msg.oReq.userInfoLen);
  1414. //
  1415. // Get the resource interface via the serial number
  1416. //
  1417. WsbAffirmHr(m_pFsaServer->FindResourceBySerial(pIoCmd->out.msg.oReq.serial, &pRecallResource));
  1418. WsbTrace(OLESTR("CFsaFilter::DoOpenAction: Found the resource.\n"));
  1419. //if (pIoCmd->out.msg.oReq.options & FILE_OPEN_BY_FILE_ID) {
  1420. // if ((pIoCmd->out.msg.oReq.objIdHi != 0) || (pIoCmd->out.msg.oReq.objIdLo != 0)) {
  1421. // WsbAffirmHr(pRecallResource->FindObjectId(pIoCmd->out.msg.oReq.objIdHi, pIoCmd->out.msg.oReq.objIdLo, NULL, &pScanItem));
  1422. // } else {
  1423. // WsbAffirmHr(pRecallResource->FindFileId(pIoCmd->out.msg.oReq.fileId, NULL, &pScanItem));
  1424. // }
  1425. // WsbAffirmHr(pScanItem->GetPathAndName(NULL, &idPath, 0));
  1426. // pPath = idPath;
  1427. //}
  1428. WsbTrace(OLESTR("CFsaFilter::DoOpenAction: Recall request for <%ls>\n"),
  1429. WsbAbbreviatePath(pPath, 120));
  1430. pFoundClient = NULL;
  1431. //
  1432. // Recall notification is not done for no-recall operations - skip the client stuf
  1433. //
  1434. if (!(pIoCmd->out.msg.oReq.options & FILE_OPEN_NO_RECALL)) {
  1435. //
  1436. // Set up the client interface.
  1437. // If one has not been created for this authentication ID then
  1438. // create one now.
  1439. //
  1440. WsbTrace(OLESTR("CFsaFilter::DoOpenAction: Client ID is %x:%x.\n"),
  1441. pIoCmd->out.msg.oReq.userAuthentication.HighPart,
  1442. pIoCmd->out.msg.oReq.userAuthentication.LowPart);
  1443. WsbAffirmHr(CoCreateInstance(CLSID_CFsaFilterClientNTFS, NULL, CLSCTX_SERVER, IID_IFsaFilterClient, (void**) &pClient));
  1444. WsbAffirmHr(pClient->SetAuthenticationId(pIoCmd->out.msg.oReq.userAuthentication.HighPart, pIoCmd->out.msg.oReq.userAuthentication.LowPart));
  1445. WsbAffirmHr(pClient->SetTokenSource(pIoCmd->out.msg.oReq.tokenSource));
  1446. WsbAffirmHr(pClient->CompareBy(FSA_FILTERCLIENT_COMPARE_ID));
  1447. EnterCriticalSection(&m_clientLock);
  1448. hr = m_pClients->Find(pClient, IID_IFsaFilterClient, (void**) &pFoundClient);
  1449. LeaveCriticalSection(&m_clientLock);
  1450. if (hr == WSB_E_NOTFOUND) {
  1451. //
  1452. // Did not find an existing client structure -
  1453. // use the one we created for the find to initialize a new
  1454. // one. Add it to the collection in the filter object.
  1455. //
  1456. WsbTrace(OLESTR("CFsaFilter::DoOpenAction: Create new client object.\n"));
  1457. EnterCriticalSection(&m_clientLock);
  1458. hr = m_pClients->Add(pClient);
  1459. LeaveCriticalSection(&m_clientLock);
  1460. WsbAffirmHr(hr);
  1461. pFoundClient = pClient;
  1462. //
  1463. // Get the username from the SID passed from the
  1464. // kernel mode filter.
  1465. //
  1466. try {
  1467. nameLen = USER_NAME_LEN;
  1468. dNameLen = USER_NAME_LEN;
  1469. WsbAffirmStatus((LookupAccountSidW(NULL,
  1470. (PSID) &aTmp->msg.riReq.userToken,
  1471. userName, &nameLen,
  1472. domainName, &dNameLen, &nUse)));
  1473. WsbTrace(OLESTR("CFsaFilter::DoOpenAction: User = %ls/%ls.\n"),
  1474. domainName, userName);
  1475. } WsbCatchAndDo(hr,
  1476. //
  1477. // We do not consider it a fatal error if we cannot
  1478. // get the user name and domain.
  1479. //
  1480. WsbTrace(OLESTR("CFsaFilter::DoOpenAction: Failed to get the user name - %x.\n"),
  1481. GetLastError());
  1482. wcscpy(userName, L"");
  1483. wcscpy(domainName, L"");
  1484. );
  1485. WsbAffirmHr(pFoundClient->SetUserName(userName));
  1486. WsbAffirmHr(pFoundClient->SetDomainName(domainName));
  1487. } else {
  1488. //
  1489. // The find did not return WSB_E_NOTFOUND. Make sure it was not
  1490. // some other error.
  1491. //
  1492. WsbAffirmHr(hr);
  1493. WsbTrace(OLESTR("CFsaFilter::DoOpenAction: Found the client object.\n"));
  1494. WsbAffirmHr(pFoundClient->GetUserName((OLECHAR **) &uName, 0));
  1495. WsbAffirmHr(pFoundClient->GetDomainName((OLECHAR **) &dName, 0));
  1496. wcsncpy(userName, (WCHAR *) uName, USER_NAME_LEN);
  1497. wcsncpy(domainName, (WCHAR *) dName, USER_NAME_LEN);
  1498. }
  1499. WsbTrace(OLESTR("CFsaFilter::DoOpenAction: User = %ls/%ls.\n"),
  1500. domainName, userName);
  1501. //
  1502. // Start the identification process if needed
  1503. //
  1504. // TBD This might be better done in an async fashion.
  1505. //
  1506. WsbAffirmHr(pFoundClient->StartIdentify());
  1507. WsbAffirmHr(pFoundClient->SetIsAdmin((BOOLEAN) pIoCmd->out.msg.oReq.isAdmin));
  1508. }
  1509. WsbTrace(OLESTR("CFsaFilter::DoOpenAction: Building recall request.\n"));
  1510. //
  1511. // Fill in the placeholder data the filter object will need
  1512. //
  1513. WsbAffirmHr(CopyRPDataToPlaceholder(&(pIoCmd->out.msg.oReq.eaData), &placeHolder));
  1514. //
  1515. // Now start the recall
  1516. //
  1517. //
  1518. // Create the recall interface and initialize it.
  1519. //
  1520. WsbAffirmHr(CoCreateInstance(CLSID_CFsaFilterRecallNTFS,
  1521. NULL, CLSCTX_SERVER, IID_IFsaFilterRecallPriv,
  1522. (void**) &pRecallPriv));
  1523. WsbTrace(OLESTR("CFsaFilter::DoOpenAction: Recall object created.\n"));
  1524. //
  1525. // Add it to the collection
  1526. //
  1527. EnterCriticalSection(&m_recallLock);
  1528. hr = m_pRecalls->Add(pRecallPriv);
  1529. LeaveCriticalSection(&m_recallLock);
  1530. WsbAffirmHr(hr);
  1531. hr = m_pRecalls->GetEntries(&numEnt);
  1532. WsbTrace(OLESTR("CFsaFilter::DoOpenAction: Recall queue has %u entries. Calling Init.\n"),
  1533. numEnt);
  1534. //
  1535. // Set marker for event logging. If we have failed before this point
  1536. // we want to issue an event. Init logs it's own events
  1537. //
  1538. gotToInit = TRUE;
  1539. WsbAffirmHr(pRecallPriv->Init(pFoundClient,
  1540. pIoCmd->out.msg.oReq.filterId,
  1541. pRecallResource, pPath, fileId,
  1542. pIoCmd->out.msg.oReq.offset.QuadPart,
  1543. pIoCmd->out.msg.oReq.size.QuadPart,
  1544. pIoCmd->out.msg.oReq.options,
  1545. &placeHolder,
  1546. (IFsaFilterPriv*) this));
  1547. WsbTrace(OLESTR("CFsaFilter::DoOpenAction: Init complete.\n"));
  1548. free(aTmp);
  1549. aTmp = NULL;
  1550. } WsbCatchAndDo(hr,
  1551. //
  1552. // Something failed while setting up the recall.
  1553. // Free any resources required and
  1554. // tell the kernel mode filter that the recall failed.
  1555. //
  1556. if (hr != S_OK) {
  1557. tmp.inout.status = TranslateHresultToNtStatus(hr);
  1558. tmp.inout.command = RP_RECALL_COMPLETE;
  1559. tmp.msg.rRep.actionFlags = 0;
  1560. tmp.msg.rRep.filterId = pIoCmd->out.msg.oReq.filterId;
  1561. DeviceIoControl(m_ioctlHandle, FSCTL_HSM_DATA, &tmp, sizeof(RP_MSG),
  1562. &tmp, sizeof(RP_MSG), &outSize, NULL);
  1563. WsbTrace(OLESTR("CFsaFilter::DoOpenAction: Exception during recall processing.\n"));
  1564. }
  1565. // NOTE: IF RUNAWAY RECALL BEHAVIOR CHANGES TO TRUNCATE ON CLOSE, CHANGE
  1566. // FSA_MESSAGE_HIT_RECALL_LIMIT_ACCESSDENIED TO FSA_MESSAGE_HIT_RECALL_LIMIT_TRUNCATEONCLOSE.
  1567. if ((hr != S_OK) && (FALSE == gotToInit)) {
  1568. // If we didn't complete init, then we need to log an event here.
  1569. // Otherwise, an event is already sent.
  1570. if (hr == FSA_E_HIT_RECALL_LIMIT) {
  1571. WsbLogEvent(FSA_MESSAGE_HIT_RECALL_LIMIT_ACCESSDENIED, 0, NULL, userName, NULL);
  1572. } else {
  1573. WsbLogEvent(FSA_MESSAGE_RECALL_FAILED, 0, NULL, (OLECHAR*) WsbAbbreviatePath(pPath, 120), WsbHrAsString(hr), NULL);
  1574. }
  1575. }
  1576. if (NULL != aTmp)
  1577. free(aTmp);
  1578. aTmp = NULL;
  1579. );
  1580. //
  1581. // Cleanup any old client structures
  1582. // TBD This should be async and not in the recall path
  1583. //
  1584. CleanupClients();
  1585. return(hr);
  1586. }
  1587. HRESULT
  1588. CFsaFilter::DoRecallWaitingAction(
  1589. PFSA_IOCTL_CONTROL pIoCmd
  1590. )
  1591. /*++
  1592. Implements:
  1593. CFsaFilter::DoRecallWaitingAction()
  1594. Start the reall notification identification process: this is just another client
  1595. waiting on an already issued recall
  1596. --*/
  1597. {
  1598. CComPtr<IFsaFilterClient> pClient, pFoundClient;
  1599. CComPtr<IFsaFilterRecallPriv> pRecallPriv;
  1600. CComPtr<IFsaFilterRecall> pRecall;
  1601. CComPtr<IFsaResource> pRecallResource;
  1602. CComPtr<IFsaScanItem> pScanItem;
  1603. HRESULT hr = S_OK;
  1604. PRP_MSG aTmp = NULL;
  1605. DWORD ioLen, outSize;
  1606. OLECHAR *pPath = NULL;
  1607. DWORD nameLen;
  1608. DWORD dNameLen;
  1609. CWsbStringPtr uName;
  1610. CWsbStringPtr dName;
  1611. CWsbStringPtr idPath;
  1612. WCHAR userName[USER_NAME_LEN];
  1613. WCHAR domainName[USER_NAME_LEN];
  1614. SID_NAME_USE nUse;
  1615. LONGLONG fileId;
  1616. BOOL status;
  1617. DWORD lErr;
  1618. //
  1619. // Got a recall request from the filter. Create the
  1620. // necessary objects. The recall is not actually started until the first read or write.
  1621. //
  1622. // See if a client object already exists for the
  1623. // authentication ID given by the filter driver.
  1624. // If it was found then check the runaway recall limit
  1625. // and fail the recall if the limit has been reached.
  1626. // If the client object does not exist then create it
  1627. // and start the identification process (this is done by
  1628. // the client object).
  1629. // Get the resource interface for the volume the file is on.
  1630. // Create the recall object and initialize it.
  1631. //
  1632. try {
  1633. //
  1634. // Get the file path from the filter.
  1635. // We get it in a separate call because the path and
  1636. // security information could be very large.
  1637. // Allocate the amount of space we will need and make the
  1638. // IOCTL call to get it.
  1639. //
  1640. ioLen = sizeof(RP_MSG) + pIoCmd->out.msg.oReq.userInfoLen +
  1641. pIoCmd->out.msg.oReq.nameLen;
  1642. WsbAffirmPointer((aTmp = (RP_MSG *) malloc(ioLen)));
  1643. aTmp->inout.command = RP_GET_RECALL_INFO;
  1644. aTmp->msg.riReq.filterId = pIoCmd->out.msg.oReq.filterId;
  1645. status = DeviceIoControl(m_ioctlHandle, FSCTL_HSM_DATA, aTmp,
  1646. ioLen,
  1647. aTmp, ioLen, &outSize, NULL);
  1648. if (!status) {
  1649. lErr = GetLastError();
  1650. if (lErr == ERROR_FILE_NOT_FOUND) {
  1651. //
  1652. // This is OK - the file must have been closed
  1653. // We can just bail out.
  1654. WsbThrow(S_OK);
  1655. } else {
  1656. //
  1657. // Anything else must be an error
  1658. //
  1659. WsbThrow(HRESULT_FROM_WIN32(lErr));
  1660. }
  1661. }
  1662. //
  1663. // The path is UNICODE and in the format of
  1664. // \path\file.ext.
  1665. // or if open by ID the the ID is in the message
  1666. //
  1667. fileId = aTmp->msg.riReq.fileId;
  1668. pPath = (OLECHAR *) ((CHAR *) &aTmp->msg.riReq.userToken +
  1669. pIoCmd->out.msg.oReq.userInfoLen);
  1670. //
  1671. // Get the resource interface via the serial number
  1672. //
  1673. WsbAffirmHr(m_pFsaServer->FindResourceBySerial(pIoCmd->out.msg.oReq.serial, &pRecallResource));
  1674. WsbTrace(OLESTR("CFsaFilter::DoRecallWaitingAction: Found the resource.\n"));
  1675. WsbTrace(OLESTR("CFsaFilter::DoRecallWaitingAction: Recall request for <%ls>\n"),
  1676. WsbAbbreviatePath(pPath, 120));
  1677. pFoundClient = NULL;
  1678. //
  1679. // Recall notification is not done for no-recall operations - skip the client stuf
  1680. //
  1681. if (!(pIoCmd->out.msg.oReq.options & FILE_OPEN_NO_RECALL)) {
  1682. //
  1683. // Set up the client interface.
  1684. // If one has not been created for this authentication ID then
  1685. // create one now.
  1686. //
  1687. WsbTrace(OLESTR("CFsaFilter::DoRecallWaitingAction: Client ID is %x:%x.\n"),
  1688. pIoCmd->out.msg.oReq.userAuthentication.HighPart,
  1689. pIoCmd->out.msg.oReq.userAuthentication.LowPart);
  1690. WsbAffirmHr(CoCreateInstance(CLSID_CFsaFilterClientNTFS, NULL, CLSCTX_SERVER, IID_IFsaFilterClient, (void**) &pClient));
  1691. WsbAffirmHr(pClient->SetAuthenticationId(pIoCmd->out.msg.oReq.userAuthentication.HighPart, pIoCmd->out.msg.oReq.userAuthentication.LowPart));
  1692. WsbAffirmHr(pClient->SetTokenSource(pIoCmd->out.msg.oReq.tokenSource));
  1693. WsbAffirmHr(pClient->CompareBy(FSA_FILTERCLIENT_COMPARE_ID));
  1694. EnterCriticalSection(&m_clientLock);
  1695. hr = m_pClients->Find(pClient, IID_IFsaFilterClient, (void**) &pFoundClient);
  1696. LeaveCriticalSection(&m_clientLock);
  1697. if (hr == WSB_E_NOTFOUND) {
  1698. //
  1699. // Did not find an existing client structure -
  1700. // use the one we created for the find to initialize a new
  1701. // one. Add it to the collection in the filter object.
  1702. //
  1703. WsbTrace(OLESTR("CFsaFilter::DoRecallWaitingAction: Create new client object.\n"));
  1704. EnterCriticalSection(&m_clientLock);
  1705. hr = m_pClients->Add(pClient);
  1706. LeaveCriticalSection(&m_clientLock);
  1707. WsbAffirmHr(hr);
  1708. pFoundClient = pClient;
  1709. //
  1710. // Get the username from the SID passed from the
  1711. // kernel mode filter.
  1712. //
  1713. try {
  1714. nameLen = USER_NAME_LEN;
  1715. dNameLen = USER_NAME_LEN;
  1716. WsbAffirmStatus((LookupAccountSidW(NULL,
  1717. (PSID) &aTmp->msg.riReq.userToken,
  1718. userName, &nameLen,
  1719. domainName, &dNameLen, &nUse)));
  1720. WsbTrace(OLESTR("CFsaFilter::DoRecallWaitingAction: User = %ls/%ls.\n"),
  1721. domainName, userName);
  1722. } WsbCatchAndDo(hr,
  1723. //
  1724. // We do not consider it a fatal error if we cannot
  1725. // get the user name and domain.
  1726. //
  1727. WsbTrace(OLESTR("CFsaFilter::DoRecallWaitingAction: Failed to get the user name - %x.\n"),
  1728. GetLastError());
  1729. wcscpy(userName, L"");
  1730. wcscpy(domainName, L"");
  1731. );
  1732. WsbAffirmHr(pFoundClient->SetUserName(userName));
  1733. WsbAffirmHr(pFoundClient->SetDomainName(domainName));
  1734. } else {
  1735. //
  1736. // The find did not return WSB_E_NOTFOUND. Make sure it was not
  1737. // some other error.
  1738. //
  1739. WsbAffirmHr(hr);
  1740. WsbTrace(OLESTR("CFsaFilter::DoRecallWaitingAction: Found the client object.\n"));
  1741. WsbAffirmHr(pFoundClient->GetUserName((OLECHAR **) &uName, 0));
  1742. WsbAffirmHr(pFoundClient->GetDomainName((OLECHAR **) &dName, 0));
  1743. wcsncpy(userName, (WCHAR *) uName, USER_NAME_LEN);
  1744. wcsncpy(domainName, (WCHAR *) dName, USER_NAME_LEN);
  1745. }
  1746. WsbTrace(OLESTR("CFsaFilter::DoRecallWaitingAction: User = %ls/%ls.\n"),
  1747. domainName, userName);
  1748. WsbAffirmHr(CoCreateInstance(CLSID_CFsaFilterRecallNTFS,
  1749. NULL, CLSCTX_SERVER, IID_IFsaFilterRecallPriv,
  1750. (void**) &pRecallPriv));
  1751. WsbAffirmHr(pRecallPriv->SetDriversRecallId((pIoCmd->out.msg.oReq.filterId & 0xFFFFFFFF)));
  1752. WsbAffirmHr(pRecallPriv->CompareBy(FSA_RECALL_COMPARE_CONTEXT_ID));
  1753. EnterCriticalSection(&m_recallLock);
  1754. hr = m_pRecalls->Find(pRecallPriv, IID_IFsaFilterRecall, (void**) &pRecall);
  1755. LeaveCriticalSection(&m_recallLock);
  1756. WsbAffirmHr(hr);
  1757. //
  1758. // Start the identification process if needed
  1759. //
  1760. // TBD This might be better done in an async fashion.
  1761. //
  1762. WsbAffirmHr(pFoundClient->StartIdentify());
  1763. WsbAffirmHr(pFoundClient->SetIsAdmin((BOOLEAN) pIoCmd->out.msg.oReq.isAdmin));
  1764. // Note: code for the notify itself is moved to AddClient method
  1765. hr = pRecall->AddClient(pFoundClient);
  1766. if (hr != S_OK) {
  1767. WsbTrace(OLESTR("CFsaFilterRecall::DoRecallWaitingAction: AddClient returned %ls.\n"),
  1768. WsbHrAsString(hr));
  1769. }
  1770. hr = S_OK;
  1771. }
  1772. free(aTmp);
  1773. aTmp = NULL;
  1774. } WsbCatchAndDo(hr,
  1775. //
  1776. // Something failed while setting up the recall.
  1777. // Free any resources required and
  1778. // tell the kernel mode filter that the recall failed.
  1779. //
  1780. if (NULL != aTmp)
  1781. free(aTmp);
  1782. aTmp = NULL;
  1783. );
  1784. //
  1785. // Cleanup any old client structures
  1786. // TBD This should be async and not in the recall path
  1787. //
  1788. CleanupClients();
  1789. return(hr);
  1790. }
  1791. HRESULT
  1792. CFsaFilter::DoNoRecallAction(
  1793. PFSA_IOCTL_CONTROL pIoCmd
  1794. )
  1795. /*++
  1796. Implements:
  1797. CFsaFilter::DoNoRecallAction()
  1798. This is used for read without recall - the data is copied to memory and not
  1799. written to the file.
  1800. --*/
  1801. {
  1802. CComPtr<IFsaFilterClient> pClient, pFoundClient;
  1803. //CComPtr<IFsaFilterRecallPriv> pRecall;
  1804. CComPtr<IFsaFilterRecallPriv> pRecallPriv;
  1805. CComPtr<IFsaResource> pRecallResource;
  1806. CComPtr<IFsaScanItem> pScanItem;
  1807. HRESULT hr = S_OK;
  1808. PRP_MSG aTmp = NULL;
  1809. RP_MSG tmp;
  1810. DWORD ioLen, outSize;
  1811. FSA_PLACEHOLDER placeHolder;
  1812. OLECHAR *pPath;
  1813. CWsbStringPtr idPath;
  1814. CWsbStringPtr uName;
  1815. CWsbStringPtr dName;
  1816. WCHAR userName[USER_NAME_LEN];
  1817. WCHAR domainName[USER_NAME_LEN];
  1818. try {
  1819. //
  1820. // Get the file path from the filter.
  1821. // We get it in a separate call because the path and
  1822. // security information could be very large.
  1823. // Allocate the amount of space we will need and make the
  1824. // IOCTL call to get it.
  1825. //
  1826. ioLen = sizeof(RP_MSG) + pIoCmd->out.msg.oReq.userInfoLen +
  1827. pIoCmd->out.msg.oReq.nameLen;
  1828. WsbAffirmPointer((aTmp = (RP_MSG *) malloc(ioLen)));
  1829. aTmp->inout.command = RP_GET_RECALL_INFO;
  1830. aTmp->msg.riReq.filterId = pIoCmd->out.msg.oReq.filterId;
  1831. WsbAffirmStatus(DeviceIoControl(m_ioctlHandle, FSCTL_HSM_DATA, aTmp,
  1832. ioLen,
  1833. aTmp, ioLen, &outSize, NULL));
  1834. //
  1835. // The path is UNICODE and in the format of
  1836. // \path\file.ext.
  1837. //
  1838. //
  1839. pPath = (OLECHAR *) ((CHAR *) &aTmp->msg.riReq.userToken +
  1840. pIoCmd->out.msg.oReq.userInfoLen);
  1841. WsbTrace(OLESTR("CFsaFilter::DoNoRecallAction: Recall (on read) request for %.80ls.\n"),
  1842. pPath);
  1843. //
  1844. // Get the resource interface via the serial number
  1845. //
  1846. WsbAffirmHr(m_pFsaServer->FindResourceBySerial(pIoCmd->out.msg.oReq.serial, &pRecallResource));
  1847. WsbTrace(OLESTR("CFsaFilter::DoNoRecallAction: Found the resource.\n"));
  1848. if (pIoCmd->out.msg.oReq.options & FILE_OPEN_BY_FILE_ID) {
  1849. if ((pIoCmd->out.msg.oReq.objIdHi != 0) || (pIoCmd->out.msg.oReq.objIdLo != 0)) {
  1850. WsbAffirmHr(pRecallResource->FindObjectId(pIoCmd->out.msg.oReq.objIdHi, pIoCmd->out.msg.oReq.objIdLo, NULL, &pScanItem));
  1851. } else {
  1852. WsbAffirmHr(pRecallResource->FindFileId(pIoCmd->out.msg.oReq.fileId, NULL, &pScanItem));
  1853. }
  1854. WsbAffirmHr(pScanItem->GetPathAndName(NULL, &idPath, 0));
  1855. pPath = idPath;
  1856. }
  1857. //
  1858. // Set up the client interface.
  1859. // If one has not been created for this authentication ID then
  1860. // they are out of luck
  1861. //
  1862. WsbTrace(OLESTR("CFsaFilter::DoNoRecallAction: Client ID is %x:%x.\n"),
  1863. pIoCmd->out.msg.oReq.userAuthentication.HighPart,
  1864. pIoCmd->out.msg.oReq.userAuthentication.LowPart);
  1865. WsbAffirmHr(CoCreateInstance(CLSID_CFsaFilterClientNTFS, NULL, CLSCTX_SERVER, IID_IFsaFilterClient, (void**) &pClient));
  1866. WsbAffirmHr(pClient->SetAuthenticationId(pIoCmd->out.msg.oReq.userAuthentication.HighPart, pIoCmd->out.msg.oReq.userAuthentication.LowPart));
  1867. WsbAffirmHr(pClient->SetTokenSource(pIoCmd->out.msg.oReq.tokenSource));
  1868. WsbAffirmHr(pClient->CompareBy(FSA_FILTERCLIENT_COMPARE_ID));
  1869. EnterCriticalSection(&m_clientLock);
  1870. hr = m_pClients->Find(pClient, IID_IFsaFilterClient, (void**) &pFoundClient);
  1871. LeaveCriticalSection(&m_clientLock);
  1872. if (hr != WSB_E_NOTFOUND) {
  1873. //
  1874. // The find did not return WSB_E_NOTFOUND. Make sure it was not
  1875. // some other error.
  1876. //
  1877. WsbAffirmHr(hr);
  1878. WsbTrace(OLESTR("CFsaFilter::DoNoRecallAction: Found the client object.\n"));
  1879. WsbAffirmHr(pFoundClient->GetUserName((OLECHAR **) &uName, 0));
  1880. WsbAffirmHr(pFoundClient->GetDomainName((OLECHAR **) &dName, 0));
  1881. wcsncpy(userName, (WCHAR *) uName, USER_NAME_LEN);
  1882. wcsncpy(domainName, (WCHAR *) dName, USER_NAME_LEN);
  1883. WsbTrace(OLESTR("CFsaFilter::DoNoRecallAction: User = %ls/%ls.\n"),
  1884. domainName, userName);
  1885. //
  1886. // Start the identification process if needed
  1887. //
  1888. // TBD This might be better done in an async fashion.
  1889. //
  1890. WsbAffirmHr(pFoundClient->StartIdentify());
  1891. } else {
  1892. WsbTrace(OLESTR("CFsaFilter::DoNoRecallAction: User = UNKNOWN.\n"));
  1893. pFoundClient = 0;
  1894. }
  1895. WsbTrace(OLESTR("CFsaFilter::DoNoRecallAction: Building recall request.\n"));
  1896. //
  1897. // Fill in the placeholder data the filter object will need
  1898. //
  1899. if (RP_FILE_IS_TRUNCATED(pIoCmd->out.msg.oReq.eaData.data.bitFlags))
  1900. placeHolder.isTruncated = TRUE;
  1901. else
  1902. placeHolder.isTruncated = FALSE;
  1903. placeHolder.migrationTime.dwLowDateTime = pIoCmd->out.msg.oReq.eaData.data.migrationTime.LowPart;
  1904. placeHolder.migrationTime.dwHighDateTime = pIoCmd->out.msg.oReq.eaData.data.migrationTime.HighPart;
  1905. placeHolder.hsmId = pIoCmd->out.msg.oReq.eaData.data.hsmId;
  1906. placeHolder.bagId = pIoCmd->out.msg.oReq.eaData.data.bagId;
  1907. placeHolder.fileStart = pIoCmd->out.msg.oReq.eaData.data.fileStart.QuadPart;
  1908. placeHolder.fileSize = pIoCmd->out.msg.oReq.eaData.data.fileSize.QuadPart;
  1909. placeHolder.dataStart = pIoCmd->out.msg.oReq.eaData.data.dataStart.QuadPart;
  1910. placeHolder.dataSize = pIoCmd->out.msg.oReq.eaData.data.dataSize.QuadPart;
  1911. placeHolder.fileVersionId = pIoCmd->out.msg.oReq.eaData.data.fileVersionId.QuadPart;
  1912. placeHolder.verificationData = pIoCmd->out.msg.oReq.eaData.data.verificationData.QuadPart;
  1913. placeHolder.verificationType = pIoCmd->out.msg.oReq.eaData.data.verificationType;
  1914. placeHolder.recallCount = pIoCmd->out.msg.oReq.eaData.data.recallCount;
  1915. placeHolder.recallTime.dwLowDateTime = pIoCmd->out.msg.oReq.eaData.data.recallTime.LowPart;
  1916. placeHolder.recallTime.dwHighDateTime = pIoCmd->out.msg.oReq.eaData.data.recallTime.HighPart;
  1917. placeHolder.dataStreamStart = pIoCmd->out.msg.oReq.eaData.data.dataStreamStart.QuadPart;
  1918. placeHolder.dataStreamSize = pIoCmd->out.msg.oReq.eaData.data.dataStreamSize.QuadPart;
  1919. placeHolder.dataStream = pIoCmd->out.msg.oReq.eaData.data.dataStream;
  1920. //
  1921. // Now start the recall
  1922. //
  1923. //
  1924. // Create the recall interface and initialize it.
  1925. //
  1926. WsbAffirmHr(CoCreateInstance(CLSID_CFsaFilterRecallNTFS,
  1927. NULL, CLSCTX_SERVER, IID_IFsaFilterRecallPriv,
  1928. (void**) &pRecallPriv));
  1929. WsbTrace(OLESTR("CFsaFilter::DoNoRecallAction: Recall object created.\n"));
  1930. //
  1931. // Add it to the collection
  1932. //
  1933. //
  1934. // Just add & init
  1935. //
  1936. //WsbAffirmHr(pRecallPriv->QueryInterface(IID_IFsaFilterRecall, (void **)&pRecall));
  1937. EnterCriticalSection(&m_recallLock);
  1938. hr = m_pRecalls->Add(pRecallPriv);
  1939. LeaveCriticalSection(&m_recallLock);
  1940. WsbAffirmHr(hr);
  1941. WsbTrace(OLESTR("CFsaFilter::DoNoRecallAction: Calling Init.\n"));
  1942. WsbAffirmHr(pRecallPriv->Init(pFoundClient,
  1943. pIoCmd->out.msg.oReq.filterId,
  1944. pRecallResource, pPath,
  1945. pIoCmd->out.msg.oReq.fileId,
  1946. pIoCmd->out.msg.oReq.offset.QuadPart,
  1947. pIoCmd->out.msg.oReq.size.QuadPart,
  1948. pIoCmd->out.msg.oReq.options,
  1949. &placeHolder,
  1950. (IFsaFilterPriv*) this));
  1951. WsbTrace(OLESTR("CFsaFilter::DoNoRecallAction: Init complete.\n"));
  1952. free(aTmp);
  1953. aTmp = NULL;
  1954. } WsbCatchAndDo(hr,
  1955. //
  1956. // Something failed while setting up the recall.
  1957. // Free any resources required and
  1958. // tell the kernel mode filter that the recall failed.
  1959. //
  1960. tmp.inout.status = TranslateHresultToNtStatus(hr);
  1961. tmp.inout.command = RP_RECALL_COMPLETE;
  1962. tmp.msg.rRep.actionFlags = 0;
  1963. tmp.msg.rRep.filterId = pIoCmd->out.msg.oReq.filterId;
  1964. DeviceIoControl(m_ioctlHandle, FSCTL_HSM_DATA, &tmp, sizeof(RP_MSG),
  1965. &tmp, sizeof(RP_MSG), &outSize, NULL);
  1966. WsbTrace(OLESTR("CFsaFilter::DoNoRecallAction: Exception during recall processing.\n"));
  1967. if (NULL != aTmp)
  1968. free(aTmp);
  1969. aTmp = NULL;
  1970. );
  1971. return(hr);
  1972. }
  1973. HRESULT
  1974. CFsaFilter::DoCloseAction(
  1975. PFSA_IOCTL_CONTROL pIoCmd
  1976. )
  1977. /*++
  1978. Implements:
  1979. CFsaFilter::DoCloseAction()
  1980. Handles any action that must be done to log the fact that a premigrated files data
  1981. has changed.
  1982. --*/
  1983. {
  1984. HRESULT hr = S_OK;
  1985. OLECHAR *pPath;
  1986. CComPtr<IFsaScanItem> pScanItem;
  1987. CComPtr<IFsaResource> pResource;
  1988. CWsbStringPtr idPath;
  1989. try {
  1990. //
  1991. WsbAffirmHr(m_pFsaServer->FindResourceBySerial(pIoCmd->out.msg.oReq.serial, &pResource));
  1992. WsbTrace(OLESTR("CFsaFilter::DoCloseAction: Found the resource.\n"));
  1993. //
  1994. // The path we give to the recall object does not include the
  1995. // device name.
  1996. //
  1997. WsbAffirmHr(pResource->FindFileId(pIoCmd->out.msg.oReq.fileId, NULL, &pScanItem));
  1998. WsbAffirmHr(pScanItem->GetPathAndName(NULL, &idPath, 0));
  1999. //
  2000. // We are done with this scan item
  2001. //
  2002. pScanItem = 0;
  2003. pPath = idPath;
  2004. WsbTrace(OLESTR("CFsaFilter::DoCloseAction: Close action logging for %.80ls.\n"),
  2005. pPath);
  2006. } WsbCatchAndDo(hr,
  2007. //
  2008. // Something failed while logging the close information.
  2009. // Free any resources required and
  2010. // tell the kernel mode filter that the close logging failed.
  2011. //
  2012. WsbTrace(OLESTR("CFsaFilter::DoCloseAction: Exception during close processing.\n"));
  2013. );
  2014. return(hr);
  2015. }
  2016. HRESULT
  2017. CFsaFilter::DoPreDeleteAction(
  2018. PFSA_IOCTL_CONTROL /*pIoCmd*/
  2019. )
  2020. /*++
  2021. Implements:
  2022. CFsaFilter::DoPreDeleteAction()
  2023. Log the possible delete. Note that the file id is passed and not the name.
  2024. --*/
  2025. {
  2026. HRESULT hr = S_OK;
  2027. WsbTrace(OLESTR("CFsaFilter::DoPreDeleteAction: Pre-Delete action.\n"));
  2028. return(hr);
  2029. }
  2030. HRESULT
  2031. CFsaFilter::DoPostDeleteAction(
  2032. PFSA_IOCTL_CONTROL /*pIoCmd*/
  2033. )
  2034. /*++
  2035. Implements:
  2036. CFsaFilter::DoPostDeleteAction()
  2037. Log the completed delete.
  2038. --*/
  2039. {
  2040. HRESULT hr = S_OK;
  2041. WsbTrace(OLESTR("CFsaFilter::DoPostDeleteAction: Post-Delete action.\n"));
  2042. return(hr);
  2043. }
  2044. HRESULT
  2045. CFsaFilter::DoCancelRecall(
  2046. ULONGLONG filterId
  2047. )
  2048. /*++
  2049. Implements:
  2050. CFsaFilter::DoCancelRecall
  2051. Cancel the specified recall request.
  2052. --*/
  2053. {
  2054. HRESULT hr = S_OK;
  2055. CComPtr<IFsaFilterRecallPriv> pRecallPriv;
  2056. CComPtr<IFsaFilterRecall> pRecall;
  2057. WsbTraceIn(OLESTR("CFsaFilter::DoCancelRecall"), OLESTR(""));
  2058. try {
  2059. ULONG numEnt;
  2060. if (S_OK == m_pRecalls->GetEntries(&numEnt)) {
  2061. WsbTrace(OLESTR("CFsaFilter::DoCancelRecall: Recall queue has %u entries before cancel\n"),
  2062. numEnt);
  2063. }
  2064. WsbAffirmHr(CoCreateInstance(CLSID_CFsaFilterRecallNTFS, NULL, CLSCTX_SERVER, IID_IFsaFilterRecallPriv, (void**) &pRecallPriv));
  2065. WsbAffirmHr(pRecallPriv->SetDriversRecallId(filterId));
  2066. WsbAffirmHr(pRecallPriv->CompareBy(FSA_RECALL_COMPARE_ID));
  2067. // >>> ENTER CRITICAL SECTION
  2068. EnterCriticalSection(&m_recallLock);
  2069. try {
  2070. //
  2071. // Find the recall, and cancel.
  2072. //
  2073. WsbAffirmHr(m_pRecalls->Find(pRecallPriv, IID_IFsaFilterRecall, (void**) &pRecall));
  2074. pRecallPriv = NULL;
  2075. WsbAffirmHr(pRecall->QueryInterface(IID_IFsaFilterRecallPriv, (void**) &pRecallPriv));
  2076. WsbAffirmHr(pRecallPriv->CancelByDriver());
  2077. //
  2078. // Now remove the recall from our collection
  2079. //
  2080. WsbAffirmHr(m_pRecalls->RemoveAndRelease(pRecallPriv));
  2081. WsbAffirmHr(m_pRecalls->GetEntries(&numEnt));
  2082. WsbTrace(OLESTR("CFsaFilter::DoCancelRecall: Recall queue has %u entries after cancel\n"), numEnt);
  2083. } WsbCatch(hr);
  2084. LeaveCriticalSection(&m_recallLock);
  2085. WsbThrow(hr);
  2086. // <<< LEAVE CRITICAL SECTION
  2087. } WsbCatch(hr);
  2088. WsbTraceOut(OLESTR("CFsaFilter::DoCancelRecall"), OLESTR("Hr = %ls"), WsbHrAsString(hr));
  2089. return(hr);
  2090. }
  2091. HRESULT
  2092. CFsaFilter::IoctlThread(
  2093. void
  2094. )
  2095. /*++
  2096. Implements:
  2097. IFsaFilterPriv::IoctlThread()
  2098. This is started as a thread and issues IOCTL requests to the
  2099. kernel mode File System Filter and waits for recall requests.
  2100. --*/
  2101. {
  2102. HRESULT hr = S_OK;
  2103. HANDLE port = NULL;
  2104. ULONG index;
  2105. RP_MSG tmp;
  2106. DWORD outSize;
  2107. OVERLAPPED *ovlp;
  2108. DWORD_PTR key;
  2109. DWORD lastError = NO_ERROR;
  2110. ULONG numIoPending = 0;
  2111. OLECHAR ioctlDrive[128];
  2112. CWsbStringPtr pDrv;
  2113. BOOL code;
  2114. PFSA_IOCTL_CONTROL pIoCmd, pIo;
  2115. PFSA_IOCTL_CONTROL pIoList = NULL;
  2116. SID_IDENTIFIER_AUTHORITY siaNtAuthority = SECURITY_NT_AUTHORITY;
  2117. CComPtr<IFsaResource> pResource;
  2118. BOOL ioctlCancelled = FALSE;
  2119. WsbTraceIn(OLESTR("CFsaFilter::IoctlThread"), OLESTR(""));
  2120. try {
  2121. //
  2122. // Set the ioctlDrive for the filter.
  2123. // The ioctlDrive needs to be any NTFS drive letter. By opening
  2124. // any NTFS drive we can issue IOCTL requests that the kernel mode filter
  2125. // will see. It does not matter if the drive chosen is managed or not.
  2126. // We just get the first resource interface in the list and get its drive
  2127. // letter to build the string.
  2128. //
  2129. swprintf(ioctlDrive, L"%s", RS_FILTER_SYM_LINK);
  2130. WsbTrace(OLESTR("CFsaFilter::IoctlThread: Drive = %ls\n"), ioctlDrive);
  2131. //
  2132. // Now issue several IOCTL requests to the filter driver to get
  2133. // recall requests. We must always keep at least one pending
  2134. // so the filter driver has somewhere to go when a migrated file is
  2135. // opened. We will issue the configured amount (m_maxRecallBuffers)
  2136. // and wait for completion of any of them via a completion port.
  2137. //
  2138. for (index = 0; index < m_maxRecallBuffers; index++) {
  2139. WsbAffirmPointer((pIoCmd = new FSA_IOCTL_CONTROL));
  2140. pIoCmd->next = pIoList;
  2141. pIoList = pIoCmd;
  2142. pIoCmd->overlap.hEvent = NULL;
  2143. pIoCmd->dHand = NULL;
  2144. //
  2145. // Create an event, a handle, and put it in the completion port.
  2146. //
  2147. WsbAffirmHandle(pIoCmd->overlap.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL));
  2148. WsbAffirmHandle(pIoCmd->dHand = CreateFile(ioctlDrive, GENERIC_READ | GENERIC_WRITE,
  2149. FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
  2150. FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL));
  2151. WsbAffirmHandle(port = CreateIoCompletionPort(pIoCmd->dHand, port, (DWORD_PTR) pIoCmd, 1));
  2152. pIoCmd->in.inout.command = RP_GET_REQUEST;
  2153. pIoCmd->outSize = sizeof(RP_MSG);
  2154. //
  2155. // DeviceIoctlControl should always return ERROR_IO_PENDING
  2156. //
  2157. code = DeviceIoControl(pIoCmd->dHand, FSCTL_HSM_MSG, &pIoCmd->in,
  2158. sizeof(RP_MSG),
  2159. &pIoCmd->out, pIoCmd->outSize, &pIoCmd->outSize,
  2160. &pIoCmd->overlap);
  2161. lastError = GetLastError();
  2162. if ( (code == 0) && (lastError == ERROR_IO_PENDING)) {
  2163. // Life is good
  2164. numIoPending++;
  2165. } else {
  2166. WsbTrace(OLESTR("CFsaFilter::IoctlThread: DeviceIoControl returned %ls/%ls\n"),
  2167. WsbBoolAsString(code), WsbLongAsString(lastError));
  2168. }
  2169. }
  2170. WsbTrace(OLESTR("CFsaFilter::IoctlThread: %ls ioctls issued successfully.\n"), WsbLongAsString(numIoPending));
  2171. //
  2172. // If we failed to send all Ioctls to the filter, there's no point in continuing - abort
  2173. // (note that the thread will log FSA_MESSAGE_IOCTLTHREADFAILED before terminating)
  2174. //
  2175. if (0 == numIoPending) {
  2176. hr = HRESULT_FROM_WIN32(lastError);
  2177. WsbTrace(OLESTR("CFsaFilter::IoctlThread: no ioctls issued successfully. hr=%ls\n"), WsbHrAsString(hr));
  2178. WsbAffirmHr(hr);
  2179. }
  2180. //
  2181. // Open the handle we will use for commands to the kernel filter
  2182. //
  2183. WsbAffirmHandle(m_ioctlHandle = CreateFile(ioctlDrive, GENERIC_READ | GENERIC_WRITE,
  2184. FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
  2185. FILE_ATTRIBUTE_NORMAL, NULL));
  2186. //
  2187. // Just in case we left the filter with outstanding recalls from a previous
  2188. // debug session or crash we tell it to cancel everything now.
  2189. //
  2190. tmp.inout.command = RP_CANCEL_ALL_RECALLS;
  2191. WsbAffirmStatus(DeviceIoControl(m_ioctlHandle, FSCTL_HSM_DATA, &tmp,
  2192. sizeof(RP_MSG),
  2193. &tmp, sizeof(RP_MSG), &outSize, NULL))
  2194. //
  2195. // Now that we are ready to get recall requests we can tell the
  2196. // driver to start checking for recall activity.
  2197. //
  2198. tmp.inout.command = RP_ALLOW_NEW_RECALLS;
  2199. WsbAffirmStatus(DeviceIoControl(m_ioctlHandle, FSCTL_HSM_DATA, &tmp,
  2200. sizeof(RP_MSG),
  2201. &tmp, sizeof(RP_MSG), &outSize, NULL))
  2202. WsbTrace(OLESTR("CFsaFilter::IoctlThread: Kernel level filter recalls enabled.\n"));
  2203. //
  2204. // We are now ready to rock and roll
  2205. //
  2206. m_state = HSM_JOB_STATE_ACTIVE;
  2207. //
  2208. // Now just sit around and wait for the IO requests to complete. When
  2209. // they do we are either quitting or a recall request was detected.
  2210. //
  2211. while (TRUE) {
  2212. //
  2213. // Wait for an IO request to complete.
  2214. //
  2215. if (! GetQueuedCompletionStatus(port, &outSize, &key, &ovlp, INFINITE)) {
  2216. DWORD dwErr = GetLastError();
  2217. if (ERROR_OPERATION_ABORTED == dwErr) {
  2218. numIoPending--;
  2219. ioctlCancelled = TRUE;
  2220. }
  2221. WsbAffirmHr(HRESULT_FROM_WIN32(dwErr));
  2222. } else {
  2223. numIoPending--;
  2224. }
  2225. pIoCmd = (FSA_IOCTL_CONTROL *) key;
  2226. WsbAffirm(NULL != pIoCmd, E_FAIL);
  2227. WsbTrace(OLESTR("CFsaFilter::IoctlThread: Filter event detected (%x:%x), Id = %I64x.\n"),
  2228. pIoCmd->out.inout.command,
  2229. pIoCmd->out.msg.oReq.action,
  2230. pIoCmd->out.msg.oReq.filterId);
  2231. switch (pIoCmd->out.inout.command) {
  2232. case RP_OPEN_FILE:
  2233. hr = DoOpenAction(pIoCmd);
  2234. break;
  2235. case RP_RECALL_WAITING:
  2236. hr = DoRecallWaitingAction(pIoCmd);
  2237. break;
  2238. //
  2239. // Must be a cancelled recall
  2240. //
  2241. case RP_CANCEL_RECALL:
  2242. DoCancelRecall(pIoCmd->out.msg.cReq.filterId);
  2243. break;
  2244. case RP_RUN_VALIDATE:
  2245. //
  2246. // A validate job is needed on a given volume (serial number is passed)
  2247. // No completion message is expected by the filter for this action.
  2248. //
  2249. WsbTrace(OLESTR("CFsaFilter::Ioctlthread - Validate job for %x is needed\n"),
  2250. pIoCmd->out.msg.oReq.serial);
  2251. try {
  2252. SYSTEMTIME sysTime;
  2253. FILETIME curTime;
  2254. LARGE_INTEGER ctime;
  2255. GetLocalTime(&sysTime);
  2256. WsbAffirmStatus(SystemTimeToFileTime(&sysTime, &curTime));
  2257. ctime.LowPart = curTime.dwLowDateTime;
  2258. ctime.HighPart = curTime.dwHighDateTime;
  2259. ctime.QuadPart += WSB_FT_TICKS_PER_HOUR * 2;
  2260. curTime.dwLowDateTime = ctime.LowPart;
  2261. curTime.dwHighDateTime = ctime.HighPart;
  2262. WsbAffirmStatus(FileTimeToSystemTime(&curTime, &sysTime));
  2263. WsbAffirmHr(m_pFsaServer->FindResourceBySerial(pIoCmd->out.msg.oReq.serial, &pResource));
  2264. WsbAffirmHr(pResource->SetupValidateJob(sysTime));
  2265. } WsbCatchAndDo(hr,
  2266. //
  2267. // Log an event indicating that the validate job should be run manually
  2268. //
  2269. CWsbStringPtr tmpStr;
  2270. if (pResource != 0) {
  2271. hr = pResource->GetLogicalName(&tmpStr, 0);
  2272. if (hr != S_OK) {
  2273. tmpStr = L"<Unknown Volume>";
  2274. }
  2275. } else {
  2276. tmpStr = L"<Unknown Volume>";
  2277. }
  2278. WsbLogEvent(FSA_MESSAGE_AUTOVALIDATE_SCHEDULE_FAILED, 0, NULL, (OLECHAR *) tmpStr, NULL);
  2279. );
  2280. break;
  2281. case RP_RECALL_FILE:
  2282. hr = DoRecallAction(pIoCmd);
  2283. break;
  2284. case RP_START_NOTIFY:
  2285. break;
  2286. case RP_END_NOTIFY:
  2287. break;
  2288. case RP_CLOSE_FILE:
  2289. break;
  2290. default:
  2291. WsbTrace(OLESTR("CFsaFilter::IoctlThread: Unknown filter request - %u.\n"),
  2292. pIoCmd->out.inout.command);
  2293. break;
  2294. }
  2295. WsbTrace(OLESTR("CFsaFilter::IoctlThread: Issue new Ioctl.\n"));
  2296. //
  2297. // If object is still active, reset the event and issue another IOCTL
  2298. //
  2299. EnterCriticalSection(&m_stateLock);
  2300. if (m_state == HSM_JOB_STATE_ACTIVE) {
  2301. ResetEvent(pIoCmd->overlap.hEvent);
  2302. pIoCmd->in.inout.command = RP_GET_REQUEST;
  2303. pIoCmd->outSize = sizeof(RP_MSG);
  2304. code = DeviceIoControl(pIoCmd->dHand, FSCTL_HSM_MSG,
  2305. &pIoCmd->in,
  2306. sizeof(RP_MSG),
  2307. &pIoCmd->out, pIoCmd->outSize,
  2308. &pIoCmd->outSize, &pIoCmd->overlap);
  2309. lastError = GetLastError();
  2310. if ( (code == 0) && (lastError == ERROR_IO_PENDING)) {
  2311. // Life is good
  2312. numIoPending++;
  2313. } else {
  2314. WsbTrace(OLESTR("CFsaFilter::IoctlThread: DeviceIoControl returned %ls/%ls\n"),
  2315. WsbBoolAsString(code), WsbLongAsString(lastError));
  2316. }
  2317. } else {
  2318. //
  2319. // Get out of the while loop
  2320. //
  2321. hr = S_OK;
  2322. LeaveCriticalSection(&m_stateLock);
  2323. break;
  2324. }
  2325. LeaveCriticalSection(&m_stateLock);
  2326. } // End while active
  2327. //
  2328. // Now tell the filter we are going away and it should fail all recall activity .
  2329. //
  2330. tmp.inout.command = RP_SUSPEND_NEW_RECALLS;
  2331. WsbAffirmStatus(DeviceIoControl(m_ioctlHandle, FSCTL_HSM_DATA, &tmp,
  2332. sizeof(RP_MSG),
  2333. &tmp, sizeof(RP_MSG), &outSize, NULL))
  2334. } WsbCatch(hr);
  2335. //
  2336. // We need to wait for rest of Ioctls to be cancelled if we got out of the loop
  2337. // either because the object is not active or the first Ioctl was cancelled
  2338. // We cannot free Ioctl related data safely until all of them are done
  2339. //
  2340. if ((S_OK == hr) || ioctlCancelled) {
  2341. //
  2342. // Try to wait for the rest of the Ioctls to be cancelled
  2343. //
  2344. HRESULT freeHr;
  2345. hr = S_OK;
  2346. try {
  2347. WsbTrace(OLESTR("CFsaFilter::IoctlThread: Waiting for %lu more Ioctls to complete before freeing their resources\n"), numIoPending);
  2348. for (index = 0; index < numIoPending; index++) {
  2349. if (! GetQueuedCompletionStatus(port, &outSize, &key, &ovlp, 2000)) {
  2350. DWORD dwErr = GetLastError();
  2351. if (ERROR_OPERATION_ABORTED != dwErr) {
  2352. WsbAffirmHr(HRESULT_FROM_WIN32(dwErr));
  2353. }
  2354. }
  2355. }
  2356. //
  2357. // If we got here, all the Ioctls were cancelled or completed as expected.
  2358. // It is safe to free their related resources
  2359. //
  2360. WsbTrace(OLESTR("CFsaFilter::IoctlThread: All of %lu Ioctls completed - free resources\n"), m_maxRecallBuffers);
  2361. pIoCmd = pIoList;
  2362. while (pIoCmd != NULL) {
  2363. if (pIoCmd->overlap.hEvent != NULL) {
  2364. CloseHandle(pIoCmd->overlap.hEvent);
  2365. }
  2366. if (pIoCmd->dHand != NULL) {
  2367. CloseHandle(pIoCmd->dHand);
  2368. }
  2369. pIo = pIoCmd;
  2370. pIoCmd = pIoCmd->next;
  2371. delete pIo;
  2372. }
  2373. pIoList = NULL;
  2374. WsbTrace(OLESTR("CFsaFilter::IoctlThread: Freed Ioctls resources successfully\n"));
  2375. } WsbCatchAndDo(freeHr,
  2376. WsbTraceAlways(L"CFsaResource::IoctlThread - Failed to free Ioctls, freeHr = %ls\n",
  2377. WsbHrAsString(freeHr));
  2378. );
  2379. }
  2380. //
  2381. // Free rest of allocated resources
  2382. // Note that if we couldn't wait for all the Ioctls to complete (or cancel)
  2383. // we better exit without freeing the Ioctl list
  2384. //
  2385. if (m_ioctlHandle != INVALID_HANDLE_VALUE) {
  2386. CloseHandle(m_ioctlHandle);
  2387. m_ioctlHandle = INVALID_HANDLE_VALUE;
  2388. }
  2389. if (port != NULL) {
  2390. CloseHandle(port);
  2391. }
  2392. if (m_state == HSM_JOB_STATE_ACTIVE) {
  2393. //
  2394. // There must have been an error of some kind
  2395. //
  2396. WsbLogEvent(FSA_MESSAGE_IOCTLTHREADFAILED, 0, NULL, WsbHrAsString(hr), NULL);
  2397. }
  2398. //
  2399. // Set the filter state to idle
  2400. //
  2401. m_state = HSM_JOB_STATE_IDLE;
  2402. WsbTraceOut(OLESTR("CFsaFilter::IoctlThread"), OLESTR("Hr = %ls"), WsbHrAsString(hr));
  2403. return(0);
  2404. }
  2405. HRESULT
  2406. CFsaFilter::PipeThread(
  2407. void
  2408. )
  2409. /*++
  2410. Implements:
  2411. IFsaFilterPriv::PipeThread()
  2412. This is started as a thread and creates the named pipe used by recall notification
  2413. clients to identify themselves. When an identification response is received we
  2414. impersonate the client, get the authentication token and find the client instance that
  2415. matches the token. If we find the client object we wet the machine name.
  2416. --*/
  2417. {
  2418. HRESULT hr = S_OK;
  2419. BOOL exitLoop, code, connected;
  2420. DWORD lastError, bytesRead, retCode;
  2421. WCHAR pName[100];
  2422. WSB_PIPE_MSG msg;
  2423. CComPtr<IFsaFilterClient> pClient;
  2424. HANDLE tHandle = INVALID_HANDLE_VALUE;
  2425. HANDLE handleArray[2];
  2426. DWORD retLen;
  2427. TOKEN_STATISTICS tStats;
  2428. SHORT result;
  2429. OVERLAPPED pOverlap;
  2430. WCHAR machineName[MAX_COMPUTERNAME_LENGTH + 1];
  2431. memset (&pOverlap, 0, sizeof(OVERLAPPED));
  2432. pOverlap.hEvent = INVALID_HANDLE_VALUE;
  2433. try {
  2434. WsbTraceIn(OLESTR("CFsaFilter::PipeThread"), OLESTR(""));
  2435. //
  2436. // Create a client instance to use for finding the client of interest.
  2437. //
  2438. WsbAffirmHr(CoCreateInstance(CLSID_CFsaFilterClientNTFS, NULL, CLSCTX_SERVER, IID_IFsaFilterClient, (void**) &pClient));
  2439. //
  2440. // Create a security scheme that allows anyone to write to the pipe on the client side,
  2441. // but preserves create-access (therefore creating-server-side privilege) to local system and admins.
  2442. //
  2443. PSID pAdminSID = NULL;
  2444. PSID pSystemSID = NULL;
  2445. PSID pWorldSID = NULL;
  2446. PSID pGuestSID = NULL;
  2447. PACL pACL = NULL;
  2448. PSECURITY_DESCRIPTOR pSD = NULL;
  2449. #define FSA_PIPE_NUM_ACE 4
  2450. EXPLICIT_ACCESS ea[FSA_PIPE_NUM_ACE];
  2451. SID_IDENTIFIER_AUTHORITY SIDAuthNT = SECURITY_NT_AUTHORITY;
  2452. SID_IDENTIFIER_AUTHORITY SIDAuthWorld = SECURITY_WORLD_SID_AUTHORITY;
  2453. SECURITY_ATTRIBUTES sa;
  2454. memset(ea, 0, sizeof(EXPLICIT_ACCESS) * FSA_PIPE_NUM_ACE);
  2455. try {
  2456. // Create a SID for World
  2457. WsbAssertStatus( AllocateAndInitializeSid( &SIDAuthWorld, 1,
  2458. SECURITY_WORLD_RID,
  2459. 0, 0, 0, 0, 0, 0, 0,
  2460. &pWorldSID) );
  2461. // Initialize an EXPLICIT_ACCESS structure for an ACE.
  2462. // The ACE allows the World limited access to the pipe
  2463. ea[0].grfAccessPermissions = (FILE_ALL_ACCESS & ~(FILE_CREATE_PIPE_INSTANCE | WRITE_OWNER | WRITE_DAC));
  2464. ea[0].grfAccessMode = SET_ACCESS;
  2465. ea[0].grfInheritance = SUB_CONTAINERS_AND_OBJECTS_INHERIT;
  2466. ea[0].Trustee.pMultipleTrustee = NULL;
  2467. ea[0].Trustee.MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE;
  2468. ea[0].Trustee.TrusteeForm = TRUSTEE_IS_SID;
  2469. ea[0].Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP;
  2470. ea[0].Trustee.ptstrName = (LPTSTR) pWorldSID;
  2471. // Create a SID for Guest
  2472. WsbAssertStatus( AllocateAndInitializeSid( &SIDAuthNT, 2,
  2473. SECURITY_BUILTIN_DOMAIN_RID,
  2474. DOMAIN_ALIAS_RID_GUESTS,
  2475. 0, 0, 0, 0, 0, 0,
  2476. &pGuestSID) );
  2477. // Initialize an EXPLICIT_ACCESS structure for an ACE.
  2478. // The ACE allows the Guests limited access to the pipe
  2479. ea[1].grfAccessPermissions = (FILE_ALL_ACCESS & ~(FILE_CREATE_PIPE_INSTANCE | WRITE_OWNER | WRITE_DAC));
  2480. ea[1].grfAccessMode = SET_ACCESS;
  2481. ea[1].grfInheritance = SUB_CONTAINERS_AND_OBJECTS_INHERIT;
  2482. ea[1].Trustee.pMultipleTrustee = NULL;
  2483. ea[1].Trustee.MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE;
  2484. ea[1].Trustee.TrusteeForm = TRUSTEE_IS_SID;
  2485. ea[1].Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP;
  2486. ea[1].Trustee.ptstrName = (LPTSTR) pGuestSID;
  2487. // Create a SID for the Administrators group.
  2488. WsbAssertStatus( AllocateAndInitializeSid( &SIDAuthNT, 2,
  2489. SECURITY_BUILTIN_DOMAIN_RID,
  2490. DOMAIN_ALIAS_RID_ADMINS,
  2491. 0, 0, 0, 0, 0, 0,
  2492. &pAdminSID) );
  2493. // Initialize an EXPLICIT_ACCESS structure for an ACE.
  2494. // The ACE allows the Administrators group full access to the pipe
  2495. ea[2].grfAccessPermissions = FILE_ALL_ACCESS;
  2496. ea[2].grfAccessMode = SET_ACCESS;
  2497. ea[2].grfInheritance = SUB_CONTAINERS_AND_OBJECTS_INHERIT;
  2498. ea[2].Trustee.pMultipleTrustee = NULL;
  2499. ea[2].Trustee.MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE;
  2500. ea[2].Trustee.TrusteeForm = TRUSTEE_IS_SID;
  2501. ea[2].Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP;
  2502. ea[2].Trustee.ptstrName = (LPTSTR) pAdminSID;
  2503. // Create a SID for the local system account
  2504. WsbAssertStatus( AllocateAndInitializeSid( &SIDAuthNT, 1,
  2505. SECURITY_LOCAL_SYSTEM_RID,
  2506. 0, 0, 0, 0, 0, 0, 0,
  2507. &pSystemSID) );
  2508. // Initialize an EXPLICIT_ACCESS structure for an ACE.
  2509. // The ACE allows the local system full access to the pipe
  2510. ea[3].grfAccessPermissions = FILE_ALL_ACCESS;
  2511. ea[3].grfAccessMode = SET_ACCESS;
  2512. ea[3].grfInheritance = SUB_CONTAINERS_AND_OBJECTS_INHERIT;
  2513. ea[3].Trustee.pMultipleTrustee = NULL;
  2514. ea[3].Trustee.MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE;
  2515. ea[3].Trustee.TrusteeForm = TRUSTEE_IS_SID;
  2516. ea[3].Trustee.TrusteeType = TRUSTEE_IS_USER;
  2517. ea[3].Trustee.ptstrName = (LPTSTR) pSystemSID;
  2518. // Create a new ACL that contains the new ACEs.
  2519. WsbAffirmNoError( SetEntriesInAcl(FSA_PIPE_NUM_ACE, ea, NULL, &pACL));
  2520. // Initialize a security descriptor.
  2521. pSD = (PSECURITY_DESCRIPTOR) WsbAlloc(SECURITY_DESCRIPTOR_MIN_LENGTH);
  2522. WsbAffirmPointer(pSD);
  2523. WsbAffirmStatus(InitializeSecurityDescriptor(pSD, SECURITY_DESCRIPTOR_REVISION));
  2524. // Add the ACL to the security descriptor.
  2525. WsbAffirmStatus(SetSecurityDescriptorDacl(
  2526. pSD,
  2527. TRUE, // fDaclPresent flag
  2528. pACL,
  2529. FALSE)); // not a default DACL
  2530. // Initialize a security attributes structure.
  2531. sa.nLength = sizeof (SECURITY_ATTRIBUTES);
  2532. sa.lpSecurityDescriptor = pSD;
  2533. sa.bInheritHandle = FALSE;
  2534. //
  2535. // Create a local named pipe with
  2536. // the hsm pipe name
  2537. // '.' signifies local pipe.
  2538. swprintf(pName, L"\\\\.\\PIPE\\%s", WSB_PIPE_NAME);
  2539. WsbAffirmHandle((m_pipeHandle = CreateNamedPipeW(pName,
  2540. PIPE_ACCESS_INBOUND // Inbound - Service only receives identify messages on this pipe
  2541. | FILE_FLAG_OVERLAPPED // Use overlapped structure.
  2542. | FILE_FLAG_FIRST_PIPE_INSTANCE, // Make sure we are the creator of the pipe
  2543. PIPE_WAIT | // Wait on messages.
  2544. PIPE_TYPE_BYTE,
  2545. WSB_MAX_PIPES,
  2546. WSB_PIPE_BUFF_SIZE,
  2547. WSB_PIPE_BUFF_SIZE,
  2548. WSB_PIPE_TIME_OUT, // Specify time out.
  2549. &sa))); // Security attributes.
  2550. } WsbCatch(hr);
  2551. //
  2552. // Free security objects and verify hr of pipe creation
  2553. //
  2554. if (pAdminSID) {
  2555. FreeSid(pAdminSID);
  2556. }
  2557. if (pSystemSID) {
  2558. FreeSid(pSystemSID);
  2559. }
  2560. if (pWorldSID) {
  2561. FreeSid(pWorldSID);
  2562. }
  2563. if (pGuestSID) {
  2564. FreeSid(pGuestSID);
  2565. }
  2566. if (pACL) {
  2567. LocalFree(pACL);
  2568. }
  2569. if (pSD) {
  2570. WsbFree(pSD);
  2571. }
  2572. WsbAffirmHr(hr);
  2573. //
  2574. // Create an event for overlapped i/o
  2575. //
  2576. WsbAffirmHandle((pOverlap.hEvent = CreateEvent(NULL,
  2577. FALSE,
  2578. FALSE,
  2579. NULL)));
  2580. //
  2581. // Initialize the handle array. The first element sbould be the terminate event,
  2582. // because we need to know if it signalled and always break out of the loop
  2583. // regardless of whether the overlapped i/o is done or not
  2584. //
  2585. handleArray[0] = m_terminateEvent;
  2586. handleArray[1] = pOverlap.hEvent;
  2587. exitLoop = FALSE;
  2588. while ((!exitLoop) && ((m_state == HSM_JOB_STATE_ACTIVE) || (m_state == HSM_JOB_STATE_STARTING))) {
  2589. connected = FALSE;
  2590. //
  2591. // Block until a client connects.
  2592. //
  2593. code = ConnectNamedPipe(m_pipeHandle, &pOverlap);
  2594. if (!code) {
  2595. lastError = GetLastError();
  2596. switch (lastError) {
  2597. // IO_PENDING, wait on the event
  2598. case ERROR_IO_PENDING: {
  2599. retCode = WaitForMultipleObjects(2,
  2600. handleArray,
  2601. FALSE,
  2602. INFINITE);
  2603. if (retCode == WAIT_OBJECT_0) {
  2604. //
  2605. // The termination event got signalled
  2606. //
  2607. exitLoop = TRUE;
  2608. continue;
  2609. } else if (retCode == (WAIT_OBJECT_0+1)) {
  2610. //
  2611. // A client connected
  2612. //
  2613. connected = TRUE;
  2614. }
  2615. break;
  2616. }
  2617. case ERROR_BROKEN_PIPE: {
  2618. //
  2619. // Pipe is broken, reconnect
  2620. //
  2621. break;
  2622. }
  2623. default: {
  2624. //
  2625. // Something else is wrong, just reconnect
  2626. //
  2627. break;
  2628. }
  2629. }
  2630. } else {
  2631. connected = TRUE;
  2632. }
  2633. if (connected) {
  2634. //
  2635. // A client connected - get the identify message, identify them and continue waiting for
  2636. // pipe conections.
  2637. //
  2638. WsbTrace(OLESTR("CFsaFilter::PipeThread: Client has connected.\n"));
  2639. pOverlap.Offset = 0;
  2640. pOverlap.OffsetHigh = 0;
  2641. code = ReadFile(m_pipeHandle, &msg, sizeof(WSB_PIPE_MSG), &bytesRead, &pOverlap);
  2642. if (!code) {
  2643. lastError = GetLastError();
  2644. }
  2645. else {
  2646. lastError = ERROR_IO_PENDING; // Read returned right away
  2647. }
  2648. switch (lastError) {
  2649. // IO_PENDING, wait on the event or timeout in 4 seconds
  2650. case ERROR_IO_PENDING:
  2651. if (!code) {
  2652. retCode = WaitForMultipleObjects(2,
  2653. handleArray,
  2654. FALSE,
  2655. (DWORD) 4000);
  2656. } else {
  2657. retCode = WAIT_OBJECT_0 + 1; // Read returned right away
  2658. }
  2659. if (retCode == (WAIT_OBJECT_0+1)) {
  2660. //
  2661. // Read some data. Do the identification
  2662. //
  2663. GetOverlappedResult(m_pipeHandle, &pOverlap, &bytesRead, FALSE);
  2664. if (bytesRead == sizeof(WSB_PIPE_MSG)) {
  2665. //
  2666. // Make sure the message is of the right type
  2667. // (Currently, only WSB_PMSG_IDENTIFY is valid)
  2668. //
  2669. if (msg.msgType != WSB_PMSG_IDENTIFY) {
  2670. // bogus message - ignore it
  2671. WsbTrace(OLESTR("CFsaFilter::PipeThread: Bad message type (%lu)\n"), msg.msgType);
  2672. DisconnectNamedPipe(m_pipeHandle);
  2673. break;
  2674. }
  2675. //
  2676. // Find the client instance that matches this user
  2677. //
  2678. code = ImpersonateNamedPipeClient(m_pipeHandle);
  2679. if (code) {
  2680. code = OpenThreadToken(GetCurrentThread(), TOKEN_QUERY,
  2681. TRUE, &tHandle);
  2682. }
  2683. if (code) {
  2684. code = GetTokenInformation(tHandle, TokenStatistics, &tStats,
  2685. sizeof(TOKEN_STATISTICS), &retLen);
  2686. CloseHandle(tHandle);
  2687. if (code) {
  2688. //
  2689. // Get the passed in machine name in a local buffer and null terminated
  2690. //
  2691. wcsncpy(machineName, msg.msg.idrp.clientName, MAX_COMPUTERNAME_LENGTH);
  2692. machineName[MAX_COMPUTERNAME_LENGTH] = L'\0';
  2693. //
  2694. // First we need to clean up any old client objects that
  2695. // have the same machine name. It is assumed that there can
  2696. // only be one client per machine and a duplicate means that
  2697. // they must have re-connected with a different authentication
  2698. // token.
  2699. //
  2700. {
  2701. CComPtr<IFsaFilterClient> pFoundClient;
  2702. WsbAffirmHr(pClient->SetMachineName(machineName));
  2703. WsbAffirmHr(pClient->CompareBy(FSA_FILTERCLIENT_COMPARE_MACHINE));
  2704. EnterCriticalSection(&m_clientLock);
  2705. hr = m_pClients->Find(pClient, IID_IFsaFilterClient, (void**) &pFoundClient);
  2706. LeaveCriticalSection(&m_clientLock);
  2707. if (hr == S_OK) {
  2708. //
  2709. // Found one with the same machine name - make sure the token
  2710. // does not match, just to be sure.
  2711. //
  2712. hr = pFoundClient->CompareToAuthenticationId(tStats.AuthenticationId.HighPart,
  2713. tStats.AuthenticationId.LowPart, &result);
  2714. if (hr != S_OK) {
  2715. //
  2716. // It did not match - remove and release this one from
  2717. // the collection.
  2718. //
  2719. EnterCriticalSection(&m_clientLock);
  2720. hr = m_pClients->RemoveAndRelease(pFoundClient);
  2721. LeaveCriticalSection(&m_clientLock);
  2722. }
  2723. }
  2724. } // Let pFoundClient go out of scope
  2725. {
  2726. CComPtr<IFsaFilterClient> pFoundClient;
  2727. //
  2728. // Now set the machine name for this client if we can find
  2729. // it by authentication id.
  2730. //
  2731. WsbAffirmHr(pClient->SetAuthenticationId(tStats.AuthenticationId.HighPart,
  2732. tStats.AuthenticationId.LowPart));
  2733. WsbAffirmHr(pClient->CompareBy(FSA_FILTERCLIENT_COMPARE_ID));
  2734. WsbTrace(OLESTR("CFsaFilter::PipeThread: Finding client instance (%x:%x).\n"),
  2735. tStats.AuthenticationId.HighPart,
  2736. tStats.AuthenticationId.LowPart);
  2737. EnterCriticalSection(&m_clientLock);
  2738. hr = m_pClients->Find(pClient, IID_IFsaFilterClient, (void**) &pFoundClient);
  2739. LeaveCriticalSection(&m_clientLock);
  2740. if (hr == S_OK) {
  2741. //
  2742. // Got it - set the machine name
  2743. //
  2744. WsbTrace(OLESTR("CFsaFilter::PipeThread: Identify client as %ws.\n"),
  2745. machineName);
  2746. pFoundClient->SetMachineName(machineName);
  2747. } else {
  2748. WsbTrace(OLESTR("CFsaFilter::PipeThread: Failed to find the client instance (%ls).\n"),
  2749. WsbHrAsString(hr));
  2750. }
  2751. } // Let pFoundClient go out of scope
  2752. } else {
  2753. WsbTrace(OLESTR("CFsaFilter::PipeThread: GetTokenInformation returned %u.\n"),
  2754. GetLastError());
  2755. }
  2756. } else {
  2757. WsbTrace(OLESTR("CFsaFilter::PipeThread: OpenThreadToken or ImpersonateNamedPipeClient returned %u.\n"),
  2758. GetLastError());
  2759. }
  2760. RevertToSelf();
  2761. DisconnectNamedPipe(m_pipeHandle);
  2762. } else {
  2763. //
  2764. // Bad data was read - blow them off
  2765. //
  2766. WsbTrace(OLESTR("CFsaFilter::PipeThread: Bad message size (%u)\n"),
  2767. bytesRead);
  2768. DisconnectNamedPipe(m_pipeHandle);
  2769. }
  2770. } else {
  2771. //
  2772. // Timeout or error - cancel the read and disconnect the client
  2773. //
  2774. DisconnectNamedPipe(m_pipeHandle);
  2775. if (retCode == WAIT_OBJECT_0) {
  2776. //
  2777. // Termination event was signalled
  2778. //
  2779. exitLoop = TRUE;
  2780. continue;
  2781. }
  2782. }
  2783. break;
  2784. case ERROR_BROKEN_PIPE: {
  2785. // Pipe is broken.,
  2786. DisconnectNamedPipe(m_pipeHandle);
  2787. break;
  2788. }
  2789. default: {
  2790. // Something else is wrong.
  2791. DisconnectNamedPipe(m_pipeHandle);
  2792. break;
  2793. }
  2794. }
  2795. }
  2796. } // End while state
  2797. } WsbCatch(hr);
  2798. if (m_pipeHandle != INVALID_HANDLE_VALUE) {
  2799. CloseHandle(m_pipeHandle);
  2800. m_pipeHandle = INVALID_HANDLE_VALUE;
  2801. }
  2802. if (pOverlap.hEvent != INVALID_HANDLE_VALUE) {
  2803. CloseHandle(pOverlap.hEvent);
  2804. }
  2805. WsbTraceOut(OLESTR("CFsaFilter::PipeThread"), OLESTR("Hr = %ls"), WsbHrAsString(hr));
  2806. return (hr);
  2807. }