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 */ 9 10 /* INCLUDES *******************************************************************/ 11 12 #include <ntoskrnl.h> 13 #define NDEBUG 14 #include <debug.h> 15 16 extern LUID SeSystemAuthenticationId; 17 extern LUID SeAnonymousAuthenticationId; 18 19 /* PRIVATE DEFINITIONS ********************************************************/ 20 21 #define SEP_LOGON_SESSION_TAG 'sLeS' 22 23 typedef struct _SEP_LOGON_SESSION_REFERENCES 24 { 25 struct _SEP_LOGON_SESSION_REFERENCES *Next; 26 LUID LogonId; 27 ULONG ReferenceCount; 28 ULONG Flags; 29 PDEVICE_MAP pDeviceMap; 30 LIST_ENTRY TokenList; 31 } SEP_LOGON_SESSION_REFERENCES, *PSEP_LOGON_SESSION_REFERENCES; 32 33 VOID 34 NTAPI 35 SepRmCommandServerThread( 36 PVOID StartContext); 37 38 static 39 NTSTATUS 40 SepRmCreateLogonSession( 41 PLUID LogonLuid); 42 43 44 /* GLOBALS ********************************************************************/ 45 46 HANDLE SeRmCommandPort; 47 HANDLE SeLsaInitEvent; 48 49 PVOID SepCommandPortViewBase; 50 PVOID SepCommandPortViewRemoteBase; 51 ULONG_PTR SepCommandPortViewBaseOffset; 52 53 static HANDLE SepRmCommandMessagePort; 54 55 BOOLEAN SepAdtAuditingEnabled; 56 ULONG SepAdtMinListLength = 0x2000; 57 ULONG SepAdtMaxListLength = 0x3000; 58 59 #define POLICY_AUDIT_EVENT_TYPE_COUNT 9 // (AuditCategoryAccountLogon - AuditCategorySystem + 1) 60 UCHAR SeAuditingState[POLICY_AUDIT_EVENT_TYPE_COUNT]; 61 62 KGUARDED_MUTEX SepRmDbLock; 63 PSEP_LOGON_SESSION_REFERENCES SepLogonSessions; 64 65 66 /* PRIVATE FUNCTIONS **********************************************************/ 67 68 NTSTATUS 69 NTAPI 70 SepRegQueryHelper( 71 PCWSTR KeyName, 72 PCWSTR ValueName, 73 ULONG ValueType, 74 ULONG DataLength, 75 PVOID ValueData) 76 { 77 UNICODE_STRING ValueNameString; 78 UNICODE_STRING KeyNameString; 79 ULONG ResultLength; 80 OBJECT_ATTRIBUTES ObjectAttributes; 81 HANDLE KeyHandle = NULL; 82 struct 83 { 84 KEY_VALUE_PARTIAL_INFORMATION Partial; 85 UCHAR Buffer[64]; 86 } KeyValueInformation; 87 NTSTATUS Status, CloseStatus; 88 PAGED_CODE(); 89 90 RtlInitUnicodeString(&KeyNameString, KeyName); 91 InitializeObjectAttributes(&ObjectAttributes, 92 &KeyNameString, 93 OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, 94 NULL, 95 NULL); 96 97 Status = ZwOpenKey(&KeyHandle, KEY_QUERY_VALUE, &ObjectAttributes); 98 if (!NT_SUCCESS(Status)) 99 { 100 return Status; 101 } 102 103 RtlInitUnicodeString(&ValueNameString, ValueName); 104 Status = ZwQueryValueKey(KeyHandle, 105 &ValueNameString, 106 KeyValuePartialInformation, 107 &KeyValueInformation.Partial, 108 sizeof(KeyValueInformation), 109 &ResultLength); 110 if (!NT_SUCCESS(Status)) 111 { 112 goto Cleanup; 113 } 114 115 if ((KeyValueInformation.Partial.Type != ValueType) || 116 (KeyValueInformation.Partial.DataLength != DataLength)) 117 { 118 Status = STATUS_OBJECT_TYPE_MISMATCH; 119 goto Cleanup; 120 } 121 122 123 if (ValueType == REG_BINARY) 124 { 125 RtlCopyMemory(ValueData, KeyValueInformation.Partial.Data, DataLength); 126 } 127 else if (ValueType == REG_DWORD) 128 { 129 *(PULONG)ValueData = *(PULONG)KeyValueInformation.Partial.Data; 130 } 131 else 132 { 133 Status = STATUS_INVALID_PARAMETER; 134 } 135 136 Cleanup: 137 CloseStatus = ZwClose(KeyHandle); 138 ASSERT(NT_SUCCESS( CloseStatus )); 139 140 return Status; 141 } 142 143 144 BOOLEAN 145 NTAPI 146 SeRmInitPhase0(VOID) 147 { 148 NTSTATUS Status; 149 150 /* Initialize the database lock */ 151 KeInitializeGuardedMutex(&SepRmDbLock); 152 153 /* Create the system logon session */ 154 Status = SepRmCreateLogonSession(&SeSystemAuthenticationId); 155 if (!NT_VERIFY(NT_SUCCESS(Status))) 156 { 157 return FALSE; 158 } 159 160 /* Create the anonymous logon session */ 161 Status = SepRmCreateLogonSession(&SeAnonymousAuthenticationId); 162 if (!NT_VERIFY(NT_SUCCESS(Status))) 163 { 164 return FALSE; 165 } 166 167 return TRUE; 168 } 169 170 171 BOOLEAN 172 NTAPI 173 SeRmInitPhase1(VOID) 174 { 175 UNICODE_STRING Name; 176 OBJECT_ATTRIBUTES ObjectAttributes; 177 HANDLE ThreadHandle; 178 NTSTATUS Status; 179 180 /* Create the SeRm command port */ 181 RtlInitUnicodeString(&Name, L"\\SeRmCommandPort"); 182 InitializeObjectAttributes(&ObjectAttributes, &Name, 0, NULL, NULL); 183 Status = ZwCreatePort(&SeRmCommandPort, 184 &ObjectAttributes, 185 sizeof(ULONG), 186 PORT_MAXIMUM_MESSAGE_LENGTH, 187 2 * PAGE_SIZE); 188 if (!NT_SUCCESS(Status)) 189 { 190 DPRINT1("Security: Rm Create Command Port failed 0x%lx\n", Status); 191 return FALSE; 192 } 193 194 /* Create SeLsaInitEvent */ 195 RtlInitUnicodeString(&Name, L"\\SeLsaInitEvent"); 196 InitializeObjectAttributes(&ObjectAttributes, &Name, 0, NULL, NULL); 197 Status = ZwCreateEvent(&SeLsaInitEvent, 198 GENERIC_WRITE, 199 &ObjectAttributes, 200 NotificationEvent, 201 FALSE); 202 if (!NT_VERIFY((NT_SUCCESS(Status)))) 203 { 204 DPRINT1("Security: LSA init event creation failed.0x%xl\n", Status); 205 return FALSE; 206 } 207 208 /* Create the SeRm server thread */ 209 Status = PsCreateSystemThread(&ThreadHandle, 210 THREAD_ALL_ACCESS, 211 NULL, 212 NULL, 213 NULL, 214 SepRmCommandServerThread, 215 NULL); 216 if (!NT_SUCCESS(Status)) 217 { 218 DPRINT1("Security: Rm Server Thread creation failed 0x%lx\n", Status); 219 return FALSE; 220 } 221 222 ObCloseHandle(ThreadHandle, KernelMode); 223 224 return TRUE; 225 } 226 227 static 228 VOID 229 SepAdtInitializeBounds(VOID) 230 { 231 struct 232 { 233 ULONG MaxLength; 234 ULONG MinLength; 235 } ListBounds; 236 NTSTATUS Status; 237 PAGED_CODE(); 238 239 Status = SepRegQueryHelper(L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Lsa", 240 L"Bounds", 241 REG_BINARY, 242 sizeof(ListBounds), 243 &ListBounds); 244 if (!NT_SUCCESS(Status)) 245 { 246 /* No registry values, so keep hardcoded defaults */ 247 return; 248 } 249 250 /* Check if the bounds are valid */ 251 if ((ListBounds.MaxLength < ListBounds.MinLength) || 252 (ListBounds.MinLength < 16) || 253 (ListBounds.MaxLength - ListBounds.MinLength < 16)) 254 { 255 DPRINT1("ListBounds are invalid: %u, %u\n", 256 ListBounds.MinLength, ListBounds.MaxLength); 257 return; 258 } 259 260 /* Set the new bounds globally */ 261 SepAdtMinListLength = ListBounds.MinLength; 262 SepAdtMaxListLength = ListBounds.MaxLength; 263 } 264 265 266 static 267 NTSTATUS 268 SepRmSetAuditEvent( 269 PSEP_RM_API_MESSAGE Message) 270 { 271 ULONG i; 272 PAGED_CODE(); 273 274 /* First re-initialize the bounds from the registry */ 275 SepAdtInitializeBounds(); 276 277 /* Make sure we have the right message and clear */ 278 ASSERT(Message->ApiNumber == RmAuditSetCommand); 279 Message->ApiNumber = 0; 280 281 /* Store the enable flag in the global variable */ 282 SepAdtAuditingEnabled = Message->u.SetAuditEvent.Enabled; 283 284 /* Loop all audit event types */ 285 for (i = 0; i < POLICY_AUDIT_EVENT_TYPE_COUNT; i++) 286 { 287 /* Save the provided flags in the global array */ 288 SeAuditingState[i] = (UCHAR)Message->u.SetAuditEvent.Flags[i]; 289 } 290 291 return STATUS_SUCCESS; 292 } 293 294 295 static 296 NTSTATUS 297 SepRmCreateLogonSession( 298 PLUID LogonLuid) 299 { 300 PSEP_LOGON_SESSION_REFERENCES CurrentSession, NewSession; 301 NTSTATUS Status; 302 PAGED_CODE(); 303 304 DPRINT("SepRmCreateLogonSession(%08lx:%08lx)\n", 305 LogonLuid->HighPart, LogonLuid->LowPart); 306 307 /* Allocate a new session structure */ 308 NewSession = ExAllocatePoolWithTag(PagedPool, 309 sizeof(SEP_LOGON_SESSION_REFERENCES), 310 SEP_LOGON_SESSION_TAG); 311 if (NewSession == NULL) 312 { 313 return STATUS_INSUFFICIENT_RESOURCES; 314 } 315 316 /* Initialize it */ 317 NewSession->LogonId = *LogonLuid; 318 NewSession->ReferenceCount = 0; 319 NewSession->Flags = 0; 320 NewSession->pDeviceMap = NULL; 321 InitializeListHead(&NewSession->TokenList); 322 323 /* Acquire the database lock */ 324 KeAcquireGuardedMutex(&SepRmDbLock); 325 326 /* Loop all existing sessions */ 327 for (CurrentSession = SepLogonSessions; 328 CurrentSession != NULL; 329 CurrentSession = CurrentSession->Next) 330 { 331 /* Check if the LUID matches the new one */ 332 if (RtlEqualLuid(&CurrentSession->LogonId, LogonLuid)) 333 { 334 Status = STATUS_LOGON_SESSION_EXISTS; 335 goto Leave; 336 } 337 } 338 339 /* Insert the new session */ 340 NewSession->Next = SepLogonSessions; 341 SepLogonSessions = NewSession; 342 343 Status = STATUS_SUCCESS; 344 345 Leave: 346 /* Release the database lock */ 347 KeReleaseGuardedMutex(&SepRmDbLock); 348 349 if (!NT_SUCCESS(Status)) 350 { 351 ExFreePoolWithTag(NewSession, SEP_LOGON_SESSION_TAG); 352 } 353 354 return Status; 355 } 356 357 static 358 NTSTATUS 359 SepRmDeleteLogonSession( 360 PLUID LogonLuid) 361 { 362 DPRINT("SepRmDeleteLogonSession(%08lx:%08lx)\n", 363 LogonLuid->HighPart, LogonLuid->LowPart); 364 365 UNIMPLEMENTED; 366 NT_ASSERT(FALSE); 367 return STATUS_NOT_IMPLEMENTED; 368 } 369 370 371 NTSTATUS 372 SepRmReferenceLogonSession( 373 PLUID LogonLuid) 374 { 375 PSEP_LOGON_SESSION_REFERENCES CurrentSession; 376 377 PAGED_CODE(); 378 379 DPRINT("SepRmReferenceLogonSession(%08lx:%08lx)\n", 380 LogonLuid->HighPart, LogonLuid->LowPart); 381 382 /* Acquire the database lock */ 383 KeAcquireGuardedMutex(&SepRmDbLock); 384 385 /* Loop all existing sessions */ 386 for (CurrentSession = SepLogonSessions; 387 CurrentSession != NULL; 388 CurrentSession = CurrentSession->Next) 389 { 390 /* Check if the LUID matches the new one */ 391 if (RtlEqualLuid(&CurrentSession->LogonId, LogonLuid)) 392 { 393 /* Reference the session */ 394 CurrentSession->ReferenceCount += 1; 395 DPRINT("ReferenceCount: %lu\n", CurrentSession->ReferenceCount); 396 397 /* Release the database lock */ 398 KeReleaseGuardedMutex(&SepRmDbLock); 399 400 return STATUS_SUCCESS; 401 } 402 } 403 404 /* Release the database lock */ 405 KeReleaseGuardedMutex(&SepRmDbLock); 406 407 return STATUS_NO_SUCH_LOGON_SESSION; 408 } 409 410 411 NTSTATUS 412 SepRmDereferenceLogonSession( 413 PLUID LogonLuid) 414 { 415 PSEP_LOGON_SESSION_REFERENCES CurrentSession; 416 417 DPRINT("SepRmDereferenceLogonSession(%08lx:%08lx)\n", 418 LogonLuid->HighPart, LogonLuid->LowPart); 419 420 /* Acquire the database lock */ 421 KeAcquireGuardedMutex(&SepRmDbLock); 422 423 /* Loop all existing sessions */ 424 for (CurrentSession = SepLogonSessions; 425 CurrentSession != NULL; 426 CurrentSession = CurrentSession->Next) 427 { 428 /* Check if the LUID matches the new one */ 429 if (RtlEqualLuid(&CurrentSession->LogonId, LogonLuid)) 430 { 431 /* Dereference the session */ 432 CurrentSession->ReferenceCount -= 1; 433 DPRINT("ReferenceCount: %lu\n", CurrentSession->ReferenceCount); 434 435 /* Release the database lock */ 436 KeReleaseGuardedMutex(&SepRmDbLock); 437 438 return STATUS_SUCCESS; 439 } 440 } 441 442 /* Release the database lock */ 443 KeReleaseGuardedMutex(&SepRmDbLock); 444 445 return STATUS_NO_SUCH_LOGON_SESSION; 446 } 447 448 449 BOOLEAN 450 NTAPI 451 SepRmCommandServerThreadInit(VOID) 452 { 453 SECURITY_QUALITY_OF_SERVICE SecurityQos; 454 SEP_RM_API_MESSAGE Message; 455 UNICODE_STRING PortName; 456 REMOTE_PORT_VIEW RemotePortView; 457 PORT_VIEW PortView; 458 LARGE_INTEGER SectionSize; 459 HANDLE SectionHandle; 460 HANDLE PortHandle; 461 NTSTATUS Status; 462 BOOLEAN Result; 463 464 SectionHandle = NULL; 465 PortHandle = NULL; 466 467 /* Assume success */ 468 Result = TRUE; 469 470 /* Wait until LSASS is ready */ 471 Status = ZwWaitForSingleObject(SeLsaInitEvent, FALSE, NULL); 472 if (!NT_SUCCESS(Status)) 473 { 474 DPRINT1("Security Rm Init: Waiting for LSA Init Event failed 0x%lx\n", Status); 475 goto Cleanup; 476 } 477 478 /* We don't need this event anymore */ 479 ObCloseHandle(SeLsaInitEvent, KernelMode); 480 481 /* Initialize the connection message */ 482 Message.Header.u1.s1.TotalLength = sizeof(Message); 483 Message.Header.u1.s1.DataLength = 0; 484 485 /* Only LSASS can connect, so handle the connection right now */ 486 Status = ZwListenPort(SeRmCommandPort, &Message.Header); 487 if (!NT_SUCCESS(Status)) 488 { 489 DPRINT1("Security Rm Init: Listen to Command Port failed 0x%lx\n", Status); 490 goto Cleanup; 491 } 492 493 /* Set the Port View structure length */ 494 RemotePortView.Length = sizeof(RemotePortView); 495 496 /* Accept the connection */ 497 Status = ZwAcceptConnectPort(&SepRmCommandMessagePort, 498 NULL, 499 &Message.Header, 500 TRUE, 501 NULL, 502 &RemotePortView); 503 if (!NT_SUCCESS(Status)) 504 { 505 DPRINT1("Security Rm Init: Accept Connect to Command Port failed 0x%lx\n", Status); 506 goto Cleanup; 507 } 508 509 /* Complete the connection */ 510 Status = ZwCompleteConnectPort(SepRmCommandMessagePort); 511 if (!NT_SUCCESS(Status)) 512 { 513 DPRINT1("Security Rm Init: Complete Connect to Command Port failed 0x%lx\n", Status); 514 goto Cleanup; 515 } 516 517 /* Create a section for messages */ 518 SectionSize.QuadPart = PAGE_SIZE; 519 Status = ZwCreateSection(&SectionHandle, 520 SECTION_ALL_ACCESS, 521 NULL, 522 &SectionSize, 523 PAGE_READWRITE, 524 SEC_COMMIT, 525 NULL); 526 if (!NT_SUCCESS(Status)) 527 { 528 DPRINT1("Security Rm Init: Create Memory Section for LSA port failed: %X\n", Status); 529 goto Cleanup; 530 } 531 532 /* Setup the PORT_VIEW structure */ 533 PortView.Length = sizeof(PortView); 534 PortView.SectionHandle = SectionHandle; 535 PortView.SectionOffset = 0; 536 PortView.ViewSize = SectionSize.LowPart; 537 PortView.ViewBase = NULL; 538 PortView.ViewRemoteBase = NULL; 539 540 /* Setup security QOS */ 541 SecurityQos.Length = sizeof(SecurityQos); 542 SecurityQos.ImpersonationLevel = SecurityImpersonation; 543 SecurityQos.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING; 544 SecurityQos.EffectiveOnly = TRUE; 545 546 /* Connect to LSASS */ 547 RtlInitUnicodeString(&PortName, L"\\SeLsaCommandPort"); 548 Status = ZwConnectPort(&PortHandle, 549 &PortName, 550 &SecurityQos, 551 &PortView, 552 NULL, 553 0, 554 0, 555 0); 556 if (!NT_SUCCESS(Status)) 557 { 558 DPRINT1("Security Rm Init: Connect to LSA Port failed 0x%lx\n", Status); 559 goto Cleanup; 560 } 561 562 /* Remember section base and view offset */ 563 SepCommandPortViewBase = PortView.ViewBase; 564 SepCommandPortViewRemoteBase = PortView.ViewRemoteBase; 565 SepCommandPortViewBaseOffset = (ULONG_PTR)SepCommandPortViewRemoteBase - 566 (ULONG_PTR)SepCommandPortViewBase; 567 568 DPRINT("SepRmCommandServerThreadInit: done\n"); 569 570 Cleanup: 571 /* Check for failure */ 572 if (!NT_SUCCESS(Status)) 573 { 574 if (PortHandle != NULL) 575 { 576 ObCloseHandle(PortHandle, KernelMode); 577 } 578 579 Result = FALSE; 580 } 581 582 /* Did we create a section? */ 583 if (SectionHandle != NULL) 584 { 585 ObCloseHandle(SectionHandle, KernelMode); 586 } 587 588 return Result; 589 } 590 591 VOID 592 NTAPI 593 SepRmCommandServerThread( 594 PVOID StartContext) 595 { 596 SEP_RM_API_MESSAGE Message; 597 PPORT_MESSAGE ReplyMessage; 598 HANDLE DummyPortHandle; 599 NTSTATUS Status; 600 601 /* Initialize the server thread */ 602 if (!SepRmCommandServerThreadInit()) 603 { 604 DPRINT1("Security: Terminating Rm Command Server Thread\n"); 605 return; 606 } 607 608 /* No reply yet */ 609 ReplyMessage = NULL; 610 611 /* Start looping */ 612 while (TRUE) 613 { 614 /* Wait for a message */ 615 Status = ZwReplyWaitReceivePort(SepRmCommandMessagePort, 616 NULL, 617 ReplyMessage, 618 &Message.Header); 619 if (!NT_SUCCESS(Status)) 620 { 621 DPRINT1("Failed to get message: 0x%lx", Status); 622 ReplyMessage = NULL; 623 continue; 624 } 625 626 /* Check if this is a connection request */ 627 if (Message.Header.u2.s2.Type == LPC_CONNECTION_REQUEST) 628 { 629 /* Reject connection request */ 630 ZwAcceptConnectPort(&DummyPortHandle, 631 NULL, 632 &Message.Header, 633 FALSE, 634 NULL, 635 NULL); 636 637 /* Start over */ 638 ReplyMessage = NULL; 639 continue; 640 } 641 642 /* Check if the port died */ 643 if ((Message.Header.u2.s2.Type == LPC_PORT_CLOSED) || 644 (Message.Header.u2.s2.Type == LPC_CLIENT_DIED)) 645 { 646 /* LSASS is dead, so let's quit as well */ 647 break; 648 } 649 650 /* Check if this is an actual request */ 651 if (Message.Header.u2.s2.Type != LPC_REQUEST) 652 { 653 DPRINT1("SepRmCommandServerThread: unexpected message type: 0x%lx\n", 654 Message.Header.u2.s2.Type); 655 656 /* Restart without replying */ 657 ReplyMessage = NULL; 658 continue; 659 } 660 661 ReplyMessage = &Message.Header; 662 663 switch (Message.ApiNumber) 664 { 665 case RmAuditSetCommand: 666 Status = SepRmSetAuditEvent(&Message); 667 break; 668 669 case RmCreateLogonSession: 670 Status = SepRmCreateLogonSession(&Message.u.LogonLuid); 671 break; 672 673 case RmDeleteLogonSession: 674 Status = SepRmDeleteLogonSession(&Message.u.LogonLuid); 675 break; 676 677 default: 678 DPRINT1("SepRmDispatchRequest: invalid API number: 0x%lx\n", 679 Message.ApiNumber); 680 ReplyMessage = NULL; 681 } 682 683 Message.u.ResultStatus = Status; 684 } 685 686 /* Close the port handles */ 687 ObCloseHandle(SepRmCommandMessagePort, KernelMode); 688 ObCloseHandle(SeRmCommandPort, KernelMode); 689 } 690 691 692 /* PUBLIC FUNCTIONS ***********************************************************/ 693 694 /* 695 * @unimplemented 696 */ 697 NTSTATUS 698 NTAPI 699 SeMarkLogonSessionForTerminationNotification( 700 IN PLUID LogonId) 701 { 702 UNIMPLEMENTED; 703 return STATUS_NOT_IMPLEMENTED; 704 } 705 706 707 /* 708 * @unimplemented 709 */ 710 NTSTATUS 711 NTAPI 712 SeRegisterLogonSessionTerminatedRoutine( 713 IN PSE_LOGON_SESSION_TERMINATED_ROUTINE CallbackRoutine) 714 { 715 UNIMPLEMENTED; 716 return STATUS_NOT_IMPLEMENTED; 717 } 718 719 720 /* 721 * @unimplemented 722 */ 723 NTSTATUS 724 NTAPI 725 SeUnregisterLogonSessionTerminatedRoutine( 726 IN PSE_LOGON_SESSION_TERMINATED_ROUTINE CallbackRoutine) 727 { 728 UNIMPLEMENTED; 729 return STATUS_NOT_IMPLEMENTED; 730 } 731