[NTOSKRNL] Implement ObpReferenceDeviceMap()
[reactos.git] / ntoskrnl / ob / devicemap.c
1 /*
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 */
9
10 /* INCLUDES ***************************************************************/
11
12 #include <ntoskrnl.h>
13 #define NDEBUG
14 #include <debug.h>
15
16 ULONG ObpLUIDDeviceMapsDisabled;
17 ULONG ObpLUIDDeviceMapsEnabled;
18
19 /* PRIVATE FUNCTIONS ******************************************************/
20
21 NTSTATUS
22 NTAPI
23 ObSetDeviceMap(IN PEPROCESS Process,
24 IN HANDLE DirectoryHandle)
25 {
26 POBJECT_DIRECTORY DirectoryObject = NULL;
27 PDEVICE_MAP DeviceMap = NULL, NewDeviceMap = NULL, OldDeviceMap;
28 NTSTATUS Status;
29 PEPROCESS WorkProcess;
30 BOOLEAN MakePermanant = FALSE;
31
32 Status = ObReferenceObjectByHandle(DirectoryHandle,
33 DIRECTORY_TRAVERSE,
34 ObpDirectoryObjectType,
35 KeGetPreviousMode(),
36 (PVOID*)&DirectoryObject,
37 NULL);
38 if (!NT_SUCCESS(Status))
39 {
40 DPRINT("ObReferenceObjectByHandle() failed (Status 0x%08lx)\n", Status);
41 return Status;
42 }
43
44 /* Allocate and initialize a new device map */
45 DeviceMap = ExAllocatePoolWithTag(PagedPool,
46 sizeof(*DeviceMap),
47 'mDbO');
48 if (DeviceMap == NULL)
49 {
50 ObDereferenceObject(DirectoryObject);
51 return STATUS_INSUFFICIENT_RESOURCES;
52 }
53
54 /* Initialize the device map */
55 RtlZeroMemory(DeviceMap, sizeof(*DeviceMap));
56 DeviceMap->ReferenceCount = 1;
57 DeviceMap->DosDevicesDirectory = DirectoryObject;
58
59 /* Acquire the device map lock */
60 KeAcquireGuardedMutex(&ObpDeviceMapLock);
61
62 /* Attach the device map to the directory object */
63 if (DirectoryObject->DeviceMap == NULL)
64 {
65 DirectoryObject->DeviceMap = DeviceMap;
66 }
67 else
68 {
69 NewDeviceMap = DeviceMap;
70
71 /* There's already a device map,
72 so reuse it */
73 DeviceMap = DirectoryObject->DeviceMap;
74 ++DeviceMap->ReferenceCount;
75 }
76
77 /* Caller gave a process, use it */
78 if (Process != NULL)
79 {
80 WorkProcess = Process;
81 }
82 /* If no process given, use current and
83 * set system device map */
84 else
85 {
86 WorkProcess = PsGetCurrentProcess();
87 ObSystemDeviceMap = DeviceMap;
88 }
89
90 /* If current object isn't system one, save system one in current
91 * device map */
92 if (DirectoryObject != ObSystemDeviceMap->DosDevicesDirectory)
93 {
94 /* We also need to make the object permanant */
95 DeviceMap->GlobalDosDevicesDirectory = ObSystemDeviceMap->DosDevicesDirectory;
96 MakePermanant = TRUE;
97 }
98
99 /* Save old process device map */
100 OldDeviceMap = WorkProcess->DeviceMap;
101 /* Attach the device map to the process */
102 WorkProcess->DeviceMap = DeviceMap;
103
104 /* Release the device map lock */
105 KeReleaseGuardedMutex(&ObpDeviceMapLock);
106
107 /* If we have to make the object permamant, do it now */
108 if (MakePermanant)
109 {
110 POBJECT_HEADER ObjectHeader;
111 POBJECT_HEADER_NAME_INFO HeaderNameInfo;
112
113 ObjectHeader = OBJECT_TO_OBJECT_HEADER(DirectoryObject);
114 HeaderNameInfo = ObpReferenceNameInfo(ObjectHeader);
115
116 ObpEnterObjectTypeMutex(ObjectHeader->Type);
117 if (HeaderNameInfo != NULL && HeaderNameInfo->Directory != NULL)
118 {
119 ObjectHeader->Flags |= OB_FLAG_PERMANENT;
120 }
121 ObpLeaveObjectTypeMutex(ObjectHeader->Type);
122
123 if (HeaderNameInfo != NULL)
124 {
125 ObpDereferenceNameInfo(HeaderNameInfo);
126 }
127 }
128
129 /* Release useless device map if required */
130 if (NewDeviceMap != NULL)
131 {
132 ObfDereferenceObject(DirectoryObject);
133 ExFreePoolWithTag(NewDeviceMap, 'mDbO');
134 }
135
136 /* And dereference previous process device map */
137 if (OldDeviceMap != NULL)
138 {
139 ObfDereferenceDeviceMap(OldDeviceMap);
140 }
141
142 return STATUS_SUCCESS;
143 }
144
145
146 NTSTATUS
147 NTAPI
148 ObpSetCurrentProcessDeviceMap(VOID)
149 {
150 return STATUS_NOT_IMPLEMENTED;
151 }
152
153
154 PDEVICE_MAP
155 NTAPI
156 ObpReferenceDeviceMap(VOID)
157 {
158 LUID LogonId;
159 NTSTATUS Status;
160 PTOKEN Token = NULL;
161 PDEVICE_MAP DeviceMap;
162 PETHREAD CurrentThread;
163 BOOLEAN LookingForSystem;
164 LUID SystemLuid = SYSTEM_LUID;
165 BOOLEAN CopyOnOpen, EffectiveOnly;
166 SECURITY_IMPERSONATION_LEVEL ImpersonationLevel;
167
168 LookingForSystem = FALSE;
169
170 /* If LUID mapping is enable, try to get appropriate device map */
171 if (ObpLUIDDeviceMapsEnabled != 0)
172 {
173 /* In case of impersonation, we've got a bit of work to do */
174 CurrentThread = PsGetCurrentThread();
175 if (CurrentThread->ActiveImpersonationInfo)
176 {
177 /* Get impersonation token */
178 Token = PsReferenceImpersonationToken(CurrentThread,
179 &CopyOnOpen,
180 &EffectiveOnly,
181 &ImpersonationLevel);
182 /* Get logon LUID */
183 if (Token != NULL)
184 {
185 Status = SeQueryAuthenticationIdToken(Token, &LogonId);
186 }
187 else
188 {
189 /* Force failure */
190 Status = STATUS_NO_TOKEN;
191 }
192
193 /* If we got logon LUID */
194 if (NT_SUCCESS(Status))
195 {
196 /*
197 * Check it's not system, system is easy to handle,
198 * we just need to return ObSystemDeviceMap
199 */
200 if (!RtlEqualLuid(&LogonId, &SystemLuid))
201 {
202 /* Ask Se for the device map */
203 Status = SeGetLogonIdDeviceMap(&LogonId, &DeviceMap);
204 if (NT_SUCCESS(Status))
205 {
206 /* Acquire the device map lock */
207 KeAcquireGuardedMutex(&ObpDeviceMapLock);
208
209 /* Reference the device map if any */
210 if (DeviceMap != NULL)
211 {
212 ++DeviceMap->ReferenceCount;
213 }
214
215 /* Release the device map lock */
216 KeReleaseGuardedMutex(&ObpDeviceMapLock);
217
218 /* If we got the device map, we're done! */
219 if (DeviceMap != NULL)
220 {
221 ObDereferenceObject(Token);
222
223 return DeviceMap;
224 }
225 }
226 }
227 else
228 {
229 LookingForSystem = TRUE;
230 }
231 }
232 }
233
234 /*
235 * Fall back case of the LUID mapping, make sure there's a
236 * a device map attached to the current process
237 */
238 if (PsGetCurrentProcess()->DeviceMap == NULL &&
239 !NT_SUCCESS(ObpSetCurrentProcessDeviceMap()))
240 {
241 /* We may have failed after we got impersonation token */
242 if (Token != NULL)
243 {
244 ObDereferenceObject(Token);
245 }
246
247 return NULL;
248 }
249 }
250
251 /* Acquire the device map lock */
252 KeAcquireGuardedMutex(&ObpDeviceMapLock);
253
254 /* If we're looking for system map, use it */
255 if (LookingForSystem)
256 {
257 DeviceMap = ObSystemDeviceMap;
258 }
259 /* Otherwise, use current process device map */
260 else
261 {
262 DeviceMap = PsGetCurrentProcess()->DeviceMap;
263 }
264
265 /* If we got one, reference it */
266 if (DeviceMap != NULL)
267 {
268 ++DeviceMap->ReferenceCount;
269 }
270
271 /* Release the device map lock */
272 KeReleaseGuardedMutex(&ObpDeviceMapLock);
273
274 /* We may have impersonation token (if we failed in impersonation branch) */
275 if (Token != NULL)
276 {
277 ObDereferenceObject(Token);
278 }
279
280 /* Return the potentially found device map */
281 return DeviceMap;
282 }
283
284
285 VOID
286 NTAPI
287 ObDereferenceDeviceMap(IN PEPROCESS Process)
288 {
289 PDEVICE_MAP DeviceMap;
290
291 DPRINT("ObDereferenceDeviceMap()\n");
292
293 /* Get the pointer to this process devicemap and reset it
294 holding the device map lock */
295 KeAcquireGuardedMutex(&ObpDeviceMapLock);
296 DeviceMap = Process->DeviceMap;
297 Process->DeviceMap = NULL;
298 KeReleaseGuardedMutex(&ObpDeviceMapLock);
299
300 /* Continue only if there is a device map */
301 if (DeviceMap != NULL)
302 ObfDereferenceDeviceMap(DeviceMap);
303 }
304
305
306 VOID
307 FASTCALL
308 ObfDereferenceDeviceMap(IN PDEVICE_MAP DeviceMap)
309 {
310 DPRINT("ObfDereferenceDeviceMap()\n");
311
312 /* Acquire the device map lock */
313 KeAcquireGuardedMutex(&ObpDeviceMapLock);
314
315 /* Decrement the reference counter */
316 DeviceMap->ReferenceCount--;
317 DPRINT("ReferenceCount: %lu\n", DeviceMap->ReferenceCount);
318
319 /* Leave, if there are still references to this device map */
320 if (DeviceMap->ReferenceCount != 0)
321 {
322 /* Release the device map lock and leave */
323 KeReleaseGuardedMutex(&ObpDeviceMapLock);
324 return;
325 }
326
327 /* Nobody is referencing it anymore, unlink the DOS directory */
328 DeviceMap->DosDevicesDirectory->DeviceMap = NULL;
329
330 /* Release the devicemap lock */
331 KeReleaseGuardedMutex(&ObpDeviceMapLock);
332
333 /* Dereference the DOS Devices Directory and free the Device Map */
334 ObMakeTemporaryObject(DeviceMap->DosDevicesDirectory);
335 ObDereferenceObject(DeviceMap->DosDevicesDirectory);
336 ExFreePoolWithTag(DeviceMap, 'mDbO');
337 }
338
339
340 VOID
341 NTAPI
342 ObInheritDeviceMap(IN PEPROCESS Parent,
343 IN PEPROCESS Process)
344 {
345 PDEVICE_MAP DeviceMap;
346
347 DPRINT("ObInheritDeviceMap()\n");
348
349 /* Acquire the device map lock */
350 KeAcquireGuardedMutex(&ObpDeviceMapLock);
351
352 /* Get the parent process device map or the system device map */
353 DeviceMap = (Parent != NULL) ? Parent->DeviceMap : ObSystemDeviceMap;
354 if (DeviceMap != NULL)
355 {
356 /* Reference the device map and attach it to the new process */
357 DeviceMap->ReferenceCount++;
358 DPRINT("ReferenceCount: %lu\n", DeviceMap->ReferenceCount);
359
360 Process->DeviceMap = DeviceMap;
361 }
362
363 /* Release the device map lock */
364 KeReleaseGuardedMutex(&ObpDeviceMapLock);
365 }
366
367
368 NTSTATUS
369 NTAPI
370 ObQueryDeviceMapInformation(IN PEPROCESS Process,
371 IN PPROCESS_DEVICEMAP_INFORMATION DeviceMapInfo,
372 IN ULONG Flags)
373 {
374 PDEVICE_MAP DeviceMap = NULL, GlobalDeviceMap;
375 BOOLEAN Dereference;
376 PROCESS_DEVICEMAP_INFORMATION MapInfo;
377 ULONG BitMask, i;
378 BOOLEAN ReturnAny;
379 NTSTATUS Status;
380
381 /* Validate flags */
382 if (Flags & ~PROCESS_LUID_DOSDEVICES_ONLY)
383 {
384 return STATUS_INVALID_PARAMETER;
385 }
386
387 Dereference = FALSE;
388 /* Do we want to return anything? */
389 ReturnAny = ~Flags & PROCESS_LUID_DOSDEVICES_ONLY;
390
391 /* If LUID mappings are enabled... */
392 if (ObpLUIDDeviceMapsEnabled != 0)
393 {
394 /* Check for process parameter validness */
395 if (Process != NULL && Process != PsGetCurrentProcess())
396 {
397 return STATUS_INVALID_PARAMETER;
398 }
399
400 /* And get the device map */
401 DeviceMap = ObpReferenceDeviceMap();
402 }
403
404 /* Acquire the device map lock */
405 KeAcquireGuardedMutex(&ObpDeviceMapLock);
406
407 /*
408 * If we had a device map, if because of LUID mappings,
409 * we'll have to dereference it afterwards
410 */
411 if (DeviceMap != NULL)
412 {
413 Dereference = TRUE;
414 }
415 else
416 {
417 /* Get the process device map or the system device map */
418 DeviceMap = (Process != NULL) ? Process->DeviceMap : ObSystemDeviceMap;
419 }
420
421 /* Fail if no device map */
422 if (DeviceMap == NULL)
423 {
424 KeReleaseGuardedMutex(&ObpDeviceMapLock);
425 return STATUS_END_OF_FILE;
426 }
427
428 /* At that point, assume success */
429 Status = STATUS_SUCCESS;
430
431 /* Try to get the global device map if any */
432 GlobalDeviceMap = DeviceMap;
433 if (DeviceMap->GlobalDosDevicesDirectory != NULL)
434 {
435 if (DeviceMap->GlobalDosDevicesDirectory->DeviceMap != NULL)
436 {
437 GlobalDeviceMap = DeviceMap->GlobalDosDevicesDirectory->DeviceMap;
438 }
439 }
440
441 /* Now, setup our device map info, especially drive types */
442 MapInfo.Query.DriveMap = DeviceMap->DriveMap;
443 /* Browse every device */
444 for (i = 0, BitMask = 1; i < 32; ++i, BitMask *= 2)
445 {
446 /* Set the type given current device map */
447 MapInfo.Query.DriveType[i] = DeviceMap->DriveType[i];
448
449 /*
450 * If device is not existing and we're asked to return
451 * more than just LUID mapped, get the entry
452 * from global device map if not remote
453 */
454 if (!(MapInfo.Query.DriveMap & BitMask) && ReturnAny)
455 {
456 if (ObpLUIDDeviceMapsEnabled != 0 ||
457 (GlobalDeviceMap->DriveType[i] != DOSDEVICE_DRIVE_REMOTE &&
458 GlobalDeviceMap->DriveType[i] != DOSDEVICE_DRIVE_CALCULATE))
459 {
460 MapInfo.Query.DriveType[i] = GlobalDeviceMap->DriveType[i];
461 MapInfo.Query.DriveMap |= BitMask & GlobalDeviceMap->DriveMap;
462 }
463 }
464 }
465
466 /* Release the device map lock */
467 KeReleaseGuardedMutex(&ObpDeviceMapLock);
468
469 /* Dereference LUID device map */
470 if (Dereference)
471 {
472 ObfDereferenceDeviceMap(DeviceMap);
473 }
474
475 /* Copy back data */
476 _SEH2_TRY
477 {
478 RtlCopyMemory(DeviceMapInfo, &MapInfo, sizeof(PROCESS_DEVICEMAP_INFORMATION));
479 }
480 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
481 {
482 Status = _SEH2_GetExceptionCode();
483 }
484 _SEH2_END;
485
486 return Status;
487 }
488
489
490 ULONG
491 NTAPI
492 ObIsLUIDDeviceMapsEnabled(VOID)
493 {
494 return ObpLUIDDeviceMapsEnabled;
495 }
496
497
498 #if 0
499 NTSTATUS
500 NTAPI
501 ObIsDosDeviceLocallyMapped(
502 IN ULONG Index,
503 OUT PUCHAR DosDeviceState)
504 {
505 /* Check the index */
506 if (Index < 1 || Index > 26)
507 return STATUS_INVALID_PARAMETER;
508
509 /* Acquire the device map lock */
510 KeAcquireGuardedMutex(&ObpDeviceMapLock);
511
512 /* Get drive mapping status */
513 *DosDeviceState = (ObSystemDeviceMap->DriveMap & (1 << Index)) != 0;
514
515 /* Release the device map lock */
516 KeReleaseGuardedMutex(&ObpDeviceMapLock);
517
518 return STATUS_SUCCESS;
519 }
520 #endif
521
522 /* EOF */