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

732 lines
18 KiB

  1. /*++
  2. Copyright (c) 1992 Microsoft Corporation
  3. Module Name:
  4. obdevmap.c
  5. Abstract:
  6. This module contains routines for creating and querying Device Map objects.
  7. Device Map objects define a DOS device name space, such as drive letters
  8. and peripheral devices (e.g. COM1)
  9. Author:
  10. Steve Wood (stevewo) 01-Oct-1996
  11. Revision History:
  12. --*/
  13. #include "obp.h"
  14. //
  15. // Global that activates/disables LUID device maps
  16. //
  17. extern ULONG ObpLUIDDeviceMapsEnabled;
  18. NTSTATUS
  19. ObSetDirectoryDeviceMap (
  20. OUT PDEVICE_MAP *ppDeviceMap OPTIONAL,
  21. IN HANDLE DirectoryHandle
  22. );
  23. NTSTATUS
  24. ObSetDeviceMap (
  25. IN PEPROCESS TargetProcess OPTIONAL,
  26. IN HANDLE DirectoryHandle
  27. );
  28. NTSTATUS
  29. ObQueryDeviceMapInformation (
  30. IN PEPROCESS TargetProcess OPTIONAL,
  31. OUT PPROCESS_DEVICEMAP_INFORMATION DeviceMapInformation,
  32. IN ULONG Flags
  33. );
  34. VOID
  35. ObInheritDeviceMap (
  36. IN PEPROCESS NewProcess,
  37. IN PEPROCESS ParentProcess OPTIONAL
  38. );
  39. VOID
  40. ObDereferenceDeviceMap (
  41. IN PEPROCESS Process
  42. );
  43. ULONG
  44. ObIsLUIDDeviceMapsEnabled (
  45. );
  46. #ifdef OBP_PAGEDPOOL_NAMESPACE
  47. #if defined(ALLOC_PRAGMA)
  48. #pragma alloc_text(PAGE,ObSetDirectoryDeviceMap)
  49. #pragma alloc_text(PAGE,ObSetDeviceMap)
  50. #pragma alloc_text(PAGE,ObQueryDeviceMapInformation)
  51. #pragma alloc_text(PAGE,ObInheritDeviceMap)
  52. #pragma alloc_text(PAGE,ObDereferenceDeviceMap)
  53. #pragma alloc_text(PAGE,ObIsLUIDDeviceMapsEnabled)
  54. #endif
  55. #endif // OBP_PAGEDPOOL_NAMESPACE
  56. NTSTATUS
  57. ObSetDirectoryDeviceMap (
  58. OUT PDEVICE_MAP *ppDeviceMap OPTIONAL,
  59. IN HANDLE DirectoryHandle
  60. )
  61. /*++
  62. Routine Description:
  63. This function sets the device map for the specified object directory.
  64. A device map is a structure associated with an object directory and
  65. a Logon ID (LUID). When the object manager sees a references to a
  66. name beginning with \??\ or just \??, then it requests the device
  67. map of the LUID from the kernel reference monitor, which keeps track
  68. of LUIDs. This allows multiple virtual \?? object directories on
  69. a per LUID basis. The WindowStation logic will use this
  70. functionality to allocate devices unique to each WindowStation.
  71. SeGetLogonIdDeviceMap() use this function to create the device map
  72. structure associated with the directory object for the LUID device
  73. map. So, this function should only be called from kernel mode.
  74. Arguments:
  75. ppDeviceMap - returns a pointer to the device map structure
  76. DirectoryHandle - Specifies the object directory to associate with the
  77. device map.
  78. Return Value:
  79. Returns one of the following status codes:
  80. STATUS_SUCCESS - normal, successful completion.
  81. STATUS_SHARING_VIOLATION - The specified object directory is already
  82. associated with a device map.
  83. STATUS_INSUFFICIENT_RESOURCES - Unable to allocate pool for the device
  84. map data structure;
  85. STATUS_ACCESS_DENIED - Caller did not have DIRECTORY_TRAVERSE access
  86. to the specified object directory.
  87. --*/
  88. {
  89. NTSTATUS Status;
  90. POBJECT_DIRECTORY DosDevicesDirectory;
  91. PDEVICE_MAP DeviceMap, FreeDeviceMap;
  92. KIRQL OldIrql;
  93. POBJECT_HEADER ObjectHeader;
  94. POBJECT_HEADER_NAME_INFO NameInfo;
  95. PAGED_CODE();
  96. //
  97. // Reference the object directory handle and see if it is already
  98. // associated with a device map structure. If so, fail this call.
  99. //
  100. Status = ObReferenceObjectByHandle( DirectoryHandle,
  101. DIRECTORY_TRAVERSE,
  102. ObpDirectoryObjectType,
  103. KernelMode,
  104. &DosDevicesDirectory,
  105. NULL );
  106. if (!NT_SUCCESS( Status )) {
  107. return( Status );
  108. }
  109. FreeDeviceMap = NULL;
  110. DeviceMap = ExAllocatePoolWithTag( OB_NAMESPACE_POOL_TYPE, sizeof( *DeviceMap ), 'mDbO' );
  111. if (DeviceMap == NULL) {
  112. ObDereferenceObject( DosDevicesDirectory );
  113. Status = STATUS_INSUFFICIENT_RESOURCES;
  114. return( Status );
  115. }
  116. RtlZeroMemory( DeviceMap, sizeof( *DeviceMap ) );
  117. DeviceMap->ReferenceCount = 1;
  118. DeviceMap->DosDevicesDirectory = DosDevicesDirectory;
  119. //
  120. // Capture the device map
  121. //
  122. ObpLockDeviceMap();
  123. if (DosDevicesDirectory->DeviceMap != NULL) {
  124. FreeDeviceMap = DeviceMap;
  125. DeviceMap = DosDevicesDirectory->DeviceMap;
  126. DeviceMap->ReferenceCount++;
  127. } else {
  128. DosDevicesDirectory->DeviceMap = DeviceMap;
  129. }
  130. if (DosDevicesDirectory != ObSystemDeviceMap->DosDevicesDirectory) {
  131. DeviceMap->GlobalDosDevicesDirectory = ObSystemDeviceMap->DosDevicesDirectory;
  132. }
  133. ObpUnlockDeviceMap();
  134. //
  135. // pass back a pointer to the device map
  136. //
  137. if (ppDeviceMap != NULL) {
  138. *ppDeviceMap = DeviceMap;
  139. }
  140. //
  141. // Make the object permanent until the devmap is removed. This keeps the name in the tree
  142. //
  143. ObjectHeader = OBJECT_TO_OBJECT_HEADER( DosDevicesDirectory );
  144. NameInfo = ObpReferenceNameInfo( ObjectHeader );
  145. //
  146. // Other bits are set in this flags field by the handle database code. Synchronize with that.
  147. //
  148. ObpLockObject( ObjectHeader );
  149. if (NameInfo != NULL && NameInfo->Directory != NULL) {
  150. ObjectHeader->Flags |= OB_FLAG_PERMANENT_OBJECT;
  151. }
  152. ObpUnlockObject( ObjectHeader );
  153. ObpDereferenceNameInfo(NameInfo);
  154. //
  155. // If the directory already had a devmap and so was already referenced.
  156. // Drop ours and free the unused block.
  157. //
  158. if (FreeDeviceMap != NULL) {
  159. ObDereferenceObject (DosDevicesDirectory);
  160. ExFreePool (FreeDeviceMap);
  161. }
  162. return( Status );
  163. }
  164. NTSTATUS
  165. ObSetDeviceMap (
  166. IN PEPROCESS TargetProcess OPTIONAL,
  167. IN HANDLE DirectoryHandle
  168. )
  169. /*++
  170. Routine Description:
  171. This function sets the device map for the specified process, using
  172. the specified object directory. A device map is a structure
  173. associated with an object directory and a process. When the object
  174. manager sees a references to a name beginning with \??\ or just \??,
  175. then it follows the device map object in the calling process's
  176. EPROCESS structure to get to the object directory to use for that
  177. reference. This allows multiple virtual \?? object directories on
  178. a per process basis. The WindowStation logic will use this
  179. functionality to allocate devices unique to each WindowStation.
  180. Arguments:
  181. TargetProcess - Specifies the target process to associate the device map
  182. with. If null then the current process is used and the directory
  183. becomes the system default dos device map.
  184. DirectoryHandle - Specifies the object directory to associate with the
  185. device map.
  186. Return Value:
  187. Returns one of the following status codes:
  188. STATUS_SUCCESS - normal, successful completion.
  189. STATUS_SHARING_VIOLATION - The specified object directory is already
  190. associated with a device map.
  191. STATUS_INSUFFICIENT_RESOURCES - Unable to allocate pool for the device
  192. map data structure;
  193. STATUS_ACCESS_DENIED - Caller did not have DIRECTORY_TRAVERSE access
  194. to the specified object directory.
  195. --*/
  196. {
  197. NTSTATUS Status;
  198. POBJECT_DIRECTORY DosDevicesDirectory;
  199. PDEVICE_MAP DeviceMap, FreeDeviceMap, DerefDeviceMap;
  200. HANDLE Handle;
  201. KIRQL OldIrql;
  202. PEPROCESS Target = TargetProcess;
  203. POBJECT_HEADER ObjectHeader;
  204. POBJECT_HEADER_NAME_INFO NameInfo;
  205. BOOLEAN PreserveName = FALSE;
  206. PAGED_CODE();
  207. //
  208. // Reference the object directory handle and see if it is already
  209. // associated with a device map structure. If so, fail this call.
  210. //
  211. Status = ObReferenceObjectByHandle( DirectoryHandle,
  212. DIRECTORY_TRAVERSE,
  213. ObpDirectoryObjectType,
  214. KeGetPreviousMode(),
  215. &DosDevicesDirectory,
  216. NULL );
  217. if (!NT_SUCCESS( Status )) {
  218. return( Status );
  219. }
  220. FreeDeviceMap = NULL;
  221. DeviceMap = ExAllocatePoolWithTag( OB_NAMESPACE_POOL_TYPE, sizeof( *DeviceMap ), 'mDbO' );
  222. if (DeviceMap == NULL) {
  223. ObDereferenceObject( DosDevicesDirectory );
  224. Status = STATUS_INSUFFICIENT_RESOURCES;
  225. return( Status );
  226. }
  227. RtlZeroMemory( DeviceMap, sizeof( *DeviceMap ) );
  228. DeviceMap->ReferenceCount = 1;
  229. DeviceMap->DosDevicesDirectory = DosDevicesDirectory;
  230. //
  231. // Capture the device map
  232. //
  233. ObpLockDeviceMap();
  234. if (DosDevicesDirectory->DeviceMap != NULL) {
  235. FreeDeviceMap = DeviceMap;
  236. DeviceMap = DosDevicesDirectory->DeviceMap;
  237. DeviceMap->ReferenceCount++;
  238. } else {
  239. DosDevicesDirectory->DeviceMap = DeviceMap;
  240. }
  241. if (Target == NULL) {
  242. Target = PsGetCurrentProcess();
  243. ObSystemDeviceMap = DeviceMap;
  244. }
  245. if (DosDevicesDirectory != ObSystemDeviceMap->DosDevicesDirectory) {
  246. DeviceMap->GlobalDosDevicesDirectory = ObSystemDeviceMap->DosDevicesDirectory;
  247. PreserveName = TRUE;
  248. }
  249. DerefDeviceMap = Target->DeviceMap;
  250. Target->DeviceMap = DeviceMap;
  251. ObpUnlockDeviceMap();
  252. if (PreserveName == TRUE) {
  253. //
  254. // Make the object permanent until the devmap is removed. This keeps the name in the tree
  255. //
  256. ObjectHeader = OBJECT_TO_OBJECT_HEADER( DosDevicesDirectory );
  257. NameInfo = ObpReferenceNameInfo( ObjectHeader );
  258. //
  259. // Other bits are set in this flags field by the handle database code. Synchronise with that.
  260. //
  261. ObpLockObject( ObjectHeader );
  262. if (NameInfo != NULL && NameInfo->Directory != NULL) {
  263. ObjectHeader->Flags |= OB_FLAG_PERMANENT_OBJECT;
  264. }
  265. ObpUnlockObject( ObjectHeader );
  266. ObpDereferenceNameInfo( NameInfo );
  267. }
  268. //
  269. // If the directory already had a devmap and so was already referenced.
  270. // Drop ours and free the unused bock.
  271. //
  272. if (FreeDeviceMap != NULL) {
  273. ObDereferenceObject (DosDevicesDirectory);
  274. ExFreePool (FreeDeviceMap);
  275. }
  276. //
  277. // If the target already had a device map then deref it now
  278. //
  279. if (DerefDeviceMap != NULL) {
  280. ObfDereferenceDeviceMap (DerefDeviceMap);
  281. }
  282. return( Status );
  283. }
  284. NTSTATUS
  285. ObQueryDeviceMapInformation (
  286. IN PEPROCESS TargetProcess OPTIONAL,
  287. OUT PPROCESS_DEVICEMAP_INFORMATION DeviceMapInformation,
  288. IN ULONG Flags
  289. )
  290. /*++
  291. Routine Description:
  292. This function queries information from the device map associated with the
  293. specified process. The returned information contains a bit map indicating
  294. which drive letters are defined in the associated object directory, along
  295. with an array of drive types that give the type of each drive letter.
  296. Arguments:
  297. TargetProcess - Specifies the target process to retreive the device map
  298. from. If not specified then we return the global default device map
  299. DeviceMapInformation - Specifies the location where to store the results.
  300. Flags - Specifies the query type
  301. Return Value:
  302. Returns one of the following status codes:
  303. STATUS_SUCCESS - normal, successful completion.
  304. STATUS_END_OF_FILE - The specified process was not associated with
  305. a device map.
  306. STATUS_ACCESS_VIOLATION - The DeviceMapInformation buffer pointer
  307. value specified an invalid address.
  308. STATUS_INVALID_PARAMETER - if LUID device maps are enabled,
  309. specified process is not the current process
  310. --*/
  311. {
  312. NTSTATUS Status;
  313. PDEVICE_MAP DeviceMap = NULL;
  314. KIRQL OldIrql;
  315. PROCESS_DEVICEMAP_INFORMATION LocalMapInformation;
  316. ULONG Mask;
  317. BOOLEAN SearchShadow;
  318. BOOLEAN UsedLUIDDeviceMap = FALSE;
  319. if (Flags & ~(PROCESS_LUID_DOSDEVICES_ONLY)) {
  320. return STATUS_INVALID_PARAMETER;
  321. }
  322. SearchShadow = !(Flags & PROCESS_LUID_DOSDEVICES_ONLY);
  323. //
  324. // if LUID device maps are enabled,
  325. // Verify that the process is the current process or
  326. // no process was specified
  327. //
  328. if (ObpLUIDDeviceMapsEnabled != 0) {
  329. if (ARGUMENT_PRESENT( TargetProcess ) &&
  330. (PsGetCurrentProcess() != TargetProcess)) {
  331. return STATUS_INVALID_PARAMETER;
  332. }
  333. //
  334. // Get the caller's LUID device map
  335. //
  336. DeviceMap = ObpReferenceDeviceMap();
  337. }
  338. //
  339. // First, while using a spinlock to protect the device map from
  340. // going away we will make local copy of the information.
  341. //
  342. ObpLockDeviceMap();
  343. if (DeviceMap == NULL) {
  344. //
  345. // Check if the caller gave us a target process and if not then use
  346. // the globally defined one
  347. //
  348. if (ARGUMENT_PRESENT( TargetProcess )) {
  349. DeviceMap = TargetProcess->DeviceMap;
  350. } else {
  351. DeviceMap = ObSystemDeviceMap;
  352. }
  353. } else {
  354. UsedLUIDDeviceMap = TRUE;
  355. }
  356. //
  357. // If we do not have a device map then we'll return an error otherwise
  358. // we simply copy over the device map structure (bitmap and drive type
  359. // array) into the output buffer
  360. //
  361. if (DeviceMap == NULL) {
  362. ObpUnlockDeviceMap();
  363. Status = STATUS_END_OF_FILE;
  364. } else {
  365. ULONG i;
  366. PDEVICE_MAP ShadowDeviceMap;
  367. Status = STATUS_SUCCESS;
  368. ShadowDeviceMap = DeviceMap;
  369. if (DeviceMap->GlobalDosDevicesDirectory != NULL &&
  370. DeviceMap->GlobalDosDevicesDirectory->DeviceMap != NULL) {
  371. ShadowDeviceMap = DeviceMap->GlobalDosDevicesDirectory->DeviceMap;
  372. }
  373. LocalMapInformation.Query.DriveMap = DeviceMap->DriveMap;
  374. for (i = 0, Mask = 1;
  375. i < sizeof (LocalMapInformation.Query.DriveType) /
  376. sizeof (LocalMapInformation.Query.DriveType[0]);
  377. i++, Mask <<= 1) {
  378. LocalMapInformation.Query.DriveType[i] = DeviceMap->DriveType[i];
  379. if ( (Mask & DeviceMap->DriveMap) == 0 &&
  380. SearchShadow &&
  381. ( ( ObpLUIDDeviceMapsEnabled != 0 // check if LUID Device
  382. // maps are enabled
  383. ) ||
  384. ( ShadowDeviceMap->DriveType[i] != DOSDEVICE_DRIVE_REMOTE &&
  385. ShadowDeviceMap->DriveType[i] != DOSDEVICE_DRIVE_CALCULATE
  386. ) ) ) {
  387. LocalMapInformation.Query.DriveType[i] = ShadowDeviceMap->DriveType[i];
  388. LocalMapInformation.Query.DriveMap |= ShadowDeviceMap->DriveMap & Mask;
  389. }
  390. }
  391. ObpUnlockDeviceMap();
  392. //
  393. // If the LUID device map was used,
  394. // then dereference the LUID device map
  395. //
  396. if (UsedLUIDDeviceMap == TRUE) {
  397. ObfDereferenceDeviceMap(DeviceMap);
  398. }
  399. //
  400. // Now we can copy the information to the caller buffer using
  401. // a try-except to guard against the output buffer changing.
  402. // Note that the caller must have already probed the buffer
  403. // for write.
  404. //
  405. try {
  406. RtlCopyMemory( &DeviceMapInformation->Query,
  407. &LocalMapInformation.Query,
  408. sizeof( DeviceMapInformation->Query ));
  409. } except( EXCEPTION_EXECUTE_HANDLER ) {
  410. Status = GetExceptionCode();
  411. }
  412. }
  413. return Status;
  414. }
  415. VOID
  416. ObInheritDeviceMap (
  417. IN PEPROCESS NewProcess,
  418. IN PEPROCESS ParentProcess OPTIONAL
  419. )
  420. /*++
  421. Routine Description:
  422. This function is called at process initialization time to inherit the
  423. device map for a process. If no parent process, then inherits from
  424. the system device map.
  425. Arguments:
  426. NewProcess - Supplies the process being initialized that needs a new
  427. dos device map
  428. ParentProcess - - Optionally specifies the parent process whose device
  429. map we inherit. This process if specified must have a device map
  430. Return Value:
  431. None.
  432. --*/
  433. {
  434. PDEVICE_MAP DeviceMap;
  435. KIRQL OldIrql;
  436. //
  437. // If we are called with a parent process then grab its device map
  438. // otherwise grab the system wide device map and check that is does
  439. // exist
  440. //
  441. ObpLockDeviceMap();
  442. if (ParentProcess) {
  443. DeviceMap = ParentProcess->DeviceMap;
  444. } else {
  445. //
  446. // Note: WindowStation guys may want a callout here to get the
  447. // device map to use for this case.
  448. //
  449. DeviceMap = ObSystemDeviceMap;
  450. }
  451. if (DeviceMap != NULL) {
  452. //
  453. // With the device map bumps its reference count and add it to the
  454. // new process
  455. //
  456. DeviceMap->ReferenceCount++;
  457. NewProcess->DeviceMap = DeviceMap;
  458. }
  459. ObpUnlockDeviceMap();
  460. return;
  461. }
  462. VOID
  463. ObDereferenceDeviceMap (
  464. IN PEPROCESS Process
  465. )
  466. /*++
  467. Routine Description:
  468. This function is called at process tear down time to decrement the
  469. reference count on a device map. When the reference count goes to
  470. zero, it means no more processes are using this, so it can be freed
  471. and the reference on the associated object directory can be released.
  472. Arguments:
  473. Process - Process being destroyed.
  474. Return Value:
  475. None.
  476. --*/
  477. {
  478. PDEVICE_MAP DeviceMap;
  479. KIRQL OldIrql;
  480. //
  481. // Grab the device map and then we only have work to do
  482. // it there is one
  483. //
  484. ObpLockDeviceMap();
  485. DeviceMap = Process->DeviceMap;
  486. Process->DeviceMap = NULL;
  487. ObpUnlockDeviceMap();
  488. if (DeviceMap != NULL) {
  489. //
  490. // To dereference the device map we need to null out the
  491. // processes device map pointer, and decrement its ref count
  492. // If the ref count goes to zero we can free up the memory
  493. // and dereference the dos device directory object
  494. //
  495. ObfDereferenceDeviceMap(DeviceMap);
  496. }
  497. //
  498. // And return to our caller
  499. //
  500. return;
  501. }
  502. ULONG
  503. ObIsLUIDDeviceMapsEnabled (
  504. )
  505. /*++
  506. Routine Description:
  507. This function is checks if LUID DosDevices are enabled.
  508. Arguments:
  509. None.
  510. Return Value:
  511. 0 - LUID DosDevices are disabled.
  512. 1 - LUID DosDevices are enabled.
  513. --*/
  514. {
  515. return( ObpLUIDDeviceMapsEnabled );
  516. }