Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

4388 lines
130 KiB

  1. /*++
  2. Copyright (c) 1989-1999 Microsoft Corporation
  3. Module Name:
  4. fspyLib.c
  5. Abstract:
  6. This contains library support routines for FileSpy. These routines
  7. do the main work for logging the I/O operations --- creating the log
  8. records, recording the relevant information, attach/detach from
  9. devices, etc.
  10. As of the Windows XP SP1 IFS Kit version of this sample and later, this
  11. sample can be built for each build environment released with the IFS Kit
  12. with no additional modifications. To provide this capability, additional
  13. compile-time logic was added -- see the '#if WINVER' locations. Comments
  14. tagged with the 'VERSION NOTE' header have also been added as appropriate to
  15. describe how the logic must change between versions.
  16. If this sample is built in the Windows XP environment or later, it will run
  17. on Windows 2000 or later. This is done by dynamically loading the routines
  18. that are only available on Windows XP or later and making run-time decisions
  19. to determine what code to execute. Comments tagged with 'MULTIVERISON NOTE'
  20. mark the locations where such logic has been added.
  21. Environment:
  22. Kernel mode
  23. // @@BEGIN_DDKSPLIT
  24. Author:
  25. George Jenkins (georgeje) 6-Jan-1999
  26. Neal Christiansen (nealch)
  27. Molly Brown (mollybro)
  28. Revision History:
  29. Neal Christiansen (nealch) 06-Jul-2001
  30. Modified to use Stream Contexts to track names
  31. Ravisankar Pudipeddi (ravisp) 07-May-2002
  32. Make it work on IA64
  33. Molly Brown (mollybro) 21-May-2002
  34. Modify sample to make it support running on Windows 2000 or later if
  35. built in the latest build environment and allow it to be built in W2K
  36. and later build environments.
  37. // @@END_DDKSPLIT
  38. --*/
  39. #include <stdio.h>
  40. #include <ntifs.h>
  41. #include "filespy.h"
  42. #include "fspyKern.h"
  43. #ifdef ALLOC_PRAGMA
  44. #pragma alloc_text(INIT, SpyReadDriverParameters)
  45. #pragma alloc_text(PAGE, SpyAttachDeviceToDeviceStack)
  46. #pragma alloc_text(PAGE, SpyQueryFileSystemForFileName)
  47. #pragma alloc_text(PAGE, SpyQueryInformationFile)
  48. #pragma alloc_text(PAGE, SpyIsAttachedToDeviceByUserDeviceName)
  49. #pragma alloc_text(PAGE, SpyIsAttachedToDevice)
  50. #pragma alloc_text(PAGE, SpyIsAttachedToDeviceW2K)
  51. #pragma alloc_text(PAGE, SpyAttachToMountedDevice)
  52. #pragma alloc_text(PAGE, SpyCleanupMountedDevice)
  53. #pragma alloc_text(PAGE, SpyAttachToDeviceOnDemand)
  54. #pragma alloc_text(PAGE, SpyAttachToDeviceOnDemandW2K)
  55. #pragma alloc_text(PAGE, SpyStartLoggingDevice)
  56. #pragma alloc_text(PAGE, SpyStopLoggingDevice)
  57. #pragma alloc_text(PAGE, SpyAttachToFileSystemDevice)
  58. #pragma alloc_text(PAGE, SpyDetachFromFileSystemDevice)
  59. #pragma alloc_text(PAGE, SpyGetAttachList)
  60. #pragma alloc_text(PAGE, SpyGetObjectName)
  61. #if WINVER >= 0x0501
  62. #pragma alloc_text(INIT, SpyLoadDynamicFunctions)
  63. #pragma alloc_text(INIT, SpyGetCurrentVersion)
  64. #pragma alloc_text(PAGE, SpyIsAttachedToDeviceWXPAndLater)
  65. #pragma alloc_text(PAGE, SpyAttachToDeviceOnDemandWXPAndLater)
  66. #pragma alloc_text(PAGE, SpyEnumerateFileSystemVolumes)
  67. #pragma alloc_text(PAGE, SpyGetBaseDeviceObjectName)
  68. #endif
  69. #endif
  70. //////////////////////////////////////////////////////////////////////////
  71. // //
  72. // Library support routines //
  73. // //
  74. //////////////////////////////////////////////////////////////////////////
  75. VOID
  76. SpyReadDriverParameters (
  77. IN PUNICODE_STRING RegistryPath
  78. )
  79. /*++
  80. Routine Description:
  81. This routine tries to read the FileSpy-specific parameters from
  82. the registry. These values will be found in the registry location
  83. indicated by the RegistryPath passed in.
  84. Arguments:
  85. RegistryPath - the path key which contains the values that are
  86. the FileSpy parameters
  87. Return Value:
  88. None.
  89. --*/
  90. {
  91. OBJECT_ATTRIBUTES attributes;
  92. HANDLE driverRegKey;
  93. NTSTATUS status;
  94. ULONG bufferSize, resultLength;
  95. PVOID buffer = NULL;
  96. UNICODE_STRING valueName;
  97. PKEY_VALUE_PARTIAL_INFORMATION pValuePartialInfo;
  98. PAGED_CODE();
  99. //
  100. // All the global values are already set to default values. Any
  101. // values we read from the registry will override these defaults.
  102. //
  103. //
  104. // Do the initial setup to start reading from the registry.
  105. //
  106. InitializeObjectAttributes( &attributes,
  107. RegistryPath,
  108. OBJ_CASE_INSENSITIVE,
  109. NULL,
  110. NULL);
  111. status = ZwOpenKey( &driverRegKey,
  112. KEY_READ,
  113. &attributes);
  114. if (!NT_SUCCESS(status)) {
  115. driverRegKey = NULL;
  116. goto SpyReadDriverParameters_Exit;
  117. }
  118. bufferSize = sizeof( KEY_VALUE_PARTIAL_INFORMATION ) + sizeof( ULONG );
  119. buffer = ExAllocatePoolWithTag( NonPagedPool, bufferSize, FILESPY_POOL_TAG );
  120. if (NULL == buffer) {
  121. goto SpyReadDriverParameters_Exit;
  122. }
  123. //
  124. // Read the gMaxRecordsToAllocate from the registry
  125. //
  126. RtlInitUnicodeString(&valueName, MAX_RECORDS_TO_ALLOCATE);
  127. status = ZwQueryValueKey( driverRegKey,
  128. &valueName,
  129. KeyValuePartialInformation,
  130. buffer,
  131. bufferSize,
  132. &resultLength);
  133. if (NT_SUCCESS(status)) {
  134. pValuePartialInfo = (PKEY_VALUE_PARTIAL_INFORMATION) buffer;
  135. ASSERT(pValuePartialInfo->Type == REG_DWORD);
  136. gMaxRecordsToAllocate = *((PLONG)&pValuePartialInfo->Data);
  137. }
  138. //
  139. // Read the gMaxNamesToAllocate from the registry
  140. //
  141. RtlInitUnicodeString(&valueName, MAX_NAMES_TO_ALLOCATE);
  142. status = ZwQueryValueKey( driverRegKey,
  143. &valueName,
  144. KeyValuePartialInformation,
  145. buffer,
  146. bufferSize,
  147. &resultLength);
  148. if (NT_SUCCESS(status)) {
  149. pValuePartialInfo = (PKEY_VALUE_PARTIAL_INFORMATION) buffer;
  150. ASSERT(pValuePartialInfo->Type == REG_DWORD);
  151. gMaxNamesToAllocate = *((PLONG)&pValuePartialInfo->Data);
  152. }
  153. //
  154. // Read the initial debug setting from the registry
  155. //
  156. RtlInitUnicodeString(&valueName, DEBUG_LEVEL);
  157. status = ZwQueryValueKey( driverRegKey,
  158. &valueName,
  159. KeyValuePartialInformation,
  160. buffer,
  161. bufferSize,
  162. &resultLength );
  163. if (NT_SUCCESS( status )) {
  164. pValuePartialInfo = (PKEY_VALUE_PARTIAL_INFORMATION) buffer;
  165. ASSERT( pValuePartialInfo->Type == REG_DWORD );
  166. gFileSpyDebugLevel |= *((PULONG)&pValuePartialInfo->Data);
  167. }
  168. //
  169. // Read the attachment mode setting from the registry
  170. //
  171. RtlInitUnicodeString(&valueName, ATTACH_MODE);
  172. status = ZwQueryValueKey( driverRegKey,
  173. &valueName,
  174. KeyValuePartialInformation,
  175. buffer,
  176. bufferSize,
  177. &resultLength );
  178. if (NT_SUCCESS( status )) {
  179. pValuePartialInfo = (PKEY_VALUE_PARTIAL_INFORMATION) buffer;
  180. ASSERT( pValuePartialInfo->Type == REG_DWORD );
  181. gFileSpyAttachMode = *((PULONG)&pValuePartialInfo->Data);
  182. }
  183. goto SpyReadDriverParameters_Exit;
  184. SpyReadDriverParameters_Exit:
  185. if (NULL != buffer) {
  186. ExFreePoolWithTag( buffer, FILESPY_POOL_TAG );
  187. }
  188. if (NULL != driverRegKey) {
  189. ZwClose(driverRegKey);
  190. }
  191. return;
  192. }
  193. #if WINVER >= 0x0501
  194. VOID
  195. SpyLoadDynamicFunctions (
  196. )
  197. /*++
  198. Routine Description:
  199. This routine tries to load the function pointers for the routines that
  200. are not supported on all versions of the OS. These function pointers are
  201. then stored in the global structure gSpyDynamicFunctions.
  202. This support allows for one driver to be built that will run on all
  203. versions of the OS Windows 2000 and greater. Note that on Windows 2000,
  204. the functionality may be limited.
  205. Arguments:
  206. None.
  207. Return Value:
  208. None.
  209. --*/
  210. {
  211. UNICODE_STRING functionName;
  212. RtlZeroMemory( &gSpyDynamicFunctions, sizeof( gSpyDynamicFunctions ) );
  213. //
  214. // For each routine that we would want to use, lookup its address in the
  215. // kernel or hal. If it is not present, that field in our global
  216. // gSpyDynamicFunctions structure will be set to NULL.
  217. //
  218. RtlInitUnicodeString( &functionName, L"FsRtlRegisterFileSystemFilterCallbacks" );
  219. gSpyDynamicFunctions.RegisterFileSystemFilterCallbacks = MmGetSystemRoutineAddress( &functionName );
  220. RtlInitUnicodeString( &functionName, L"IoAttachDeviceToDeviceStackSafe" );
  221. gSpyDynamicFunctions.AttachDeviceToDeviceStackSafe = MmGetSystemRoutineAddress( &functionName );
  222. RtlInitUnicodeString( &functionName, L"IoEnumerateDeviceObjectList" );
  223. gSpyDynamicFunctions.EnumerateDeviceObjectList = MmGetSystemRoutineAddress( &functionName );
  224. RtlInitUnicodeString( &functionName, L"IoGetLowerDeviceObject" );
  225. gSpyDynamicFunctions.GetLowerDeviceObject = MmGetSystemRoutineAddress( &functionName );
  226. RtlInitUnicodeString( &functionName, L"IoGetDeviceAttachmentBaseRef" );
  227. gSpyDynamicFunctions.GetDeviceAttachmentBaseRef = MmGetSystemRoutineAddress( &functionName );
  228. RtlInitUnicodeString( &functionName, L"IoGetDiskDeviceObject" );
  229. gSpyDynamicFunctions.GetDiskDeviceObject = MmGetSystemRoutineAddress( &functionName );
  230. RtlInitUnicodeString( &functionName, L"IoGetAttachedDeviceReference" );
  231. gSpyDynamicFunctions.GetAttachedDeviceReference = MmGetSystemRoutineAddress( &functionName );
  232. RtlInitUnicodeString( &functionName, L"RtlGetVersion" );
  233. gSpyDynamicFunctions.GetVersion = MmGetSystemRoutineAddress( &functionName );
  234. }
  235. VOID
  236. SpyGetCurrentVersion (
  237. )
  238. /*++
  239. Routine Description:
  240. This routine reads the current OS version using the correct routine based
  241. on what routine is available.
  242. Arguments:
  243. None.
  244. Return Value:
  245. None.
  246. --*/
  247. {
  248. if (NULL != gSpyDynamicFunctions.GetVersion) {
  249. RTL_OSVERSIONINFOW versionInfo;
  250. NTSTATUS status;
  251. //
  252. // VERSION NOTE: RtlGetVersion does a bit more than we need, but
  253. // we are using it if it is available to show how to use it. It
  254. // is available on Windows XP and later. RtlGetVersion and
  255. // RtlVerifyVersionInfo (both documented in the IFS Kit docs) allow
  256. // you to make correct choices when you need to change logic based
  257. // on the current OS executing your code.
  258. //
  259. versionInfo.dwOSVersionInfoSize = sizeof( RTL_OSVERSIONINFOW );
  260. status = (gSpyDynamicFunctions.GetVersion)( &versionInfo );
  261. ASSERT( NT_SUCCESS( status ) );
  262. gSpyOsMajorVersion = versionInfo.dwMajorVersion;
  263. gSpyOsMinorVersion = versionInfo.dwMinorVersion;
  264. } else {
  265. PsGetVersion( &gSpyOsMajorVersion,
  266. &gSpyOsMinorVersion,
  267. NULL,
  268. NULL );
  269. }
  270. }
  271. #endif
  272. ////////////////////////////////////////////////////////////////////////
  273. // //
  274. // Memory allocation routines //
  275. // //
  276. ////////////////////////////////////////////////////////////////////////
  277. PVOID
  278. SpyAllocateBuffer (
  279. IN OUT PLONG Counter,
  280. IN LONG MaxCounterValue,
  281. OUT PULONG RecordType
  282. )
  283. /*++
  284. Routine Description:
  285. Allocates a new buffer from the gFreeBufferList if there is enough memory
  286. to do so and Counter does not exceed MaxCounterValue. The RecordType
  287. is set to one of the record type constants based on the allocation state.
  288. Arguments:
  289. Counter - (optional) the counter variable to test and increment if
  290. we can allocate
  291. MaxCounterValue - (ignored if Counter not given) the value which
  292. Counter should not exceed
  293. RecordType - (optional) set to one of the following:
  294. RECORD_TYPE_NORMAL allocation succeeded
  295. RECORD_TYPE_OUT_OF_MEMORY allocation failed because the system was
  296. out of memory
  297. RECORD_TYPE_EXCEED_MEMORY_ALLOWANCE allocation failed because the
  298. counter exceeded its maximum value.
  299. Return Value:
  300. Pointer to the buffer allocate, or NULL if allocation failed (either
  301. because system is out of memory or we have exceeded the MaxCounterValue).
  302. --*/
  303. {
  304. PVOID newBuffer;
  305. ULONG newRecordType = RECORD_TYPE_NORMAL;
  306. #ifdef MEMORY_DBG
  307. //
  308. // When we are debugging the memory usage to make sure that we
  309. // don't leak memory, we want to allocate the memory from pool
  310. // so that we can use the Driver Verifier to help debug any
  311. // memory problems.
  312. //
  313. newBuffer = ExAllocatePoolWithTag( NonPagedPool,
  314. RECORD_SIZE,
  315. FILESPY_LOGRECORD_TAG );
  316. #else
  317. //
  318. // When we are not debugging the memory usage, we use a look-aside
  319. // list for better performance.
  320. //
  321. newBuffer = ExAllocateFromNPagedLookasideList( &gFreeBufferList );
  322. #endif
  323. if (newBuffer) {
  324. if (Counter) {
  325. if (*Counter < MaxCounterValue) {
  326. InterlockedIncrement(Counter);
  327. } else {
  328. //
  329. // We've exceed our driver's memory limit so note that
  330. // and give back the record
  331. //
  332. SetFlag( newRecordType,
  333. (RECORD_TYPE_STATIC | RECORD_TYPE_EXCEED_MEMORY_ALLOWANCE) );
  334. #ifdef MEMORY_DBG
  335. ExFreePoolWithTag( newBuffer, FILESPY_POOL_TAG );
  336. #else
  337. ExFreeToNPagedLookasideList( &gFreeBufferList, newBuffer );
  338. #endif
  339. newBuffer = NULL;
  340. }
  341. }
  342. } else {
  343. SetFlag( newRecordType,
  344. (RECORD_TYPE_STATIC | RECORD_TYPE_OUT_OF_MEMORY) );
  345. }
  346. if (RecordType) {
  347. *RecordType = newRecordType;
  348. }
  349. return newBuffer;
  350. }
  351. VOID
  352. SpyFreeBuffer (
  353. IN PVOID Buffer,
  354. IN PLONG Counter
  355. )
  356. /*++
  357. Routine Description:
  358. Returns a Buffer to the gFreeBufferList.
  359. Arguments:
  360. Buffer - the buffer to return to the gFreeBufferList
  361. Return Value:
  362. None.
  363. --*/
  364. {
  365. #ifdef MEMORY_DBG
  366. ExFreePoolWithTag( Buffer, FILESPY_POOL_TAG );
  367. #else
  368. ExFreeToNPagedLookasideList( &gFreeBufferList, Buffer );
  369. #endif
  370. //
  371. // Update the count
  372. //
  373. if (Counter) {
  374. InterlockedDecrement(Counter);
  375. }
  376. }
  377. ////////////////////////////////////////////////////////////////////////
  378. // //
  379. // Logging routines //
  380. // //
  381. ////////////////////////////////////////////////////////////////////////
  382. PRECORD_LIST
  383. SpyNewRecord (
  384. IN ULONG AssignedSequenceNumber
  385. )
  386. /*++
  387. Routine Description:
  388. Allocates a new RECORD_LIST structure if there is enough memory to do so. A
  389. sequence number is updated for each request for a new record.
  390. Arguments:
  391. AssignedSequenceNumber - 0 if you want this function to generate the
  392. next sequence number; if not 0, the new record is assigned the
  393. given sequence number.
  394. Return Value:
  395. Pointer to the RECORD_LIST allocated, or NULL if no memory is available.
  396. --*/
  397. {
  398. PRECORD_LIST newRecord = NULL;
  399. ULONG currentSequenceNumber;
  400. KIRQL irql;
  401. ULONG initialRecordType;
  402. newRecord = (PRECORD_LIST) SpyAllocateBuffer( &gRecordsAllocated,
  403. gMaxRecordsToAllocate,
  404. &initialRecordType);
  405. KeAcquireSpinLock(&gLogSequenceLock, &irql);
  406. //
  407. // Assign a new sequence number if 0 was passed in, otherwise use the
  408. // number passed in
  409. //
  410. if (AssignedSequenceNumber == 0) {
  411. gLogSequenceNumber++;
  412. currentSequenceNumber = gLogSequenceNumber;
  413. } else {
  414. currentSequenceNumber = AssignedSequenceNumber;
  415. }
  416. if ((newRecord == NULL) &&
  417. !InterlockedCompareExchange( &gStaticBufferInUse, TRUE, FALSE)) {
  418. //
  419. // Toggle on our gStaticBufferInUse flag and use the static out of memory
  420. // buffer to record this log entry. This special log record is used
  421. // to notify the user application that we are out of memory. Log
  422. // request will be dropped until we can get more memory.
  423. //
  424. newRecord = (PRECORD_LIST)gOutOfMemoryBuffer;
  425. newRecord->LogRecord.RecordType = initialRecordType;
  426. newRecord->LogRecord.Length = SIZE_OF_LOG_RECORD;
  427. newRecord->LogRecord.SequenceNumber = currentSequenceNumber;
  428. } else if (newRecord) {
  429. //
  430. // We were able to allocate a new record so initialize it
  431. // appropriately.
  432. //
  433. newRecord->LogRecord.RecordType = initialRecordType;
  434. newRecord->LogRecord.Length = SIZE_OF_LOG_RECORD;
  435. newRecord->LogRecord.SequenceNumber = currentSequenceNumber;
  436. }
  437. KeReleaseSpinLock(&gLogSequenceLock, irql);
  438. //
  439. // Init record specific fields.
  440. //
  441. if (newRecord != NULL) {
  442. newRecord->NewContext = NULL;
  443. newRecord->WaitEvent = NULL;
  444. newRecord->Flags = 0;
  445. }
  446. return( newRecord );
  447. }
  448. VOID
  449. SpyFreeRecord (
  450. IN PRECORD_LIST Record
  451. )
  452. /*++
  453. Routine Description:
  454. Frees a RECORD_LIST, which returns the memory to the gFreeBufferList look-aside
  455. list and updates the gRecordsAllocated count.
  456. Arguments:
  457. Record - the record to free
  458. Return Value:
  459. None.
  460. --*/
  461. {
  462. //
  463. // If there is a context record defined, release it now
  464. //
  465. #if USE_STREAM_CONTEXTS
  466. if (NULL != Record->NewContext) {
  467. SpyReleaseContext( Record->NewContext );
  468. }
  469. #endif
  470. if (FlagOn( Record->LogRecord.RecordType, RECORD_TYPE_STATIC )) {
  471. //
  472. // This is our static record, so reset our gStaticBufferInUse
  473. // flag.
  474. //
  475. InterlockedExchange( &gStaticBufferInUse, FALSE );
  476. } else {
  477. //
  478. // This isn't our static memory buffer, so free the dynamically
  479. // allocated memory.
  480. //
  481. SpyFreeBuffer( Record, &gRecordsAllocated );
  482. }
  483. }
  484. PRECORD_LIST
  485. SpyLogFastIoStart (
  486. IN FASTIO_TYPE FastIoType,
  487. IN PDEVICE_OBJECT DeviceObject,
  488. IN PFILE_OBJECT FileObject OPTIONAL,
  489. IN PLARGE_INTEGER FileOffset OPTIONAL,
  490. IN ULONG Length OPTIONAL,
  491. IN BOOLEAN Wait OPTIONAL
  492. )
  493. /*++
  494. Routine Description:
  495. Creates the log record if possible and records the necessary Fast I/O
  496. information at the beginning of the fast I/O operation in RecordList
  497. according to LoggingFlags.
  498. The optional arguments are not recorded for all Fast I/O types. If
  499. the argument is not needed for a given Fast I/O type, the parameter
  500. was ignored.
  501. Arguments:
  502. FastIoType - The type of fast I/O we are logging (REQUIRED)
  503. DeviceObject - The device object for our filter. (REQUIRED)
  504. FileObject - Pointer to the file object this operation is on (OPTIONAL)
  505. FileOffset - Pointer to the file offset for this operation (OPTIONAL)
  506. Length - Length of the data for this operation (OPTIONAL)
  507. Wait - Whether or not this operation can wait for a result (OPTIONAL)
  508. Return Value:
  509. The RECORD_LIST structure created with the appropriate information
  510. filled in. If a RECORD_LIST structure couldn't be allocated, NULL
  511. is returned.
  512. --*/
  513. {
  514. PRECORD_LIST pRecordList;
  515. PRECORD_FASTIO pRecordFastIo;
  516. PFILESPY_DEVICE_EXTENSION devExt;
  517. //
  518. // Try to get a new record
  519. //
  520. pRecordList = SpyNewRecord(0);
  521. //
  522. // If we didn't get a RECORD_LIST, exit and return NULL
  523. //
  524. if (pRecordList == NULL) {
  525. return NULL;
  526. }
  527. //
  528. // We got a RECORD_LIST, so now fill in the appropriate information
  529. //
  530. pRecordFastIo = &pRecordList->LogRecord.Record.RecordFastIo;
  531. //
  532. // Perform the necessary book keeping for the RECORD_LIST
  533. //
  534. SetFlag( pRecordList->LogRecord.RecordType, RECORD_TYPE_FASTIO );
  535. //
  536. // Set the RECORD_FASTIO fields that are set for all Fast I/O types
  537. //
  538. pRecordFastIo->Type = FastIoType;
  539. KeQuerySystemTime(&pRecordFastIo->StartTime);
  540. //
  541. // Get process and thread information
  542. //
  543. pRecordFastIo->ProcessId = (ULONG_PTR) PsGetCurrentProcessId();
  544. pRecordFastIo->ThreadId = (ULONG_PTR) PsGetCurrentThreadId();
  545. //
  546. // Record the information that is appropriate based on the
  547. // Fast I/O type
  548. //
  549. pRecordFastIo->FileObject = (FILE_ID)FileObject;
  550. pRecordFastIo->DeviceObject = (DEVICE_ID)DeviceObject;
  551. pRecordFastIo->FileOffset.QuadPart = ((FileOffset != NULL) ? FileOffset->QuadPart : 0);
  552. pRecordFastIo->Length = Length;
  553. pRecordFastIo->Wait = Wait;
  554. devExt = DeviceObject->DeviceExtension;
  555. if (FastIoType == CHECK_IF_POSSIBLE) {
  556. //
  557. // On NTFS, locks are sometimes held but top-level irp is not set,
  558. // therefore it is not safe to query the base file system for the
  559. // file name at this time. If we've got it in the cache, we'll
  560. // use it. Otherwise, we will not return a name.
  561. //
  562. SpySetName(pRecordList, DeviceObject, FileObject, NLFL_ONLY_CHECK_CACHE, NULL);
  563. } else {
  564. SpySetName(pRecordList, DeviceObject, FileObject, 0, NULL);
  565. }
  566. return pRecordList;
  567. }
  568. VOID
  569. SpyLogFastIoComplete (
  570. IN PIO_STATUS_BLOCK ReturnStatus,
  571. IN PRECORD_LIST RecordList
  572. )
  573. /*++
  574. Routine Description:
  575. Records the necessary Fast I/O information in RecordList according to
  576. LoggingFlags.
  577. The optional arguments are not recorded for all Fast I/O types. If
  578. the argument is not needed for a given Fast I/O type, the parameter
  579. was ignored.
  580. Arguments:
  581. ReturnStatus - The return value of the operation (OPTIONAL)
  582. RecordList - The PRECORD_LIST in which the Fast I/O information is stored.
  583. Return Value:
  584. None.
  585. --*/
  586. {
  587. PRECORD_FASTIO pRecordFastIo;
  588. ASSERT(RecordList);
  589. pRecordFastIo = &RecordList->LogRecord.Record.RecordFastIo;
  590. //
  591. // Set the RECORD_FASTIO fields that are set for all Fast I/O types
  592. //
  593. KeQuerySystemTime(&pRecordFastIo->CompletionTime);
  594. if (ReturnStatus != NULL) {
  595. pRecordFastIo->ReturnStatus = ReturnStatus->Status;
  596. } else {
  597. pRecordFastIo->ReturnStatus = 0;
  598. }
  599. SpyLog(RecordList);
  600. }
  601. #if WINVER >= 0x0501 /* See comment in DriverEntry */
  602. VOID
  603. SpyLogPreFsFilterOperation (
  604. IN PFS_FILTER_CALLBACK_DATA Data,
  605. OUT PRECORD_LIST RecordList
  606. )
  607. {
  608. NAME_LOOKUP_FLAGS lookupFlags = 0;
  609. PRECORD_FS_FILTER_OPERATION pRecordFsFilterOp;
  610. pRecordFsFilterOp = &RecordList->LogRecord.Record.RecordFsFilterOp;
  611. //
  612. // Record the information we use for an originating Irp. We first
  613. // need to initialize some of the RECORD_LIST and RECORD_IRP fields.
  614. // Then get the interesting information from the Irp.
  615. //
  616. SetFlag( RecordList->LogRecord.RecordType, RECORD_TYPE_FS_FILTER_OP );
  617. pRecordFsFilterOp->FsFilterOperation = Data->Operation;
  618. pRecordFsFilterOp->FileObject = (FILE_ID) Data->FileObject;
  619. pRecordFsFilterOp->DeviceObject = (FILE_ID) Data->DeviceObject;
  620. pRecordFsFilterOp->ProcessId = (FILE_ID)PsGetCurrentProcessId();
  621. pRecordFsFilterOp->ThreadId = (FILE_ID)PsGetCurrentThreadId();
  622. KeQuerySystemTime(&pRecordFsFilterOp->OriginatingTime);
  623. //
  624. // Do not query for the name on any of the release operations
  625. // because a file system resource is currently being held and
  626. // we may deadlock.
  627. //
  628. switch (Data->Operation) {
  629. case FS_FILTER_RELEASE_FOR_CC_FLUSH:
  630. case FS_FILTER_RELEASE_FOR_SECTION_SYNCHRONIZATION:
  631. case FS_FILTER_RELEASE_FOR_MOD_WRITE:
  632. SPY_LOG_PRINT( SPYDEBUG_TRACE_DETAILED_CONTEXT_OPS,
  633. ("FileSpy!SpyLogPreFsFilterOp: RelOper\n") );
  634. SetFlag( lookupFlags, NLFL_ONLY_CHECK_CACHE );
  635. break;
  636. }
  637. //
  638. // Only set the volumeName if the next device is a file system
  639. // since we only want to prepend the volumeName if we are on
  640. // top of a local file system.
  641. //
  642. SpySetName( RecordList, Data->DeviceObject, Data->FileObject, lookupFlags, NULL);
  643. }
  644. VOID
  645. SpyLogPostFsFilterOperation (
  646. IN NTSTATUS OperationStatus,
  647. OUT PRECORD_LIST RecordList
  648. )
  649. {
  650. PRECORD_FS_FILTER_OPERATION pRecordFsFilterOp;
  651. pRecordFsFilterOp = &RecordList->LogRecord.Record.RecordFsFilterOp;
  652. //
  653. // Record the information we see in the post operation.
  654. //
  655. pRecordFsFilterOp->ReturnStatus = OperationStatus;
  656. KeQuerySystemTime(&pRecordFsFilterOp->CompletionTime);
  657. }
  658. #endif
  659. NTSTATUS
  660. SpyAttachDeviceToDeviceStack (
  661. IN PDEVICE_OBJECT SourceDevice,
  662. IN PDEVICE_OBJECT TargetDevice,
  663. IN OUT PDEVICE_OBJECT *AttachedToDeviceObject
  664. )
  665. /*++
  666. Routine Description:
  667. This routine attaches the SourceDevice to the TargetDevice's stack and
  668. returns the device object SourceDevice was directly attached to in
  669. AttachedToDeviceObject. Note that the SourceDevice does not necessarily
  670. get attached directly to TargetDevice. The SourceDevice will get attached
  671. to the top of the stack of which TargetDevice is a member.
  672. VERSION NOTE:
  673. In Windows XP, a new API was introduced to close a rare timing window that
  674. can cause IOs to start being sent to a device before its
  675. AttachedToDeviceObject is set in its device extension. This is possible
  676. if a filter is attaching to a device stack while the system is actively
  677. processing IOs. The new API closes this timing window by setting the
  678. device extension field that holds the AttachedToDeviceObject while holding
  679. the IO Manager's lock that protects the device stack.
  680. A sufficient work around for earlier versions of the OS is to set the
  681. AttachedToDeviceObject to the device object that the SourceDevice is most
  682. likely to attach to. While it is possible that another filter will attach
  683. in between the SourceDevice and TargetDevice, this will prevent the
  684. system from bug checking if the SourceDevice receives IOs before the
  685. AttachedToDeviceObject is correctly set.
  686. For a driver built in the Windows 2000 build environment, we will always
  687. use the work-around code to attach. For a driver that is built in the
  688. Windows XP or later build environments (therefore you are building a
  689. multiversion driver), we will determine which method of attachment to use
  690. based on which APIs are available.
  691. Arguments:
  692. SourceDevice - The device object to be attached to the stack.
  693. TargetDevice - The device that we currently think is the top of the stack
  694. to which SourceDevice should be attached.
  695. AttachedToDeviceObject - This is set to the device object to which
  696. SourceDevice is attached if the attach is successful.
  697. Return Value:
  698. Return STATUS_SUCCESS if the device is successfully attached. If
  699. TargetDevice represents a stack to which devices can no longer be attached,
  700. STATUS_NO_SUCH_DEVICE is returned.
  701. --*/
  702. {
  703. PAGED_CODE();
  704. #if WINVER >= 0x0501
  705. if (IS_WINDOWSXP_OR_LATER()) {
  706. ASSERT( NULL != gSpyDynamicFunctions.AttachDeviceToDeviceStackSafe );
  707. return (gSpyDynamicFunctions.AttachDeviceToDeviceStackSafe)( SourceDevice,
  708. TargetDevice,
  709. AttachedToDeviceObject );
  710. } else {
  711. #endif
  712. *AttachedToDeviceObject = TargetDevice;
  713. *AttachedToDeviceObject = IoAttachDeviceToDeviceStack( SourceDevice,
  714. TargetDevice );
  715. if (*AttachedToDeviceObject == NULL) {
  716. return STATUS_NO_SUCH_DEVICE;
  717. }
  718. return STATUS_SUCCESS;
  719. #if WINVER >= 0x0501
  720. }
  721. #endif
  722. }
  723. NTSTATUS
  724. SpyLog (
  725. IN PRECORD_LIST NewRecord
  726. )
  727. /*++
  728. Routine Description:
  729. This routine appends the completed log record to the gOutputBufferList.
  730. Arguments:
  731. NewRecord - The record to append to the gOutputBufferList
  732. Return Value:
  733. The function returns STATUS_SUCCESS.
  734. --*/
  735. {
  736. KIRQL controlDeviceIrql;
  737. KIRQL outputBufferIrql;
  738. KeAcquireSpinLock( &gControlDeviceStateLock, &controlDeviceIrql );
  739. if (gControlDeviceState == OPENED) {
  740. //
  741. // The device is still open so add this record onto the list
  742. //
  743. KeAcquireSpinLock(&gOutputBufferLock, &outputBufferIrql);
  744. InsertTailList(&gOutputBufferList, &NewRecord->List);
  745. KeReleaseSpinLock(&gOutputBufferLock, outputBufferIrql);
  746. } else {
  747. //
  748. // We can no longer log this record, so free the record
  749. //
  750. SpyFreeRecord( NewRecord );
  751. }
  752. KeReleaseSpinLock( &gControlDeviceStateLock, controlDeviceIrql );
  753. return STATUS_SUCCESS;
  754. }
  755. ////////////////////////////////////////////////////////////////////////
  756. // //
  757. // FileName cache routines //
  758. // //
  759. ////////////////////////////////////////////////////////////////////////
  760. BOOLEAN
  761. SpyGetFullPathName (
  762. IN PFILE_OBJECT FileObject,
  763. IN OUT PUNICODE_STRING FileName,
  764. IN PFILESPY_DEVICE_EXTENSION devExt,
  765. IN NAME_LOOKUP_FLAGS LookupFlags
  766. )
  767. /*++
  768. Routine Description:
  769. This routine retrieves the full pathname of the FileObject. Note that
  770. the buffers containing pathname components may be stored in paged pool,
  771. therefore if we are at DISPATCH_LEVEL we cannot look up the name.
  772. The file is looked up one of the following ways based on the LookupFlags:
  773. 1. FlagOn( FileObject->Flags, FO_VOLUME_OPEN ) or (FileObject->FileName.Length == 0).
  774. This is a volume open, so just use DeviceName from the devExt
  775. for the FileName, if it exists.
  776. 2. NAMELOOKUPFL_IN_CREATE and NAMELOOKUPFL_OPEN_BY_ID are set.
  777. This is an open by file id, so format the file id into the FileName
  778. string if there is enough room.
  779. 3. NAMELOOKUPFL_IN_CREATE set and FileObject->RelatedFileObject != NULL.
  780. This is a relative open, therefore the fullpath file name must
  781. be built up from the name of the FileObject->RelatedFileObject
  782. and FileObject->FileName.
  783. 4. NAMELOOKUPFL_IN_CREATE and FileObject->RelatedFileObject == NULL.
  784. This is an absolute open, therefore the fullpath file name is
  785. found in FileObject->FileName.
  786. 5. No LookupFlags set.
  787. This is a lookup sometime after CREATE. FileObject->FileName is
  788. no longer guaranteed to be valid, so use ObQueryNameString
  789. to get the fullpath name of the FileObject.
  790. Arguments:
  791. FileObject - Pointer to the FileObject to the get name of.
  792. FileName - Unicode string that will be filled in with the filename, It
  793. is assumed that the caller allocates and frees the memory used by
  794. the string. The buffer and MaximumLength for this string should be
  795. set. If there is room in the buffer, the string will be NULL
  796. terminated.
  797. devExt - Contains the device name and next device object
  798. which are needed to build the full path name.
  799. LookupFlags - The flags to say whether to get the name from the file
  800. object or to get the file id.
  801. Return Value:
  802. Returns TRUE if the returned name should be saved in the cache,
  803. returns FALSE if the returned name should NOT be saved in the cache.
  804. In all cases some sort of valid name is always returned.
  805. --*/
  806. {
  807. NTSTATUS status;
  808. ULONG i;
  809. BOOLEAN retValue = TRUE;
  810. UCHAR buffer[sizeof(FILE_NAME_INFORMATION) + MAX_NAME_SPACE];
  811. //
  812. // Copy over the name the user gave for this device. These names
  813. // should be meaningful to the user. Note that we do not do this for
  814. // NETWORK file system because internally they already show the
  815. // connection name. If this is a direct device open of the network
  816. // file system device, we will copy over the device name to be
  817. // returned to the user.
  818. //
  819. if (FILE_DEVICE_NETWORK_FILE_SYSTEM != devExt->ThisDeviceObject->DeviceType) {
  820. RtlCopyUnicodeString( FileName, &devExt->UserNames );
  821. } else if (FlagOn( FileObject->Flags, FO_DIRECT_DEVICE_OPEN )) {
  822. ASSERT( devExt->ThisDeviceObject->DeviceType == FILE_DEVICE_NETWORK_FILE_SYSTEM );
  823. RtlCopyUnicodeString( FileName, &devExt->DeviceName );
  824. //
  825. // We are now done since there will be no more to the name in this
  826. // case, so return TRUE.
  827. //
  828. return TRUE;
  829. }
  830. //
  831. // See if we can request the name
  832. //
  833. if (FlagOn( LookupFlags, NLFL_ONLY_CHECK_CACHE )) {
  834. RtlAppendUnicodeToString( FileName, L"[-=Not In Cache=-]" );
  835. return FALSE;
  836. }
  837. //
  838. // Can not get the name at DPC level
  839. //
  840. if (KeGetCurrentIrql() > APC_LEVEL) {
  841. RtlAppendUnicodeToString( FileName, L"[-=At DPC Level=-]" );
  842. return FALSE;
  843. }
  844. //
  845. // If there is a ToplevelIrp then this is a nested operation and
  846. // there might be other locks held. Can not get name without the
  847. // potential of deadlocking.
  848. //
  849. if (IoGetTopLevelIrp() != NULL) {
  850. RtlAppendUnicodeToString( FileName, L"[-=Nested Operation=-]" );
  851. return FALSE;
  852. }
  853. //
  854. // CASE 1: This FileObject refers to a Volume open. Either the
  855. // flag is set or no filename is specified.
  856. //
  857. if (FlagOn( FileObject->Flags, FO_VOLUME_OPEN ) ||
  858. (FlagOn( LookupFlags, NLFL_IN_CREATE ) &&
  859. (FileObject->FileName.Length == 0) &&
  860. (FileObject->RelatedFileObject == NULL))) {
  861. //
  862. // We've already copied the VolumeName so just return.
  863. //
  864. }
  865. //
  866. // CASE 2: We are opening the file by ID.
  867. //
  868. else if (FlagOn( LookupFlags, NLFL_IN_CREATE ) &&
  869. FlagOn( LookupFlags, NLFL_OPEN_BY_ID )) {
  870. # define OBJECT_ID_KEY_LENGTH 16
  871. UNICODE_STRING fileIdName;
  872. RtlInitEmptyUnicodeString( &fileIdName,
  873. (PWSTR)buffer,
  874. sizeof(buffer) );
  875. if (FileObject->FileName.Length == sizeof(LONGLONG)) {
  876. //
  877. // Opening by FILE ID, generate a name
  878. //
  879. swprintf( fileIdName.Buffer,
  880. L"<%016I64x>",
  881. *((PLONGLONG)FileObject->FileName.Buffer) );
  882. } else if ((FileObject->FileName.Length == OBJECT_ID_KEY_LENGTH) ||
  883. (FileObject->FileName.Length == OBJECT_ID_KEY_LENGTH +
  884. sizeof(WCHAR)))
  885. {
  886. PUCHAR idBuffer;
  887. //
  888. // Opening by Object ID, generate a name
  889. //
  890. idBuffer = (PUCHAR)&FileObject->FileName.Buffer[0];
  891. if (FileObject->FileName.Length != OBJECT_ID_KEY_LENGTH) {
  892. //
  893. // Skip win32 backslash at start of buffer
  894. //
  895. idBuffer = (PUCHAR)&FileObject->FileName.Buffer[1];
  896. }
  897. swprintf( fileIdName.Buffer,
  898. L"<%08x-%04hx-%04hx-%04hx-%04hx%08x>",
  899. *(PULONG)&idBuffer[0],
  900. *(PUSHORT)&idBuffer[0+4],
  901. *(PUSHORT)&idBuffer[0+4+2],
  902. *(PUSHORT)&idBuffer[0+4+2+2],
  903. *(PUSHORT)&idBuffer[0+4+2+2+2],
  904. *(PULONG)&idBuffer[0+4+2+2+2+2]);
  905. } else {
  906. //
  907. // Unknown ID format
  908. //
  909. swprintf( fileIdName.Buffer,
  910. L"[-=Unknown ID (Len=%u)=-]",
  911. FileObject->FileName.Length);
  912. }
  913. fileIdName.Length = wcslen( fileIdName.Buffer ) * sizeof( WCHAR );
  914. //
  915. // Append the fileIdName to FileName.
  916. //
  917. RtlAppendUnicodeStringToString( FileName, &fileIdName );
  918. //
  919. // Don't cache the ID name
  920. //
  921. retValue = FALSE;
  922. }
  923. //
  924. // CASE 3: We are opening a file that has a RelatedFileObject.
  925. //
  926. else if (FlagOn( LookupFlags, NLFL_IN_CREATE ) &&
  927. (NULL != FileObject->RelatedFileObject)) {
  928. //
  929. // Must be a relative open. Use ObQueryNameString to get
  930. // the name of the related FileObject. Then we will append this
  931. // fileObject's name.
  932. //
  933. // Note:
  934. // The name in FileObject and FileObject->RelatedFileObject are accessible. Names further up
  935. // the related file object chain (ie FileObject->RelatedFileObject->RelatedFileObject)
  936. // may not be accessible. This is the reason we use ObQueryNameString
  937. // to get the name for the RelatedFileObject.
  938. //
  939. PFILE_NAME_INFORMATION relativeNameInfo = (PFILE_NAME_INFORMATION)buffer;
  940. ULONG returnLength;
  941. status = SpyQueryFileSystemForFileName( FileObject->RelatedFileObject,
  942. devExt->AttachedToDeviceObject,
  943. sizeof( buffer ),
  944. relativeNameInfo,
  945. &returnLength );
  946. if (NT_SUCCESS( status ) &&
  947. ((FileName->Length + relativeNameInfo->FileNameLength + FileObject->FileName.Length + sizeof( L'\\' ))
  948. <= FileName->MaximumLength)) {
  949. //
  950. // We were able to get the relative fileobject's name and we have
  951. // enough room in the FileName buffer, so build up the file name
  952. // in the following format:
  953. // [volumeName]\[relativeFileObjectName]\[FileObjectName]
  954. // The VolumeName is already in FileName if we've got one.
  955. //
  956. RtlCopyMemory( &FileName->Buffer[FileName->Length/sizeof(WCHAR)],
  957. relativeNameInfo->FileName,
  958. relativeNameInfo->FileNameLength );
  959. FileName->Length += (USHORT)relativeNameInfo->FileNameLength;
  960. } else if ((FileName->Length + FileObject->FileName.Length + sizeof(L"...\\")) <=
  961. FileName->MaximumLength ) {
  962. //
  963. // Either the query for the relative fileObject name was unsuccessful,
  964. // or we don't have enough room for the relativeFileObject name, but we
  965. // do have enough room for "...\[fileObjectName]" in FileName.
  966. //
  967. status = RtlAppendUnicodeToString( FileName, L"...\\" );
  968. ASSERT( status == STATUS_SUCCESS );
  969. }
  970. //
  971. // If there is not a slash and the end of the related file object
  972. // string and there is not a slash at the front of the file object
  973. // string, then add one.
  974. //
  975. if (((FileName->Length < sizeof(WCHAR) ||
  976. (FileName->Buffer[(FileName->Length/sizeof(WCHAR))-1] != L'\\'))) &&
  977. ((FileObject->FileName.Length < sizeof(WCHAR)) ||
  978. (FileObject->FileName.Buffer[0] != L'\\')))
  979. {
  980. RtlAppendUnicodeToString( FileName, L"\\" );
  981. }
  982. //
  983. // At this time, copy over the FileObject->FileName to the FileName
  984. // unicode string.
  985. //
  986. RtlAppendUnicodeStringToString( FileName, &FileObject->FileName );
  987. }
  988. //
  989. // CASE 4: We have a open on a file with an absolute path.
  990. //
  991. else if (FlagOn( LookupFlags, NLFL_IN_CREATE ) &&
  992. (FileObject->RelatedFileObject == NULL) ) {
  993. //
  994. // We have an absolute path, so try to copy that into FileName.
  995. //
  996. RtlAppendUnicodeStringToString( FileName, &FileObject->FileName );
  997. }
  998. //
  999. // CASE 5: We are retrieving the file name sometime after the
  1000. // CREATE operation.
  1001. //
  1002. else if (!FlagOn( LookupFlags, NLFL_IN_CREATE )) {
  1003. PFILE_NAME_INFORMATION nameInfo = (PFILE_NAME_INFORMATION)buffer;
  1004. ULONG returnLength;
  1005. status = SpyQueryFileSystemForFileName( FileObject,
  1006. devExt->AttachedToDeviceObject,
  1007. sizeof( buffer ),
  1008. nameInfo,
  1009. &returnLength );
  1010. if (NT_SUCCESS( status )) {
  1011. if ((FileName->Length + nameInfo->FileNameLength) <= FileName->MaximumLength) {
  1012. //
  1013. // We've got enough room for the file name, so copy it into
  1014. // FileName.
  1015. //
  1016. RtlCopyMemory( &FileName->Buffer[FileName->Length/sizeof(WCHAR)],
  1017. nameInfo->FileName,
  1018. nameInfo->FileNameLength );
  1019. FileName->Length += (USHORT)nameInfo->FileNameLength;
  1020. } else {
  1021. //
  1022. // We don't have enough room for the file name, so copy our
  1023. // EXCEED_NAME_BUFFER error message.
  1024. //
  1025. RtlAppendUnicodeToString( FileName,
  1026. L"[-=Name To Large=-]" );
  1027. }
  1028. } else {
  1029. //
  1030. // Got an error trying to get the file name from the base file system,
  1031. // so put that error message into FileName.
  1032. //
  1033. swprintf((PWCHAR)buffer,L"[-=Error 0x%x Getting Name=-]",status );
  1034. RtlAppendUnicodeToString( FileName, (PWCHAR)buffer );
  1035. //
  1036. // Don't cache an error-generated name
  1037. //
  1038. retValue = FALSE;
  1039. }
  1040. }
  1041. //
  1042. // When we get here we have a valid name.
  1043. // Sometimes when we query a name it has a trailing slash, other times
  1044. // it doesn't. To make sure the contexts are correct we are going to
  1045. // remove a trailing slash if there is not a ":" just before it.
  1046. //
  1047. if ((FileName->Length >= (2*sizeof(WCHAR))) &&
  1048. (FileName->Buffer[(FileName->Length/sizeof(WCHAR))-1] == L'\\') &&
  1049. (FileName->Buffer[(FileName->Length/sizeof(WCHAR))-2] != L':'))
  1050. {
  1051. FileName->Length -= sizeof(WCHAR);
  1052. }
  1053. //
  1054. // See if we are actually opening the target directory. If so then
  1055. // remove the trailing name and slash. Note that we won't remove
  1056. // the initial slash (just after the colon).
  1057. //
  1058. if (FlagOn( LookupFlags, NLFL_OPEN_TARGET_DIR ) &&
  1059. (FileName->Length > 0))
  1060. {
  1061. i = (FileName->Length / sizeof(WCHAR)) - 1;
  1062. //
  1063. // See if the path ends in a backslash, if so skip over it
  1064. // (since the file system did).
  1065. //
  1066. if ((i > 0) &&
  1067. (FileName->Buffer[i] == L'\\') &&
  1068. (FileName->Buffer[i-1] != L':')) {
  1069. i--;
  1070. }
  1071. //
  1072. // Scan backwards over the last component
  1073. //
  1074. for ( ;
  1075. i > 0;
  1076. i-- )
  1077. {
  1078. if (FileName->Buffer[i] == L'\\') {
  1079. if ((i > 0) && (FileName->Buffer[i-1] == L':')) {
  1080. i++;
  1081. }
  1082. FileName->Length = (USHORT)(i * sizeof(WCHAR));
  1083. break;
  1084. }
  1085. }
  1086. }
  1087. return retValue;
  1088. }
  1089. NTSTATUS
  1090. SpyQueryCompletion (
  1091. IN PDEVICE_OBJECT DeviceObject,
  1092. IN PIRP Irp,
  1093. IN PKEVENT SynchronizingEvent
  1094. )
  1095. /*++
  1096. Routine Description:
  1097. This routine does the cleanup necessary once the query request completed
  1098. by the file system.
  1099. Arguments:
  1100. DeviceObject - This will be NULL since we originated this
  1101. Irp.
  1102. Irp - The io request structure containing the information
  1103. about the current state of our file name query.
  1104. SynchronizingEvent - The event to signal to notify the
  1105. originator of this request that the operation is
  1106. complete.
  1107. Return Value:
  1108. Returns STATUS_MORE_PROCESSING_REQUIRED so that IO Manager
  1109. will not try to free the Irp again.
  1110. --*/
  1111. {
  1112. UNREFERENCED_PARAMETER( DeviceObject );
  1113. //
  1114. // Make sure that the Irp status is copied over to the user's
  1115. // IO_STATUS_BLOCK so that the originator of this irp will know
  1116. // the final status of this operation.
  1117. //
  1118. ASSERT( NULL != Irp->UserIosb );
  1119. *Irp->UserIosb = Irp->IoStatus;
  1120. //
  1121. // Signal SynchronizingEvent so that the originator of this
  1122. // Irp know that the operation is completed.
  1123. //
  1124. KeSetEvent( SynchronizingEvent, IO_NO_INCREMENT, FALSE );
  1125. //
  1126. // We are now done, so clean up the irp that we allocated.
  1127. //
  1128. IoFreeIrp( Irp );
  1129. //
  1130. // If we return STATUS_SUCCESS here, the IO Manager will
  1131. // perform the cleanup work that it thinks needs to be done
  1132. // for this IO operation. This cleanup work includes:
  1133. // * Copying data from the system buffer to the user's buffer
  1134. // if this was a buffered IO operation.
  1135. // * Freeing any MDLs that are in the Irp.
  1136. // * Copying the Irp->IoStatus to Irp->UserIosb so that the
  1137. // originator of this irp can see the final status of the
  1138. // operation.
  1139. // * If this was an asynchronous request or this was a
  1140. // synchronous request that got pending somewhere along the
  1141. // way, the IO Manager will signal the Irp->UserEvent, if one
  1142. // exists, otherwise it will signal the FileObject->Event.
  1143. // (This can have REALLY bad implications if the irp originator
  1144. // did not an Irp->UserEvent and the irp originator is not
  1145. // waiting on the FileObject->Event. It would not be that
  1146. // farfetched to believe that someone else in the system is
  1147. // waiting on FileObject->Event and who knows who will be
  1148. // awoken as a result of the IO Manager signaling this event.
  1149. //
  1150. // Since some of these operations require the originating thread's
  1151. // context (e.g., the IO Manager need the UserBuffer address to
  1152. // be valid when copy is done), the IO Manager queues this work
  1153. // to an APC on the Irp's originating thread.
  1154. //
  1155. // Since FileSpy allocated and initialized this irp, we know
  1156. // what cleanup work needs to be done. We can do this cleanup
  1157. // work more efficiently than the IO Manager since we are handling
  1158. // a very specific case. Therefore, it is better for us to
  1159. // perform the cleanup work here then free the irp than passing
  1160. // control back to the IO Manager to do this work.
  1161. //
  1162. // By returning STATUS_MORE_PROCESS_REQUIRED, we tell the IO Manager
  1163. // to stop processing this irp until it is told to restart processing
  1164. // with a call to IoCompleteRequest. Since the IO Manager has
  1165. // already performed all the work we want it to do on this
  1166. // irp, we do the cleanup work, return STATUS_MORE_PROCESSING_REQUIRED,
  1167. // and ask the IO Manager to resume processing by calling
  1168. // IoCompleteRequest.
  1169. //
  1170. return STATUS_MORE_PROCESSING_REQUIRED;
  1171. }
  1172. NTSTATUS
  1173. SpyQueryFileSystemForFileName (
  1174. IN PFILE_OBJECT FileObject,
  1175. IN PDEVICE_OBJECT NextDeviceObject,
  1176. IN ULONG FileNameInfoLength,
  1177. OUT PFILE_NAME_INFORMATION FileNameInfo,
  1178. OUT PULONG ReturnedLength
  1179. )
  1180. /*++
  1181. Routine Description:
  1182. This routine rolls an irp to query the name of the
  1183. FileObject parameter from the base file system.
  1184. Note: ObQueryNameString CANNOT be used here because it
  1185. would cause recursive lookup of the file name for FileObject.
  1186. Arguments:
  1187. FileObject - the file object for which we want the name.
  1188. NextDeviceObject - the device object for the next driver in the
  1189. stack. This is where we want to start our request
  1190. for the name of FileObject.
  1191. FileNameInfoLength - the length in bytes of FileNameInfo
  1192. parameter.
  1193. FileNameInfo - the buffer that will be receive the name
  1194. information. This must be memory that safe to write
  1195. to from kernel space.
  1196. ReturnedLength - the number of bytes written to FileNameInfo.
  1197. Return Value:
  1198. Returns the status of the operation.
  1199. --*/
  1200. {
  1201. PIRP irp;
  1202. PIO_STACK_LOCATION irpSp;
  1203. KEVENT event;
  1204. IO_STATUS_BLOCK ioStatus;
  1205. NTSTATUS status;
  1206. PAGED_CODE();
  1207. irp = IoAllocateIrp( NextDeviceObject->StackSize, FALSE );
  1208. if (irp == NULL) {
  1209. return STATUS_INSUFFICIENT_RESOURCES;
  1210. }
  1211. //
  1212. // Set our current thread as the thread for this
  1213. // irp so that the IO Manager always knows which
  1214. // thread to return to if it needs to get back into
  1215. // the context of the thread that originated this
  1216. // irp.
  1217. //
  1218. irp->Tail.Overlay.Thread = PsGetCurrentThread();
  1219. //
  1220. // Set that this irp originated from the kernel so that
  1221. // the IO Manager knows that the buffers do not
  1222. // need to be probed.
  1223. //
  1224. irp->RequestorMode = KernelMode;
  1225. //
  1226. // Initialize the UserIosb and UserEvent in the
  1227. //
  1228. ioStatus.Status = STATUS_SUCCESS;
  1229. ioStatus.Information = 0;
  1230. irp->UserIosb = &ioStatus;
  1231. irp->UserEvent = NULL; //already zeroed
  1232. //
  1233. // Set the IRP_SYNCHRONOUS_API to denote that this
  1234. // is a synchronous IO request.
  1235. //
  1236. irp->Flags = IRP_SYNCHRONOUS_API;
  1237. irpSp = IoGetNextIrpStackLocation( irp );
  1238. irpSp->MajorFunction = IRP_MJ_QUERY_INFORMATION;
  1239. irpSp->FileObject = FileObject;
  1240. //
  1241. // Setup the parameters for IRP_MJ_QUERY_INFORMATION.
  1242. // The buffer we want to be filled in should be placed in
  1243. // the system buffer.
  1244. //
  1245. irp->AssociatedIrp.SystemBuffer = FileNameInfo;
  1246. irpSp->Parameters.QueryFile.Length = FileNameInfoLength;
  1247. irpSp->Parameters.QueryFile.FileInformationClass = FileNameInformation;
  1248. //
  1249. // Set up the completion routine so that we know when our
  1250. // request for the file name is completed. At that time,
  1251. // we can free the irp.
  1252. //
  1253. KeInitializeEvent( &event, NotificationEvent, FALSE );
  1254. IoSetCompletionRoutine( irp,
  1255. SpyQueryCompletion,
  1256. &event,
  1257. TRUE,
  1258. TRUE,
  1259. TRUE );
  1260. status = IoCallDriver( NextDeviceObject, irp );
  1261. SPY_LOG_PRINT( SPYDEBUG_TRACE_NAME_REQUESTS,
  1262. ("FileSpy!SpyQueryFileSystemForFileName: Issued name request -- IoCallDriver status: 0x%08x\n",
  1263. status) );
  1264. if (STATUS_PENDING == status) {
  1265. (VOID) KeWaitForSingleObject( &event,
  1266. Executive,
  1267. KernelMode,
  1268. FALSE,
  1269. NULL );
  1270. }
  1271. ASSERT(KeReadStateEvent(&event) || !NT_SUCCESS(ioStatus.Status));
  1272. SPY_LOG_PRINT( SPYDEBUG_TRACE_NAME_REQUESTS,
  1273. ("FileSpy!SpyQueryFileSystemForFileName: Finished waiting for name request to complete...\n") );
  1274. *ReturnedLength = (ULONG) ioStatus.Information;
  1275. return ioStatus.Status;
  1276. }
  1277. NTSTATUS
  1278. SpyQueryInformationFile (
  1279. IN PDEVICE_OBJECT NextDeviceObject,
  1280. IN PFILE_OBJECT FileObject,
  1281. OUT PVOID FileInformation,
  1282. IN ULONG Length,
  1283. IN FILE_INFORMATION_CLASS FileInformationClass,
  1284. OUT PULONG LengthReturned OPTIONAL
  1285. )
  1286. /*++
  1287. Routine Description:
  1288. This routine returns the requested information about a specified file.
  1289. The information returned is determined by the FileInformationClass that
  1290. is specified, and it is placed into the caller's FileInformation buffer.
  1291. Arguments:
  1292. NextDeviceObject - Supplies the device object where this IO should start
  1293. in the device stack.
  1294. FileObject - Supplies the file object about which the requested
  1295. information should be returned.
  1296. FileInformation - Supplies a buffer to receive the requested information
  1297. returned about the file. This must be a buffer allocated from kernel
  1298. space.
  1299. Length - Supplies the length, in bytes, of the FileInformation buffer.
  1300. FileInformationClass - Specifies the type of information which should be
  1301. returned about the file.
  1302. LengthReturned - the number of bytes returned if the operation was
  1303. successful.
  1304. Return Value:
  1305. The status returned is the final completion status of the operation.
  1306. --*/
  1307. {
  1308. PIRP irp = NULL;
  1309. PIO_STACK_LOCATION irpSp = NULL;
  1310. IO_STATUS_BLOCK ioStatusBlock;
  1311. KEVENT event;
  1312. NTSTATUS status;
  1313. PAGED_CODE();
  1314. //
  1315. // In DBG builds, make sure that we have valid parameters before we do
  1316. // any work here.
  1317. //
  1318. ASSERT( NULL != NextDeviceObject );
  1319. ASSERT( NULL != FileObject );
  1320. ASSERT( NULL != FileInformation );
  1321. //
  1322. // The parameters look ok, so setup the Irp.
  1323. //
  1324. KeInitializeEvent( &event, NotificationEvent, FALSE );
  1325. ioStatusBlock.Status = STATUS_SUCCESS;
  1326. ioStatusBlock.Information = 0;
  1327. irp = IoAllocateIrp( NextDeviceObject->StackSize, FALSE );
  1328. if (irp == NULL) {
  1329. return STATUS_INSUFFICIENT_RESOURCES;
  1330. }
  1331. //
  1332. // Set our current thread as the thread for this
  1333. // irp so that the IO Manager always knows which
  1334. // thread to return to if it needs to get back into
  1335. // the context of the thread that originated this
  1336. // irp.
  1337. //
  1338. irp->Tail.Overlay.Thread = PsGetCurrentThread();
  1339. //
  1340. // Set that this irp originated from the kernel so that
  1341. // the IO Manager knows that the buffers do not
  1342. // need to be probed.
  1343. //
  1344. irp->RequestorMode = KernelMode;
  1345. //
  1346. // Initialize the UserIosb and UserEvent in the
  1347. irp->UserIosb = &ioStatusBlock;
  1348. irp->UserEvent = NULL;
  1349. //
  1350. // Set the IRP_SYNCHRONOUS_API to denote that this
  1351. // is a synchronous IO request.
  1352. //
  1353. irp->Flags = IRP_SYNCHRONOUS_API;
  1354. irpSp = IoGetNextIrpStackLocation( irp );
  1355. irpSp->MajorFunction = IRP_MJ_QUERY_INFORMATION;
  1356. irpSp->FileObject = FileObject;
  1357. //
  1358. // Setup the parameters for IRP_MJ_QUERY_INFORMATION. These
  1359. // were supplied by the caller of this routine.
  1360. // The buffer we want to be filled in should be placed in
  1361. // the system buffer.
  1362. //
  1363. irp->AssociatedIrp.SystemBuffer = FileInformation;
  1364. irpSp->Parameters.QueryFile.Length = Length;
  1365. irpSp->Parameters.QueryFile.FileInformationClass = FileInformationClass;
  1366. //
  1367. // Set up the completion routine so that we know when our
  1368. // request for the file name is completed. At that time,
  1369. // we can free the irp.
  1370. //
  1371. IoSetCompletionRoutine( irp,
  1372. SpyQueryCompletion,
  1373. &event,
  1374. TRUE,
  1375. TRUE,
  1376. TRUE );
  1377. status = IoCallDriver( NextDeviceObject, irp );
  1378. if (STATUS_PENDING == status) {
  1379. KeWaitForSingleObject( &event,
  1380. Executive,
  1381. KernelMode,
  1382. FALSE,
  1383. NULL );
  1384. }
  1385. //
  1386. // Verify the completion has actually been run
  1387. //
  1388. ASSERT(KeReadStateEvent(&event) || !NT_SUCCESS(ioStatusBlock.Status));
  1389. if (ARGUMENT_PRESENT(LengthReturned)) {
  1390. *LengthReturned = (ULONG) ioStatusBlock.Information;
  1391. }
  1392. return ioStatusBlock.Status;
  1393. }
  1394. ////////////////////////////////////////////////////////////////////////
  1395. // //
  1396. // Common attachment and detachment routines //
  1397. // //
  1398. ////////////////////////////////////////////////////////////////////////
  1399. //
  1400. // VERSION NOTE:
  1401. //
  1402. // To be able to safely find out if our filter is attached to a device given
  1403. // its name on Windows 2000 and later, we need to use the approach in
  1404. // SpyIsAttachedToDeviceByUserDeviceName. This method uses APIs that are
  1405. // available on Windows 2000 and later. On Windows XP or later, you could
  1406. // change this routine to separate the translation from DeviceName to device
  1407. // object from the search to see if our filter's device is attached to the
  1408. // device stack. In Windows XP and later, the logic to translate the
  1409. // DeviceName to the device object is the same, but you can use the logic
  1410. // in SpyIsAttachedToDeviceWXPAndLater to find your filter's device object
  1411. // in the device stack safely.
  1412. //
  1413. NTSTATUS
  1414. SpyIsAttachedToDeviceByUserDeviceName (
  1415. IN PUNICODE_STRING DeviceName,
  1416. IN OUT PBOOLEAN IsAttached,
  1417. IN OUT PDEVICE_OBJECT *StackDeviceObject,
  1418. IN OUT PDEVICE_OBJECT *OurAttachedDeviceObject
  1419. )
  1420. /*++
  1421. Routine Description:
  1422. This routine maps a user's device name to a file system device stack, if
  1423. one exists. Then this routine walks the device stack to find a device
  1424. object belonging to our driver.
  1425. The APIs used here to walk the device stack are all safe to use while you
  1426. are guaranteed that the device stack will not go away. We enforce this
  1427. guarantee
  1428. Arguments:
  1429. DeviceName - The name provided by the user to identify this device.
  1430. IsAttached - This is set to TRUE if our filter is attached to this device
  1431. stack, otherwise this is set to FALSE.
  1432. StackDeviceObject - Set to a device object in the stack identified by the
  1433. DeviceName. If this is non-NULL, the caller is responsible for removing
  1434. the reference put on this object before it was returned.
  1435. AttachedDeviceObject - Set to the deviceObject which FileSpy has previously
  1436. attached to the device stack identify by DeviceName. If this is
  1437. non-NULL, the caller is responsible for removing the reference put on
  1438. this object before it was returned.
  1439. Return Value:
  1440. Returns STATUS_SUCCESS if we were able to successfully translate the
  1441. DeviceName into a device stack and return the StackDeviceObject. If an
  1442. error occurs during the translation of the DeviceName into a device stack,
  1443. the appropriate error code is returned.
  1444. --*/
  1445. {
  1446. WCHAR nameBuf[DEVICE_NAMES_SZ];
  1447. UNICODE_STRING volumeNameUnicodeString;
  1448. NTSTATUS status;
  1449. OBJECT_ATTRIBUTES objectAttributes;
  1450. IO_STATUS_BLOCK openStatus;
  1451. PFILE_OBJECT volumeFileObject;
  1452. HANDLE fileHandle;
  1453. PDEVICE_OBJECT baseFsDeviceObject;
  1454. PAGED_CODE();
  1455. //
  1456. // Initialize return state
  1457. //
  1458. ASSERT( NULL != StackDeviceObject );
  1459. ASSERT( NULL != OurAttachedDeviceObject );
  1460. ASSERT( NULL != IsAttached );
  1461. *StackDeviceObject = NULL;
  1462. *OurAttachedDeviceObject = NULL;
  1463. *IsAttached = FALSE;
  1464. //
  1465. // Setup the name to open
  1466. //
  1467. RtlInitEmptyUnicodeString( &volumeNameUnicodeString, nameBuf, sizeof( nameBuf ) );
  1468. RtlAppendUnicodeToString( &volumeNameUnicodeString, L"\\DosDevices\\" );
  1469. RtlAppendUnicodeStringToString( &volumeNameUnicodeString, DeviceName );
  1470. InitializeObjectAttributes( &objectAttributes,
  1471. &volumeNameUnicodeString,
  1472. OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
  1473. NULL,
  1474. NULL);
  1475. //
  1476. // open the file object for the given device
  1477. //
  1478. status = ZwCreateFile( &fileHandle,
  1479. SYNCHRONIZE|FILE_READ_DATA,
  1480. &objectAttributes,
  1481. &openStatus,
  1482. NULL,
  1483. 0,
  1484. FILE_SHARE_READ|FILE_SHARE_WRITE,
  1485. FILE_OPEN,
  1486. FILE_SYNCHRONOUS_IO_NONALERT,
  1487. NULL,
  1488. 0);
  1489. if (STATUS_OBJECT_PATH_NOT_FOUND == status ||
  1490. STATUS_OBJECT_NAME_INVALID == status) {
  1491. //
  1492. // Maybe this name didn't need the "\DosDevices\" prepended to the
  1493. // name. Try the open again using just the DeviceName passed in.
  1494. //
  1495. InitializeObjectAttributes( &objectAttributes,
  1496. DeviceName,
  1497. OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
  1498. NULL,
  1499. NULL);
  1500. //
  1501. // open the file object for the given device
  1502. //
  1503. status = ZwCreateFile( &fileHandle,
  1504. SYNCHRONIZE|FILE_READ_DATA,
  1505. &objectAttributes,
  1506. &openStatus,
  1507. NULL,
  1508. 0,
  1509. FILE_SHARE_READ|FILE_SHARE_WRITE,
  1510. FILE_OPEN,
  1511. FILE_SYNCHRONOUS_IO_NONALERT,
  1512. NULL,
  1513. 0);
  1514. if (!NT_SUCCESS( status )) {
  1515. return status;
  1516. }
  1517. //
  1518. // We were able to open the device using the name passed in, so
  1519. // now we will fall through and do the rest of this work.
  1520. //
  1521. } else if (!NT_SUCCESS( status )) {
  1522. return status;
  1523. }
  1524. //
  1525. // get a pointer to the volumes file object
  1526. //
  1527. status = ObReferenceObjectByHandle( fileHandle,
  1528. FILE_READ_DATA,
  1529. *IoFileObjectType,
  1530. KernelMode,
  1531. &volumeFileObject,
  1532. NULL);
  1533. if(!NT_SUCCESS( status )) {
  1534. ZwClose( fileHandle );
  1535. return status;
  1536. }
  1537. //
  1538. // Get the device object we want to attach to (parent device object in chain)
  1539. //
  1540. baseFsDeviceObject = IoGetBaseFileSystemDeviceObject( volumeFileObject );
  1541. if (baseFsDeviceObject == NULL) {
  1542. ObDereferenceObject( volumeFileObject );
  1543. ZwClose( fileHandle );
  1544. return STATUS_INVALID_DEVICE_STATE;
  1545. }
  1546. //
  1547. // Now see if we are attached to this device stack. Note that we need to
  1548. // keep this file object open while we do this search to ensure that the
  1549. // stack won't get torn down while SpyIsAttachedToDevice does its work.
  1550. //
  1551. *IsAttached = SpyIsAttachedToDevice( baseFsDeviceObject,
  1552. OurAttachedDeviceObject );
  1553. //
  1554. // Return the base file system's device object to represent this device
  1555. // stack even if we didn't find our device object in the stack.
  1556. //
  1557. ObReferenceObject( baseFsDeviceObject );
  1558. *StackDeviceObject = baseFsDeviceObject;
  1559. //
  1560. // Close our handle
  1561. //
  1562. ObDereferenceObject( volumeFileObject );
  1563. ZwClose( fileHandle );
  1564. return STATUS_SUCCESS;
  1565. }
  1566. //
  1567. // VERSION NOTE:
  1568. //
  1569. // In Windows 2000, the APIs to safely walk an arbitrary file system device
  1570. // stack were not supported. If we can guarantee that a device stack won't
  1571. // be torn down during the walking of the device stack, we can walk from
  1572. // the base file system's device object up to the top of the device stack
  1573. // to see if we are attached. We know the device stack will not go away if
  1574. // we are in the process of processing a mount request OR we have a file object
  1575. // open on this device.
  1576. //
  1577. // In Windows XP and later, the IO Manager provides APIs that will allow us to
  1578. // walk through the chain safely using reference counts to protect the device
  1579. // object from going away while we are inspecting it. This can be done at any
  1580. // time.
  1581. //
  1582. // MULTIVERSION NOTE:
  1583. //
  1584. // If built for Windows XP or later, this driver is built to run on
  1585. // multiple versions. When this is the case, we will test for the presence of
  1586. // the new IO Manager routines that allow for a filter to safely walk the file
  1587. // system device stack and use those APIs if they are present to determine if
  1588. // we have already attached to this volume. If these new IO Manager routines
  1589. // are not present, we will assume that we are at the bottom of the file
  1590. // system stack and walk up the stack looking for our device object.
  1591. //
  1592. BOOLEAN
  1593. SpyIsAttachedToDevice (
  1594. IN PDEVICE_OBJECT DeviceObject,
  1595. IN OUT PDEVICE_OBJECT *AttachedDeviceObject OPTIONAL
  1596. )
  1597. {
  1598. PAGED_CODE();
  1599. #if WINVER >= 0x0501
  1600. if (IS_WINDOWSXP_OR_LATER()) {
  1601. ASSERT( NULL != gSpyDynamicFunctions.GetLowerDeviceObject &&
  1602. NULL != gSpyDynamicFunctions.GetDeviceAttachmentBaseRef );
  1603. return SpyIsAttachedToDeviceWXPAndLater( DeviceObject, AttachedDeviceObject );
  1604. } else {
  1605. #endif
  1606. return SpyIsAttachedToDeviceW2K( DeviceObject, AttachedDeviceObject );
  1607. #if WINVER >= 0x0501
  1608. }
  1609. #endif
  1610. }
  1611. BOOLEAN
  1612. SpyIsAttachedToDeviceW2K (
  1613. PDEVICE_OBJECT DeviceObject,
  1614. PDEVICE_OBJECT *AttachedDeviceObject OPTIONAL
  1615. )
  1616. /*++
  1617. Routine Description:
  1618. VERSION: Windows 2000
  1619. This routine walks up the device stack from the DeviceObject passed in
  1620. looking for a device object that belongs to our filter.
  1621. Note: For this routine to operate safely, the caller must ensure two
  1622. things:
  1623. * the DeviceObject is the base file system's device object and therefore
  1624. is at the bottom of the file system stack
  1625. * this device stack won't be going away while we walk up this stack. If
  1626. we currently have a file object open for this device stack or we are
  1627. in the process of mounting this device, this guarantee is satisfied.
  1628. Arguments:
  1629. DeviceObject - The device chain we want to look through
  1630. AttachedDeviceObject - Set to the deviceObject which FileSpy
  1631. has previously attached to DeviceObject. If this is non-NULL,
  1632. the caller must clear the reference put on this device object.
  1633. Return Value:
  1634. TRUE if we are attached, FALSE if not
  1635. --*/
  1636. {
  1637. PDEVICE_OBJECT currentDeviceObject;
  1638. PAGED_CODE();
  1639. for (currentDeviceObject = DeviceObject;
  1640. currentDeviceObject != NULL;
  1641. currentDeviceObject = currentDeviceObject->AttachedDevice) {
  1642. if (IS_FILESPY_DEVICE_OBJECT( currentDeviceObject )) {
  1643. //
  1644. // We are attached. If requested, return the found device object.
  1645. //
  1646. if (ARGUMENT_PRESENT( AttachedDeviceObject )) {
  1647. ObReferenceObject( currentDeviceObject );
  1648. *AttachedDeviceObject = currentDeviceObject;
  1649. }
  1650. return TRUE;
  1651. }
  1652. }
  1653. //
  1654. // We did not find ourselves on the attachment chain. Return a NULL
  1655. // device object pointer (if requested) and return we did not find
  1656. // ourselves.
  1657. //
  1658. if (ARGUMENT_PRESENT(AttachedDeviceObject)) {
  1659. *AttachedDeviceObject = NULL;
  1660. }
  1661. return FALSE;
  1662. }
  1663. #if WINVER >= 0x0501
  1664. BOOLEAN
  1665. SpyIsAttachedToDeviceWXPAndLater (
  1666. PDEVICE_OBJECT DeviceObject,
  1667. PDEVICE_OBJECT *AttachedDeviceObject OPTIONAL
  1668. )
  1669. /*++
  1670. Routine Description:
  1671. VERSION: Windows XP and later
  1672. This walks down the attachment chain looking for a device object that
  1673. belongs to this driver. If one is found, the attached device object
  1674. is returned in AttachedDeviceObject.
  1675. Arguments:
  1676. DeviceObject - The device chain we want to look through
  1677. AttachedDeviceObject - Set to the deviceObject which FileSpy
  1678. has previously attached to DeviceObject.
  1679. Return Value:
  1680. TRUE if we are attached, FALSE if not
  1681. --*/
  1682. {
  1683. PDEVICE_OBJECT currentDevObj;
  1684. PDEVICE_OBJECT nextDevObj;
  1685. PAGED_CODE();
  1686. //
  1687. // Get the device object at the TOP of the attachment chain
  1688. //
  1689. ASSERT( NULL != gSpyDynamicFunctions.GetAttachedDeviceReference );
  1690. currentDevObj = (gSpyDynamicFunctions.GetAttachedDeviceReference)( DeviceObject );
  1691. //
  1692. // Scan down the list to find our device object.
  1693. //
  1694. do {
  1695. if (IS_FILESPY_DEVICE_OBJECT( currentDevObj )) {
  1696. //
  1697. // We have found that we are already attached. If we are
  1698. // returning the device object, leave it referenced else remove
  1699. // the reference.
  1700. //
  1701. if (NULL != AttachedDeviceObject) {
  1702. *AttachedDeviceObject = currentDevObj;
  1703. } else {
  1704. ObDereferenceObject( currentDevObj );
  1705. }
  1706. return TRUE;
  1707. }
  1708. //
  1709. // Get the next attached object. This puts a reference on
  1710. // the device object.
  1711. //
  1712. ASSERT( NULL != gSpyDynamicFunctions.GetLowerDeviceObject );
  1713. nextDevObj = (gSpyDynamicFunctions.GetLowerDeviceObject)( currentDevObj );
  1714. //
  1715. // Dereference our current device object, before
  1716. // moving to the next one.
  1717. //
  1718. ObDereferenceObject( currentDevObj );
  1719. currentDevObj = nextDevObj;
  1720. } while (NULL != currentDevObj);
  1721. //
  1722. // Mark no device returned
  1723. //
  1724. if (ARGUMENT_PRESENT(AttachedDeviceObject)) {
  1725. *AttachedDeviceObject = NULL;
  1726. }
  1727. return FALSE;
  1728. }
  1729. #endif //WINVER >= 0x0501
  1730. NTSTATUS
  1731. SpyAttachToMountedDevice (
  1732. IN PDEVICE_OBJECT DeviceObject,
  1733. IN PDEVICE_OBJECT FilespyDeviceObject
  1734. )
  1735. /*++
  1736. Routine Description:
  1737. This routine will attach the FileSpyDeviceObject to the filter stack
  1738. that DeviceObject is in.
  1739. NOTE: If there is an error in attaching, the caller is responsible
  1740. for deleting the FilespyDeviceObject.
  1741. Arguments:
  1742. DeviceObject - The device object in the stack to which we want to attach.
  1743. FilespyDeviceObject - The filespy device object that is to be attached to
  1744. "DeviceObject".
  1745. Return Value:
  1746. Returns STATUS_SUCCESS if the filespy deviceObject could be attached,
  1747. otherwise an appropriate error code is returned.
  1748. --*/
  1749. {
  1750. PFILESPY_DEVICE_EXTENSION devExt = FilespyDeviceObject->DeviceExtension;
  1751. NTSTATUS status = STATUS_SUCCESS;
  1752. ULONG i;
  1753. PAGED_CODE();
  1754. ASSERT( IS_FILESPY_DEVICE_OBJECT( FilespyDeviceObject ) );
  1755. #if WINVER >= 0x0501
  1756. ASSERT( !SpyIsAttachedToDevice( DeviceObject, NULL ) );
  1757. #endif
  1758. //
  1759. // Insert pointer from extension back to owning device object
  1760. //
  1761. devExt->ThisDeviceObject = FilespyDeviceObject;
  1762. //
  1763. // Propagate flags from Device Object we are trying to attach to.
  1764. // Note that we do this before the actual attachment to make sure
  1765. // the flags are properly set once we are attached (since an IRP
  1766. // can come in immediately after attachment but before the flags would
  1767. // be set).
  1768. //
  1769. if (FlagOn( DeviceObject->Flags, DO_BUFFERED_IO )) {
  1770. SetFlag( FilespyDeviceObject->Flags, DO_BUFFERED_IO );
  1771. }
  1772. if (FlagOn( DeviceObject->Flags, DO_DIRECT_IO )) {
  1773. SetFlag( FilespyDeviceObject->Flags, DO_DIRECT_IO );
  1774. }
  1775. //
  1776. // It is possible for this attachment request to fail because this device
  1777. // object has not finished initializing. This can occur if this filter
  1778. // loaded just as this volume was being mounted.
  1779. //
  1780. for (i=0; i < 8; i++) {
  1781. LARGE_INTEGER interval;
  1782. //
  1783. // Attach our device object to the given device object
  1784. // The only reason this can fail is if someone is trying to dismount
  1785. // this volume while we are attaching to it.
  1786. //
  1787. status = SpyAttachDeviceToDeviceStack( FilespyDeviceObject,
  1788. DeviceObject,
  1789. &devExt->AttachedToDeviceObject );
  1790. if (NT_SUCCESS(status) ) {
  1791. //
  1792. // Do all common initializing of the device extension
  1793. //
  1794. SetFlag(devExt->Flags,IsVolumeDeviceObject);
  1795. RtlInitEmptyUnicodeString( &devExt->UserNames,
  1796. devExt->UserNamesBuffer,
  1797. sizeof(devExt->UserNamesBuffer) );
  1798. SpyInitDeviceNamingEnvironment( FilespyDeviceObject );
  1799. SPY_LOG_PRINT( SPYDEBUG_DISPLAY_ATTACHMENT_NAMES,
  1800. ("FileSpy!SpyAttachToMountedDevice: Attaching to volume %p \"%wZ\"\n",
  1801. devExt->AttachedToDeviceObject,
  1802. &devExt->DeviceName) );
  1803. //
  1804. // Add this device to our attachment list
  1805. //
  1806. ExAcquireFastMutex( &gSpyDeviceExtensionListLock );
  1807. InsertTailList( &gSpyDeviceExtensionList, &devExt->NextFileSpyDeviceLink );
  1808. ExReleaseFastMutex( &gSpyDeviceExtensionListLock );
  1809. SetFlag(devExt->Flags,ExtensionIsLinked);
  1810. return STATUS_SUCCESS;
  1811. }
  1812. //
  1813. // Delay, giving the device object a chance to finish its
  1814. // initialization so we can try again
  1815. //
  1816. interval.QuadPart = (500 * DELAY_ONE_MILLISECOND); //delay 1/2 second
  1817. KeDelayExecutionThread( KernelMode, FALSE, &interval );
  1818. }
  1819. return status;
  1820. }
  1821. VOID
  1822. SpyCleanupMountedDevice (
  1823. IN PDEVICE_OBJECT DeviceObject
  1824. )
  1825. /*++
  1826. Routine Description:
  1827. This cleans up any allocated memory in the device extension.
  1828. Arguments:
  1829. DeviceObject - The device we are cleaning up
  1830. Return Value:
  1831. --*/
  1832. {
  1833. PFILESPY_DEVICE_EXTENSION devExt = DeviceObject->DeviceExtension;
  1834. PAGED_CODE();
  1835. ASSERT(IS_FILESPY_DEVICE_OBJECT( DeviceObject ));
  1836. SpyCleanupDeviceNamingEnvironment( DeviceObject );
  1837. //
  1838. // Unlink from global list
  1839. //
  1840. if (FlagOn(devExt->Flags,ExtensionIsLinked)) {
  1841. ExAcquireFastMutex( &gSpyDeviceExtensionListLock );
  1842. RemoveEntryList( &devExt->NextFileSpyDeviceLink );
  1843. ExReleaseFastMutex( &gSpyDeviceExtensionListLock );
  1844. ClearFlag(devExt->Flags,ExtensionIsLinked);
  1845. }
  1846. }
  1847. ////////////////////////////////////////////////////////////////////////
  1848. // //
  1849. // Start/stop logging routines //
  1850. // //
  1851. ////////////////////////////////////////////////////////////////////////
  1852. //
  1853. // VERSION NOTE:
  1854. //
  1855. // On Windows 2000, we will try to attach a new FileSpy device object to the
  1856. // device stack represented by the DeviceObject parameter. We cannot get the
  1857. // real disk device at this time, so this field will be set to NULL in the
  1858. // device extension. We also cannot get the device name as it is named
  1859. // in the storage stack for this volume (e.g., \Device\HarddiskVolume1), so we
  1860. // will just use the user's name for the device for our device name. On
  1861. // Windows 2000, this information is only available as the device mounts.
  1862. //
  1863. // On Windows XP and later, we will try to attach a new FileSpy device object
  1864. // to the device stack represented by the DeviceObject parameter. We are able
  1865. // to get the disk device object for this stack, so that will be appropriately
  1866. // set in the device extension. We will also be able to get the device name
  1867. // as it is named by the storage stack.
  1868. //
  1869. // MULTIVERSION NOTE:
  1870. //
  1871. // In SpyAttachToDeviceOnDemand, you see the code to determine which method of
  1872. // determining if we are already attached based on the dynamically loaded
  1873. // functions present. If this driver is build for Windows 2000 specifically,
  1874. // this logic will not be used.
  1875. //
  1876. NTSTATUS
  1877. SpyAttachToDeviceOnDemand (
  1878. IN PDEVICE_OBJECT DeviceObject,
  1879. IN PUNICODE_STRING UserDeviceName,
  1880. IN OUT PDEVICE_OBJECT *FileSpyDeviceObject
  1881. )
  1882. /*++
  1883. Routine Description:
  1884. This routine does what is necessary to attach to a device sometime after
  1885. the device has been mounted.
  1886. Arguments:
  1887. DeviceObject - The device object that represents the file system stack
  1888. for the volume named by UserDeviceName.
  1889. UserDeviceName - Name of device for which logging should be started
  1890. FileSpyDeviceObject - Set to the new filespy device object that was
  1891. attached if we could successfully attach.
  1892. Return Value:
  1893. STATUS_SUCCESS if we were able to attach, or an appropriate error code
  1894. otherwise.
  1895. --*/
  1896. {
  1897. PAGED_CODE();
  1898. //
  1899. // If this device is a DFS device, we do not want to attach to it, so
  1900. // do this quick check here and return an error if this is the case.
  1901. //
  1902. // DFS will just redirect the operation to the appropriate redirector. If
  1903. // you are interested in monitoring these IOs, you should attach to the
  1904. // redirectors. You cannot attach to these on demand by naming the DFS
  1905. // device, therefore we fail these requests.
  1906. //
  1907. if (DeviceObject->DeviceType == FILE_DEVICE_DFS) {
  1908. return STATUS_NOT_SUPPORTED;
  1909. }
  1910. #if WINVER >= 0x0501
  1911. if (IS_WINDOWSXP_OR_LATER()) {
  1912. ASSERT( NULL != gSpyDynamicFunctions.GetDeviceAttachmentBaseRef &&
  1913. NULL != gSpyDynamicFunctions.GetDiskDeviceObject );
  1914. return SpyAttachToDeviceOnDemandWXPAndLater( DeviceObject,
  1915. UserDeviceName,
  1916. FileSpyDeviceObject );
  1917. } else {
  1918. #endif
  1919. return SpyAttachToDeviceOnDemandW2K( DeviceObject,
  1920. UserDeviceName,
  1921. FileSpyDeviceObject );
  1922. #if WINVER >= 0x0501
  1923. }
  1924. #endif
  1925. }
  1926. NTSTATUS
  1927. SpyAttachToDeviceOnDemandW2K (
  1928. IN PDEVICE_OBJECT DeviceObject,
  1929. IN PUNICODE_STRING UserDeviceName,
  1930. IN OUT PDEVICE_OBJECT *FileSpyDeviceObject
  1931. )
  1932. /*++
  1933. Routine Description:
  1934. VERSION: Windows 2000
  1935. This routine does what is necessary to attach to a device sometime after
  1936. the device has been mounted.
  1937. Note that on Windows 2000, we cannot get the disk device object, therefore
  1938. we will just use the User's device name as our name here.
  1939. Arguments:
  1940. DeviceObject - The device object that represents the file system stack
  1941. for the volume named by UserDeviceName.
  1942. UserDeviceName - Name of device for which logging should be started
  1943. FileSpyDeviceObject - Set to the new filespy device object that was
  1944. attached if we could successfully attach.
  1945. Return Value:
  1946. STATUS_SUCCESS if we were able to attach, or an appropriate error code
  1947. otherwise.
  1948. --*/
  1949. {
  1950. NTSTATUS status;
  1951. PFILESPY_DEVICE_EXTENSION devExt;
  1952. PAGED_CODE();
  1953. ASSERT( FileSpyDeviceObject != NULL );
  1954. //
  1955. // Create a new device object so we can attach it in the filter stack
  1956. //
  1957. status = IoCreateDevice( gFileSpyDriverObject,
  1958. sizeof( FILESPY_DEVICE_EXTENSION ),
  1959. NULL,
  1960. DeviceObject->DeviceType,
  1961. 0,
  1962. FALSE,
  1963. FileSpyDeviceObject );
  1964. if (!NT_SUCCESS( status )) {
  1965. return status;
  1966. }
  1967. //
  1968. // Set disk device object
  1969. //
  1970. devExt = (*FileSpyDeviceObject)->DeviceExtension;
  1971. devExt->Flags = 0;
  1972. //
  1973. // We cannot get the disk device object when we attach on demand in W2K.
  1974. //
  1975. devExt->DiskDeviceObject = NULL;
  1976. //
  1977. // Set Device Name, we will just use the user's device name on W2K.
  1978. //
  1979. RtlInitEmptyUnicodeString( &devExt->DeviceName,
  1980. devExt->DeviceNameBuffer,
  1981. sizeof(devExt->DeviceNameBuffer) );
  1982. RtlAppendUnicodeStringToString( &devExt->DeviceName,
  1983. UserDeviceName );
  1984. //
  1985. // Call the routine to attach to a mounted device.
  1986. //
  1987. status = SpyAttachToMountedDevice( DeviceObject,
  1988. *FileSpyDeviceObject );
  1989. if (!NT_SUCCESS( status )) {
  1990. SPY_LOG_PRINT( SPYDEBUG_ERROR,
  1991. ("FileSpy!SpyStartLoggingDevice: Could not attach to \"%wZ\"; logging not started.\n",
  1992. UserDeviceName) );
  1993. SpyCleanupMountedDevice( *FileSpyDeviceObject );
  1994. IoDeleteDevice( *FileSpyDeviceObject );
  1995. *FileSpyDeviceObject = NULL;
  1996. }
  1997. return status;
  1998. }
  1999. #if WINVER >= 0x0501
  2000. NTSTATUS
  2001. SpyAttachToDeviceOnDemandWXPAndLater (
  2002. IN PDEVICE_OBJECT DeviceObject,
  2003. IN PUNICODE_STRING UserDeviceName,
  2004. IN OUT PDEVICE_OBJECT *FileSpyDeviceObject
  2005. )
  2006. /*++
  2007. Routine Description:
  2008. This routine does what is necessary to attach to a device sometime after
  2009. the device has been mounted.
  2010. Arguments:
  2011. DeviceObject - The device object that represents the file system stack
  2012. for the volume named by UserDeviceName.
  2013. UserDeviceName - Name of device for which logging should be started
  2014. FileSpyDeviceObject - Set to the new filespy device object that was
  2015. attached if we could successfully attach.
  2016. Return Value:
  2017. STATUS_SUCCESS if we were able to attach, or an appropriate error code
  2018. otherwise.
  2019. --*/
  2020. {
  2021. NTSTATUS status;
  2022. PFILESPY_DEVICE_EXTENSION devExt;
  2023. PDEVICE_OBJECT baseFileSystemDeviceObject = NULL;
  2024. PDEVICE_OBJECT diskDeviceObject = NULL;
  2025. PAGED_CODE();
  2026. UNREFERENCED_PARAMETER( UserDeviceName );
  2027. ASSERT( FileSpyDeviceObject != NULL );
  2028. //
  2029. // If this is a network file system, there will not be a disk device
  2030. // associated with this device, so there is no need to make this request
  2031. // of the IO Manager. We will get the name of the network file system
  2032. // later from the baseFileSystemDeviceObject vs. the diskDeviceObject
  2033. // which is used to retrieve the device name for local volumes.
  2034. //
  2035. baseFileSystemDeviceObject = (gSpyDynamicFunctions.GetDeviceAttachmentBaseRef)( DeviceObject );
  2036. if (FILE_DEVICE_NETWORK_FILE_SYSTEM != baseFileSystemDeviceObject->DeviceType) {
  2037. //
  2038. // If this is not a network file system, query the IO Manager to get
  2039. // the diskDeviceObject. We will only attach if this device has a
  2040. // disk device object.
  2041. //
  2042. // It may not have a disk device object for the following reasons:
  2043. // - It is a control device object for a driver
  2044. // - There is no media in the device.
  2045. //
  2046. status = (gSpyDynamicFunctions.GetDiskDeviceObject)( baseFileSystemDeviceObject,
  2047. &diskDeviceObject );
  2048. if (!NT_SUCCESS( status )) {
  2049. SPY_LOG_PRINT( SPYDEBUG_ERROR,
  2050. ("FileSpy!SpyStartLoggingDevice: No disk device object exists for \"%wZ\"; cannot log this volume.\n",
  2051. UserDeviceName) );
  2052. goto SpyAttachToDeviceOnDemand_Exit;
  2053. }
  2054. }
  2055. //
  2056. // Create a new device object so we can attach it in the filter stack
  2057. //
  2058. status = IoCreateDevice( gFileSpyDriverObject,
  2059. sizeof( FILESPY_DEVICE_EXTENSION ),
  2060. NULL,
  2061. DeviceObject->DeviceType,
  2062. 0,
  2063. FALSE,
  2064. FileSpyDeviceObject );
  2065. if (!NT_SUCCESS( status )) {
  2066. goto SpyAttachToDeviceOnDemand_Exit;
  2067. }
  2068. //
  2069. // Set disk device object
  2070. //
  2071. devExt = (*FileSpyDeviceObject)->DeviceExtension;
  2072. devExt->Flags = 0;
  2073. devExt->DiskDeviceObject = diskDeviceObject;
  2074. //
  2075. // Set Device Name
  2076. //
  2077. RtlInitEmptyUnicodeString( &devExt->DeviceName,
  2078. devExt->DeviceNameBuffer,
  2079. sizeof(devExt->DeviceNameBuffer) );
  2080. if (NULL != diskDeviceObject) {
  2081. SpyGetObjectName( diskDeviceObject,
  2082. &devExt->DeviceName );
  2083. } else {
  2084. ASSERT( NULL != baseFileSystemDeviceObject &&
  2085. FILE_DEVICE_NETWORK_FILE_SYSTEM == baseFileSystemDeviceObject->DeviceType);
  2086. SpyGetObjectName( baseFileSystemDeviceObject,
  2087. &devExt->DeviceName );
  2088. }
  2089. //
  2090. // Call the routine to attach to a mounted device.
  2091. //
  2092. status = SpyAttachToMountedDevice( DeviceObject,
  2093. *FileSpyDeviceObject );
  2094. if (!NT_SUCCESS( status )) {
  2095. SPY_LOG_PRINT( SPYDEBUG_ERROR,
  2096. ("FileSpy!SpyStartLoggingDevice: Could not attach to \"%wZ\"; logging not started.\n",
  2097. UserDeviceName) );
  2098. SpyCleanupMountedDevice( *FileSpyDeviceObject );
  2099. IoDeleteDevice( *FileSpyDeviceObject );
  2100. *FileSpyDeviceObject = NULL;
  2101. goto SpyAttachToDeviceOnDemand_Exit;
  2102. }
  2103. SpyAttachToDeviceOnDemand_Exit:
  2104. if (NULL != baseFileSystemDeviceObject) {
  2105. ObDereferenceObject( baseFileSystemDeviceObject );
  2106. }
  2107. if (NULL != diskDeviceObject) {
  2108. ObDereferenceObject( diskDeviceObject );
  2109. }
  2110. return status;
  2111. }
  2112. #endif
  2113. NTSTATUS
  2114. SpyStartLoggingDevice (
  2115. IN PWSTR UserDeviceName
  2116. )
  2117. /*++
  2118. Routine Description:
  2119. This routine ensures that we are attached to the specified device
  2120. then turns on logging for that device.
  2121. Note: Since all network drives through LAN Manager are represented by _
  2122. one_ device object, we want to only attach to this device stack once
  2123. and use only one device extension to represent all these drives.
  2124. Since FileSpy does not do anything to filter I/O on the LAN Manager's
  2125. device object to only log the I/O to the requested drive, the user
  2126. will see all I/O to a network drive it he/she is attached to a
  2127. network drive.
  2128. Arguments:
  2129. UserDeviceName - Name of device for which logging should be started
  2130. Return Value:
  2131. STATUS_SUCCESS if the logging has been successfully started, or
  2132. an appropriate error code if the logging could not be started.
  2133. --*/
  2134. {
  2135. UNICODE_STRING userDeviceName;
  2136. NTSTATUS status;
  2137. PFILESPY_DEVICE_EXTENSION devExt;
  2138. BOOLEAN isAttached = FALSE;
  2139. PDEVICE_OBJECT stackDeviceObject;
  2140. PDEVICE_OBJECT filespyDeviceObject;
  2141. PAGED_CODE();
  2142. //
  2143. // Check to see if we have previously attached to this device by
  2144. // opening this device name then looking through its list of attached
  2145. // devices.
  2146. //
  2147. RtlInitUnicodeString( &userDeviceName, UserDeviceName );
  2148. status = SpyIsAttachedToDeviceByUserDeviceName( &userDeviceName,
  2149. &isAttached,
  2150. &stackDeviceObject,
  2151. &filespyDeviceObject );
  2152. if (!NT_SUCCESS( status )) {
  2153. //
  2154. // There was an error, so return the error code.
  2155. //
  2156. return status;
  2157. }
  2158. if (isAttached) {
  2159. //
  2160. // We are already attached, so just make sure that logging is turned on
  2161. // for this device.
  2162. //
  2163. ASSERT( NULL != filespyDeviceObject );
  2164. devExt = filespyDeviceObject->DeviceExtension;
  2165. SetFlag(devExt->Flags,LogThisDevice);
  2166. SpyStoreUserName( devExt, &userDeviceName );
  2167. //
  2168. // Clear the reference that was returned from SpyIsAttachedToDevice.
  2169. //
  2170. ObDereferenceObject( filespyDeviceObject );
  2171. } else {
  2172. status = SpyAttachToDeviceOnDemand( stackDeviceObject,
  2173. &userDeviceName,
  2174. &filespyDeviceObject );
  2175. if (!NT_SUCCESS( status )) {
  2176. ObDereferenceObject( stackDeviceObject );
  2177. return status;
  2178. }
  2179. ASSERT( filespyDeviceObject != NULL );
  2180. devExt = filespyDeviceObject->DeviceExtension;
  2181. //
  2182. // We successfully attached so finish our device extension
  2183. // initialization. Along this code path, we want to turn on
  2184. // logging and store our device name.
  2185. //
  2186. SetFlag(devExt->Flags,LogThisDevice);
  2187. //
  2188. // We want to store the name that was used by the user-mode
  2189. // application to name this device.
  2190. //
  2191. SpyStoreUserName( devExt, &userDeviceName );
  2192. //
  2193. //
  2194. // Finished all initialization of the new device object, so clear the
  2195. // initializing flag now. This allows other filters to now attach
  2196. // to our device object.
  2197. //
  2198. //
  2199. ClearFlag( filespyDeviceObject->Flags, DO_DEVICE_INITIALIZING );
  2200. }
  2201. ObDereferenceObject( stackDeviceObject );
  2202. return STATUS_SUCCESS;
  2203. }
  2204. NTSTATUS
  2205. SpyStopLoggingDevice (
  2206. IN PWSTR DeviceName
  2207. )
  2208. /*++
  2209. Routine Description:
  2210. This routine stop logging the specified device. Since you can not
  2211. physically detach from devices, this routine simply sets a flag saying
  2212. to not log the device anymore.
  2213. Note: Since all network drives are represented by _one_ device object,
  2214. and, therefore, one device extension, if the user detaches from one
  2215. network drive, it has the affect of detaching from _all_ network
  2216. devices.
  2217. Arguments:
  2218. DeviceName - The name of the device to stop logging.
  2219. Return Value:
  2220. NT Status code
  2221. --*/
  2222. {
  2223. WCHAR nameBuf[DEVICE_NAMES_SZ];
  2224. UNICODE_STRING volumeNameUnicodeString;
  2225. PDEVICE_OBJECT deviceObject;
  2226. PDEVICE_OBJECT filespyDeviceObject;
  2227. BOOLEAN isAttached = FALSE;
  2228. PFILESPY_DEVICE_EXTENSION devExt;
  2229. NTSTATUS status;
  2230. PAGED_CODE();
  2231. RtlInitEmptyUnicodeString( &volumeNameUnicodeString, nameBuf, sizeof( nameBuf ) );
  2232. RtlAppendUnicodeToString( &volumeNameUnicodeString, DeviceName );
  2233. status = SpyIsAttachedToDeviceByUserDeviceName( &volumeNameUnicodeString,
  2234. &isAttached,
  2235. &deviceObject,
  2236. &filespyDeviceObject );
  2237. if (!NT_SUCCESS( status )) {
  2238. //
  2239. // We could not get the deviceObject from this DeviceName, so
  2240. // return the error code.
  2241. //
  2242. return status;
  2243. }
  2244. //
  2245. // Find Filespy's device object from the device stack to which
  2246. // deviceObject is attached.
  2247. //
  2248. if (isAttached) {
  2249. //
  2250. // FileSpy is attached and FileSpy's deviceObject was returned.
  2251. //
  2252. ASSERT( NULL != filespyDeviceObject );
  2253. devExt = filespyDeviceObject->DeviceExtension;
  2254. //
  2255. // Stop logging
  2256. //
  2257. ClearFlag(devExt->Flags,LogThisDevice);
  2258. status = STATUS_SUCCESS;
  2259. ObDereferenceObject( filespyDeviceObject );
  2260. } else {
  2261. status = STATUS_INVALID_PARAMETER;
  2262. }
  2263. ObDereferenceObject( deviceObject );
  2264. return status;
  2265. }
  2266. ////////////////////////////////////////////////////////////////////////
  2267. // //
  2268. // Attaching/detaching to all volumes in system routines //
  2269. // //
  2270. ////////////////////////////////////////////////////////////////////////
  2271. NTSTATUS
  2272. SpyAttachToFileSystemDevice (
  2273. IN PDEVICE_OBJECT DeviceObject,
  2274. IN PUNICODE_STRING DeviceName
  2275. )
  2276. /*++
  2277. Routine Description:
  2278. This will attach to the given file system device object. We attach to
  2279. these devices so we will know when new devices are mounted.
  2280. Arguments:
  2281. DeviceObject - The device to attach to
  2282. DeviceName - Contains the name of this device.
  2283. Return Value:
  2284. Status of the operation
  2285. --*/
  2286. {
  2287. PDEVICE_OBJECT filespyDeviceObject;
  2288. PFILESPY_DEVICE_EXTENSION devExt;
  2289. UNICODE_STRING fsrecName;
  2290. NTSTATUS status;
  2291. UNICODE_STRING tempName;
  2292. WCHAR tempNameBuffer[DEVICE_NAMES_SZ];
  2293. PAGED_CODE();
  2294. //
  2295. // See if this is a file system we care about. If not, return.
  2296. //
  2297. if (!IS_SUPPORTED_DEVICE_TYPE(DeviceObject->DeviceType)) {
  2298. return STATUS_SUCCESS;
  2299. }
  2300. //
  2301. // See if this is Microsoft's file system recognizer device (see if the name of the
  2302. // driver is the FS_REC driver). If so skip it. We don't need to
  2303. // attach to file system recognizer devices since we can just wait for the
  2304. // real file system driver to load. Therefore, if we can identify them, we won't
  2305. // attach to them.
  2306. //
  2307. RtlInitUnicodeString( &fsrecName, L"\\FileSystem\\Fs_Rec" );
  2308. RtlInitEmptyUnicodeString( &tempName,
  2309. tempNameBuffer,
  2310. sizeof(tempNameBuffer) );
  2311. SpyGetObjectName( DeviceObject->DriverObject, &tempName );
  2312. if (RtlCompareUnicodeString( &tempName, &fsrecName, TRUE ) == 0) {
  2313. return STATUS_SUCCESS;
  2314. }
  2315. //
  2316. // Create a new device object we can attach with
  2317. //
  2318. status = IoCreateDevice( gFileSpyDriverObject,
  2319. sizeof( FILESPY_DEVICE_EXTENSION ),
  2320. (PUNICODE_STRING) NULL,
  2321. DeviceObject->DeviceType,
  2322. 0,
  2323. FALSE,
  2324. &filespyDeviceObject );
  2325. if (!NT_SUCCESS( status )) {
  2326. SPY_LOG_PRINT( SPYDEBUG_ERROR,
  2327. ("FileSpy!SpyAttachToFileSystemDevice: Error creating volume device object for \"%wZ\", status=%08x\n",
  2328. DeviceName,
  2329. status) );
  2330. return status;
  2331. }
  2332. //
  2333. // Load extension, set device object associated with extension
  2334. //
  2335. devExt = filespyDeviceObject->DeviceExtension;
  2336. devExt->Flags = 0;
  2337. devExt->ThisDeviceObject = filespyDeviceObject;
  2338. //
  2339. // Propagate flags from Device Object we are trying to attach to.
  2340. // Note that we do this before the actual attachment to make sure
  2341. // the flags are properly set once we are attached (since an IRP
  2342. // can come in immediately after attachment but before the flags would
  2343. // be set).
  2344. //
  2345. if ( FlagOn( DeviceObject->Flags, DO_BUFFERED_IO )) {
  2346. SetFlag( filespyDeviceObject->Flags, DO_BUFFERED_IO );
  2347. }
  2348. if ( FlagOn( DeviceObject->Flags, DO_DIRECT_IO )) {
  2349. SetFlag( filespyDeviceObject->Flags, DO_DIRECT_IO );
  2350. }
  2351. if ( FlagOn( DeviceObject->Characteristics, FILE_DEVICE_SECURE_OPEN ) ) {
  2352. SetFlag( filespyDeviceObject->Characteristics, FILE_DEVICE_SECURE_OPEN );
  2353. }
  2354. //
  2355. // Do the attachment
  2356. //
  2357. status = SpyAttachDeviceToDeviceStack( filespyDeviceObject,
  2358. DeviceObject,
  2359. &devExt->AttachedToDeviceObject );
  2360. if (!NT_SUCCESS( status )) {
  2361. SPY_LOG_PRINT( SPYDEBUG_ERROR,
  2362. ("FileSpy!SpyAttachToFileSystemDevice: Could not attach FileSpy to the filesystem control device object \"%wZ\".\n",
  2363. DeviceName) );
  2364. goto ErrorCleanupDevice;
  2365. }
  2366. //
  2367. // Since this is an attachment to a file system control device object
  2368. // we are not going to log anything, but properly initialize our
  2369. // extension.
  2370. //
  2371. RtlInitEmptyUnicodeString( &devExt->DeviceName,
  2372. devExt->DeviceNameBuffer,
  2373. sizeof(devExt->DeviceNameBuffer) );
  2374. RtlCopyUnicodeString( &devExt->DeviceName, DeviceName ); //Save Name
  2375. RtlInitEmptyUnicodeString( &devExt->UserNames,
  2376. devExt->UserNamesBuffer,
  2377. sizeof(devExt->UserNamesBuffer) );
  2378. SpyInitDeviceNamingEnvironment( filespyDeviceObject );
  2379. //
  2380. // The NETWORK device objects function as both CDOs (control device object)
  2381. // and VDOs (volume device object) so insert the NETWORK CDO devices into
  2382. // the list of attached device so we will properly enumerate it.
  2383. //
  2384. if (FILE_DEVICE_NETWORK_FILE_SYSTEM == DeviceObject->DeviceType) {
  2385. ExAcquireFastMutex( &gSpyDeviceExtensionListLock );
  2386. InsertTailList( &gSpyDeviceExtensionList, &devExt->NextFileSpyDeviceLink );
  2387. ExReleaseFastMutex( &gSpyDeviceExtensionListLock );
  2388. SetFlag(devExt->Flags,ExtensionIsLinked);
  2389. }
  2390. //
  2391. // Flag we are no longer initializing this device object
  2392. //
  2393. ClearFlag( filespyDeviceObject->Flags, DO_DEVICE_INITIALIZING );
  2394. //
  2395. // Display who we have attached to
  2396. //
  2397. SPY_LOG_PRINT( SPYDEBUG_DISPLAY_ATTACHMENT_NAMES,
  2398. ("FileSpy!SpyAttachToFileSystemDevice: Attaching to file system %p \"%wZ\" (%s)\n",
  2399. DeviceObject,
  2400. &devExt->DeviceName,
  2401. GET_DEVICE_TYPE_NAME(filespyDeviceObject->DeviceType)) );
  2402. //
  2403. // VERSION NOTE:
  2404. //
  2405. // In Windows XP, the IO Manager provided APIs to safely enumerate all the
  2406. // device objects for a given driver. This allows filters to attach to
  2407. // all mounted volumes for a given file system at some time after the
  2408. // volume has been mounted. There is no support for this functionality
  2409. // in Windows 2000.
  2410. //
  2411. // MULTIVERSION NOTE:
  2412. //
  2413. // If built for Windows XP or later, this driver is built to run on
  2414. // multiple versions. When this is the case, we will test
  2415. // for the presence of the new IO Manager routines that allow for volume
  2416. // enumeration. If they are not present, we will not enumerate the volumes
  2417. // when we attach to a new file system.
  2418. //
  2419. #if WINVER >= 0x0501
  2420. if (IS_WINDOWSXP_OR_LATER()) {
  2421. ASSERT( NULL != gSpyDynamicFunctions.EnumerateDeviceObjectList &&
  2422. NULL != gSpyDynamicFunctions.GetDiskDeviceObject &&
  2423. NULL != gSpyDynamicFunctions.GetDeviceAttachmentBaseRef &&
  2424. NULL != gSpyDynamicFunctions.GetLowerDeviceObject );
  2425. //
  2426. // Enumerate all the mounted devices that currently
  2427. // exist for this file system and attach to them.
  2428. //
  2429. status = SpyEnumerateFileSystemVolumes( DeviceObject, &tempName );
  2430. if (!NT_SUCCESS( status )) {
  2431. SPY_LOG_PRINT( SPYDEBUG_ERROR,
  2432. ("FileSpy!SpyAttachToFileSystemDevice: Error attaching to existing volumes for \"%wZ\", status=%08x\n",
  2433. DeviceName,
  2434. status) );
  2435. IoDetachDevice( devExt->AttachedToDeviceObject );
  2436. goto ErrorCleanupDevice;
  2437. }
  2438. }
  2439. #endif
  2440. return STATUS_SUCCESS;
  2441. /////////////////////////////////////////////////////////////////////
  2442. // Cleanup error handling
  2443. /////////////////////////////////////////////////////////////////////
  2444. ErrorCleanupDevice:
  2445. SpyCleanupMountedDevice( filespyDeviceObject );
  2446. IoDeleteDevice( filespyDeviceObject );
  2447. return status;
  2448. }
  2449. VOID
  2450. SpyDetachFromFileSystemDevice (
  2451. IN PDEVICE_OBJECT DeviceObject
  2452. )
  2453. /*++
  2454. Routine Description:
  2455. Given a base file system device object, this will scan up the attachment
  2456. chain looking for our attached device object. If found it will detach
  2457. us from the chain.
  2458. Arguments:
  2459. DeviceObject - The file system device to detach from.
  2460. Return Value:
  2461. --*/
  2462. {
  2463. PDEVICE_OBJECT ourAttachedDevice;
  2464. PFILESPY_DEVICE_EXTENSION devExt;
  2465. PAGED_CODE();
  2466. //
  2467. // We have to iterate through the device objects in the filter stack
  2468. // attached to DeviceObject. If we are attached to this filesystem device
  2469. // object, We should be at the top of the stack, but there is no guarantee.
  2470. // If we are in the stack and not at the top, we can safely call IoDetachDevice
  2471. // at this time because the IO Manager will only really detach our device
  2472. // object from the stack at a safe time.
  2473. //
  2474. //
  2475. // Skip the base file system device object (since it can't be us)
  2476. //
  2477. ourAttachedDevice = DeviceObject->AttachedDevice;
  2478. while (NULL != ourAttachedDevice) {
  2479. if (IS_FILESPY_DEVICE_OBJECT( ourAttachedDevice )) {
  2480. devExt = ourAttachedDevice->DeviceExtension;
  2481. //
  2482. // Display who we detached from
  2483. //
  2484. SPY_LOG_PRINT( SPYDEBUG_DISPLAY_ATTACHMENT_NAMES,
  2485. ("FileSpy!SpyDetachFromFileSystem: Detaching from file system %p \"%wZ\" (%s)\n",
  2486. devExt->AttachedToDeviceObject,
  2487. &devExt->DeviceName,
  2488. GET_DEVICE_TYPE_NAME(ourAttachedDevice->DeviceType)) );
  2489. //
  2490. // Unlink from global list
  2491. //
  2492. if (FlagOn(devExt->Flags,ExtensionIsLinked)) {
  2493. ExAcquireFastMutex( &gSpyDeviceExtensionListLock );
  2494. RemoveEntryList( &devExt->NextFileSpyDeviceLink );
  2495. ExReleaseFastMutex( &gSpyDeviceExtensionListLock );
  2496. ClearFlag(devExt->Flags,ExtensionIsLinked);
  2497. }
  2498. //
  2499. // Detach us from the object just below us
  2500. // Cleanup and delete the object
  2501. //
  2502. SpyCleanupMountedDevice( ourAttachedDevice );
  2503. IoDetachDevice( DeviceObject );
  2504. IoDeleteDevice( ourAttachedDevice );
  2505. return;
  2506. }
  2507. //
  2508. // Look at the next device up in the attachment chain
  2509. //
  2510. DeviceObject = ourAttachedDevice;
  2511. ourAttachedDevice = ourAttachedDevice->AttachedDevice;
  2512. }
  2513. }
  2514. #if WINVER >= 0x0501
  2515. NTSTATUS
  2516. SpyEnumerateFileSystemVolumes (
  2517. IN PDEVICE_OBJECT FSDeviceObject,
  2518. IN PUNICODE_STRING Name
  2519. )
  2520. /*++
  2521. Routine Description:
  2522. Enumerate all the mounted devices that currently exist for the given file
  2523. system and attach to them. We do this because this filter could be loaded
  2524. at any time and there might already be mounted volumes for this file system.
  2525. Arguments:
  2526. FSDeviceObject - The device object for the file system we want to enumerate
  2527. Name - An already initialized unicode string used to retrieve names
  2528. Return Value:
  2529. The status of the operation
  2530. --*/
  2531. {
  2532. PDEVICE_OBJECT newDeviceObject;
  2533. PFILESPY_DEVICE_EXTENSION newDevExt;
  2534. PDEVICE_OBJECT *devList;
  2535. PDEVICE_OBJECT diskDeviceObject;
  2536. NTSTATUS status;
  2537. ULONG numDevices;
  2538. ULONG i;
  2539. PAGED_CODE();
  2540. //
  2541. // Find out how big of an array we need to allocate for the
  2542. // mounted device list.
  2543. //
  2544. ASSERT( NULL != gSpyDynamicFunctions.EnumerateDeviceObjectList );
  2545. status = (gSpyDynamicFunctions.EnumerateDeviceObjectList)( FSDeviceObject->DriverObject,
  2546. NULL,
  2547. 0,
  2548. &numDevices);
  2549. //
  2550. // We only need to get this list of there are devices. If we
  2551. // don't get an error there are no devices so go on.
  2552. //
  2553. if (!NT_SUCCESS( status )) {
  2554. ASSERT(STATUS_BUFFER_TOO_SMALL == status);
  2555. //
  2556. // Allocate memory for the list of known devices
  2557. //
  2558. numDevices += 8; //grab a few extra slots
  2559. devList = ExAllocatePoolWithTag( NonPagedPool,
  2560. (numDevices * sizeof(PDEVICE_OBJECT)),
  2561. FILESPY_POOL_TAG );
  2562. if (NULL == devList) {
  2563. return STATUS_INSUFFICIENT_RESOURCES;
  2564. }
  2565. //
  2566. // Now get the list of devices. If we get an error again
  2567. // something is wrong, so just fail.
  2568. //
  2569. status = (gSpyDynamicFunctions.EnumerateDeviceObjectList)(
  2570. FSDeviceObject->DriverObject,
  2571. devList,
  2572. (numDevices * sizeof(PDEVICE_OBJECT)),
  2573. &numDevices);
  2574. if (!NT_SUCCESS( status )) {
  2575. ExFreePoolWithTag( devList, FILESPY_POOL_TAG );
  2576. return status;
  2577. }
  2578. //
  2579. // Walk the given list of devices and attach to them if we should.
  2580. //
  2581. for (i=0; i < numDevices; i++) {
  2582. //
  2583. // Do not attach if:
  2584. // - This is the control device object (the one passed in)
  2585. // - The device type does not match
  2586. // - We are already attached to it
  2587. //
  2588. if ((devList[i] != FSDeviceObject) &&
  2589. (devList[i]->DeviceType == FSDeviceObject->DeviceType) &&
  2590. !SpyIsAttachedToDevice( devList[i], NULL )) {
  2591. //
  2592. // See if this device has a name. If so, then it must
  2593. // be a control device so don't attach to it. This handles
  2594. // drivers with more then one control device.
  2595. //
  2596. SpyGetBaseDeviceObjectName( devList[i], Name );
  2597. if (Name->Length <= 0) {
  2598. //
  2599. // Get the disk device object associated with this
  2600. // file system device object. Only try to attach if we
  2601. // have a disk device object.
  2602. //
  2603. ASSERT( NULL != gSpyDynamicFunctions.GetDiskDeviceObject );
  2604. status = (gSpyDynamicFunctions.GetDiskDeviceObject)( devList[i], &diskDeviceObject );
  2605. if (NT_SUCCESS( status )) {
  2606. //
  2607. // Allocate a new device object to attach with
  2608. //
  2609. status = IoCreateDevice( gFileSpyDriverObject,
  2610. sizeof( FILESPY_DEVICE_EXTENSION ),
  2611. (PUNICODE_STRING) NULL,
  2612. devList[i]->DeviceType,
  2613. 0,
  2614. FALSE,
  2615. &newDeviceObject );
  2616. if (NT_SUCCESS( status )) {
  2617. //
  2618. // Set disk device object
  2619. //
  2620. newDevExt = newDeviceObject->DeviceExtension;
  2621. newDevExt->Flags = 0;
  2622. newDevExt->DiskDeviceObject = diskDeviceObject;
  2623. //
  2624. // Set Device Name
  2625. //
  2626. RtlInitEmptyUnicodeString( &newDevExt->DeviceName,
  2627. newDevExt->DeviceNameBuffer,
  2628. sizeof(newDevExt->DeviceNameBuffer) );
  2629. SpyGetObjectName( diskDeviceObject,
  2630. &newDevExt->DeviceName );
  2631. //
  2632. // We have done a lot of work since the last time
  2633. // we tested to see if we were already attached
  2634. // to this device object. Test again, this time
  2635. // with a lock, and attach if we are not attached.
  2636. // The lock is used to atomically test if we are
  2637. // attached, and then do the attach.
  2638. //
  2639. ExAcquireFastMutex( &gSpyAttachLock );
  2640. if (!SpyIsAttachedToDevice( devList[i], NULL )) {
  2641. //
  2642. // Attach to this device object
  2643. //
  2644. status = SpyAttachToMountedDevice( devList[i],
  2645. newDeviceObject );
  2646. //
  2647. // Handle normal vs error cases, but keep going
  2648. //
  2649. if (NT_SUCCESS( status )) {
  2650. //
  2651. // Finished all initialization of the new
  2652. // device object, so clear the initializing
  2653. // flag now. This allows other filters to
  2654. // now attach to our device object.
  2655. //
  2656. ClearFlag( newDeviceObject->Flags, DO_DEVICE_INITIALIZING );
  2657. } else {
  2658. //
  2659. // The attachment failed, cleanup. Note that
  2660. // we continue processing so we will cleanup
  2661. // the reference counts and try to attach to
  2662. // the rest of the volumes.
  2663. //
  2664. // One of the reasons this could have failed
  2665. // is because this volume is just being
  2666. // mounted as we are attaching and the
  2667. // DO_DEVICE_INITIALIZING flag has not yet
  2668. // been cleared. A filter could handle
  2669. // this situation by pausing for a short
  2670. // period of time and retrying the attachment.
  2671. //
  2672. SpyCleanupMountedDevice( newDeviceObject );
  2673. IoDeleteDevice( newDeviceObject );
  2674. }
  2675. } else {
  2676. //
  2677. // We were already attached, cleanup this
  2678. // device object.
  2679. //
  2680. SpyCleanupMountedDevice( newDeviceObject );
  2681. IoDeleteDevice( newDeviceObject );
  2682. }
  2683. //
  2684. // Release the lock
  2685. //
  2686. ExReleaseFastMutex( &gSpyAttachLock );
  2687. } else {
  2688. SPY_LOG_PRINT( SPYDEBUG_ERROR,
  2689. ("FileSpy!SpyEnumberateFileSystemVolumes: Error creating volume device object, status=%08x\n",
  2690. status) );
  2691. }
  2692. //
  2693. // Remove reference added by IoGetDiskDeviceObject.
  2694. // We only need to hold this reference until we are
  2695. // successfully attached to the current volume. Once
  2696. // we are successfully attached to devList[i], the
  2697. // IO Manager will make sure that the underlying
  2698. // diskDeviceObject will not go away until the file
  2699. // system stack is torn down.
  2700. //
  2701. ObDereferenceObject( diskDeviceObject );
  2702. }
  2703. }
  2704. }
  2705. //
  2706. // Dereference the object (reference added by
  2707. // IoEnumerateDeviceObjectList)
  2708. //
  2709. ObDereferenceObject( devList[i] );
  2710. }
  2711. //
  2712. // We are going to ignore any errors received while loading. We
  2713. // simply won't be attached to those volumes if we get an error
  2714. //
  2715. status = STATUS_SUCCESS;
  2716. //
  2717. // Free the memory we allocated for the list
  2718. //
  2719. ExFreePoolWithTag( devList, FILESPY_POOL_TAG );
  2720. }
  2721. return status;
  2722. }
  2723. #endif
  2724. ////////////////////////////////////////////////////////////////////////
  2725. // //
  2726. // Private Filespy IOCTLs helper routines //
  2727. // //
  2728. ////////////////////////////////////////////////////////////////////////
  2729. NTSTATUS
  2730. SpyGetAttachList (
  2731. IN PVOID Buffer,
  2732. IN ULONG BufferSize,
  2733. OUT PULONG_PTR ReturnLength
  2734. )
  2735. /*++
  2736. Routine Description:
  2737. This returns an array of structure identifying all of the devices
  2738. we are currently physical attached to and whether logging is on or
  2739. off for the given device
  2740. Arguments:
  2741. buffer - buffer to receive the attachment list
  2742. bufferSize - total size in bytes of the return buffer
  2743. returnLength - receives number of bytes we actually return
  2744. Return Value:
  2745. NT Status code
  2746. --*/
  2747. {
  2748. PLIST_ENTRY link;
  2749. PFILESPY_DEVICE_EXTENSION devExt;
  2750. PATTACHED_DEVICE pAttDev;
  2751. ULONG retlen = 0;
  2752. UNICODE_STRING attachedDevName;
  2753. PAGED_CODE();
  2754. pAttDev = Buffer;
  2755. try {
  2756. ExAcquireFastMutex( &gSpyDeviceExtensionListLock );
  2757. for (link = gSpyDeviceExtensionList.Flink;
  2758. link != &gSpyDeviceExtensionList;
  2759. link = link->Flink) {
  2760. devExt = CONTAINING_RECORD(link, FILESPY_DEVICE_EXTENSION, NextFileSpyDeviceLink);
  2761. if (BufferSize < sizeof(ATTACHED_DEVICE)) {
  2762. break;
  2763. }
  2764. pAttDev->LoggingOn = BooleanFlagOn(devExt->Flags,LogThisDevice);
  2765. //
  2766. // We set up a unicode string to represent the buffer where we
  2767. // want to copy the device name. We will reserve space for the
  2768. // terminating NULL that the caller is expecting.
  2769. //
  2770. // NOTE: Since DeviceNames is an imbedded array in the
  2771. // ATTACHED_DEVICE structure, sizeof( pAttDev->DeviceNames )
  2772. // returns the correct size. RtlCopyUnicodeString ensure that the
  2773. // copy does not extend past the MaximumLength of our destination
  2774. // string.
  2775. //
  2776. attachedDevName.MaximumLength = sizeof( pAttDev->DeviceNames ) -
  2777. sizeof( UNICODE_NULL );
  2778. attachedDevName.Length = 0;
  2779. attachedDevName.Buffer = pAttDev->DeviceNames;
  2780. RtlCopyUnicodeString( &attachedDevName,
  2781. &devExt->DeviceName );
  2782. attachedDevName.Buffer[attachedDevName.Length/sizeof(WCHAR)] = UNICODE_NULL;
  2783. retlen += sizeof( ATTACHED_DEVICE );
  2784. BufferSize -= sizeof( ATTACHED_DEVICE );
  2785. pAttDev++;
  2786. }
  2787. } finally {
  2788. ExReleaseFastMutex( &gSpyDeviceExtensionListLock );
  2789. }
  2790. *ReturnLength = retlen;
  2791. return STATUS_SUCCESS;
  2792. }
  2793. VOID
  2794. SpyGetLog (
  2795. OUT PVOID OutputBuffer,
  2796. IN ULONG OutputBufferLength,
  2797. OUT PIO_STATUS_BLOCK IoStatus
  2798. )
  2799. /*++
  2800. Routine Description:
  2801. This function fills OutputBuffer with as many LOG_RECORDs as possible.
  2802. The LOG_RECORDs are variable sizes and are tightly packed in the
  2803. OutputBuffer.
  2804. Arguments:
  2805. OutputBuffer - the user's buffer to fill with the log data we have
  2806. collected
  2807. OutputBufferLength - the size in bytes of OutputBuffer
  2808. IoStatus - is set to the correct return status information for this
  2809. operation
  2810. Return Value:
  2811. None
  2812. --*/
  2813. {
  2814. PLIST_ENTRY pList = NULL;
  2815. ULONG length = OutputBufferLength;
  2816. PCHAR pOutBuffer = OutputBuffer;
  2817. PLOG_RECORD pLogRecord = NULL;
  2818. ULONG recordsAvailable = 0, logRecordLength;
  2819. PRECORD_LIST pRecordList;
  2820. KIRQL oldIrql;
  2821. IoStatus->Information = 0;
  2822. KeAcquireSpinLock(&gOutputBufferLock, &oldIrql);
  2823. while (!IsListEmpty( &gOutputBufferList ) && (length > 0)) {
  2824. pList = RemoveHeadList( &gOutputBufferList );
  2825. pRecordList = CONTAINING_RECORD( pList, RECORD_LIST, List );
  2826. pLogRecord = &pRecordList->LogRecord;
  2827. recordsAvailable++;
  2828. //
  2829. // Pack log records on PVOID boundaries to avoid alignment faults when accessing
  2830. // the packed buffer on 64-bit architectures
  2831. //
  2832. logRecordLength = ROUND_TO_SIZE( pLogRecord->Length, sizeof( PVOID ) );
  2833. if (length < logRecordLength) {
  2834. InsertHeadList( &gOutputBufferList, pList );
  2835. break;
  2836. }
  2837. KeReleaseSpinLock( &gOutputBufferLock, oldIrql );
  2838. //
  2839. // We wrap these logic in a try/finally because it is possible that our
  2840. // output buffer is invalid if we are coming through the FastIO path to
  2841. // service the FILESPY_GetLog IOCTLs. If this is the case, the
  2842. // exception will be caught in SpyFastIoDeviceControl, but we want to
  2843. // make sure that we don't lose this current record we are dealing
  2844. // with.
  2845. //
  2846. try {
  2847. //
  2848. // Copy of course the non-padded number of bytes
  2849. //
  2850. RtlCopyMemory( pOutBuffer, pLogRecord, pLogRecord->Length );
  2851. //
  2852. // Adjust the log-record length to the padded length in the copied record
  2853. //
  2854. ((PLOG_RECORD) pOutBuffer)->Length = logRecordLength;
  2855. IoStatus->Information += logRecordLength;
  2856. length -= logRecordLength;
  2857. pOutBuffer += logRecordLength;
  2858. SpyFreeRecord( pRecordList );
  2859. pRecordList = NULL;
  2860. } finally {
  2861. if (pRecordList != NULL) {
  2862. //
  2863. // We did not successfully process this record, so put it back
  2864. // on the gOutputBufferList. The log records contain a sequence
  2865. // number, so the fact that this may disrupt the ordering of the
  2866. // log records is not a problem.
  2867. //
  2868. KeAcquireSpinLock( &gOutputBufferLock, &oldIrql );
  2869. InsertHeadList( &gOutputBufferList, &pRecordList->List );
  2870. KeReleaseSpinLock( &gOutputBufferLock, oldIrql );
  2871. }
  2872. }
  2873. KeAcquireSpinLock( &gOutputBufferLock, &oldIrql );
  2874. }
  2875. KeReleaseSpinLock( &gOutputBufferLock, oldIrql );
  2876. //
  2877. // no copies occurred
  2878. //
  2879. if (length == OutputBufferLength && recordsAvailable > 0) {
  2880. IoStatus->Status = STATUS_BUFFER_TOO_SMALL;
  2881. }
  2882. return;
  2883. }
  2884. VOID
  2885. SpyCloseControlDevice (
  2886. )
  2887. /*++
  2888. Routine Description:
  2889. This is the routine that is associated with IRP_MJ_
  2890. This routine does the cleanup involved in closing the ControlDevice.
  2891. On the close of the Control Device, we need to empty the queue of
  2892. logRecords that are waiting to be returned to the user.
  2893. Arguments:
  2894. None.
  2895. Return Value:
  2896. None.
  2897. --*/
  2898. {
  2899. PLIST_ENTRY pList;
  2900. PRECORD_LIST pRecordList;
  2901. KIRQL oldIrql;
  2902. //
  2903. // Set the gControlDeviceState to CLEANING_UP so that we can
  2904. // signal that we are cleaning up the device.
  2905. //
  2906. KeAcquireSpinLock( &gControlDeviceStateLock, &oldIrql );
  2907. gControlDeviceState = CLEANING_UP;
  2908. KeReleaseSpinLock( &gControlDeviceStateLock, oldIrql );
  2909. KeAcquireSpinLock( &gOutputBufferLock, &oldIrql );
  2910. while (!IsListEmpty( &gOutputBufferList )) {
  2911. pList = RemoveHeadList( &gOutputBufferList );
  2912. KeReleaseSpinLock( &gOutputBufferLock, oldIrql );
  2913. pRecordList = CONTAINING_RECORD( pList, RECORD_LIST, List );
  2914. SpyFreeRecord( pRecordList );
  2915. KeAcquireSpinLock( &gOutputBufferLock, &oldIrql );
  2916. }
  2917. KeReleaseSpinLock( &gOutputBufferLock, oldIrql );
  2918. SpyNameDeleteAllNames();
  2919. //
  2920. // All the cleanup is done, so set the gControlDeviceState
  2921. // to CLOSED.
  2922. //
  2923. KeAcquireSpinLock( &gControlDeviceStateLock, &oldIrql );
  2924. gControlDeviceState = CLOSED;
  2925. KeReleaseSpinLock( &gControlDeviceStateLock, oldIrql );
  2926. }
  2927. ////////////////////////////////////////////////////////////////////////
  2928. // //
  2929. // Device name tracking helper routines //
  2930. // //
  2931. ////////////////////////////////////////////////////////////////////////
  2932. VOID
  2933. SpyGetObjectName (
  2934. IN PVOID Object,
  2935. IN OUT PUNICODE_STRING Name
  2936. )
  2937. /*++
  2938. Routine Description:
  2939. This routine will return the name of the given object.
  2940. If a name can not be found an empty string will be returned.
  2941. Arguments:
  2942. Object - The object whose name we want
  2943. Name - A unicode string that is already initialized with a buffer
  2944. Return Value:
  2945. None
  2946. --*/
  2947. {
  2948. NTSTATUS status;
  2949. CHAR nibuf[512]; //buffer that receives NAME information and name
  2950. POBJECT_NAME_INFORMATION nameInfo = (POBJECT_NAME_INFORMATION)nibuf;
  2951. ULONG retLength;
  2952. PAGED_CODE();
  2953. status = ObQueryNameString( Object,
  2954. nameInfo,
  2955. sizeof(nibuf),
  2956. &retLength );
  2957. //
  2958. // Init current length, if we have an error a NULL string will be returned
  2959. //
  2960. Name->Length = 0;
  2961. if (NT_SUCCESS( status )) {
  2962. //
  2963. // Copy what we can of the name string
  2964. //
  2965. RtlCopyUnicodeString( Name, &nameInfo->Name );
  2966. }
  2967. }
  2968. //
  2969. // VERSION NOTE:
  2970. //
  2971. // This helper routine is only needed when enumerating all volumes in the
  2972. // system, which is only supported on Windows XP and later.
  2973. //
  2974. #if WINVER >= 0x0501
  2975. VOID
  2976. SpyGetBaseDeviceObjectName (
  2977. IN PDEVICE_OBJECT DeviceObject,
  2978. IN OUT PUNICODE_STRING Name
  2979. )
  2980. /*++
  2981. Routine Description:
  2982. This locates the base device object in the given attachment chain and then
  2983. returns the name of that object.
  2984. If no name can be found, an empty string is returned.
  2985. Arguments:
  2986. Object - The object whose name we want
  2987. Name - A unicode string that is already initialized with a buffer
  2988. Return Value:
  2989. None
  2990. --*/
  2991. {
  2992. PAGED_CODE();
  2993. //
  2994. // Get the base file system device object
  2995. //
  2996. ASSERT( NULL != gSpyDynamicFunctions.GetDeviceAttachmentBaseRef );
  2997. DeviceObject = (gSpyDynamicFunctions.GetDeviceAttachmentBaseRef)( DeviceObject );
  2998. //
  2999. // Get the name of that object
  3000. //
  3001. SpyGetObjectName( DeviceObject, Name );
  3002. //
  3003. // Remove the reference added by IoGetDeviceAttachmentBaseRef
  3004. //
  3005. ObDereferenceObject( DeviceObject );
  3006. }
  3007. #endif
  3008. BOOLEAN
  3009. SpyFindSubString (
  3010. IN PUNICODE_STRING String,
  3011. IN PUNICODE_STRING SubString
  3012. )
  3013. /*++
  3014. Routine Description:
  3015. This routine looks to see if SubString is a substring of String.
  3016. Arguments:
  3017. String - the string to search in
  3018. SubString - the substring to find in String
  3019. Return Value:
  3020. Returns TRUE if the substring is found in string and FALSE otherwise.
  3021. --*/
  3022. {
  3023. ULONG index;
  3024. //
  3025. // First, check to see if the strings are equal.
  3026. //
  3027. if (RtlEqualUnicodeString( String, SubString, TRUE )) {
  3028. return TRUE;
  3029. }
  3030. //
  3031. // String and SubString aren't equal, so now see if SubString
  3032. // is in String any where.
  3033. //
  3034. for (index = 0;
  3035. index + SubString->Length <= String->Length;
  3036. index++) {
  3037. if (_wcsnicmp( &String->Buffer[index], SubString->Buffer, SubString->Length ) == 0) {
  3038. //
  3039. // SubString is found in String, so return TRUE.
  3040. //
  3041. return TRUE;
  3042. }
  3043. }
  3044. return FALSE;
  3045. }
  3046. VOID
  3047. SpyStoreUserName (
  3048. IN PFILESPY_DEVICE_EXTENSION devExt,
  3049. IN PUNICODE_STRING UserName
  3050. )
  3051. /*++
  3052. Routine Description:
  3053. Stores the current device name in the device extension. If
  3054. this name is already in the device name list of this extension,
  3055. it will not be added. If there is already a name for this device,
  3056. the new device name is appended to the DeviceName in the device extension.
  3057. Arguments:
  3058. devExt - The device extension that will store the
  3059. device name.
  3060. UserName - The device name as specified by the user to be stored.
  3061. Return Value:
  3062. None
  3063. --*/
  3064. {
  3065. //
  3066. // See if this UserName is already in the list of user names filespy
  3067. // keeps in its device extension. If not, add it to the list.
  3068. //
  3069. if (!SpyFindSubString( &devExt->UserNames, UserName )) {
  3070. //
  3071. // We didn't find this name in the list, so if there are no names
  3072. // in the UserNames list, just append UserName. Otherwise, append a
  3073. // delimiter then append UserName.
  3074. //
  3075. if (devExt->UserNames.Length == 0) {
  3076. RtlAppendUnicodeStringToString( &devExt->UserNames, UserName );
  3077. } else {
  3078. RtlAppendUnicodeToString( &devExt->UserNames, L", " );
  3079. RtlAppendUnicodeStringToString( &devExt->UserNames, UserName );
  3080. }
  3081. }
  3082. //
  3083. // See if this UserName is already in the list of device names filespy
  3084. // keeps in its device extension. If not, add it to the list.
  3085. //
  3086. if (!SpyFindSubString( &devExt->DeviceName, UserName )) {
  3087. //
  3088. // We didn't find this name in the list, so if there are no names
  3089. // in the UserNames list, just append UserName. Otherwise, append a
  3090. // delimiter then append UserName.
  3091. //
  3092. if (devExt->DeviceName.Length == 0) {
  3093. RtlAppendUnicodeStringToString( &devExt->DeviceName, UserName );
  3094. } else {
  3095. RtlAppendUnicodeToString( &devExt->DeviceName, L", " );
  3096. RtlAppendUnicodeStringToString( &devExt->DeviceName, UserName );
  3097. }
  3098. }
  3099. }
  3100. ////////////////////////////////////////////////////////////////////////
  3101. // //
  3102. // Debug support routines //
  3103. // //
  3104. ////////////////////////////////////////////////////////////////////////
  3105. VOID
  3106. SpyDumpIrpOperation (
  3107. IN BOOLEAN InOriginatingPath,
  3108. IN PIRP Irp
  3109. )
  3110. /*++
  3111. Routine Description:
  3112. This routine is for debugging and prints out a string to the
  3113. debugger specifying what Irp operation is being seen.
  3114. Arguments:
  3115. InOriginatingPath - TRUE if we are in the originating path
  3116. for the IRP, FALSE if in the completion path.
  3117. Irp - The IRP for this operation.
  3118. Return Value:
  3119. None.
  3120. --*/
  3121. {
  3122. CHAR irpMajorString[OPERATION_NAME_BUFFER_SIZE];
  3123. CHAR irpMinorString[OPERATION_NAME_BUFFER_SIZE];
  3124. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation( Irp );
  3125. GetIrpName(irpSp->MajorFunction,
  3126. irpSp->MinorFunction,
  3127. irpSp->Parameters.FileSystemControl.FsControlCode,
  3128. irpMajorString,irpMinorString);
  3129. if (InOriginatingPath) {
  3130. DbgPrint( "FILESPY: Irp preoperation for %s %s\n", irpMajorString, irpMinorString );
  3131. } else {
  3132. DbgPrint( "FILESPY: Irp postoperation for %s %s\n", irpMajorString, irpMinorString );
  3133. }
  3134. }
  3135. VOID
  3136. SpyDumpFastIoOperation (
  3137. IN BOOLEAN InPreOperation,
  3138. IN FASTIO_TYPE FastIoOperation
  3139. )
  3140. /*++
  3141. Routine Description:
  3142. This routine is for debugging and prints out a string to the
  3143. debugger specifying what FsFilter operation is being seen.
  3144. Arguments:
  3145. InPreOperation - TRUE if we have not called down to the next
  3146. device in the stack, FALSE otherwise.
  3147. FastIoOperation - The code for the Fast Io operation.
  3148. Return Value:
  3149. None.
  3150. --*/
  3151. {
  3152. CHAR operationString[OPERATION_NAME_BUFFER_SIZE];
  3153. GetFastioName(FastIoOperation,
  3154. operationString);
  3155. if (InPreOperation) {
  3156. DbgPrint( "FILESPY: Fast IO preOperation for %s\n", operationString );
  3157. } else {
  3158. DbgPrint( "FILESPY: Fast IO postOperation for %s\n", operationString );
  3159. }
  3160. }
  3161. #if WINVER >= 0x0501 /* See comment in DriverEntry */
  3162. VOID
  3163. SpyDumpFsFilterOperation (
  3164. IN BOOLEAN InPreOperationCallback,
  3165. IN PFS_FILTER_CALLBACK_DATA Data
  3166. )
  3167. /*++
  3168. Routine Description:
  3169. This routine is for debugging and prints out a string to the
  3170. debugger specifying what FsFilter operation is being seen.
  3171. Arguments:
  3172. InPreOperationCallback - TRUE if we are in a preOperation
  3173. callback, FALSE otherwise.
  3174. Data - The FS_FILTER_CALLBACK_DATA structure for this
  3175. operation.
  3176. Return Value:
  3177. None.
  3178. --*/
  3179. {
  3180. CHAR operationString[OPERATION_NAME_BUFFER_SIZE];
  3181. GetFsFilterOperationName(Data->Operation,operationString);
  3182. if (InPreOperationCallback) {
  3183. DbgPrint( "FILESPY: FsFilter preOperation for %s\n", operationString );
  3184. } else {
  3185. DbgPrint( "FILESPY: FsFilter postOperation for %s\n", operationString );
  3186. }
  3187. }
  3188. #endif