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(IN PEPROCESS Process, 540 IN PPROCESS_DEVICEMAP_INFORMATION DeviceMapInfo, 541 IN ULONG Flags) 542 { 543 PDEVICE_MAP DeviceMap = NULL, GlobalDeviceMap; 544 BOOLEAN Dereference; 545 PROCESS_DEVICEMAP_INFORMATION MapInfo; 546 ULONG BitMask, i; 547 BOOLEAN ReturnAny; 548 NTSTATUS Status; 549 550 /* Validate flags */ 551 if (Flags & ~PROCESS_LUID_DOSDEVICES_ONLY) 552 { 553 return STATUS_INVALID_PARAMETER; 554 } 555 556 Dereference = FALSE; 557 /* Do we want to return anything? */ 558 ReturnAny = ~Flags & PROCESS_LUID_DOSDEVICES_ONLY; 559 560 /* If LUID mappings are enabled... */ 561 if (ObpLUIDDeviceMapsEnabled != 0) 562 { 563 /* Check for process parameter validness */ 564 if (Process != NULL && Process != PsGetCurrentProcess()) 565 { 566 return STATUS_INVALID_PARAMETER; 567 } 568 569 /* And get the device map */ 570 DeviceMap = ObpReferenceDeviceMap(); 571 } 572 573 /* Acquire the device map lock */ 574 KeAcquireGuardedMutex(&ObpDeviceMapLock); 575 576 /* 577 * If we had a device map, if because of LUID mappings, 578 * we'll have to dereference it afterwards 579 */ 580 if (DeviceMap != NULL) 581 { 582 Dereference = TRUE; 583 } 584 else 585 { 586 /* Get the process device map or the system device map */ 587 DeviceMap = (Process != NULL) ? Process->DeviceMap : ObSystemDeviceMap; 588 } 589 590 /* Fail if no device map */ 591 if (DeviceMap == NULL) 592 { 593 KeReleaseGuardedMutex(&ObpDeviceMapLock); 594 return STATUS_END_OF_FILE; 595 } 596 597 /* At that point, assume success */ 598 Status = STATUS_SUCCESS; 599 600 /* Try to get the global device map if any */ 601 GlobalDeviceMap = DeviceMap; 602 if (DeviceMap->GlobalDosDevicesDirectory != NULL) 603 { 604 if (DeviceMap->GlobalDosDevicesDirectory->DeviceMap != NULL) 605 { 606 GlobalDeviceMap = DeviceMap->GlobalDosDevicesDirectory->DeviceMap; 607 } 608 } 609 610 /* Now, setup our device map info, especially drive types */ 611 MapInfo.Query.DriveMap = DeviceMap->DriveMap; 612 /* Browse every device */ 613 for (i = 0, BitMask = 1; i < 32; ++i, BitMask *= 2) 614 { 615 /* Set the type given current device map */ 616 MapInfo.Query.DriveType[i] = DeviceMap->DriveType[i]; 617 618 /* 619 * If device is not existing and we're asked to return 620 * more than just LUID mapped, get the entry 621 * from global device map if not remote 622 */ 623 if (!(MapInfo.Query.DriveMap & BitMask) && ReturnAny) 624 { 625 if (ObpLUIDDeviceMapsEnabled != 0 || 626 (GlobalDeviceMap->DriveType[i] != DOSDEVICE_DRIVE_REMOTE && 627 GlobalDeviceMap->DriveType[i] != DOSDEVICE_DRIVE_CALCULATE)) 628 { 629 MapInfo.Query.DriveType[i] = GlobalDeviceMap->DriveType[i]; 630 MapInfo.Query.DriveMap |= BitMask & GlobalDeviceMap->DriveMap; 631 } 632 } 633 } 634 635 /* Release the device map lock */ 636 KeReleaseGuardedMutex(&ObpDeviceMapLock); 637 638 /* Dereference LUID device map */ 639 if (Dereference) 640 { 641 ObfDereferenceDeviceMap(DeviceMap); 642 } 643 644 /* Copy back data */ 645 _SEH2_TRY 646 { 647 RtlCopyMemory(DeviceMapInfo, &MapInfo, sizeof(PROCESS_DEVICEMAP_INFORMATION)); 648 } 649 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 650 { 651 Status = _SEH2_GetExceptionCode(); 652 } 653 _SEH2_END; 654 655 return Status; 656 } 657 658 659 ULONG 660 NTAPI 661 ObIsLUIDDeviceMapsEnabled(VOID) 662 { 663 return ObpLUIDDeviceMapsEnabled; 664 } 665 666 667 #if 0 668 NTSTATUS 669 NTAPI 670 ObIsDosDeviceLocallyMapped( 671 IN ULONG Index, 672 OUT PUCHAR DosDeviceState) 673 { 674 /* Check the index */ 675 if (Index < 1 || Index > 26) 676 return STATUS_INVALID_PARAMETER; 677 678 /* Acquire the device map lock */ 679 KeAcquireGuardedMutex(&ObpDeviceMapLock); 680 681 /* Get drive mapping status */ 682 *DosDeviceState = (ObSystemDeviceMap->DriveMap & (1 << Index)) != 0; 683 684 /* Release the device map lock */ 685 KeReleaseGuardedMutex(&ObpDeviceMapLock); 686 687 return STATUS_SUCCESS; 688 } 689 #endif 690 691 /* EOF */ 692