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 ObDereferenceObject(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 POBJECT_DIRECTORY DirectoryObject = NULL; 153 PDEVICE_MAP LocalMap = NULL, NewDeviceMap = NULL; 154 NTSTATUS Status; 155 POBJECT_HEADER ObjectHeader; 156 POBJECT_HEADER_NAME_INFO HeaderNameInfo; 157 158 Status = ObReferenceObjectByHandle(DirectoryHandle, 159 DIRECTORY_TRAVERSE, 160 ObpDirectoryObjectType, 161 KernelMode, 162 (PVOID*)&DirectoryObject, 163 NULL); 164 if (!NT_SUCCESS(Status)) 165 { 166 DPRINT("ObReferenceObjectByHandle() failed (Status 0x%08lx)\n", Status); 167 return Status; 168 } 169 170 /* Allocate and initialize a new device map */ 171 LocalMap = ExAllocatePoolWithTag(PagedPool, 172 sizeof(*LocalMap), 173 'mDbO'); 174 if (LocalMap == NULL) 175 { 176 ObDereferenceObject(DirectoryObject); 177 return STATUS_INSUFFICIENT_RESOURCES; 178 } 179 180 /* Initialize the device map */ 181 RtlZeroMemory(LocalMap, sizeof(*LocalMap)); 182 LocalMap->ReferenceCount = 1; 183 LocalMap->DosDevicesDirectory = DirectoryObject; 184 185 /* Acquire the device map lock */ 186 KeAcquireGuardedMutex(&ObpDeviceMapLock); 187 188 /* Attach the device map to the directory object */ 189 if (DirectoryObject->DeviceMap == NULL) 190 { 191 DirectoryObject->DeviceMap = LocalMap; 192 } 193 else 194 { 195 NewDeviceMap = LocalMap; 196 197 /* There's already a device map, 198 so reuse it */ 199 LocalMap = DirectoryObject->DeviceMap; 200 ++LocalMap->ReferenceCount; 201 } 202 203 /* If current object isn't system one, save system one in current 204 * device map */ 205 if (DirectoryObject != ObSystemDeviceMap->DosDevicesDirectory) 206 { 207 /* We also need to make the object permanant */ 208 LocalMap->GlobalDosDevicesDirectory = ObSystemDeviceMap->DosDevicesDirectory; 209 } 210 211 /* Release the device map lock */ 212 KeReleaseGuardedMutex(&ObpDeviceMapLock); 213 214 if (DeviceMap != NULL) 215 { 216 *DeviceMap = LocalMap; 217 } 218 219 /* Caller expects us to make the object permanant, so do it! */ 220 ObjectHeader = OBJECT_TO_OBJECT_HEADER(DirectoryObject); 221 HeaderNameInfo = ObpReferenceNameInfo(ObjectHeader); 222 223 ObpEnterObjectTypeMutex(ObjectHeader->Type); 224 if (HeaderNameInfo != NULL && HeaderNameInfo->Directory != NULL) 225 { 226 ObjectHeader->Flags |= OB_FLAG_PERMANENT; 227 } 228 ObpLeaveObjectTypeMutex(ObjectHeader->Type); 229 230 if (HeaderNameInfo != NULL) 231 { 232 ObpDereferenceNameInfo(HeaderNameInfo); 233 } 234 235 /* Release useless device map if required */ 236 if (NewDeviceMap != NULL) 237 { 238 ObDereferenceObject(DirectoryObject); 239 ExFreePoolWithTag(NewDeviceMap, 'mDbO'); 240 } 241 242 return Status; 243 } 244 245 246 NTSTATUS 247 NTAPI 248 ObpSetCurrentProcessDeviceMap(VOID) 249 { 250 PTOKEN Token; 251 LUID LogonId; 252 NTSTATUS Status; 253 PEPROCESS CurrentProcess; 254 LUID SystemLuid = SYSTEM_LUID; 255 PDEVICE_MAP DeviceMap, OldDeviceMap; 256 257 /* Get our impersonation token */ 258 CurrentProcess = PsGetCurrentProcess(); 259 Token = PsReferencePrimaryToken(CurrentProcess); 260 if (Token == NULL) 261 { 262 return STATUS_NO_TOKEN; 263 } 264 265 /* Query the Logon ID */ 266 Status = SeQueryAuthenticationIdToken(Token, &LogonId); 267 if (!NT_SUCCESS(Status)) 268 { 269 goto done; 270 } 271 272 /* If that's system, then use system device map */ 273 if (RtlEqualLuid(&LogonId, &SystemLuid)) 274 { 275 DeviceMap = ObSystemDeviceMap; 276 } 277 /* Otherwise ask Se for the device map */ 278 else 279 { 280 Status = SeGetLogonIdDeviceMap(&LogonId, &DeviceMap); 281 if (!NT_SUCCESS(Status)) 282 { 283 /* Normalize failure status */ 284 Status = STATUS_OBJECT_PATH_INVALID; 285 goto done; 286 } 287 } 288 289 /* Fail if no device map */ 290 if (DeviceMap == NULL) 291 { 292 Status = STATUS_OBJECT_PATH_INVALID; 293 goto done; 294 } 295 296 /* Acquire the device map lock */ 297 KeAcquireGuardedMutex(&ObpDeviceMapLock); 298 299 /* Save old device map attached to the process */ 300 OldDeviceMap = CurrentProcess->DeviceMap; 301 302 /* Set new device map & reference it */ 303 ++DeviceMap->ReferenceCount; 304 CurrentProcess->DeviceMap = DeviceMap; 305 306 /* Release the device map lock */ 307 KeReleaseGuardedMutex(&ObpDeviceMapLock); 308 309 /* If we had a device map, dereference it */ 310 if (OldDeviceMap != NULL) 311 { 312 ObfDereferenceDeviceMap(OldDeviceMap); 313 } 314 315 done: 316 /* We're done with the token! */ 317 ObDereferenceObject(Token); 318 319 return Status; 320 } 321 322 323 PDEVICE_MAP 324 NTAPI 325 ObpReferenceDeviceMap(VOID) 326 { 327 LUID LogonId; 328 NTSTATUS Status; 329 PTOKEN Token = NULL; 330 PDEVICE_MAP DeviceMap; 331 PETHREAD CurrentThread; 332 BOOLEAN LookingForSystem; 333 LUID SystemLuid = SYSTEM_LUID; 334 BOOLEAN CopyOnOpen, EffectiveOnly; 335 SECURITY_IMPERSONATION_LEVEL ImpersonationLevel; 336 337 LookingForSystem = FALSE; 338 339 /* If LUID mapping is enable, try to get appropriate device map */ 340 if (ObpLUIDDeviceMapsEnabled != 0) 341 { 342 /* In case of impersonation, we've got a bit of work to do */ 343 CurrentThread = PsGetCurrentThread(); 344 if (CurrentThread->ActiveImpersonationInfo) 345 { 346 /* Get impersonation token */ 347 Token = PsReferenceImpersonationToken(CurrentThread, 348 &CopyOnOpen, 349 &EffectiveOnly, 350 &ImpersonationLevel); 351 /* Get logon LUID */ 352 if (Token != NULL) 353 { 354 Status = SeQueryAuthenticationIdToken(Token, &LogonId); 355 } 356 else 357 { 358 /* Force failure */ 359 Status = STATUS_NO_TOKEN; 360 } 361 362 /* If we got logon LUID */ 363 if (NT_SUCCESS(Status)) 364 { 365 /* 366 * Check it's not system, system is easy to handle, 367 * we just need to return ObSystemDeviceMap 368 */ 369 if (!RtlEqualLuid(&LogonId, &SystemLuid)) 370 { 371 /* Ask Se for the device map */ 372 Status = SeGetLogonIdDeviceMap(&LogonId, &DeviceMap); 373 if (NT_SUCCESS(Status)) 374 { 375 /* Acquire the device map lock */ 376 KeAcquireGuardedMutex(&ObpDeviceMapLock); 377 378 /* Reference the device map if any */ 379 if (DeviceMap != NULL) 380 { 381 ++DeviceMap->ReferenceCount; 382 } 383 384 /* Release the device map lock */ 385 KeReleaseGuardedMutex(&ObpDeviceMapLock); 386 387 /* If we got the device map, we're done! */ 388 if (DeviceMap != NULL) 389 { 390 ObDereferenceObject(Token); 391 392 return DeviceMap; 393 } 394 } 395 } 396 else 397 { 398 LookingForSystem = TRUE; 399 } 400 } 401 } 402 403 /* 404 * Fall back case of the LUID mapping, make sure there's a 405 * a device map attached to the current process 406 */ 407 if (PsGetCurrentProcess()->DeviceMap == NULL && 408 !NT_SUCCESS(ObpSetCurrentProcessDeviceMap())) 409 { 410 /* We may have failed after we got impersonation token */ 411 if (Token != NULL) 412 { 413 ObDereferenceObject(Token); 414 } 415 416 return NULL; 417 } 418 } 419 420 /* Acquire the device map lock */ 421 KeAcquireGuardedMutex(&ObpDeviceMapLock); 422 423 /* If we're looking for system map, use it */ 424 if (LookingForSystem) 425 { 426 DeviceMap = ObSystemDeviceMap; 427 } 428 /* Otherwise, use current process device map */ 429 else 430 { 431 DeviceMap = PsGetCurrentProcess()->DeviceMap; 432 } 433 434 /* If we got one, reference it */ 435 if (DeviceMap != NULL) 436 { 437 ++DeviceMap->ReferenceCount; 438 } 439 440 /* Release the device map lock */ 441 KeReleaseGuardedMutex(&ObpDeviceMapLock); 442 443 /* We may have impersonation token (if we failed in impersonation branch) */ 444 if (Token != NULL) 445 { 446 ObDereferenceObject(Token); 447 } 448 449 /* Return the potentially found device map */ 450 return DeviceMap; 451 } 452 453 454 VOID 455 NTAPI 456 ObDereferenceDeviceMap(IN PEPROCESS Process) 457 { 458 PDEVICE_MAP DeviceMap; 459 460 DPRINT("ObDereferenceDeviceMap()\n"); 461 462 /* Get the pointer to this process devicemap and reset it 463 holding the device map lock */ 464 KeAcquireGuardedMutex(&ObpDeviceMapLock); 465 DeviceMap = Process->DeviceMap; 466 Process->DeviceMap = NULL; 467 KeReleaseGuardedMutex(&ObpDeviceMapLock); 468 469 /* Continue only if there is a device map */ 470 if (DeviceMap != NULL) 471 ObfDereferenceDeviceMap(DeviceMap); 472 } 473 474 475 VOID 476 FASTCALL 477 ObfDereferenceDeviceMap(IN PDEVICE_MAP DeviceMap) 478 { 479 DPRINT("ObfDereferenceDeviceMap()\n"); 480 481 /* Acquire the device map lock */ 482 KeAcquireGuardedMutex(&ObpDeviceMapLock); 483 484 /* Decrement the reference counter */ 485 DeviceMap->ReferenceCount--; 486 DPRINT("ReferenceCount: %lu\n", DeviceMap->ReferenceCount); 487 488 /* Leave, if there are still references to this device map */ 489 if (DeviceMap->ReferenceCount != 0) 490 { 491 /* Release the device map lock and leave */ 492 KeReleaseGuardedMutex(&ObpDeviceMapLock); 493 return; 494 } 495 496 /* Nobody is referencing it anymore, unlink the DOS directory */ 497 DeviceMap->DosDevicesDirectory->DeviceMap = NULL; 498 499 /* Release the devicemap lock */ 500 KeReleaseGuardedMutex(&ObpDeviceMapLock); 501 502 /* Dereference the DOS Devices Directory and free the Device Map */ 503 ObMakeTemporaryObject(DeviceMap->DosDevicesDirectory); 504 ObDereferenceObject(DeviceMap->DosDevicesDirectory); 505 ExFreePoolWithTag(DeviceMap, 'mDbO'); 506 } 507 508 509 VOID 510 NTAPI 511 ObInheritDeviceMap(IN PEPROCESS Parent, 512 IN PEPROCESS Process) 513 { 514 PDEVICE_MAP DeviceMap; 515 516 DPRINT("ObInheritDeviceMap()\n"); 517 518 /* Acquire the device map lock */ 519 KeAcquireGuardedMutex(&ObpDeviceMapLock); 520 521 /* Get the parent process device map or the system device map */ 522 DeviceMap = (Parent != NULL) ? Parent->DeviceMap : ObSystemDeviceMap; 523 if (DeviceMap != NULL) 524 { 525 /* Reference the device map and attach it to the new process */ 526 DeviceMap->ReferenceCount++; 527 DPRINT("ReferenceCount: %lu\n", DeviceMap->ReferenceCount); 528 529 Process->DeviceMap = DeviceMap; 530 } 531 532 /* Release the device map lock */ 533 KeReleaseGuardedMutex(&ObpDeviceMapLock); 534 } 535 536 537 NTSTATUS 538 NTAPI 539 ObQueryDeviceMapInformation( 540 _In_opt_ PEPROCESS Process, 541 _Out_ PPROCESS_DEVICEMAP_INFORMATION DeviceMapInfo, 542 _In_ ULONG Flags) 543 { 544 PDEVICE_MAP DeviceMap = NULL, GlobalDeviceMap; 545 BOOLEAN Dereference; 546 PROCESS_DEVICEMAP_INFORMATION MapInfo; 547 ULONG BitMask, i; 548 BOOLEAN ReturnAny; 549 NTSTATUS Status; 550 551 /* Validate flags */ 552 if (Flags & ~PROCESS_LUID_DOSDEVICES_ONLY) 553 { 554 return STATUS_INVALID_PARAMETER; 555 } 556 557 Dereference = FALSE; 558 /* Do we want to return anything? */ 559 ReturnAny = ~Flags & PROCESS_LUID_DOSDEVICES_ONLY; 560 561 /* If LUID mappings are enabled... */ 562 if (ObpLUIDDeviceMapsEnabled != 0) 563 { 564 /* Check for process parameter validness */ 565 if (Process != NULL && Process != PsGetCurrentProcess()) 566 { 567 return STATUS_INVALID_PARAMETER; 568 } 569 570 /* And get the device map */ 571 DeviceMap = ObpReferenceDeviceMap(); 572 } 573 574 /* Acquire the device map lock */ 575 KeAcquireGuardedMutex(&ObpDeviceMapLock); 576 577 /* 578 * If we had a device map, if because of LUID mappings, 579 * we'll have to dereference it afterwards 580 */ 581 if (DeviceMap != NULL) 582 { 583 Dereference = TRUE; 584 } 585 else 586 { 587 /* Get the process device map or the system device map */ 588 DeviceMap = (Process != NULL) ? Process->DeviceMap : ObSystemDeviceMap; 589 } 590 591 /* Fail if no device map */ 592 if (DeviceMap == NULL) 593 { 594 KeReleaseGuardedMutex(&ObpDeviceMapLock); 595 return STATUS_END_OF_FILE; 596 } 597 598 /* At that point, assume success */ 599 Status = STATUS_SUCCESS; 600 601 /* Try to get the global device map if any */ 602 GlobalDeviceMap = DeviceMap; 603 if (DeviceMap->GlobalDosDevicesDirectory != NULL) 604 { 605 if (DeviceMap->GlobalDosDevicesDirectory->DeviceMap != NULL) 606 { 607 GlobalDeviceMap = DeviceMap->GlobalDosDevicesDirectory->DeviceMap; 608 } 609 } 610 611 /* Now, setup our device map info, especially drive types */ 612 MapInfo.Query.DriveMap = DeviceMap->DriveMap; 613 /* Browse every device */ 614 for (i = 0, BitMask = 1; i < 32; ++i, BitMask *= 2) 615 { 616 /* Set the type given current device map */ 617 MapInfo.Query.DriveType[i] = DeviceMap->DriveType[i]; 618 619 /* 620 * If device is not existing and we're asked to return 621 * more than just LUID mapped, get the entry 622 * from global device map if not remote 623 */ 624 if (!(MapInfo.Query.DriveMap & BitMask) && ReturnAny) 625 { 626 if (ObpLUIDDeviceMapsEnabled != 0 || 627 (GlobalDeviceMap->DriveType[i] != DOSDEVICE_DRIVE_REMOTE && 628 GlobalDeviceMap->DriveType[i] != DOSDEVICE_DRIVE_CALCULATE)) 629 { 630 MapInfo.Query.DriveType[i] = GlobalDeviceMap->DriveType[i]; 631 MapInfo.Query.DriveMap |= BitMask & GlobalDeviceMap->DriveMap; 632 } 633 } 634 } 635 636 /* Release the device map lock */ 637 KeReleaseGuardedMutex(&ObpDeviceMapLock); 638 639 /* Dereference LUID device map */ 640 if (Dereference) 641 { 642 ObfDereferenceDeviceMap(DeviceMap); 643 } 644 645 /* Copy back data */ 646 _SEH2_TRY 647 { 648 RtlCopyMemory(DeviceMapInfo, &MapInfo, sizeof(PROCESS_DEVICEMAP_INFORMATION)); 649 } 650 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 651 { 652 Status = _SEH2_GetExceptionCode(); 653 } 654 _SEH2_END; 655 656 return Status; 657 } 658 659 660 ULONG 661 NTAPI 662 ObIsLUIDDeviceMapsEnabled(VOID) 663 { 664 return ObpLUIDDeviceMapsEnabled; 665 } 666 667 668 #if 0 669 NTSTATUS 670 NTAPI 671 ObIsDosDeviceLocallyMapped( 672 IN ULONG Index, 673 OUT PUCHAR DosDeviceState) 674 { 675 /* Check the index */ 676 if (Index < 1 || Index > 26) 677 return STATUS_INVALID_PARAMETER; 678 679 /* Acquire the device map lock */ 680 KeAcquireGuardedMutex(&ObpDeviceMapLock); 681 682 /* Get drive mapping status */ 683 *DosDeviceState = (ObSystemDeviceMap->DriveMap & (1 << Index)) != 0; 684 685 /* Release the device map lock */ 686 KeReleaseGuardedMutex(&ObpDeviceMapLock); 687 688 return STATUS_SUCCESS; 689 } 690 #endif 691 692 /* EOF */ 693