1 /* 2 * COPYRIGHT: See COPYING in the top level directory 3 * PROJECT: ReactOS kernel 4 * FILE: ntoskrnl/se/srm.c 5 * PURPOSE: Security Reference Monitor Server 6 * 7 * PROGRAMMERS: Timo Kreuzer (timo.kreuzer@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 extern LUID SeSystemAuthenticationId; 18 extern LUID SeAnonymousAuthenticationId; 19 20 /* PRIVATE DEFINITIONS ********************************************************/ 21 22 #define SEP_LOGON_SESSION_TAG 'sLeS' 23 #define SEP_LOGON_NOTIFICATION_TAG 'nLeS' 24 25 typedef struct _SEP_LOGON_SESSION_REFERENCES 26 { 27 struct _SEP_LOGON_SESSION_REFERENCES *Next; 28 LUID LogonId; 29 ULONG ReferenceCount; 30 ULONG Flags; 31 PDEVICE_MAP pDeviceMap; 32 LIST_ENTRY TokenList; 33 } SEP_LOGON_SESSION_REFERENCES, *PSEP_LOGON_SESSION_REFERENCES; 34 35 typedef struct _SEP_LOGON_SESSION_TERMINATED_NOTIFICATION 36 { 37 struct _SEP_LOGON_SESSION_TERMINATED_NOTIFICATION *Next; 38 PSE_LOGON_SESSION_TERMINATED_ROUTINE CallbackRoutine; 39 } SEP_LOGON_SESSION_TERMINATED_NOTIFICATION, *PSEP_LOGON_SESSION_TERMINATED_NOTIFICATION; 40 41 VOID 42 NTAPI 43 SepRmCommandServerThread( 44 PVOID StartContext); 45 46 static 47 NTSTATUS 48 SepRmCreateLogonSession( 49 PLUID LogonLuid); 50 51 52 /* GLOBALS ********************************************************************/ 53 54 HANDLE SeRmCommandPort; 55 HANDLE SeLsaInitEvent; 56 57 PVOID SepCommandPortViewBase; 58 PVOID SepCommandPortViewRemoteBase; 59 ULONG_PTR SepCommandPortViewBaseOffset; 60 61 static HANDLE SepRmCommandMessagePort; 62 63 BOOLEAN SepAdtAuditingEnabled; 64 ULONG SepAdtMinListLength = 0x2000; 65 ULONG SepAdtMaxListLength = 0x3000; 66 67 #define POLICY_AUDIT_EVENT_TYPE_COUNT 9 // (AuditCategoryAccountLogon - AuditCategorySystem + 1) 68 UCHAR SeAuditingState[POLICY_AUDIT_EVENT_TYPE_COUNT]; 69 70 KGUARDED_MUTEX SepRmDbLock; 71 PSEP_LOGON_SESSION_REFERENCES SepLogonSessions = NULL; 72 PSEP_LOGON_SESSION_TERMINATED_NOTIFICATION SepLogonNotifications = NULL; 73 74 75 /* PRIVATE FUNCTIONS **********************************************************/ 76 77 NTSTATUS 78 NTAPI 79 SepRegQueryHelper( 80 PCWSTR KeyName, 81 PCWSTR ValueName, 82 ULONG ValueType, 83 ULONG DataLength, 84 PVOID ValueData) 85 { 86 UNICODE_STRING ValueNameString; 87 UNICODE_STRING KeyNameString; 88 ULONG ResultLength; 89 OBJECT_ATTRIBUTES ObjectAttributes; 90 HANDLE KeyHandle = NULL; 91 struct 92 { 93 KEY_VALUE_PARTIAL_INFORMATION Partial; 94 UCHAR Buffer[64]; 95 } KeyValueInformation; 96 NTSTATUS Status, CloseStatus; 97 PAGED_CODE(); 98 99 RtlInitUnicodeString(&KeyNameString, KeyName); 100 InitializeObjectAttributes(&ObjectAttributes, 101 &KeyNameString, 102 OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, 103 NULL, 104 NULL); 105 106 Status = ZwOpenKey(&KeyHandle, KEY_QUERY_VALUE, &ObjectAttributes); 107 if (!NT_SUCCESS(Status)) 108 { 109 return Status; 110 } 111 112 RtlInitUnicodeString(&ValueNameString, ValueName); 113 Status = ZwQueryValueKey(KeyHandle, 114 &ValueNameString, 115 KeyValuePartialInformation, 116 &KeyValueInformation.Partial, 117 sizeof(KeyValueInformation), 118 &ResultLength); 119 if (!NT_SUCCESS(Status)) 120 { 121 goto Cleanup; 122 } 123 124 if ((KeyValueInformation.Partial.Type != ValueType) || 125 (KeyValueInformation.Partial.DataLength != DataLength)) 126 { 127 Status = STATUS_OBJECT_TYPE_MISMATCH; 128 goto Cleanup; 129 } 130 131 132 if (ValueType == REG_BINARY) 133 { 134 RtlCopyMemory(ValueData, KeyValueInformation.Partial.Data, DataLength); 135 } 136 else if (ValueType == REG_DWORD) 137 { 138 *(PULONG)ValueData = *(PULONG)KeyValueInformation.Partial.Data; 139 } 140 else 141 { 142 Status = STATUS_INVALID_PARAMETER; 143 } 144 145 Cleanup: 146 CloseStatus = ZwClose(KeyHandle); 147 ASSERT(NT_SUCCESS( CloseStatus )); 148 149 return Status; 150 } 151 152 153 BOOLEAN 154 NTAPI 155 SeRmInitPhase0(VOID) 156 { 157 NTSTATUS Status; 158 159 /* Initialize the database lock */ 160 KeInitializeGuardedMutex(&SepRmDbLock); 161 162 /* Create the system logon session */ 163 Status = SepRmCreateLogonSession(&SeSystemAuthenticationId); 164 if (!NT_VERIFY(NT_SUCCESS(Status))) 165 { 166 return FALSE; 167 } 168 169 /* Create the anonymous logon session */ 170 Status = SepRmCreateLogonSession(&SeAnonymousAuthenticationId); 171 if (!NT_VERIFY(NT_SUCCESS(Status))) 172 { 173 return FALSE; 174 } 175 176 return TRUE; 177 } 178 179 180 BOOLEAN 181 NTAPI 182 SeRmInitPhase1(VOID) 183 { 184 UNICODE_STRING Name; 185 OBJECT_ATTRIBUTES ObjectAttributes; 186 HANDLE ThreadHandle; 187 NTSTATUS Status; 188 189 /* Create the SeRm command port */ 190 RtlInitUnicodeString(&Name, L"\\SeRmCommandPort"); 191 InitializeObjectAttributes(&ObjectAttributes, &Name, 0, NULL, NULL); 192 Status = ZwCreatePort(&SeRmCommandPort, 193 &ObjectAttributes, 194 sizeof(ULONG), 195 PORT_MAXIMUM_MESSAGE_LENGTH, 196 2 * PAGE_SIZE); 197 if (!NT_SUCCESS(Status)) 198 { 199 DPRINT1("Security: Rm Create Command Port failed 0x%lx\n", Status); 200 return FALSE; 201 } 202 203 /* Create SeLsaInitEvent */ 204 RtlInitUnicodeString(&Name, L"\\SeLsaInitEvent"); 205 InitializeObjectAttributes(&ObjectAttributes, &Name, 0, NULL, NULL); 206 Status = ZwCreateEvent(&SeLsaInitEvent, 207 GENERIC_WRITE, 208 &ObjectAttributes, 209 NotificationEvent, 210 FALSE); 211 if (!NT_VERIFY((NT_SUCCESS(Status)))) 212 { 213 DPRINT1("Security: LSA init event creation failed.0x%xl\n", Status); 214 return FALSE; 215 } 216 217 /* Create the SeRm server thread */ 218 Status = PsCreateSystemThread(&ThreadHandle, 219 THREAD_ALL_ACCESS, 220 NULL, 221 NULL, 222 NULL, 223 SepRmCommandServerThread, 224 NULL); 225 if (!NT_SUCCESS(Status)) 226 { 227 DPRINT1("Security: Rm Server Thread creation failed 0x%lx\n", Status); 228 return FALSE; 229 } 230 231 ObCloseHandle(ThreadHandle, KernelMode); 232 233 return TRUE; 234 } 235 236 static 237 VOID 238 SepAdtInitializeBounds(VOID) 239 { 240 struct 241 { 242 ULONG MaxLength; 243 ULONG MinLength; 244 } ListBounds; 245 NTSTATUS Status; 246 PAGED_CODE(); 247 248 Status = SepRegQueryHelper(L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Lsa", 249 L"Bounds", 250 REG_BINARY, 251 sizeof(ListBounds), 252 &ListBounds); 253 if (!NT_SUCCESS(Status)) 254 { 255 /* No registry values, so keep hardcoded defaults */ 256 return; 257 } 258 259 /* Check if the bounds are valid */ 260 if ((ListBounds.MaxLength < ListBounds.MinLength) || 261 (ListBounds.MinLength < 16) || 262 (ListBounds.MaxLength - ListBounds.MinLength < 16)) 263 { 264 DPRINT1("ListBounds are invalid: %u, %u\n", 265 ListBounds.MinLength, ListBounds.MaxLength); 266 return; 267 } 268 269 /* Set the new bounds globally */ 270 SepAdtMinListLength = ListBounds.MinLength; 271 SepAdtMaxListLength = ListBounds.MaxLength; 272 } 273 274 275 static 276 NTSTATUS 277 SepRmSetAuditEvent( 278 PSEP_RM_API_MESSAGE Message) 279 { 280 ULONG i; 281 PAGED_CODE(); 282 283 /* First re-initialize the bounds from the registry */ 284 SepAdtInitializeBounds(); 285 286 /* Make sure we have the right message and clear */ 287 ASSERT(Message->ApiNumber == RmAuditSetCommand); 288 Message->ApiNumber = 0; 289 290 /* Store the enable flag in the global variable */ 291 SepAdtAuditingEnabled = Message->u.SetAuditEvent.Enabled; 292 293 /* Loop all audit event types */ 294 for (i = 0; i < POLICY_AUDIT_EVENT_TYPE_COUNT; i++) 295 { 296 /* Save the provided flags in the global array */ 297 SeAuditingState[i] = (UCHAR)Message->u.SetAuditEvent.Flags[i]; 298 } 299 300 return STATUS_SUCCESS; 301 } 302 303 304 static 305 NTSTATUS 306 SepRmCreateLogonSession( 307 PLUID LogonLuid) 308 { 309 PSEP_LOGON_SESSION_REFERENCES CurrentSession, NewSession; 310 NTSTATUS Status; 311 PAGED_CODE(); 312 313 DPRINT("SepRmCreateLogonSession(%08lx:%08lx)\n", 314 LogonLuid->HighPart, LogonLuid->LowPart); 315 316 /* Allocate a new session structure */ 317 NewSession = ExAllocatePoolWithTag(PagedPool, 318 sizeof(SEP_LOGON_SESSION_REFERENCES), 319 SEP_LOGON_SESSION_TAG); 320 if (NewSession == NULL) 321 { 322 return STATUS_INSUFFICIENT_RESOURCES; 323 } 324 325 /* Initialize it */ 326 NewSession->LogonId = *LogonLuid; 327 NewSession->ReferenceCount = 0; 328 NewSession->Flags = 0; 329 NewSession->pDeviceMap = NULL; 330 InitializeListHead(&NewSession->TokenList); 331 332 /* Acquire the database lock */ 333 KeAcquireGuardedMutex(&SepRmDbLock); 334 335 /* Loop all existing sessions */ 336 for (CurrentSession = SepLogonSessions; 337 CurrentSession != NULL; 338 CurrentSession = CurrentSession->Next) 339 { 340 /* Check if the LUID matches the new one */ 341 if (RtlEqualLuid(&CurrentSession->LogonId, LogonLuid)) 342 { 343 Status = STATUS_LOGON_SESSION_EXISTS; 344 goto Leave; 345 } 346 } 347 348 /* Insert the new session */ 349 NewSession->Next = SepLogonSessions; 350 SepLogonSessions = NewSession; 351 352 Status = STATUS_SUCCESS; 353 354 Leave: 355 /* Release the database lock */ 356 KeReleaseGuardedMutex(&SepRmDbLock); 357 358 if (!NT_SUCCESS(Status)) 359 { 360 ExFreePoolWithTag(NewSession, SEP_LOGON_SESSION_TAG); 361 } 362 363 return Status; 364 } 365 366 static 367 NTSTATUS 368 SepRmDeleteLogonSession( 369 PLUID LogonLuid) 370 { 371 DPRINT("SepRmDeleteLogonSession(%08lx:%08lx)\n", 372 LogonLuid->HighPart, LogonLuid->LowPart); 373 374 UNIMPLEMENTED; 375 NT_ASSERT(FALSE); 376 return STATUS_NOT_IMPLEMENTED; 377 } 378 379 380 NTSTATUS 381 SepRmReferenceLogonSession( 382 PLUID LogonLuid) 383 { 384 PSEP_LOGON_SESSION_REFERENCES CurrentSession; 385 386 PAGED_CODE(); 387 388 DPRINT("SepRmReferenceLogonSession(%08lx:%08lx)\n", 389 LogonLuid->HighPart, LogonLuid->LowPart); 390 391 /* Acquire the database lock */ 392 KeAcquireGuardedMutex(&SepRmDbLock); 393 394 /* Loop all existing sessions */ 395 for (CurrentSession = SepLogonSessions; 396 CurrentSession != NULL; 397 CurrentSession = CurrentSession->Next) 398 { 399 /* Check if the LUID matches the new one */ 400 if (RtlEqualLuid(&CurrentSession->LogonId, LogonLuid)) 401 { 402 /* Reference the session */ 403 ++CurrentSession->ReferenceCount; 404 DPRINT("ReferenceCount: %lu\n", CurrentSession->ReferenceCount); 405 406 /* Release the database lock */ 407 KeReleaseGuardedMutex(&SepRmDbLock); 408 409 return STATUS_SUCCESS; 410 } 411 } 412 413 /* Release the database lock */ 414 KeReleaseGuardedMutex(&SepRmDbLock); 415 416 return STATUS_NO_SUCH_LOGON_SESSION; 417 } 418 419 420 NTSTATUS 421 SepCleanupLUIDDeviceMapDirectory( 422 PLUID LogonLuid) 423 { 424 BOOLEAN UseCurrentProc; 425 KAPC_STATE ApcState; 426 WCHAR Buffer[63]; 427 UNICODE_STRING DirectoryName; 428 OBJECT_ATTRIBUTES ObjectAttributes; 429 NTSTATUS Status; 430 HANDLE DirectoryHandle, LinkHandle; 431 PHANDLE LinksBuffer; 432 POBJECT_DIRECTORY_INFORMATION DirectoryInfo; 433 ULONG LinksCount, LinksSize, DirInfoLength, ReturnLength, Context, CurrentLinks, i; 434 BOOLEAN RestartScan; 435 436 PAGED_CODE(); 437 438 /* We need a logon LUID */ 439 if (LogonLuid == NULL) 440 { 441 return STATUS_INVALID_PARAMETER; 442 } 443 444 /* Use current process */ 445 UseCurrentProc = ObReferenceObjectSafe(PsGetCurrentProcess()); 446 if (UseCurrentProc) 447 { 448 ObDereferenceObject(PsGetCurrentProcess()); 449 } 450 /* Unless it's gone, then use system process */ 451 else 452 { 453 KeStackAttachProcess(&PsInitialSystemProcess->Pcb, &ApcState); 454 } 455 456 /* Initialize our directory name */ 457 _snwprintf(Buffer, 458 sizeof(Buffer) / sizeof(WCHAR), 459 L"\\Sessions\\0\\DosDevices\\%08x-%08x", 460 LogonLuid->HighPart, 461 LogonLuid->LowPart); 462 RtlInitUnicodeString(&DirectoryName, Buffer); 463 464 /* And open it */ 465 InitializeObjectAttributes(&ObjectAttributes, 466 &DirectoryName, 467 OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, 468 NULL, 469 NULL); 470 Status = ZwOpenDirectoryObject(&DirectoryHandle, 471 DIRECTORY_QUERY, 472 &ObjectAttributes); 473 if (!NT_SUCCESS(Status)) 474 { 475 if (!UseCurrentProc) 476 { 477 KeUnstackDetachProcess(&ApcState); 478 } 479 480 return Status; 481 } 482 483 /* Some initialization needed for browsing all our links... */ 484 Context = 0; 485 DirectoryInfo = NULL; 486 DirInfoLength = 0; 487 /* In our buffer, we'll store at max 100 HANDLE */ 488 LinksCount = 100; 489 CurrentLinks = 0; 490 /* Which gives a certain size */ 491 LinksSize = LinksCount * sizeof(HANDLE); 492 493 /* 494 * This label is hit if we need to store more than a hundred 495 * of links. In that case, we jump here after having cleaned 496 * and deleted previous buffer. 497 * All handles have been already closed 498 */ 499 AllocateLinksAgain: 500 LinksBuffer = ExAllocatePoolWithTag(PagedPool, 501 LinksSize, 502 TAG_SE_HANDLES_TAB); 503 if (LinksBuffer == NULL) 504 { 505 /* 506 * Failure path: no need to clear handles: 507 * already closed and the buffer is already gone 508 */ 509 ZwClose(DirectoryHandle); 510 511 /* 512 * On the first round, DirectoryInfo is NULL, 513 * if we grow LinksBuffer, it has been allocated 514 */ 515 if (DirectoryInfo != NULL) 516 { 517 ExFreePoolWithTag(DirectoryInfo, TAG_SE_DIR_BUFFER); 518 } 519 520 if (!UseCurrentProc) 521 { 522 KeUnstackDetachProcess(&ApcState); 523 } 524 525 return STATUS_NO_MEMORY; 526 } 527 528 /* 529 * We always restart scan, but on the first loop 530 * if we couldn't fit everything in our buffer, 531 * then, we continue scan. 532 * But we restart if link buffer was too small 533 */ 534 for (RestartScan = TRUE; ; RestartScan = FALSE) 535 { 536 /* 537 * Loop until our buffer is big enough to store 538 * one entry 539 */ 540 while (TRUE) 541 { 542 Status = ZwQueryDirectoryObject(DirectoryHandle, 543 DirectoryInfo, 544 DirInfoLength, 545 TRUE, 546 RestartScan, 547 &Context, 548 &ReturnLength); 549 /* Only handle buffer growth in that loop */ 550 if (Status != STATUS_BUFFER_TOO_SMALL) 551 { 552 break; 553 } 554 555 /* Get output length as new length */ 556 DirInfoLength = ReturnLength; 557 /* Delete old buffer if any */ 558 if (DirectoryInfo != NULL) 559 { 560 ExFreePoolWithTag(DirectoryInfo, 'bDeS'); 561 } 562 563 /* And reallocate a bigger one */ 564 DirectoryInfo = ExAllocatePoolWithTag(PagedPool, 565 DirInfoLength, 566 TAG_SE_DIR_BUFFER); 567 /* Fail if we cannot allocate */ 568 if (DirectoryInfo == NULL) 569 { 570 Status = STATUS_INSUFFICIENT_RESOURCES; 571 break; 572 } 573 } 574 575 /* If querying the entry failed, quit */ 576 if (!NT_SUCCESS(Status)) 577 { 578 break; 579 } 580 581 /* We only look for symbolic links, the rest, we ignore */ 582 if (wcscmp(DirectoryInfo->TypeName.Buffer, L"SymbolicLink")) 583 { 584 continue; 585 } 586 587 /* If our link buffer is out of space, reallocate */ 588 if (CurrentLinks >= LinksCount) 589 { 590 /* First, close the links */ 591 for (i = 0; i < CurrentLinks; ++i) 592 { 593 ZwClose(LinksBuffer[i]); 594 } 595 596 /* Allow 20 more HANDLEs */ 597 LinksCount += 20; 598 CurrentLinks = 0; 599 ExFreePoolWithTag(LinksBuffer, TAG_SE_HANDLES_TAB); 600 LinksSize = LinksCount * sizeof(HANDLE); 601 602 /* And reloop again */ 603 goto AllocateLinksAgain; 604 } 605 606 /* Open the found link */ 607 InitializeObjectAttributes(&ObjectAttributes, 608 &DirectoryInfo->Name, 609 OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, 610 DirectoryHandle, 611 NULL); 612 if (NT_SUCCESS(ZwOpenSymbolicLinkObject(&LinkHandle, 613 SYMBOLIC_LINK_ALL_ACCESS, 614 &ObjectAttributes))) 615 { 616 /* If we cannot make it temporary, just close the link handle */ 617 if (!NT_SUCCESS(ZwMakeTemporaryObject(LinkHandle))) 618 { 619 ZwClose(LinkHandle); 620 } 621 /* Otherwise, store it to defer deletion */ 622 else 623 { 624 LinksBuffer[CurrentLinks] = LinkHandle; 625 ++CurrentLinks; 626 } 627 } 628 } 629 630 /* No more entries means we handled all links, that's not a failure */ 631 if (Status == STATUS_NO_MORE_ENTRIES) 632 { 633 Status = STATUS_SUCCESS; 634 } 635 636 /* Close all the links we stored, this will like cause their deletion */ 637 for (i = 0; i < CurrentLinks; ++i) 638 { 639 ZwClose(LinksBuffer[i]); 640 } 641 /* And free our links buffer */ 642 ExFreePoolWithTag(LinksBuffer, TAG_SE_HANDLES_TAB); 643 644 /* Free our directory info buffer - it might be NULL if we failed realloc */ 645 if (DirectoryInfo != NULL) 646 { 647 ExFreePoolWithTag(DirectoryInfo, TAG_SE_DIR_BUFFER); 648 } 649 650 /* Close our session directory */ 651 ZwClose(DirectoryHandle); 652 653 /* And detach from system */ 654 if (!UseCurrentProc) 655 { 656 KeUnstackDetachProcess(&ApcState); 657 } 658 659 return Status; 660 } 661 662 663 NTSTATUS 664 SepRmDereferenceLogonSession( 665 PLUID LogonLuid) 666 { 667 ULONG RefCount; 668 PDEVICE_MAP DeviceMap; 669 PSEP_LOGON_SESSION_REFERENCES CurrentSession; 670 671 DPRINT("SepRmDereferenceLogonSession(%08lx:%08lx)\n", 672 LogonLuid->HighPart, LogonLuid->LowPart); 673 674 /* Acquire the database lock */ 675 KeAcquireGuardedMutex(&SepRmDbLock); 676 677 /* Loop all existing sessions */ 678 for (CurrentSession = SepLogonSessions; 679 CurrentSession != NULL; 680 CurrentSession = CurrentSession->Next) 681 { 682 /* Check if the LUID matches the new one */ 683 if (RtlEqualLuid(&CurrentSession->LogonId, LogonLuid)) 684 { 685 /* Dereference the session */ 686 RefCount = --CurrentSession->ReferenceCount; 687 DPRINT("ReferenceCount: %lu\n", CurrentSession->ReferenceCount); 688 689 /* Release the database lock */ 690 KeReleaseGuardedMutex(&SepRmDbLock); 691 692 /* We're done with the session */ 693 if (RefCount == 0) 694 { 695 /* Get rid of the LUID device map */ 696 DeviceMap = CurrentSession->pDeviceMap; 697 if (DeviceMap != NULL) 698 { 699 CurrentSession->pDeviceMap = NULL; 700 SepCleanupLUIDDeviceMapDirectory(LogonLuid); 701 ObfDereferenceDeviceMap(DeviceMap); 702 } 703 } 704 705 return STATUS_SUCCESS; 706 } 707 } 708 709 /* Release the database lock */ 710 KeReleaseGuardedMutex(&SepRmDbLock); 711 712 return STATUS_NO_SUCH_LOGON_SESSION; 713 } 714 715 716 BOOLEAN 717 NTAPI 718 SepRmCommandServerThreadInit(VOID) 719 { 720 SECURITY_QUALITY_OF_SERVICE SecurityQos; 721 SEP_RM_API_MESSAGE Message; 722 UNICODE_STRING PortName; 723 REMOTE_PORT_VIEW RemotePortView; 724 PORT_VIEW PortView; 725 LARGE_INTEGER SectionSize; 726 HANDLE SectionHandle; 727 HANDLE PortHandle; 728 NTSTATUS Status; 729 BOOLEAN Result; 730 731 SectionHandle = NULL; 732 PortHandle = NULL; 733 734 /* Assume success */ 735 Result = TRUE; 736 737 /* Wait until LSASS is ready */ 738 Status = ZwWaitForSingleObject(SeLsaInitEvent, FALSE, NULL); 739 if (!NT_SUCCESS(Status)) 740 { 741 DPRINT1("Security Rm Init: Waiting for LSA Init Event failed 0x%lx\n", Status); 742 goto Cleanup; 743 } 744 745 /* We don't need this event anymore */ 746 ObCloseHandle(SeLsaInitEvent, KernelMode); 747 748 /* Initialize the connection message */ 749 Message.Header.u1.s1.TotalLength = sizeof(Message); 750 Message.Header.u1.s1.DataLength = 0; 751 752 /* Only LSASS can connect, so handle the connection right now */ 753 Status = ZwListenPort(SeRmCommandPort, &Message.Header); 754 if (!NT_SUCCESS(Status)) 755 { 756 DPRINT1("Security Rm Init: Listen to Command Port failed 0x%lx\n", Status); 757 goto Cleanup; 758 } 759 760 /* Set the Port View structure length */ 761 RemotePortView.Length = sizeof(RemotePortView); 762 763 /* Accept the connection */ 764 Status = ZwAcceptConnectPort(&SepRmCommandMessagePort, 765 NULL, 766 &Message.Header, 767 TRUE, 768 NULL, 769 &RemotePortView); 770 if (!NT_SUCCESS(Status)) 771 { 772 DPRINT1("Security Rm Init: Accept Connect to Command Port failed 0x%lx\n", Status); 773 goto Cleanup; 774 } 775 776 /* Complete the connection */ 777 Status = ZwCompleteConnectPort(SepRmCommandMessagePort); 778 if (!NT_SUCCESS(Status)) 779 { 780 DPRINT1("Security Rm Init: Complete Connect to Command Port failed 0x%lx\n", Status); 781 goto Cleanup; 782 } 783 784 /* Create a section for messages */ 785 SectionSize.QuadPart = PAGE_SIZE; 786 Status = ZwCreateSection(&SectionHandle, 787 SECTION_ALL_ACCESS, 788 NULL, 789 &SectionSize, 790 PAGE_READWRITE, 791 SEC_COMMIT, 792 NULL); 793 if (!NT_SUCCESS(Status)) 794 { 795 DPRINT1("Security Rm Init: Create Memory Section for LSA port failed: %X\n", Status); 796 goto Cleanup; 797 } 798 799 /* Setup the PORT_VIEW structure */ 800 PortView.Length = sizeof(PortView); 801 PortView.SectionHandle = SectionHandle; 802 PortView.SectionOffset = 0; 803 PortView.ViewSize = SectionSize.LowPart; 804 PortView.ViewBase = NULL; 805 PortView.ViewRemoteBase = NULL; 806 807 /* Setup security QOS */ 808 SecurityQos.Length = sizeof(SecurityQos); 809 SecurityQos.ImpersonationLevel = SecurityImpersonation; 810 SecurityQos.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING; 811 SecurityQos.EffectiveOnly = TRUE; 812 813 /* Connect to LSASS */ 814 RtlInitUnicodeString(&PortName, L"\\SeLsaCommandPort"); 815 Status = ZwConnectPort(&PortHandle, 816 &PortName, 817 &SecurityQos, 818 &PortView, 819 NULL, 820 0, 821 0, 822 0); 823 if (!NT_SUCCESS(Status)) 824 { 825 DPRINT1("Security Rm Init: Connect to LSA Port failed 0x%lx\n", Status); 826 goto Cleanup; 827 } 828 829 /* Remember section base and view offset */ 830 SepCommandPortViewBase = PortView.ViewBase; 831 SepCommandPortViewRemoteBase = PortView.ViewRemoteBase; 832 SepCommandPortViewBaseOffset = (ULONG_PTR)SepCommandPortViewRemoteBase - 833 (ULONG_PTR)SepCommandPortViewBase; 834 835 DPRINT("SepRmCommandServerThreadInit: done\n"); 836 837 Cleanup: 838 /* Check for failure */ 839 if (!NT_SUCCESS(Status)) 840 { 841 if (PortHandle != NULL) 842 { 843 ObCloseHandle(PortHandle, KernelMode); 844 } 845 846 Result = FALSE; 847 } 848 849 /* Did we create a section? */ 850 if (SectionHandle != NULL) 851 { 852 ObCloseHandle(SectionHandle, KernelMode); 853 } 854 855 return Result; 856 } 857 858 VOID 859 NTAPI 860 SepRmCommandServerThread( 861 PVOID StartContext) 862 { 863 SEP_RM_API_MESSAGE Message; 864 PPORT_MESSAGE ReplyMessage; 865 HANDLE DummyPortHandle; 866 NTSTATUS Status; 867 868 /* Initialize the server thread */ 869 if (!SepRmCommandServerThreadInit()) 870 { 871 DPRINT1("Security: Terminating Rm Command Server Thread\n"); 872 return; 873 } 874 875 /* No reply yet */ 876 ReplyMessage = NULL; 877 878 /* Start looping */ 879 while (TRUE) 880 { 881 /* Wait for a message */ 882 Status = ZwReplyWaitReceivePort(SepRmCommandMessagePort, 883 NULL, 884 ReplyMessage, 885 &Message.Header); 886 if (!NT_SUCCESS(Status)) 887 { 888 DPRINT1("Failed to get message: 0x%lx", Status); 889 ReplyMessage = NULL; 890 continue; 891 } 892 893 /* Check if this is a connection request */ 894 if (Message.Header.u2.s2.Type == LPC_CONNECTION_REQUEST) 895 { 896 /* Reject connection request */ 897 ZwAcceptConnectPort(&DummyPortHandle, 898 NULL, 899 &Message.Header, 900 FALSE, 901 NULL, 902 NULL); 903 904 /* Start over */ 905 ReplyMessage = NULL; 906 continue; 907 } 908 909 /* Check if the port died */ 910 if ((Message.Header.u2.s2.Type == LPC_PORT_CLOSED) || 911 (Message.Header.u2.s2.Type == LPC_CLIENT_DIED)) 912 { 913 /* LSASS is dead, so let's quit as well */ 914 break; 915 } 916 917 /* Check if this is an actual request */ 918 if (Message.Header.u2.s2.Type != LPC_REQUEST) 919 { 920 DPRINT1("SepRmCommandServerThread: unexpected message type: 0x%lx\n", 921 Message.Header.u2.s2.Type); 922 923 /* Restart without replying */ 924 ReplyMessage = NULL; 925 continue; 926 } 927 928 ReplyMessage = &Message.Header; 929 930 switch (Message.ApiNumber) 931 { 932 case RmAuditSetCommand: 933 Status = SepRmSetAuditEvent(&Message); 934 break; 935 936 case RmCreateLogonSession: 937 Status = SepRmCreateLogonSession(&Message.u.LogonLuid); 938 break; 939 940 case RmDeleteLogonSession: 941 Status = SepRmDeleteLogonSession(&Message.u.LogonLuid); 942 break; 943 944 default: 945 DPRINT1("SepRmDispatchRequest: invalid API number: 0x%lx\n", 946 Message.ApiNumber); 947 ReplyMessage = NULL; 948 } 949 950 Message.u.ResultStatus = Status; 951 } 952 953 /* Close the port handles */ 954 ObCloseHandle(SepRmCommandMessagePort, KernelMode); 955 ObCloseHandle(SeRmCommandPort, KernelMode); 956 } 957 958 959 /* PUBLIC FUNCTIONS ***********************************************************/ 960 961 /* 962 * @unimplemented 963 */ 964 NTSTATUS 965 NTAPI 966 SeGetLogonIdDeviceMap( 967 IN PLUID LogonId, 968 OUT PDEVICE_MAP * DeviceMap 969 ) 970 { 971 NTSTATUS Status; 972 WCHAR Buffer[63]; 973 PDEVICE_MAP LocalMap; 974 HANDLE DirectoryHandle, LinkHandle; 975 OBJECT_ATTRIBUTES ObjectAttributes; 976 PSEP_LOGON_SESSION_REFERENCES CurrentSession; 977 UNICODE_STRING DirectoryName, LinkName, TargetName; 978 979 PAGED_CODE(); 980 981 if (LogonId == NULL || 982 DeviceMap == NULL) 983 { 984 return STATUS_INVALID_PARAMETER; 985 } 986 987 /* Acquire the database lock */ 988 KeAcquireGuardedMutex(&SepRmDbLock); 989 990 /* Loop all existing sessions */ 991 for (CurrentSession = SepLogonSessions; 992 CurrentSession != NULL; 993 CurrentSession = CurrentSession->Next) 994 { 995 /* Check if the LUID matches the provided one */ 996 if (RtlEqualLuid(&CurrentSession->LogonId, LogonId)) 997 { 998 break; 999 } 1000 } 1001 1002 /* No session found, fail */ 1003 if (CurrentSession == NULL) 1004 { 1005 /* Release the database lock */ 1006 KeReleaseGuardedMutex(&SepRmDbLock); 1007 1008 return STATUS_NO_SUCH_LOGON_SESSION; 1009 } 1010 1011 /* The found session has a device map, return it! */ 1012 if (CurrentSession->pDeviceMap != NULL) 1013 { 1014 *DeviceMap = CurrentSession->pDeviceMap; 1015 1016 /* Release the database lock */ 1017 KeReleaseGuardedMutex(&SepRmDbLock); 1018 1019 return STATUS_SUCCESS; 1020 } 1021 1022 /* At that point, we'll setup a new device map for the session */ 1023 LocalMap = NULL; 1024 1025 /* Reference the session so that it doesn't go away */ 1026 CurrentSession->ReferenceCount += 1; 1027 1028 /* Release the database lock */ 1029 KeReleaseGuardedMutex(&SepRmDbLock); 1030 1031 /* Create our object directory given the LUID */ 1032 _snwprintf(Buffer, 1033 sizeof(Buffer) / sizeof(WCHAR), 1034 L"\\Sessions\\0\\DosDevices\\%08x-%08x", 1035 LogonId->HighPart, 1036 LogonId->LowPart); 1037 RtlInitUnicodeString(&DirectoryName, Buffer); 1038 1039 InitializeObjectAttributes(&ObjectAttributes, 1040 &DirectoryName, 1041 OBJ_KERNEL_HANDLE | OBJ_OPENIF | OBJ_CASE_INSENSITIVE, 1042 NULL, 1043 NULL); 1044 Status = ZwCreateDirectoryObject(&DirectoryHandle, 1045 DIRECTORY_ALL_ACCESS, 1046 &ObjectAttributes); 1047 if (NT_SUCCESS(Status)) 1048 { 1049 /* Create the associated device map */ 1050 Status = ObSetDirectoryDeviceMap(&LocalMap, DirectoryHandle); 1051 if (NT_SUCCESS(Status)) 1052 { 1053 /* Make Global point to \Global?? in the directory */ 1054 RtlInitUnicodeString(&LinkName, L"Global"); 1055 RtlInitUnicodeString(&TargetName, L"\\Global??"); 1056 1057 InitializeObjectAttributes(&ObjectAttributes, 1058 &LinkName, 1059 OBJ_KERNEL_HANDLE | OBJ_OPENIF | OBJ_CASE_INSENSITIVE | OBJ_PERMANENT, 1060 DirectoryHandle, 1061 NULL); 1062 Status = ZwCreateSymbolicLinkObject(&LinkHandle, 1063 SYMBOLIC_LINK_ALL_ACCESS, 1064 &ObjectAttributes, 1065 &TargetName); 1066 if (!NT_SUCCESS(Status)) 1067 { 1068 ObfDereferenceDeviceMap(LocalMap); 1069 } 1070 else 1071 { 1072 ZwClose(LinkHandle); 1073 } 1074 } 1075 1076 ZwClose(DirectoryHandle); 1077 } 1078 1079 /* Acquire the database lock */ 1080 KeAcquireGuardedMutex(&SepRmDbLock); 1081 1082 /* If we succeed... */ 1083 if (NT_SUCCESS(Status)) 1084 { 1085 /* The session now has a device map? We raced with someone else */ 1086 if (CurrentSession->pDeviceMap != NULL) 1087 { 1088 /* Give up on our new device map */ 1089 ObfDereferenceDeviceMap(LocalMap); 1090 } 1091 /* Otherwise use our newly allocated device map */ 1092 else 1093 { 1094 CurrentSession->pDeviceMap = LocalMap; 1095 } 1096 1097 /* Return the device map */ 1098 *DeviceMap = CurrentSession->pDeviceMap; 1099 } 1100 /* Zero output */ 1101 else 1102 { 1103 *DeviceMap = NULL; 1104 } 1105 1106 /* Release the database lock */ 1107 KeReleaseGuardedMutex(&SepRmDbLock); 1108 1109 /* We're done with the session */ 1110 SepRmDereferenceLogonSession(&CurrentSession->LogonId); 1111 1112 return Status; 1113 } 1114 1115 /* 1116 * @unimplemented 1117 */ 1118 NTSTATUS 1119 NTAPI 1120 SeMarkLogonSessionForTerminationNotification( 1121 IN PLUID LogonId) 1122 { 1123 UNIMPLEMENTED; 1124 return STATUS_NOT_IMPLEMENTED; 1125 } 1126 1127 1128 /* 1129 * @implemented 1130 */ 1131 NTSTATUS 1132 NTAPI 1133 SeRegisterLogonSessionTerminatedRoutine( 1134 IN PSE_LOGON_SESSION_TERMINATED_ROUTINE CallbackRoutine) 1135 { 1136 PSEP_LOGON_SESSION_TERMINATED_NOTIFICATION Notification; 1137 PAGED_CODE(); 1138 1139 /* Fail, if we don not have a callback routine */ 1140 if (CallbackRoutine == NULL) 1141 return STATUS_INVALID_PARAMETER; 1142 1143 /* Allocate a new notification item */ 1144 Notification = ExAllocatePoolWithTag(PagedPool, 1145 sizeof(SEP_LOGON_SESSION_TERMINATED_NOTIFICATION), 1146 SEP_LOGON_NOTIFICATION_TAG); 1147 if (Notification == NULL) 1148 return STATUS_INSUFFICIENT_RESOURCES; 1149 1150 /* Acquire the database lock */ 1151 KeAcquireGuardedMutex(&SepRmDbLock); 1152 1153 /* Set the callback routine */ 1154 Notification->CallbackRoutine = CallbackRoutine; 1155 1156 /* Insert the new notification item into the list */ 1157 Notification->Next = SepLogonNotifications; 1158 SepLogonNotifications = Notification; 1159 1160 /* Release the database lock */ 1161 KeReleaseGuardedMutex(&SepRmDbLock); 1162 1163 return STATUS_SUCCESS; 1164 } 1165 1166 1167 /* 1168 * @implemented 1169 */ 1170 NTSTATUS 1171 NTAPI 1172 SeUnregisterLogonSessionTerminatedRoutine( 1173 IN PSE_LOGON_SESSION_TERMINATED_ROUTINE CallbackRoutine) 1174 { 1175 PSEP_LOGON_SESSION_TERMINATED_NOTIFICATION Current, Previous = NULL; 1176 NTSTATUS Status; 1177 PAGED_CODE(); 1178 1179 /* Fail, if we don not have a callback routine */ 1180 if (CallbackRoutine == NULL) 1181 return STATUS_INVALID_PARAMETER; 1182 1183 /* Acquire the database lock */ 1184 KeAcquireGuardedMutex(&SepRmDbLock); 1185 1186 /* Loop all registered notification items */ 1187 for (Current = SepLogonNotifications; 1188 Current != NULL; 1189 Current = Current->Next) 1190 { 1191 /* Check if the callback routine matches the provided one */ 1192 if (Current->CallbackRoutine == CallbackRoutine) 1193 break; 1194 1195 Previous = Current; 1196 } 1197 1198 if (Current == NULL) 1199 { 1200 Status = STATUS_NOT_FOUND; 1201 } 1202 else 1203 { 1204 /* Remove the current notification item from the list */ 1205 if (Previous == NULL) 1206 SepLogonNotifications = Current->Next; 1207 else 1208 Previous->Next = Current->Next; 1209 1210 /* Free the current notification item */ 1211 ExFreePoolWithTag(Current, 1212 SEP_LOGON_NOTIFICATION_TAG); 1213 1214 Status = STATUS_SUCCESS; 1215 } 1216 1217 /* Release the database lock */ 1218 KeReleaseGuardedMutex(&SepRmDbLock); 1219 1220 return Status; 1221 } 1222