[NTOSKRNL] Implement SeGetLogonIdDeviceMap
[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 ObSetDirectoryDeviceMap(OUT PDEVICE_MAP * DeviceMap,
150 IN HANDLE DirectoryHandle)
151 {
152 UNIMPLEMENTED;
153 return STATUS_NOT_IMPLEMENTED;
154 }
155
156
157 NTSTATUS
158 NTAPI
159 ObpSetCurrentProcessDeviceMap(VOID)
160 {
161 PTOKEN Token;
162 LUID LogonId;
163 NTSTATUS Status;
164 PEPROCESS CurrentProcess;
165 LUID SystemLuid = SYSTEM_LUID;
166 PDEVICE_MAP DeviceMap, OldDeviceMap;
167
168 /* Get our impersonation token */
169 CurrentProcess = PsGetCurrentProcess();
170 Token = PsReferencePrimaryToken(CurrentProcess);
171 if (Token == NULL)
172 {
173 return STATUS_NO_TOKEN;
174 }
175
176 /* Query the Logon ID */
177 Status = SeQueryAuthenticationIdToken(Token, &LogonId);
178 if (!NT_SUCCESS(Status))
179 {
180 goto done;
181 }
182
183 /* If that's system, then use system device map */
184 if (RtlEqualLuid(&LogonId, &SystemLuid))
185 {
186 DeviceMap = ObSystemDeviceMap;
187 }
188 /* Otherwise ask Se for the device map */
189 else
190 {
191 Status = SeGetLogonIdDeviceMap(&LogonId, &DeviceMap);
192 if (!NT_SUCCESS(Status))
193 {
194 /* Normalize failure status */
195 Status = STATUS_OBJECT_PATH_INVALID;
196 goto done;
197 }
198 }
199
200 /* Fail if no device map */
201 if (DeviceMap == NULL)
202 {
203 Status = STATUS_OBJECT_PATH_INVALID;
204 goto done;
205 }
206
207 /* Acquire the device map lock */
208 KeAcquireGuardedMutex(&ObpDeviceMapLock);
209
210 /* Save old device map attached to the process */
211 OldDeviceMap = CurrentProcess->DeviceMap;
212
213 /* Set new device map & reference it */
214 ++DeviceMap->ReferenceCount;
215 CurrentProcess->DeviceMap = DeviceMap;
216
217 /* Release the device map lock */
218 KeReleaseGuardedMutex(&ObpDeviceMapLock);
219
220 /* If we had a device map, dereference it */
221 if (OldDeviceMap != NULL)
222 {
223 ObfDereferenceDeviceMap(OldDeviceMap);
224 }
225
226 done:
227 /* We're done with the token! */
228 ObDereferenceObject(Token);
229
230 return Status;
231 }
232
233
234 PDEVICE_MAP
235 NTAPI
236 ObpReferenceDeviceMap(VOID)
237 {
238 LUID LogonId;
239 NTSTATUS Status;
240 PTOKEN Token = NULL;
241 PDEVICE_MAP DeviceMap;
242 PETHREAD CurrentThread;
243 BOOLEAN LookingForSystem;
244 LUID SystemLuid = SYSTEM_LUID;
245 BOOLEAN CopyOnOpen, EffectiveOnly;
246 SECURITY_IMPERSONATION_LEVEL ImpersonationLevel;
247
248 LookingForSystem = FALSE;
249
250 /* If LUID mapping is enable, try to get appropriate device map */
251 if (ObpLUIDDeviceMapsEnabled != 0)
252 {
253 /* In case of impersonation, we've got a bit of work to do */
254 CurrentThread = PsGetCurrentThread();
255 if (CurrentThread->ActiveImpersonationInfo)
256 {
257 /* Get impersonation token */
258 Token = PsReferenceImpersonationToken(CurrentThread,
259 &CopyOnOpen,
260 &EffectiveOnly,
261 &ImpersonationLevel);
262 /* Get logon LUID */
263 if (Token != NULL)
264 {
265 Status = SeQueryAuthenticationIdToken(Token, &LogonId);
266 }
267 else
268 {
269 /* Force failure */
270 Status = STATUS_NO_TOKEN;
271 }
272
273 /* If we got logon LUID */
274 if (NT_SUCCESS(Status))
275 {
276 /*
277 * Check it's not system, system is easy to handle,
278 * we just need to return ObSystemDeviceMap
279 */
280 if (!RtlEqualLuid(&LogonId, &SystemLuid))
281 {
282 /* Ask Se for the device map */
283 Status = SeGetLogonIdDeviceMap(&LogonId, &DeviceMap);
284 if (NT_SUCCESS(Status))
285 {
286 /* Acquire the device map lock */
287 KeAcquireGuardedMutex(&ObpDeviceMapLock);
288
289 /* Reference the device map if any */
290 if (DeviceMap != NULL)
291 {
292 ++DeviceMap->ReferenceCount;
293 }
294
295 /* Release the device map lock */
296 KeReleaseGuardedMutex(&ObpDeviceMapLock);
297
298 /* If we got the device map, we're done! */
299 if (DeviceMap != NULL)
300 {
301 ObDereferenceObject(Token);
302
303 return DeviceMap;
304 }
305 }
306 }
307 else
308 {
309 LookingForSystem = TRUE;
310 }
311 }
312 }
313
314 /*
315 * Fall back case of the LUID mapping, make sure there's a
316 * a device map attached to the current process
317 */
318 if (PsGetCurrentProcess()->DeviceMap == NULL &&
319 !NT_SUCCESS(ObpSetCurrentProcessDeviceMap()))
320 {
321 /* We may have failed after we got impersonation token */
322 if (Token != NULL)
323 {
324 ObDereferenceObject(Token);
325 }
326
327 return NULL;
328 }
329 }
330
331 /* Acquire the device map lock */
332 KeAcquireGuardedMutex(&ObpDeviceMapLock);
333
334 /* If we're looking for system map, use it */
335 if (LookingForSystem)
336 {
337 DeviceMap = ObSystemDeviceMap;
338 }
339 /* Otherwise, use current process device map */
340 else
341 {
342 DeviceMap = PsGetCurrentProcess()->DeviceMap;
343 }
344
345 /* If we got one, reference it */
346 if (DeviceMap != NULL)
347 {
348 ++DeviceMap->ReferenceCount;
349 }
350
351 /* Release the device map lock */
352 KeReleaseGuardedMutex(&ObpDeviceMapLock);
353
354 /* We may have impersonation token (if we failed in impersonation branch) */
355 if (Token != NULL)
356 {
357 ObDereferenceObject(Token);
358 }
359
360 /* Return the potentially found device map */
361 return DeviceMap;
362 }
363
364
365 VOID
366 NTAPI
367 ObDereferenceDeviceMap(IN PEPROCESS Process)
368 {
369 PDEVICE_MAP DeviceMap;
370
371 DPRINT("ObDereferenceDeviceMap()\n");
372
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);
379
380 /* Continue only if there is a device map */
381 if (DeviceMap != NULL)
382 ObfDereferenceDeviceMap(DeviceMap);
383 }
384
385
386 VOID
387 FASTCALL
388 ObfDereferenceDeviceMap(IN PDEVICE_MAP DeviceMap)
389 {
390 DPRINT("ObfDereferenceDeviceMap()\n");
391
392 /* Acquire the device map lock */
393 KeAcquireGuardedMutex(&ObpDeviceMapLock);
394
395 /* Decrement the reference counter */
396 DeviceMap->ReferenceCount--;
397 DPRINT("ReferenceCount: %lu\n", DeviceMap->ReferenceCount);
398
399 /* Leave, if there are still references to this device map */
400 if (DeviceMap->ReferenceCount != 0)
401 {
402 /* Release the device map lock and leave */
403 KeReleaseGuardedMutex(&ObpDeviceMapLock);
404 return;
405 }
406
407 /* Nobody is referencing it anymore, unlink the DOS directory */
408 DeviceMap->DosDevicesDirectory->DeviceMap = NULL;
409
410 /* Release the devicemap lock */
411 KeReleaseGuardedMutex(&ObpDeviceMapLock);
412
413 /* Dereference the DOS Devices Directory and free the Device Map */
414 ObMakeTemporaryObject(DeviceMap->DosDevicesDirectory);
415 ObDereferenceObject(DeviceMap->DosDevicesDirectory);
416 ExFreePoolWithTag(DeviceMap, 'mDbO');
417 }
418
419
420 VOID
421 NTAPI
422 ObInheritDeviceMap(IN PEPROCESS Parent,
423 IN PEPROCESS Process)
424 {
425 PDEVICE_MAP DeviceMap;
426
427 DPRINT("ObInheritDeviceMap()\n");
428
429 /* Acquire the device map lock */
430 KeAcquireGuardedMutex(&ObpDeviceMapLock);
431
432 /* Get the parent process device map or the system device map */
433 DeviceMap = (Parent != NULL) ? Parent->DeviceMap : ObSystemDeviceMap;
434 if (DeviceMap != NULL)
435 {
436 /* Reference the device map and attach it to the new process */
437 DeviceMap->ReferenceCount++;
438 DPRINT("ReferenceCount: %lu\n", DeviceMap->ReferenceCount);
439
440 Process->DeviceMap = DeviceMap;
441 }
442
443 /* Release the device map lock */
444 KeReleaseGuardedMutex(&ObpDeviceMapLock);
445 }
446
447
448 NTSTATUS
449 NTAPI
450 ObQueryDeviceMapInformation(IN PEPROCESS Process,
451 IN PPROCESS_DEVICEMAP_INFORMATION DeviceMapInfo,
452 IN ULONG Flags)
453 {
454 PDEVICE_MAP DeviceMap = NULL, GlobalDeviceMap;
455 BOOLEAN Dereference;
456 PROCESS_DEVICEMAP_INFORMATION MapInfo;
457 ULONG BitMask, i;
458 BOOLEAN ReturnAny;
459 NTSTATUS Status;
460
461 /* Validate flags */
462 if (Flags & ~PROCESS_LUID_DOSDEVICES_ONLY)
463 {
464 return STATUS_INVALID_PARAMETER;
465 }
466
467 Dereference = FALSE;
468 /* Do we want to return anything? */
469 ReturnAny = ~Flags & PROCESS_LUID_DOSDEVICES_ONLY;
470
471 /* If LUID mappings are enabled... */
472 if (ObpLUIDDeviceMapsEnabled != 0)
473 {
474 /* Check for process parameter validness */
475 if (Process != NULL && Process != PsGetCurrentProcess())
476 {
477 return STATUS_INVALID_PARAMETER;
478 }
479
480 /* And get the device map */
481 DeviceMap = ObpReferenceDeviceMap();
482 }
483
484 /* Acquire the device map lock */
485 KeAcquireGuardedMutex(&ObpDeviceMapLock);
486
487 /*
488 * If we had a device map, if because of LUID mappings,
489 * we'll have to dereference it afterwards
490 */
491 if (DeviceMap != NULL)
492 {
493 Dereference = TRUE;
494 }
495 else
496 {
497 /* Get the process device map or the system device map */
498 DeviceMap = (Process != NULL) ? Process->DeviceMap : ObSystemDeviceMap;
499 }
500
501 /* Fail if no device map */
502 if (DeviceMap == NULL)
503 {
504 KeReleaseGuardedMutex(&ObpDeviceMapLock);
505 return STATUS_END_OF_FILE;
506 }
507
508 /* At that point, assume success */
509 Status = STATUS_SUCCESS;
510
511 /* Try to get the global device map if any */
512 GlobalDeviceMap = DeviceMap;
513 if (DeviceMap->GlobalDosDevicesDirectory != NULL)
514 {
515 if (DeviceMap->GlobalDosDevicesDirectory->DeviceMap != NULL)
516 {
517 GlobalDeviceMap = DeviceMap->GlobalDosDevicesDirectory->DeviceMap;
518 }
519 }
520
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)
525 {
526 /* Set the type given current device map */
527 MapInfo.Query.DriveType[i] = DeviceMap->DriveType[i];
528
529 /*
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
533 */
534 if (!(MapInfo.Query.DriveMap & BitMask) && ReturnAny)
535 {
536 if (ObpLUIDDeviceMapsEnabled != 0 ||
537 (GlobalDeviceMap->DriveType[i] != DOSDEVICE_DRIVE_REMOTE &&
538 GlobalDeviceMap->DriveType[i] != DOSDEVICE_DRIVE_CALCULATE))
539 {
540 MapInfo.Query.DriveType[i] = GlobalDeviceMap->DriveType[i];
541 MapInfo.Query.DriveMap |= BitMask & GlobalDeviceMap->DriveMap;
542 }
543 }
544 }
545
546 /* Release the device map lock */
547 KeReleaseGuardedMutex(&ObpDeviceMapLock);
548
549 /* Dereference LUID device map */
550 if (Dereference)
551 {
552 ObfDereferenceDeviceMap(DeviceMap);
553 }
554
555 /* Copy back data */
556 _SEH2_TRY
557 {
558 RtlCopyMemory(DeviceMapInfo, &MapInfo, sizeof(PROCESS_DEVICEMAP_INFORMATION));
559 }
560 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
561 {
562 Status = _SEH2_GetExceptionCode();
563 }
564 _SEH2_END;
565
566 return Status;
567 }
568
569
570 ULONG
571 NTAPI
572 ObIsLUIDDeviceMapsEnabled(VOID)
573 {
574 return ObpLUIDDeviceMapsEnabled;
575 }
576
577
578 #if 0
579 NTSTATUS
580 NTAPI
581 ObIsDosDeviceLocallyMapped(
582 IN ULONG Index,
583 OUT PUCHAR DosDeviceState)
584 {
585 /* Check the index */
586 if (Index < 1 || Index > 26)
587 return STATUS_INVALID_PARAMETER;
588
589 /* Acquire the device map lock */
590 KeAcquireGuardedMutex(&ObpDeviceMapLock);
591
592 /* Get drive mapping status */
593 *DosDeviceState = (ObSystemDeviceMap->DriveMap & (1 << Index)) != 0;
594
595 /* Release the device map lock */
596 KeReleaseGuardedMutex(&ObpDeviceMapLock);
597
598 return STATUS_SUCCESS;
599 }
600 #endif
601
602 /* EOF */