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