2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/ob/devicemap.c
5 * PURPOSE: Device map implementation
6 * PROGRAMMERS: Eric Kohl (eric.kohl@reactos.org)
7 * Alex Ionescu (alex.ionescu@reactos.org)
8 * Pierre Schweitzer (pierre@reactos.org)
11 /* INCLUDES ***************************************************************/
17 ULONG ObpLUIDDeviceMapsDisabled
;
18 ULONG ObpLUIDDeviceMapsEnabled
;
20 /* PRIVATE FUNCTIONS ******************************************************/
24 ObSetDeviceMap(IN PEPROCESS Process
,
25 IN HANDLE DirectoryHandle
)
27 POBJECT_DIRECTORY DirectoryObject
= NULL
;
28 PDEVICE_MAP DeviceMap
= NULL
, NewDeviceMap
= NULL
, OldDeviceMap
;
30 PEPROCESS WorkProcess
;
31 BOOLEAN MakePermanant
= FALSE
;
33 Status
= ObReferenceObjectByHandle(DirectoryHandle
,
35 ObpDirectoryObjectType
,
37 (PVOID
*)&DirectoryObject
,
39 if (!NT_SUCCESS(Status
))
41 DPRINT("ObReferenceObjectByHandle() failed (Status 0x%08lx)\n", Status
);
45 /* Allocate and initialize a new device map */
46 DeviceMap
= ExAllocatePoolWithTag(PagedPool
,
49 if (DeviceMap
== NULL
)
51 ObDereferenceObject(DirectoryObject
);
52 return STATUS_INSUFFICIENT_RESOURCES
;
55 /* Initialize the device map */
56 RtlZeroMemory(DeviceMap
, sizeof(*DeviceMap
));
57 DeviceMap
->ReferenceCount
= 1;
58 DeviceMap
->DosDevicesDirectory
= DirectoryObject
;
60 /* Acquire the device map lock */
61 KeAcquireGuardedMutex(&ObpDeviceMapLock
);
63 /* Attach the device map to the directory object */
64 if (DirectoryObject
->DeviceMap
== NULL
)
66 DirectoryObject
->DeviceMap
= DeviceMap
;
70 NewDeviceMap
= DeviceMap
;
72 /* There's already a device map,
74 DeviceMap
= DirectoryObject
->DeviceMap
;
75 ++DeviceMap
->ReferenceCount
;
78 /* Caller gave a process, use it */
81 WorkProcess
= Process
;
83 /* If no process given, use current and
84 * set system device map */
87 WorkProcess
= PsGetCurrentProcess();
88 ObSystemDeviceMap
= DeviceMap
;
91 /* If current object isn't system one, save system one in current
93 if (DirectoryObject
!= ObSystemDeviceMap
->DosDevicesDirectory
)
95 /* We also need to make the object permanant */
96 DeviceMap
->GlobalDosDevicesDirectory
= ObSystemDeviceMap
->DosDevicesDirectory
;
100 /* Save old process device map */
101 OldDeviceMap
= WorkProcess
->DeviceMap
;
102 /* Attach the device map to the process */
103 WorkProcess
->DeviceMap
= DeviceMap
;
105 /* Release the device map lock */
106 KeReleaseGuardedMutex(&ObpDeviceMapLock
);
108 /* If we have to make the object permamant, do it now */
111 POBJECT_HEADER ObjectHeader
;
112 POBJECT_HEADER_NAME_INFO HeaderNameInfo
;
114 ObjectHeader
= OBJECT_TO_OBJECT_HEADER(DirectoryObject
);
115 HeaderNameInfo
= ObpReferenceNameInfo(ObjectHeader
);
117 ObpEnterObjectTypeMutex(ObjectHeader
->Type
);
118 if (HeaderNameInfo
!= NULL
&& HeaderNameInfo
->Directory
!= NULL
)
120 ObjectHeader
->Flags
|= OB_FLAG_PERMANENT
;
122 ObpLeaveObjectTypeMutex(ObjectHeader
->Type
);
124 if (HeaderNameInfo
!= NULL
)
126 ObpDereferenceNameInfo(HeaderNameInfo
);
130 /* Release useless device map if required */
131 if (NewDeviceMap
!= NULL
)
133 ObfDereferenceObject(DirectoryObject
);
134 ExFreePoolWithTag(NewDeviceMap
, 'mDbO');
137 /* And dereference previous process device map */
138 if (OldDeviceMap
!= NULL
)
140 ObfDereferenceDeviceMap(OldDeviceMap
);
143 return STATUS_SUCCESS
;
149 ObSetDirectoryDeviceMap(OUT PDEVICE_MAP
* DeviceMap
,
150 IN HANDLE DirectoryHandle
)
153 return STATUS_NOT_IMPLEMENTED
;
159 ObpSetCurrentProcessDeviceMap(VOID
)
164 PEPROCESS CurrentProcess
;
165 LUID SystemLuid
= SYSTEM_LUID
;
166 PDEVICE_MAP DeviceMap
, OldDeviceMap
;
168 /* Get our impersonation token */
169 CurrentProcess
= PsGetCurrentProcess();
170 Token
= PsReferencePrimaryToken(CurrentProcess
);
173 return STATUS_NO_TOKEN
;
176 /* Query the Logon ID */
177 Status
= SeQueryAuthenticationIdToken(Token
, &LogonId
);
178 if (!NT_SUCCESS(Status
))
183 /* If that's system, then use system device map */
184 if (RtlEqualLuid(&LogonId
, &SystemLuid
))
186 DeviceMap
= ObSystemDeviceMap
;
188 /* Otherwise ask Se for the device map */
191 Status
= SeGetLogonIdDeviceMap(&LogonId
, &DeviceMap
);
192 if (!NT_SUCCESS(Status
))
194 /* Normalize failure status */
195 Status
= STATUS_OBJECT_PATH_INVALID
;
200 /* Fail if no device map */
201 if (DeviceMap
== NULL
)
203 Status
= STATUS_OBJECT_PATH_INVALID
;
207 /* Acquire the device map lock */
208 KeAcquireGuardedMutex(&ObpDeviceMapLock
);
210 /* Save old device map attached to the process */
211 OldDeviceMap
= CurrentProcess
->DeviceMap
;
213 /* Set new device map & reference it */
214 ++DeviceMap
->ReferenceCount
;
215 CurrentProcess
->DeviceMap
= DeviceMap
;
217 /* Release the device map lock */
218 KeReleaseGuardedMutex(&ObpDeviceMapLock
);
220 /* If we had a device map, dereference it */
221 if (OldDeviceMap
!= NULL
)
223 ObfDereferenceDeviceMap(OldDeviceMap
);
227 /* We're done with the token! */
228 ObDereferenceObject(Token
);
236 ObpReferenceDeviceMap(VOID
)
241 PDEVICE_MAP DeviceMap
;
242 PETHREAD CurrentThread
;
243 BOOLEAN LookingForSystem
;
244 LUID SystemLuid
= SYSTEM_LUID
;
245 BOOLEAN CopyOnOpen
, EffectiveOnly
;
246 SECURITY_IMPERSONATION_LEVEL ImpersonationLevel
;
248 LookingForSystem
= FALSE
;
250 /* If LUID mapping is enable, try to get appropriate device map */
251 if (ObpLUIDDeviceMapsEnabled
!= 0)
253 /* In case of impersonation, we've got a bit of work to do */
254 CurrentThread
= PsGetCurrentThread();
255 if (CurrentThread
->ActiveImpersonationInfo
)
257 /* Get impersonation token */
258 Token
= PsReferenceImpersonationToken(CurrentThread
,
261 &ImpersonationLevel
);
265 Status
= SeQueryAuthenticationIdToken(Token
, &LogonId
);
270 Status
= STATUS_NO_TOKEN
;
273 /* If we got logon LUID */
274 if (NT_SUCCESS(Status
))
277 * Check it's not system, system is easy to handle,
278 * we just need to return ObSystemDeviceMap
280 if (!RtlEqualLuid(&LogonId
, &SystemLuid
))
282 /* Ask Se for the device map */
283 Status
= SeGetLogonIdDeviceMap(&LogonId
, &DeviceMap
);
284 if (NT_SUCCESS(Status
))
286 /* Acquire the device map lock */
287 KeAcquireGuardedMutex(&ObpDeviceMapLock
);
289 /* Reference the device map if any */
290 if (DeviceMap
!= NULL
)
292 ++DeviceMap
->ReferenceCount
;
295 /* Release the device map lock */
296 KeReleaseGuardedMutex(&ObpDeviceMapLock
);
298 /* If we got the device map, we're done! */
299 if (DeviceMap
!= NULL
)
301 ObDereferenceObject(Token
);
309 LookingForSystem
= TRUE
;
315 * Fall back case of the LUID mapping, make sure there's a
316 * a device map attached to the current process
318 if (PsGetCurrentProcess()->DeviceMap
== NULL
&&
319 !NT_SUCCESS(ObpSetCurrentProcessDeviceMap()))
321 /* We may have failed after we got impersonation token */
324 ObDereferenceObject(Token
);
331 /* Acquire the device map lock */
332 KeAcquireGuardedMutex(&ObpDeviceMapLock
);
334 /* If we're looking for system map, use it */
335 if (LookingForSystem
)
337 DeviceMap
= ObSystemDeviceMap
;
339 /* Otherwise, use current process device map */
342 DeviceMap
= PsGetCurrentProcess()->DeviceMap
;
345 /* If we got one, reference it */
346 if (DeviceMap
!= NULL
)
348 ++DeviceMap
->ReferenceCount
;
351 /* Release the device map lock */
352 KeReleaseGuardedMutex(&ObpDeviceMapLock
);
354 /* We may have impersonation token (if we failed in impersonation branch) */
357 ObDereferenceObject(Token
);
360 /* Return the potentially found device map */
367 ObDereferenceDeviceMap(IN PEPROCESS Process
)
369 PDEVICE_MAP DeviceMap
;
371 DPRINT("ObDereferenceDeviceMap()\n");
373 /* Get the pointer to this process devicemap and reset it
374 holding the device map lock */
375 KeAcquireGuardedMutex(&ObpDeviceMapLock
);
376 DeviceMap
= Process
->DeviceMap
;
377 Process
->DeviceMap
= NULL
;
378 KeReleaseGuardedMutex(&ObpDeviceMapLock
);
380 /* Continue only if there is a device map */
381 if (DeviceMap
!= NULL
)
382 ObfDereferenceDeviceMap(DeviceMap
);
388 ObfDereferenceDeviceMap(IN PDEVICE_MAP DeviceMap
)
390 DPRINT("ObfDereferenceDeviceMap()\n");
392 /* Acquire the device map lock */
393 KeAcquireGuardedMutex(&ObpDeviceMapLock
);
395 /* Decrement the reference counter */
396 DeviceMap
->ReferenceCount
--;
397 DPRINT("ReferenceCount: %lu\n", DeviceMap
->ReferenceCount
);
399 /* Leave, if there are still references to this device map */
400 if (DeviceMap
->ReferenceCount
!= 0)
402 /* Release the device map lock and leave */
403 KeReleaseGuardedMutex(&ObpDeviceMapLock
);
407 /* Nobody is referencing it anymore, unlink the DOS directory */
408 DeviceMap
->DosDevicesDirectory
->DeviceMap
= NULL
;
410 /* Release the devicemap lock */
411 KeReleaseGuardedMutex(&ObpDeviceMapLock
);
413 /* Dereference the DOS Devices Directory and free the Device Map */
414 ObMakeTemporaryObject(DeviceMap
->DosDevicesDirectory
);
415 ObDereferenceObject(DeviceMap
->DosDevicesDirectory
);
416 ExFreePoolWithTag(DeviceMap
, 'mDbO');
422 ObInheritDeviceMap(IN PEPROCESS Parent
,
423 IN PEPROCESS Process
)
425 PDEVICE_MAP DeviceMap
;
427 DPRINT("ObInheritDeviceMap()\n");
429 /* Acquire the device map lock */
430 KeAcquireGuardedMutex(&ObpDeviceMapLock
);
432 /* Get the parent process device map or the system device map */
433 DeviceMap
= (Parent
!= NULL
) ? Parent
->DeviceMap
: ObSystemDeviceMap
;
434 if (DeviceMap
!= NULL
)
436 /* Reference the device map and attach it to the new process */
437 DeviceMap
->ReferenceCount
++;
438 DPRINT("ReferenceCount: %lu\n", DeviceMap
->ReferenceCount
);
440 Process
->DeviceMap
= DeviceMap
;
443 /* Release the device map lock */
444 KeReleaseGuardedMutex(&ObpDeviceMapLock
);
450 ObQueryDeviceMapInformation(IN PEPROCESS Process
,
451 IN PPROCESS_DEVICEMAP_INFORMATION DeviceMapInfo
,
454 PDEVICE_MAP DeviceMap
= NULL
, GlobalDeviceMap
;
456 PROCESS_DEVICEMAP_INFORMATION MapInfo
;
462 if (Flags
& ~PROCESS_LUID_DOSDEVICES_ONLY
)
464 return STATUS_INVALID_PARAMETER
;
468 /* Do we want to return anything? */
469 ReturnAny
= ~Flags
& PROCESS_LUID_DOSDEVICES_ONLY
;
471 /* If LUID mappings are enabled... */
472 if (ObpLUIDDeviceMapsEnabled
!= 0)
474 /* Check for process parameter validness */
475 if (Process
!= NULL
&& Process
!= PsGetCurrentProcess())
477 return STATUS_INVALID_PARAMETER
;
480 /* And get the device map */
481 DeviceMap
= ObpReferenceDeviceMap();
484 /* Acquire the device map lock */
485 KeAcquireGuardedMutex(&ObpDeviceMapLock
);
488 * If we had a device map, if because of LUID mappings,
489 * we'll have to dereference it afterwards
491 if (DeviceMap
!= NULL
)
497 /* Get the process device map or the system device map */
498 DeviceMap
= (Process
!= NULL
) ? Process
->DeviceMap
: ObSystemDeviceMap
;
501 /* Fail if no device map */
502 if (DeviceMap
== NULL
)
504 KeReleaseGuardedMutex(&ObpDeviceMapLock
);
505 return STATUS_END_OF_FILE
;
508 /* At that point, assume success */
509 Status
= STATUS_SUCCESS
;
511 /* Try to get the global device map if any */
512 GlobalDeviceMap
= DeviceMap
;
513 if (DeviceMap
->GlobalDosDevicesDirectory
!= NULL
)
515 if (DeviceMap
->GlobalDosDevicesDirectory
->DeviceMap
!= NULL
)
517 GlobalDeviceMap
= DeviceMap
->GlobalDosDevicesDirectory
->DeviceMap
;
521 /* Now, setup our device map info, especially drive types */
522 MapInfo
.Query
.DriveMap
= DeviceMap
->DriveMap
;
523 /* Browse every device */
524 for (i
= 0, BitMask
= 1; i
< 32; ++i
, BitMask
*= 2)
526 /* Set the type given current device map */
527 MapInfo
.Query
.DriveType
[i
] = DeviceMap
->DriveType
[i
];
530 * If device is not existing and we're asked to return
531 * more than just LUID mapped, get the entry
532 * from global device map if not remote
534 if (!(MapInfo
.Query
.DriveMap
& BitMask
) && ReturnAny
)
536 if (ObpLUIDDeviceMapsEnabled
!= 0 ||
537 (GlobalDeviceMap
->DriveType
[i
] != DOSDEVICE_DRIVE_REMOTE
&&
538 GlobalDeviceMap
->DriveType
[i
] != DOSDEVICE_DRIVE_CALCULATE
))
540 MapInfo
.Query
.DriveType
[i
] = GlobalDeviceMap
->DriveType
[i
];
541 MapInfo
.Query
.DriveMap
|= BitMask
& GlobalDeviceMap
->DriveMap
;
546 /* Release the device map lock */
547 KeReleaseGuardedMutex(&ObpDeviceMapLock
);
549 /* Dereference LUID device map */
552 ObfDereferenceDeviceMap(DeviceMap
);
558 RtlCopyMemory(DeviceMapInfo
, &MapInfo
, sizeof(PROCESS_DEVICEMAP_INFORMATION
));
560 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
562 Status
= _SEH2_GetExceptionCode();
572 ObIsLUIDDeviceMapsEnabled(VOID
)
574 return ObpLUIDDeviceMapsEnabled
;
581 ObIsDosDeviceLocallyMapped(
583 OUT PUCHAR DosDeviceState
)
585 /* Check the index */
586 if (Index
< 1 || Index
> 26)
587 return STATUS_INVALID_PARAMETER
;
589 /* Acquire the device map lock */
590 KeAcquireGuardedMutex(&ObpDeviceMapLock
);
592 /* Get drive mapping status */
593 *DosDeviceState
= (ObSystemDeviceMap
->DriveMap
& (1 << Index
)) != 0;
595 /* Release the device map lock */
596 KeReleaseGuardedMutex(&ObpDeviceMapLock
);
598 return STATUS_SUCCESS
;