Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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